1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16importScripts('trace_streamer_builtin.js');
17import { execProtoForWorker } from './data-trafic/utils/ExecProtoForWorker';
18import { QueryEnum, TraficEnum } from './data-trafic/utils/QueryEnum';
19// @ts-ignore
20import { temp_init_sql_list } from './TempSql';
21// @ts-ignore
22import { BatchSphData } from '../proto/SphBaseData';
23
24enum TsLogLevel {
25  DEBUG = 0,
26  INFO = 1,
27  WARN = 2,
28  ERROR = 3,
29  FATAL = 4,
30  OFF = 5,
31}
32
33let wasmModule: unknown = null;
34let enc = new TextEncoder();
35let dec = new TextDecoder();
36let arr: Uint8Array | undefined;
37const REQ_BUF_SIZE = 4 * 1024 * 1024;
38let reqBufferAddr: number = -1;
39let bufferSlice: Array<Uint8Array> = [];
40let headUnitArray: Uint8Array | undefined;
41let thirdWasmMap = new Map();
42let thirdJsonResult = new Map();
43
44const CONTENT_TYPE_CMDLINES = 2;
45const CONTENT_TYPE_TGIDS = 3;
46const CONTENT_TYPE_HEADER_PAGE = 30;
47const CONTENT_TYPE_PRINTK_FORMATS = 31;
48const CONTENT_TYPE_KALLSYMS = 32;
49
50let arkTsData: Array<Uint8Array> = [];
51let arkTsDataSize: number = 0;
52
53let currentAction: string = '';
54let currentActionId: string = '';
55let ffrtFileCacheKey = '-1';
56let indexDB: IDBDatabase;
57const maxSize = 48 * 1024 * 1024;
58const currentTSLogLevel = TsLogLevel.OFF;
59//@ts-ignore
60let protoDataMap: Map<QueryEnum, BatchSphData> = new Map<QueryEnum, BatchSphData>();
61function clear(): void {
62  if (wasmModule !== null) {
63    //@ts-ignore
64    wasmModule._TraceStreamerReset();
65    wasmModule = null;
66  }
67  if (arr) {
68    arr = undefined;
69  }
70  if (headUnitArray) {
71    headUnitArray = undefined;
72  }
73  if (bufferSlice) {
74    bufferSlice.length = 0;
75  }
76  thirdWasmMap.clear();
77  thirdJsonResult.clear();
78}
79
80self.addEventListener('unhandledrejection', (err) => {
81  self.postMessage({
82    id: currentActionId,
83    action: currentAction,
84    init: false,
85    status: false,
86    msg: err.reason.message,
87  });
88});
89
90function initWASM(): Promise<unknown> {
91  return new Promise((resolve, reject) => {
92    //@ts-ignore
93    let wasm = trace_streamer_builtin_wasm;
94    wasmModule = wasm({
95      locateFile: (s: unknown) => {
96        return s;
97      },
98      print: (line: string) => {
99        if (currentTSLogLevel < TsLogLevel.OFF) {
100          console.log(line);
101        }
102      },
103      printErr: (line: string) => {
104        if (currentTSLogLevel < TsLogLevel.OFF) {
105          console.error(line);
106        }
107      },
108      onRuntimeInitialized: () => {
109        resolve('ok');
110      },
111      onAbort: () => {
112        reject('on abort');
113      },
114    });
115  });
116}
117
118function initThirdWASM(wasmFunctionName: string): unknown {
119  function callModelFun(functionName: string): unknown {
120    let func = eval(functionName);
121    return new func({
122      locateFile: (s: unknown): unknown => {
123        return s;
124      },
125      print: (line: string): void => {
126        if (currentTSLogLevel < TsLogLevel.OFF) {
127          console.log(line);
128        }
129      },
130      printErr: (line: string): void => {
131        if (currentTSLogLevel < TsLogLevel.OFF) {
132          console.error(line);
133        }
134      },
135      onRuntimeInitialized: (): void => { },
136      onAbort: (): void => { },
137    });
138  }
139
140  return callModelFun(wasmFunctionName);
141}
142
143let merged = (): Uint8Array => {
144  let length = 0;
145  bufferSlice.forEach((item) => {
146    //@ts-ignore
147    length += item.length;
148  });
149  let mergedArray = new Uint8Array(length);
150  let offset = 0;
151  bufferSlice.forEach((item) => {
152    //@ts-ignore
153    mergedArray.set(item, offset);
154    //@ts-ignore
155    offset += item.length;
156  });
157  return mergedArray;
158};
159
160let translateJsonString = (str: string): string => {
161  return str //   .padding
162    .replace(/[\t|\r|\n]/g, '');
163};
164
165let convertJSON = (): unknown[] => {
166  try {
167    let str = dec.decode(arr);
168    let jsonArray: Array<unknown> = [];
169    str = str.substring(str.indexOf('\n') + 1);
170    if (!str) {
171    } else {
172      let parse;
173      let tansStr: string;
174      try {
175        tansStr = str.replace(/[\t\r\n]/g, '');
176        parse = JSON.parse(tansStr);
177      } catch {
178        try {
179          tansStr = tansStr!.replace(/[^\x20-\x7E]/g, '?'); //匹配乱码字 符,将其转换为?
180          parse = JSON.parse(tansStr);
181        } catch {
182          tansStr = tansStr!.replace(/\\/g, '\\\\');
183          parse = JSON.parse(tansStr);
184        }
185      }
186      let columns = parse.columns;
187      let values = parse.values;
188      for (let i = 0; i < values.length; i++) {
189        let obj: unknown = {};
190        for (let j = 0; j < columns.length; j++) {
191          //@ts-ignore
192          obj[columns[j]] = values[i][j];
193        }
194        jsonArray.push(obj);
195      }
196    }
197    return jsonArray;
198  } catch (e) {
199    self.postMessage({
200      id: currentActionId,
201      action: currentAction,
202      init: false,
203      status: false,
204      //@ts-ignore
205      msg: e.message,
206    });
207    return [];
208  }
209};
210
211/**
212 * 计算预留缓存空间,如果空间不够,则删除部分缓存
213 * @param size
214 */
215function saveTraceFileBuffer(key: string, buffer: ArrayBuffer): void {
216  obligateFileBufferSpace(buffer.byteLength).then(() => {
217    caches.open(key).then((cache) => {
218      let headers = new Headers();
219      headers.append('Content-Length', `${buffer.byteLength}`);
220      headers.append('Content-Type', 'application/octet-stream');
221      cache
222        .put(
223          key,
224          new Response(buffer, {
225            status: 200,
226            headers: headers,
227          })
228        )
229        .then();
230    });
231  });
232}
233
234async function obligateFileBufferSpace(size: number): Promise<void> {
235  let es = await navigator.storage.estimate();
236  let remainderByte = (es.quota || 0) - (es.usage || 0) - 20 * 1024 * 1024;
237  if (remainderByte < size) {
238    let keys = await caches.keys();
239    keys.sort((keyA, keyB) => {
240      if (keyA.includes('/') && keyB.includes('/')) {
241        let splitA = keyA.split('/');
242        let splitB = keyB.split('/');
243        let timeA = splitA[splitA.length - 1].split('-')[0];
244        let timeB = splitB[splitB.length - 1].split('-')[0];
245        return parseInt(timeA) - parseInt(timeB);
246      } else {
247        return 0;
248      }
249    });
250    let needSize = size - remainderByte;
251    for (let key of keys) {
252      await caches.delete(key);
253      let keySize = parseInt(key.split('-')[1]);
254      if (keySize > needSize) {
255        return;
256      } else {
257        needSize -= keySize;
258      }
259    }
260  }
261}
262
263async function onmessageByOpenAction(e: MessageEvent): Promise<void> {
264  await initWASM();
265  ffrtFileCacheKey = '-1';
266  // @ts-ignore
267  self.postMessage({
268    id: e.data.id,
269    action: e.data.action,
270    ready: true,
271    index: 0,
272  });
273  let uint8Array = new Uint8Array(e.data.buffer);
274  initModuleCallBackAndFun();
275  parseThirdWasmByOpenAction(e);
276  let wrSize = 0;
277  let r2 = -1;
278  if (isRawTrace(e.data)) {
279    r2 = parseRawTraceByOpenAction(e, wrSize, r2, uint8Array);
280  } else {
281    r2 = parseNormalTraceByOpenAction(wrSize, r2, uint8Array);
282  }
283  //@ts-ignore
284  wasmModule._TraceStreamerParseDataOver();
285  for (let value of thirdWasmMap.values()) {
286    value.model._TraceStreamerInParseDataOver();
287  }
288  postMessageByOpenAction(r2, e);
289}
290
291function initModuleCallBackAndFun(): void {
292  let callback = (heapPtr: number, size: number, isEnd: number): void => {
293    //@ts-ignore
294    let out: Uint8Array = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
295    bufferSlice.push(out);
296    if (isEnd === 1) {
297      arr = merged();
298      bufferSlice.length = 0;
299    }
300  };
301  let ffrtConvertCallback = (heapPtr: number, size: number, isEnd: number): void => {
302    if (isEnd !== 1) {
303      //@ts-ignore
304      let out: Uint8Array = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
305      bufferSlice.push(out);
306    } else {
307      arr = merged();
308      bufferSlice.length = 0;
309      ffrtFileCacheKey = `ffrt/${new Date().getTime()}-${arr.buffer.byteLength}`;
310      saveTraceFileBuffer(ffrtFileCacheKey, arr.buffer);
311    }
312  };
313  let tlvResultCallback = (heapPtr: number, size: number, type: number, isEnd: number): void => {
314    //@ts-ignore
315    let out: Uint8Array = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
316    protoDataMap.set(type, BatchSphData.decode(out).values);
317  };
318  //@ts-ignore
319  let fn1 = wasmModule.addFunction(callback, 'viii');
320  //@ts-ignore
321  let fn2 = wasmModule.addFunction(ffrtConvertCallback, 'viii');
322  //@ts-ignore
323  let tlvResultFun = wasmModule.addFunction(tlvResultCallback, 'viiii');
324  //@ts-ignore
325  wasmModule._TraceStreamerSetLogLevel(currentTSLogLevel);
326  //@ts-ignore
327  reqBufferAddr = wasmModule._Initialize(REQ_BUF_SIZE, fn1, tlvResultFun, fn2);
328}
329
330function parseThirdWasmByOpenAction(e: MessageEvent): void {
331  let parseConfig = e.data.parseConfig;
332  if (parseConfig !== '') {
333    let parseConfigArray = enc.encode(parseConfig);
334    //@ts-ignore
335    let parseConfigAddr = wasmModule._InitializeParseConfig(1024);
336    //@ts-ignore
337    wasmModule.HEAPU8.set(parseConfigArray, parseConfigAddr);
338    //@ts-ignore
339    wasmModule._TraceStreamerParserConfigEx(parseConfigArray.length);
340  }
341  let wasmConfigStr = e.data.wasmConfig;
342  if (wasmConfigStr !== '' && wasmConfigStr.indexOf('WasmFiles') !== -1) {
343    let wasmConfig = JSON.parse(wasmConfigStr);
344    let wasmConfigs = wasmConfig.WasmFiles;
345    let itemArray = wasmConfigs.map((item: unknown) => {
346      //@ts-ignore
347      return item.componentId + ';' + item.pluginName;
348    });
349    let thirdWasmStr: string = itemArray.join(';');
350    let configUintArray = enc.encode(thirdWasmStr + ';');
351    //@ts-ignore
352    wasmModule.HEAPU8.set(configUintArray, reqBufferAddr);
353    //@ts-ignore
354    wasmModule._TraceStreamerInitThirdPartyConfig(configUintArray.length);
355    let first = true;
356    let sendDataCallback = (heapPtr: number, size: number, componentID: number): void => {
357      if (componentID === 100) {
358        if (first) {
359          first = false;
360          //@ts-ignore
361          headUnitArray = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
362        }
363        return;
364      }
365      let configs = wasmConfigs.filter((wasmConfig: unknown) => {
366        //@ts-ignore
367        return wasmConfig.componentId === componentID;
368      });
369      if (configs.length > 0) {
370        let config = configs[0];
371        let model = thirdWasmMap.get(componentID);
372        if (!model && config.componentId === componentID) {
373          importScripts(config.wasmJsName);
374          setThirdWasmMap(config, heapPtr, size, componentID);
375        } else {
376          let mm = model.model;
377          //@ts-ignore
378          let out: Uint8Array = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
379          mm.HEAPU8.set(out, model.bufferAddr);
380          mm._ParserData(out.length, componentID);
381        }
382      }
383    };
384    //@ts-ignore
385    let fn1 = wasmModule.addFunction(sendDataCallback, 'viii');
386    //@ts-ignore
387    wasmModule._TraceStreamerSetThirdPartyDataDealer(fn1, REQ_BUF_SIZE);
388  }
389}
390
391function isCommonData(dataType: number): boolean {
392  return (
393    dataType === CONTENT_TYPE_CMDLINES ||
394    dataType === CONTENT_TYPE_TGIDS ||
395    dataType === CONTENT_TYPE_HEADER_PAGE ||
396    dataType === CONTENT_TYPE_PRINTK_FORMATS ||
397    dataType === CONTENT_TYPE_KALLSYMS
398  );
399}
400
401function parseRawTraceByOpenAction(e: MessageEvent, wrSize: number, r2: number, uint8Array: Uint8Array): number {
402  let commonDataOffsetList: Array<{ startOffset: number; endOffset: number }> = []; // common Data
403  let offset = 12;
404  let tlvTypeLength = 4;
405  let headArray = uint8Array.slice(0, offset);
406  let commonTotalLength = 0;
407  while (offset < uint8Array.length) {
408    let commonDataOffset = { startOffset: offset, endOffset: offset };
409    let dataTypeData = e.data.buffer.slice(offset, offset + tlvTypeLength);
410    offset += tlvTypeLength;
411    let dataType = Array.from(new Uint32Array(dataTypeData));
412    let currentLData = e.data.buffer.slice(offset, offset + tlvTypeLength);
413    offset += tlvTypeLength;
414    let currentVLength = Array.from(new Uint32Array(currentLData));
415    offset += currentVLength[0];
416    commonDataOffset.endOffset = offset;
417    if (isCommonData(dataType[0])) {
418      commonTotalLength += commonDataOffset.endOffset - commonDataOffset.startOffset;
419      commonDataOffsetList.push(commonDataOffset);
420    }
421  }
422  let frontData = new Uint8Array(headArray.byteLength + commonTotalLength); // HeadArray
423  frontData.set(headArray, 0);
424  let lengthOffset = headArray.byteLength;
425  commonDataOffsetList.forEach((item) => {
426    let commonData = uint8Array.slice(item.startOffset, item.endOffset);
427    frontData.set(commonData, lengthOffset);
428    lengthOffset += commonData.byteLength;
429  });
430  let freeData = uint8Array.slice(12);
431  let final = new Uint8Array(frontData.length + freeData.length);
432  final.set(frontData);
433  final.set(freeData, frontData.length);
434  wrSize = 0;
435  while (wrSize < final.length) {
436    const sliceLen = Math.min(final.length - wrSize, REQ_BUF_SIZE);
437    const dataSlice = final.subarray(wrSize, wrSize + sliceLen);
438    //@ts-ignore
439    wasmModule.HEAPU8.set(dataSlice, reqBufferAddr);
440    wrSize += sliceLen;
441    //@ts-ignore
442    r2 = wasmModule._TraceStreamerParseDataEx(sliceLen, wrSize === final.length ? 1 : 0);
443    if (r2 === -1) {
444      break;
445    }
446  }
447  return r2;
448}
449
450function parseNormalTraceByOpenAction(wrSize: number, r2: number, uint8Array: Uint8Array): number {
451  while (wrSize < uint8Array.length) {
452    const sliceLen = Math.min(uint8Array.length - wrSize, REQ_BUF_SIZE);
453    const dataSlice = uint8Array.subarray(wrSize, wrSize + sliceLen);
454    //@ts-ignore
455    wasmModule.HEAPU8.set(dataSlice, reqBufferAddr);
456    wrSize += sliceLen;
457    //@ts-ignore
458    r2 = wasmModule._TraceStreamerParseDataEx(sliceLen, wrSize === uint8Array.length ? 1 : 0);
459    if (r2 === -1) {
460      break;
461    }
462  }
463  return r2;
464}
465
466function setThirdWasmMap(config: unknown, heapPtr: number, size: number, componentID: number): void {
467  //@ts-ignore
468  let thirdMode = initThirdWASM(config.wasmName);
469  //@ts-ignore
470  let configPluginName = config.pluginName;
471  let pluginNameUintArray = enc.encode(configPluginName);
472  //@ts-ignore
473  let pluginNameBuffer = thirdMode._InitPluginName(pluginNameUintArray.length);
474  //@ts-ignore
475  thirdMode.HEAPU8.set(pluginNameUintArray, pluginNameBuffer);
476  //@ts-ignore
477  thirdMode._TraceStreamerGetPluginNameEx(configPluginName.length);
478  let thirdQueryDataCallBack = (heapPtr: number, size: number, isEnd: number, isConfig: number): void => {
479    if (isConfig === 1) {
480      //@ts-ignore
481      let out: Uint8Array = thirdMode.HEAPU8.slice(heapPtr, heapPtr + size);
482      thirdJsonResult.set(componentID, {
483        jsonConfig: dec.decode(out),
484        //@ts-ignore
485        disPlayName: config.disPlayName,
486        //@ts-ignore
487        pluginName: config.pluginName,
488      });
489    } else {
490      //@ts-ignore
491      let out: Uint8Array = thirdMode.HEAPU8.slice(heapPtr, heapPtr + size);
492      bufferSlice.push(out);
493      if (isEnd === 1) {
494        arr = merged();
495        bufferSlice.length = 0;
496      }
497    }
498  };
499  //@ts-ignore
500  let fn = thirdMode.addFunction(thirdQueryDataCallBack, 'viiii');
501  //@ts-ignore
502  let thirdreqBufferAddr = thirdMode._Init(fn, REQ_BUF_SIZE);
503  initTraceRange(thirdMode);
504  //@ts-ignore
505  thirdMode._TraceStreamerInJsonConfig();
506  //@ts-ignore
507  thirdMode.HEAPU8.set(headUnitArray, thirdreqBufferAddr);
508  //@ts-ignore
509  thirdMode._ParserData(headUnitArray!.length, 100);
510  //@ts-ignore
511  let out: Uint8Array = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
512  //@ts-ignore
513  thirdMode.HEAPU8.set(out, thirdreqBufferAddr);
514  //@ts-ignore
515  thirdMode._ParserData(out.length, componentID);
516  thirdWasmMap.set(componentID, {
517    model: thirdMode,
518    bufferAddr: thirdreqBufferAddr,
519  });
520}
521
522function postMessageByOpenAction(r2: number, e: MessageEvent): void {
523  if (r2 === -1) {
524    // @ts-ignore
525    self.postMessage({
526      id: e.data.id,
527      action: e.data.action,
528      init: false,
529      msg: 'parse data error',
530    });
531    return;
532  }
533  // @ts-ignore
534  if (temp_init_sql_list && temp_init_sql_list.length > 0) {
535    // @ts-ignore
536    temp_init_sql_list.forEach((item, index) => {
537      createView(item);
538      // @ts-ignore
539      self.postMessage({ id: e.data.id, ready: true, index: index + 1 });
540    });
541  }
542
543  self.postMessage(
544    {
545      id: e.data.id,
546      action: e.data.action,
547      init: true,
548      msg: 'ok',
549      configSqlMap: thirdJsonResult,
550      buffer: e.data.buffer,
551      fileKey: ffrtFileCacheKey,
552    },
553    // @ts-ignore
554    [e.data.buffer]
555  );
556}
557
558function initTraceRange(thirdMode: unknown): void {
559  let updateTraceTimeCallBack = (heapPtr: number, size: number): void => {
560    //@ts-ignore
561    let out: Uint8Array = thirdMode.HEAPU8.slice(heapPtr, heapPtr + size);
562    //@ts-ignore
563    wasmModule.HEAPU8.set(out, reqBufferAddr);
564    //@ts-ignore
565    wasmModule._UpdateTraceTime(out.length);
566  };
567  //@ts-ignore
568  let traceRangeFn = thirdMode.addFunction(updateTraceTimeCallBack, 'vii');
569  //@ts-ignore
570  thirdMode._InitTraceRange(traceRangeFn, 1024);
571}
572
573function onmessageByExecAction(e: MessageEvent): void {
574  query(e.data.name, e.data.sql, e.data.params);
575  let jsonArray = convertJSON();
576  // @ts-ignore
577  self.postMessage({
578    id: e.data.id,
579    action: e.data.action,
580    results: jsonArray,
581  });
582}
583
584function onmessageByExecProtoAction(e: MessageEvent): void {
585  let typeLength = 4;
586  execProtoForWorker(e.data, (sql: string) => {
587    let sqlUintArray = enc.encode(sql);
588    if (e.data.params.trafic !== TraficEnum.ProtoBuffer) {
589      //@ts-ignore
590      wasmModule.HEAPU8.set(sqlUintArray, reqBufferAddr);
591      //@ts-ignore
592      wasmModule._TraceStreamerSqlQueryEx(sqlUintArray.length);
593      let jsonArray = convertJSON();
594      return jsonArray;
595    } else {
596      let allArray = new Uint8Array(typeLength + sqlUintArray.length);
597      allArray[0] = e.data.name;
598      allArray.set(sqlUintArray, typeLength);
599      //@ts-ignore
600      wasmModule.HEAPU8.set(allArray, reqBufferAddr);
601      //@ts-ignore
602      wasmModule._TraceStreamerSqlQueryToProtoCallback(allArray.length);
603      let finalArrayBuffer = [];
604      if (protoDataMap.has(e.data.name)) {
605        //@ts-ignore
606        finalArrayBuffer = protoDataMap.get(e.data.name);
607        protoDataMap.delete(e.data.name);
608      }
609      return finalArrayBuffer;
610    }
611  });
612}
613
614function onmessageByExecBufAction(e: MessageEvent): void {
615  query(e.data.name, e.data.sql, e.data.params);
616  self.postMessage(
617    { id: e.data.id, action: e.data.action, results: arr!.buffer },
618    // @ts-ignore
619    [arr.buffer]
620  );
621}
622
623function onmessageByExecSdkAction(e: MessageEvent): void {
624  querySdk(e.data.name, e.data.sql, e.data.params, e.data.action);
625  let jsonArray = convertJSON();
626  // @ts-ignore
627  self.postMessage({
628    id: e.data.id,
629    action: e.data.action,
630    results: jsonArray,
631  });
632}
633
634function onmessageByExecMetricAction(e: MessageEvent): void {
635  queryMetric(e.data.sql);
636  let metricResult = dec.decode(arr);
637  // @ts-ignore
638  self.postMessage({
639    id: e.data.id,
640    action: e.data.action,
641    results: metricResult,
642  });
643}
644
645function onmessageByInitPortAction(e: MessageEvent): void {
646  let port = e.ports[0];
647  port.onmessage = (me): void => {
648    query(me.data.action, me.data.sql, me.data.params);
649    let msg = {
650      id: me.data.id,
651      action: me.data.action,
652      results: arr!.buffer,
653    };
654    port.postMessage(msg, [arr!.buffer]);
655  };
656}
657
658function onmessageByDownloadDBAction(e: MessageEvent): void {
659  let bufferSliceUint: Array<Uint8Array> = [];
660  let mergedUint = (): Uint8Array => {
661    let length = 0;
662    bufferSliceUint.forEach((item) => {
663      length += item.length;
664    });
665    let mergedArray = new Uint8Array(length);
666    let offset = 0;
667    bufferSliceUint.forEach((item) => {
668      mergedArray.set(item, offset);
669      offset += item.length;
670    });
671    return mergedArray;
672  };
673  let getDownloadDb = (heapPtr: number, size: number, isEnd: number): void => {
674    //@ts-ignore
675    let out: Uint8Array = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
676    bufferSliceUint.push(out);
677    if (isEnd === 1) {
678      let arr: Uint8Array = mergedUint();
679      self.postMessage({
680        id: e.data.id,
681        action: e.data.action,
682        results: arr,
683      });
684    }
685  };
686  //@ts-ignore
687  let fn1 = wasmModule.addFunction(getDownloadDb, 'viii');
688  //@ts-ignore
689  wasmModule._WasmExportDatabase(fn1);
690}
691
692function onmessageByUploadSoAction(e: MessageEvent): void {
693  uploadSoActionId = e.data.id;
694  const fileList = e.data.params as Array<File>;
695  failedArray.length = 0;
696  if (fileList) {
697    fileList.sort((a, b) => b.size - a.size);
698    soFileList = fileList;
699    uploadFileIndex = 0;
700    if (!uploadSoCallbackFn) {
701      //@ts-ignore
702      uploadSoCallbackFn = wasmModule.addFunction(uploadSoCallBack, 'viii');
703    }
704    uploadSoFile(soFileList[uploadFileIndex]).then();
705  }
706}
707
708async function saveDataToIndexDB(
709  currentChunk: Uint8Array,
710  currentChunkOffset: number,
711  fileType: string,
712  timStamp: number,
713  pageNum: number,
714  saveIndex: number,
715  saveStartOffset: number
716): Promise<void> {
717  let freeArray = currentChunk.slice(0, currentChunkOffset);
718  await addDataToIndexeddb(indexDB, {
719    buf: freeArray,
720    id: `${fileType}_new_${timStamp}_${pageNum}_${saveIndex}`,
721    fileType: `${fileType}_new`,
722    pageNum: pageNum,
723    startOffset: saveStartOffset,
724    endOffset: saveStartOffset + maxSize,
725    index: saveIndex,
726    timStamp: timStamp,
727  });
728}
729
730function cutLongTraceCallBackHandle(
731  traceFileType: string,
732  currentPageNum: number,
733  heapPtr: number,
734  size: number,
735  dataType: number,
736  newCutFilePageInfo: Map<
737    string,
738    {
739      traceFileType: string;
740      dataArray: [{ data: Uint8Array | Array<{ offset: number; size: number }>; dataTypes: string }];
741    }
742  >
743): void {
744  let key = `${traceFileType}_${currentPageNum}`;
745  //@ts-ignore
746  let out: Uint8Array = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
747  if (DataTypeEnum.data === dataType) {
748    if (traceFileType === 'arkts') {
749      arkTsData.push(out);
750      arkTsDataSize += size;
751    } else {
752      if (newCutFilePageInfo.has(key)) {
753        let newVar = newCutFilePageInfo.get(key);
754        newVar?.dataArray.push({ data: out, dataTypes: 'data' });
755      } else {
756        newCutFilePageInfo.set(key, {
757          traceFileType: traceFileType,
758          dataArray: [{ data: out, dataTypes: 'data' }],
759        });
760      }
761    }
762  } else if (DataTypeEnum.json === dataType) {
763    let cutFilePageInfo = newCutFilePageInfo.get(key);
764    if (cutFilePageInfo) {
765      let jsonStr: string = dec.decode(out);
766      let jsonObj = JSON.parse(jsonStr);
767      let valueArray: Array<{ offset: number; size: number }> = jsonObj.value;
768      cutFilePageInfo.dataArray.push({ data: valueArray, dataTypes: 'json' });
769    }
770  }
771}
772
773function initSplitLongTraceModuleAndFun(
774  headArray: Uint8Array,
775  cutFileCallBack: (heapPtr: number, size: number, dataType: number, isEnd: number) => void
776): number {
777  //@ts-ignore
778  splitReqBufferAddr = wasmModule._InitializeSplitFile(wasmModule.addFunction(cutFileCallBack, 'viiii'), REQ_BUF_SIZE);
779  //@ts-ignore
780  wasmModule.HEAPU8.set(headArray, splitReqBufferAddr);
781  //@ts-ignore
782  wasmModule._TraceStreamerGetLongTraceTimeSnapEx(headArray.length);
783  return splitReqBufferAddr;
784}
785
786async function handleDataTypeBySplitLongTrace(
787  receiveData: { data: Uint8Array | Array<{ offset: number; size: number }>; dataTypes: string },
788  currentChunkOffset: number,
789  currentChunk: Uint8Array,
790  fileType: string,
791  timStamp: number,
792  pageNum: number,
793  saveIndex: number,
794  saveStartOffset: number
795): Promise<[number, number, number, Uint8Array]> {
796  let receiveDataArray = receiveData.data as Uint8Array;
797  if (currentChunkOffset + receiveDataArray.length > maxSize) {
798    let freeSize = maxSize - currentChunkOffset;
799    let freeSaveData = receiveDataArray.slice(0, freeSize);
800    currentChunk.set(freeSaveData, currentChunkOffset);
801    await addDataToIndexeddb(indexDB, {
802      buf: currentChunk,
803      id: `${fileType}_new_${timStamp}_${pageNum}_${saveIndex}`,
804      fileType: `${fileType}_new`,
805      pageNum: pageNum,
806      startOffset: saveStartOffset,
807      endOffset: saveStartOffset + maxSize,
808      index: saveIndex,
809      timStamp: timStamp,
810    });
811    saveStartOffset += maxSize;
812    saveIndex++;
813    currentChunk = new Uint8Array(maxSize);
814    let remnantArray = receiveDataArray.slice(freeSize);
815    currentChunkOffset = 0;
816    currentChunk.set(remnantArray, currentChunkOffset);
817    currentChunkOffset += remnantArray.length;
818  } else {
819    currentChunk.set(receiveDataArray, currentChunkOffset);
820    currentChunkOffset += receiveDataArray.length;
821  }
822  return [currentChunkOffset, saveIndex, saveStartOffset, currentChunk];
823}
824
825async function saveAllDataByLongTrace(
826  range: IDBKeyRange,
827  nowCutInfoList: Array<unknown>,
828  searchDataInfo: {
829    fileType: string;
830    index: number;
831    pageNum: number;
832    startOffsetSize: number;
833    endOffsetSize: number;
834  }[],
835  currentChunkOffset: number,
836  currentChunk: Uint8Array,
837  fileType: string,
838  timStamp: number,
839  pageNum: number,
840  saveIndex: number,
841  saveStartOffset: number
842): Promise<[number, number, number, Uint8Array]> {
843  let transaction = indexDB.transaction(STORE_NAME, 'readonly');
844  let store = transaction.objectStore(STORE_NAME);
845  let index = store.index('QueryCompleteFile');
846  const getRequest = index.openCursor(range);
847  let queryAllData = await queryDataFromIndexeddb(getRequest);
848  let mergeData = indexedDataToBufferData(queryAllData);
849  for (let cutOffsetObjIndex = 0; cutOffsetObjIndex < nowCutInfoList.length; cutOffsetObjIndex++) {
850    let cutUseOffsetObj = nowCutInfoList[cutOffsetObjIndex];
851    //@ts-ignore
852    let endOffset = cutUseOffsetObj.offset + cutUseOffsetObj.size;
853    let sliceData = mergeData.slice(
854      //@ts-ignore
855      cutUseOffsetObj.offset - searchDataInfo[0].startOffsetSize,
856      endOffset - searchDataInfo[0].startOffsetSize
857    );
858    let sliceDataLength = sliceData.length;
859    if (currentChunkOffset + sliceDataLength >= maxSize) {
860      let handleCurrentData = new Uint8Array(currentChunkOffset + sliceDataLength);
861      let freeSaveArray = currentChunk.slice(0, currentChunkOffset);
862      handleCurrentData.set(freeSaveArray, 0);
863      handleCurrentData.set(sliceData, freeSaveArray.length);
864      let newSliceDataLength: number = Math.ceil(handleCurrentData.length / maxSize);
865      for (let newSliceIndex = 0; newSliceIndex < newSliceDataLength; newSliceIndex++) {
866        let newSliceSize = newSliceIndex * maxSize;
867        let number = Math.min(newSliceSize + maxSize, handleCurrentData.length);
868        let saveArray = handleCurrentData.slice(newSliceSize, number);
869        if (newSliceIndex === newSliceDataLength - 1 && number - newSliceSize < maxSize) {
870          currentChunk = new Uint8Array(maxSize);
871          currentChunkOffset = 0;
872          currentChunk.set(saveArray, currentChunkOffset);
873          currentChunkOffset += saveArray.length;
874        } else {
875          await addDataToIndexeddb(indexDB, {
876            buf: saveArray,
877            id: `${fileType}_new_${timStamp}_${pageNum}_${saveIndex}`,
878            fileType: `${fileType}_new`,
879            pageNum: pageNum,
880            startOffset: saveStartOffset,
881            endOffset: saveStartOffset + maxSize,
882            index: saveIndex,
883            timStamp: timStamp,
884          });
885          saveStartOffset += maxSize;
886          saveIndex++;
887        }
888      }
889    } else {
890      currentChunk.set(sliceData, currentChunkOffset);
891      currentChunkOffset += sliceDataLength;
892    }
893  }
894  return [currentChunkOffset, saveIndex, saveStartOffset, currentChunk];
895}
896
897async function handleJsonTypeBySplitLongTrace(
898  receiveData: { data: Uint8Array | Array<{ offset: number; size: number }>; dataTypes: string },
899  allIndexDataList: Array<{
900    fileType: string;
901    index: number;
902    pageNum: number;
903    startOffsetSize: number;
904    endOffsetSize: number;
905  }>,
906  fileType: string,
907  timStamp: number,
908  currentChunkOffset: number,
909  currentChunk: Uint8Array,
910  pageNum: number,
911  saveIndex: number,
912  saveStartOffset: number
913): Promise<[number, number, number, Uint8Array]> {
914  let needCutMessage = receiveData.data as Array<{ offset: number; size: number }>;
915  let startOffset = needCutMessage[0].offset;
916  let nowCutInfoList: Array<{
917    offset: number;
918    size: number;
919  }> = [];
920  let isBeforeCutFinish = false;
921  for (let needCutIndex = 0; needCutIndex < needCutMessage.length; needCutIndex++) {
922    let cutInfo = needCutMessage[needCutIndex];
923    if (isBeforeCutFinish) {
924      startOffset = cutInfo.offset;
925      isBeforeCutFinish = false;
926      nowCutInfoList.length = 0;
927    }
928    if (cutInfo.offset + cutInfo.size - startOffset >= maxSize * 10 || needCutIndex === needCutMessage.length - 1) {
929      nowCutInfoList.push(cutInfo);
930      //@ts-ignore
931      let nowStartCutOffset = nowCutInfoList[0].offset;
932      let nowEndCutOffset = cutInfo.offset + cutInfo.size;
933      let searchDataInfo = allIndexDataList.filter(
934        (value: {
935          fileType: string;
936          index: number;
937          pageNum: number;
938          startOffsetSize: number;
939          endOffsetSize: number;
940        }) => {
941          return (
942            value.fileType === fileType &&
943            value.startOffsetSize <= nowEndCutOffset &&
944            value.endOffsetSize >= nowStartCutOffset
945          );
946        }
947      );
948      let startIndex = searchDataInfo[0].index;
949      let endIndex = searchDataInfo[searchDataInfo.length - 1].index;
950      let range = IDBKeyRange.bound(
951        [timStamp, fileType, 0, startIndex],
952        [timStamp, fileType, 0, endIndex],
953        false,
954        false
955      );
956      [currentChunkOffset, saveIndex, saveStartOffset, currentChunk] = await saveAllDataByLongTrace(
957        range,
958        nowCutInfoList,
959        searchDataInfo,
960        currentChunkOffset,
961        currentChunk,
962        fileType,
963        timStamp,
964        pageNum,
965        saveIndex,
966        saveStartOffset
967      );
968      isBeforeCutFinish = true;
969    } else {
970      nowCutInfoList.push(cutInfo);
971    }
972  }
973  return [currentChunkOffset, saveIndex, saveStartOffset, currentChunk];
974}
975
976async function handleAllTypeDataByLongTrace(
977  newCutFilePageInfo: Map<
978    string,
979    {
980      traceFileType: string;
981      dataArray: [
982        {
983          data: Uint8Array | Array<{ offset: number; size: number }>;
984          dataTypes: string;
985        }
986      ];
987    }
988  >,
989  timStamp: number,
990  allIndexDataList: Array<{
991    fileType: string;
992    index: number;
993    pageNum: number;
994    startOffsetSize: number;
995    endOffsetSize: number;
996  }>
997): Promise<void> {
998  for (const [fileTypePageNum, fileMessage] of newCutFilePageInfo) {
999    let fileTypePageNumArr = fileTypePageNum.split('_');
1000    let fileType = fileTypePageNumArr[0];
1001    let pageNum = Number(fileTypePageNumArr[1]);
1002    let saveIndex = 0;
1003    let saveStartOffset = 0;
1004    let dataArray = fileMessage.dataArray;
1005    let currentChunk = new Uint8Array(maxSize);
1006    let currentChunkOffset = 0;
1007    for (let fileDataIndex = 0; fileDataIndex < dataArray.length; fileDataIndex++) {
1008      let receiveData = dataArray[fileDataIndex];
1009      if (receiveData.dataTypes === 'data') {
1010        [currentChunkOffset, saveIndex, saveStartOffset, currentChunk] = await handleDataTypeBySplitLongTrace(
1011          receiveData,
1012          currentChunkOffset,
1013          currentChunk,
1014          fileType,
1015          timStamp,
1016          pageNum,
1017          saveIndex,
1018          saveStartOffset
1019        );
1020      } else {
1021        if (receiveData.data.length > 0) {
1022          [currentChunkOffset, saveIndex, saveStartOffset, currentChunk] = await handleJsonTypeBySplitLongTrace(
1023            receiveData,
1024            allIndexDataList,
1025            fileType,
1026            timStamp,
1027            currentChunkOffset,
1028            currentChunk,
1029            pageNum,
1030            saveIndex,
1031            saveStartOffset
1032          );
1033        }
1034      }
1035    }
1036    if (currentChunkOffset !== 0) {
1037      await saveDataToIndexDB(
1038        currentChunk,
1039        currentChunkOffset,
1040        fileType,
1041        timStamp,
1042        pageNum,
1043        saveIndex,
1044        saveStartOffset
1045      );
1046      saveStartOffset += maxSize;
1047      saveIndex++;
1048    }
1049  }
1050}
1051
1052async function onmessageByLongTraceAction(e: MessageEvent): Promise<void> {
1053  await initWASM();
1054  let result = {};
1055  let headArray = e.data.params.headArray;
1056  let timStamp = e.data.params.timeStamp;
1057  let allIndexDataList = e.data.params.splitDataList;
1058  let splitFileInfos = e.data.params.splitFileInfo as Array<{
1059    fileType: string;
1060    startIndex: number;
1061    endIndex: number;
1062    size: number;
1063  }>;
1064  let maxPageNum = headArray.length / 1024;
1065  let currentPageNum = 0;
1066  let splitReqBufferAddr: number;
1067  if (splitFileInfos) {
1068    let splitFileInfo = splitFileInfos.filter((splitFileInfo) => splitFileInfo.fileType !== 'trace');
1069    if (splitFileInfo && splitFileInfo.length > 0) {
1070      let traceFileType: string = '';
1071      indexDB = await openDB();
1072      let newCutFilePageInfo: Map<
1073        string,
1074        {
1075          traceFileType: string;
1076          dataArray: [{ data: Uint8Array | Array<{ offset: number; size: number }>; dataTypes: string }];
1077        }
1078      > = new Map();
1079      let cutFileCallBack = (heapPtr: number, size: number, dataType: number, isEnd: number): void => {
1080        cutLongTraceCallBackHandle(traceFileType, currentPageNum, heapPtr, size, dataType, newCutFilePageInfo);
1081      };
1082      splitReqBufferAddr = initSplitLongTraceModuleAndFun(headArray, cutFileCallBack);
1083      for (let fileIndex = 0; fileIndex < splitFileInfo.length; fileIndex++) {
1084        let fileInfo = splitFileInfo[fileIndex];
1085        traceFileType = fileInfo.fileType;
1086        for (let pageNum = 0; pageNum < maxPageNum; pageNum++) {
1087          currentPageNum = pageNum;
1088          await splitFileAndSave(timStamp, fileInfo, pageNum, splitReqBufferAddr);
1089          await initWASM();
1090          splitReqBufferAddr = initSplitLongTraceModuleAndFun(headArray, cutFileCallBack);
1091        }
1092      }
1093      await handleAllTypeDataByLongTrace(newCutFilePageInfo, timStamp, allIndexDataList);
1094    }
1095  }
1096  self.postMessage({
1097    id: e.data.id,
1098    action: e.data.action,
1099    results: result,
1100  });
1101  return;
1102}
1103
1104self.onmessage = async (e: MessageEvent): Promise<void> => {
1105  currentAction = e.data.action;
1106  currentActionId = e.data.id;
1107  if (e.data.action === 'reset') {
1108    clear();
1109  } else if (e.data.action === 'open') {
1110    await onmessageByOpenAction(e);
1111  } else if (e.data.action === 'exec') {
1112    onmessageByExecAction(e);
1113  } else if (e.data.action === 'exec-proto') {
1114    onmessageByExecProtoAction(e);
1115  } else if (e.data.action === 'exec-buf') {
1116    onmessageByExecBufAction(e);
1117  } else if (e.data.action.startsWith('exec-sdk')) {
1118    onmessageByExecSdkAction(e);
1119  } else if (e.data.action.startsWith('exec-metric')) {
1120    onmessageByExecMetricAction(e);
1121  } else if (e.data.action === 'init-port') {
1122    onmessageByInitPortAction(e);
1123  } else if (e.data.action === 'download-db') {
1124    onmessageByDownloadDBAction(e);
1125  } else if (e.data.action === 'upload-so') {
1126    onmessageByUploadSoAction(e);
1127  } else if (e.data.action === 'cut-file') {
1128    cutFileByRange(e);
1129  } else if (e.data.action === 'long_trace') {
1130    await onmessageByLongTraceAction(e);
1131  }
1132};
1133
1134function indexedDataToBufferData(sourceData: unknown): Uint8Array {
1135  let uintArrayLength = 0;
1136  //@ts-ignore
1137  let uintDataList = sourceData.map((item: unknown) => {
1138    //@ts-ignore
1139    let currentBufData = new Uint8Array(item.buf);
1140    uintArrayLength += currentBufData.length;
1141    return currentBufData;
1142  });
1143  let resultUintArray = new Uint8Array(uintArrayLength);
1144  let offset = 0;
1145  uintDataList.forEach((currentArray: Uint8Array) => {
1146    resultUintArray.set(currentArray, offset);
1147    offset += currentArray.length;
1148  });
1149  return resultUintArray;
1150}
1151
1152async function splitFileAndSaveArkTs(
1153  currentChunkOffset: number,
1154  currentChunk: Uint8Array,
1155  fileType: string,
1156  pageNum: number,
1157  saveStartOffset: number,
1158  saveIndex: number,
1159  timStamp: number
1160): Promise<void> {
1161  for (let arkTsAllDataIndex = 0; arkTsAllDataIndex < arkTsData.length; arkTsAllDataIndex++) {
1162    let currentArkTsData = arkTsData[arkTsAllDataIndex];
1163    let freeSize = maxSize - currentChunkOffset;
1164    if (currentArkTsData.length > freeSize) {
1165      let freeSaveData = currentArkTsData.slice(0, freeSize);
1166      currentChunk.set(freeSaveData, currentChunkOffset);
1167      let arg2 = setArg(currentChunk, fileType, pageNum, saveStartOffset, saveIndex, timStamp);
1168      await addDataToIndexeddb(indexDB, arg2);
1169      saveStartOffset += maxSize;
1170      saveIndex++;
1171      let remnantData = currentArkTsData.slice(freeSize);
1172      let remnantDataLength: number = Math.ceil(remnantData.length / maxSize);
1173      for (let newSliceIndex = 0; newSliceIndex < remnantDataLength; newSliceIndex++) {
1174        let newSliceSize = newSliceIndex * maxSize;
1175        let number = Math.min(newSliceSize + maxSize, remnantData.length);
1176        let saveArray = remnantData.slice(newSliceSize, number);
1177        if (newSliceIndex === remnantDataLength - 1 && number - newSliceSize < maxSize) {
1178          currentChunk = new Uint8Array(maxSize);
1179          currentChunkOffset = 0;
1180          currentChunk.set(saveArray, currentChunkOffset);
1181          currentChunkOffset += saveArray.length;
1182        } else {
1183          let arg2 = setArg(saveArray, fileType, pageNum, saveStartOffset, saveIndex, timStamp);
1184          await addDataToIndexeddb(indexDB, arg2);
1185          saveStartOffset += maxSize;
1186          saveIndex++;
1187        }
1188      }
1189    } else {
1190      currentChunk.set(currentArkTsData, currentChunkOffset);
1191      currentChunkOffset += currentArkTsData.length;
1192    }
1193  }
1194}
1195
1196const splitFileAndSave = async (
1197  timStamp: number,
1198  fileInfo: {
1199    fileType: string;
1200    startIndex: number;
1201    endIndex: number;
1202    size: number;
1203  },
1204  pageNum: number,
1205  splitBufAddr?: number
1206): Promise<void> => {
1207  let fileType = fileInfo.fileType;
1208  let fileSize = fileInfo.size;
1209  let startIndex = fileInfo.startIndex;
1210  let endIndex = fileInfo.endIndex;
1211  let queryStartIndex = startIndex;
1212  let queryEndIndex = startIndex;
1213  let saveIndex = 0;
1214  let saveStartOffset = 0;
1215  let current = new Uint8Array(maxSize);
1216  let currentOffset = 0;
1217  let resSize = 0;
1218  do {
1219    queryEndIndex = queryStartIndex + 9;
1220    if (queryEndIndex > endIndex) {
1221      queryEndIndex = endIndex;
1222    }
1223    let range = getRange(timStamp, fileType, queryStartIndex, queryEndIndex);
1224    let res = await getIndexedDBQueryData(indexDB, range);
1225    queryStartIndex = queryEndIndex + 1;
1226    //@ts-ignore
1227    for (let i = 0; i < res.length; i++) {
1228      //@ts-ignore
1229      let arrayBuffer = res[i];
1230      let uint8Array = new Uint8Array(arrayBuffer.buf);
1231      let cutFileSize = 0;
1232      while (cutFileSize < uint8Array.length) {
1233        [cutFileSize, resSize] = splitLongTrace(pageNum, fileSize, resSize, cutFileSize, uint8Array, splitBufAddr);
1234        if (arkTsDataSize > 0 && fileType === 'arkts') {
1235          splitFileAndSaveArkTs(currentOffset, current, fileType, pageNum, saveStartOffset, saveIndex, timStamp);
1236        }
1237      }
1238    }
1239  } while (queryEndIndex < endIndex);
1240  if (fileType === 'arkts' && currentOffset > 0) {
1241    let remnantArray = new Uint8Array(currentOffset);
1242    let remnantChunk = current.slice(0, currentOffset);
1243    remnantArray.set(remnantChunk, 0);
1244    let arg2 = setArg(remnantArray, fileType, pageNum, saveStartOffset, saveIndex, timStamp);
1245    await addDataToIndexeddb(indexDB, arg2);
1246    arkTsDataSize = 0;
1247    arkTsData.length = 0;
1248  }
1249};
1250
1251async function getIndexedDBQueryData(db: IDBDatabase, range: IDBKeyRange): Promise<unknown> {
1252  const transaction = db.transaction(STORE_NAME, 'readonly');
1253  const store = transaction.objectStore(STORE_NAME);
1254  const index = store.index('QueryCompleteFile');
1255  const getRequest = index.openCursor(range);
1256  return await queryDataFromIndexeddb(getRequest);
1257}
1258
1259function splitLongTrace(
1260  pageNum: number,
1261  fileSize: number,
1262  resultFileSize: number,
1263  cutFileSize: number,
1264  uint8Array: Uint8Array,
1265  splitReqBufferAddr?: number
1266): [number, number] {
1267  const sliceLen = Math.min(uint8Array.length - cutFileSize, REQ_BUF_SIZE);
1268  const dataSlice = uint8Array.subarray(cutFileSize, cutFileSize + sliceLen);
1269  //@ts-ignore
1270  wasmModule.HEAPU8.set(dataSlice, splitReqBufferAddr);
1271  cutFileSize += sliceLen;
1272  resultFileSize += sliceLen;
1273  if (resultFileSize >= fileSize) {
1274    //@ts-ignore
1275    wasmModule._TraceStreamerLongTraceSplitFileEx(sliceLen, 1, pageNum);
1276  } else {
1277    //@ts-ignore
1278    wasmModule._TraceStreamerLongTraceSplitFileEx(sliceLen, 0, pageNum);
1279  }
1280  return [cutFileSize, resultFileSize];
1281}
1282
1283function setArg(
1284  remnantArray: Uint8Array,
1285  fileType: string,
1286  pageNum: number,
1287  saveStartOffset: number,
1288  saveIndex: number,
1289  timStamp: number
1290): unknown {
1291  return {
1292    buf: remnantArray,
1293    id: `${fileType}_new_${timStamp}_${pageNum}_${saveIndex}`,
1294    fileType: `${fileType}_new`,
1295    pageNum: pageNum,
1296    startOffset: saveStartOffset,
1297    endOffset: saveStartOffset + maxSize,
1298    index: saveIndex,
1299    timStamp: timStamp,
1300  };
1301}
1302function getRange(timStamp: number, fileType: string, queryStartIndex: number, queryEndIndex: number): IDBKeyRange {
1303  return IDBKeyRange.bound(
1304    [timStamp, fileType, 0, queryStartIndex],
1305    [timStamp, fileType, 0, queryEndIndex],
1306    false,
1307    false
1308  );
1309}
1310
1311enum DataTypeEnum {
1312  data,
1313  json,
1314}
1315
1316let uploadSoActionId: string = '';
1317let uploadFileIndex: number = 0;
1318let uploadSoCallbackFn: Function;
1319let soFileList: Array<File | null> = [];
1320const failedArray: Array<string> = [];
1321const uploadSoFile = async (file: File | null): Promise<void> => {
1322  if (file) {
1323    let fileNameBuffer: Uint8Array | null = enc.encode(file.webkitRelativePath);
1324    let fileNameLength = fileNameBuffer.length;
1325    //@ts-ignore
1326    let addr = wasmModule._InitFileName(uploadSoCallbackFn, fileNameBuffer.length);
1327    //@ts-ignore
1328    wasmModule.HEAPU8.set(fileNameBuffer, addr);
1329    let writeSize = 0;
1330    let upRes = -1;
1331    while (writeSize < file.size) {
1332      let sliceLen = Math.min(file.size - writeSize, REQ_BUF_SIZE);
1333      let blob: Blob | null = file.slice(writeSize, writeSize + sliceLen);
1334      let buffer: ArrayBuffer | null = await blob.arrayBuffer();
1335      let data: Uint8Array | null = new Uint8Array(buffer);
1336      let size = file.size;
1337      //@ts-ignore
1338      wasmModule.HEAPU8.set(data, reqBufferAddr);
1339      writeSize += sliceLen;
1340      //@ts-ignore
1341      upRes = wasmModule._TraceStreamerDownloadELFEx(size, fileNameLength, sliceLen, 1);
1342      data = null;
1343      buffer = null;
1344      blob = null;
1345    }
1346    file = null;
1347    soFileList[uploadFileIndex] = null;
1348    fileNameBuffer = null;
1349  }
1350};
1351
1352const uploadSoCallBack = (heapPtr: number, size: number, isFinish: number): void => {
1353  //@ts-ignore
1354  let out: Uint8Array | null = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
1355  if (out) {
1356    let res = dec.decode(out);
1357    out = null;
1358    if (res.includes('ok') || res.includes('failed')) {
1359      if (res.includes('failed')) {
1360        failedArray.push(soFileList[uploadFileIndex]!.name);
1361      }
1362      if (uploadFileIndex < soFileList.length - 1) {
1363        uploadSoFile(soFileList[uploadFileIndex + 1]).then();
1364      }
1365      uploadFileIndex++;
1366    }
1367    if (uploadFileIndex === soFileList.length) {
1368      soFileList.length = 0;
1369      const result = failedArray.length === 0 ? 'ok' : 'failed';
1370      self.postMessage({
1371        id: uploadSoActionId,
1372        action: 'upload-so',
1373        results: { result: result, failedArray: failedArray },
1374      });
1375    }
1376  }
1377};
1378
1379let splitReqBufferAddr = -1;
1380
1381enum FileTypeEnum {
1382  data,
1383  json,
1384}
1385
1386function isRawTrace(uint8Array: Uint8Array): boolean {
1387  let rowTraceStr = Array.from(new Uint16Array(uint8Array.buffer.slice(0, 2)));
1388  return rowTraceStr[0] === 57161;
1389}
1390
1391function cutFileBufferByOffSet(out: Uint8Array, uint8Array: Uint8Array): Uint8Array {
1392  let jsonStr: string = dec.decode(out);
1393  let jsonObj = JSON.parse(jsonStr);
1394  let valueArray: Array<{ type: number; offset: number; size: number }> = jsonObj.value;
1395  let cutBuffer: Uint8Array;
1396  if (isRawTrace(uint8Array)) {
1397    let commDataSize = 0;
1398    let otherDataSize = 0;
1399    valueArray.forEach((item) => {
1400      const type = item.type;
1401      if (type === 0) {
1402        commDataSize += item.size;
1403      } else {
1404        otherDataSize += item.size;
1405        otherDataSize += 8;
1406      }
1407    });
1408    cutBuffer = new Uint8Array(commDataSize + otherDataSize);
1409    let commOffset = 0;
1410    let tlvOffset = commDataSize;
1411    valueArray.forEach((item) => {
1412      if (item.type !== 0) {
1413        let typeArray = new Uint32Array(1);
1414        typeArray[0] = item.type;
1415        cutBuffer.set(new Uint8Array(typeArray.buffer), tlvOffset);
1416        tlvOffset += typeArray.byteLength;
1417        let lengthArray = new Uint32Array(1);
1418        lengthArray[0] = item.size;
1419        cutBuffer.set(new Uint8Array(lengthArray.buffer), tlvOffset);
1420        tlvOffset += typeArray.byteLength;
1421        const dataSlice = uint8Array.subarray(item.offset, item.offset + item.size);
1422        cutBuffer.set(dataSlice, tlvOffset);
1423        tlvOffset += item.size;
1424      } else {
1425        const dataSlice = uint8Array.subarray(item.offset, item.offset + item.size);
1426        cutBuffer.set(dataSlice, commOffset);
1427        commOffset += item.size;
1428      }
1429    });
1430  } else {
1431    const sum = valueArray.reduce((total, obj) => total + obj.size, 0);
1432    cutBuffer = new Uint8Array(sum);
1433    let offset = 0;
1434    valueArray.forEach((item, index) => {
1435      const dataSlice = uint8Array.subarray(item.offset, item.offset + item.size);
1436      cutBuffer.set(dataSlice, offset);
1437      offset += item.size;
1438    });
1439  }
1440  return cutBuffer;
1441}
1442
1443function cutFileByRange(e: MessageEvent): void {
1444  let cutLeftTs = e.data.leftTs;
1445  let cutRightTs = e.data.rightTs;
1446  let uint8Array = new Uint8Array(e.data.buffer);
1447  let resultBuffer: Array<Uint8Array> = [];
1448  let cutFileCallBack = cutFileCallBackFunc(resultBuffer, uint8Array, e);
1449  //@ts-ignore
1450  splitReqBufferAddr = wasmModule._InitializeSplitFile(wasmModule.addFunction(cutFileCallBack, 'viiii'), REQ_BUF_SIZE);
1451  let cutTimeRange = `${cutLeftTs};${cutRightTs};`;
1452  let cutTimeRangeBuffer = enc.encode(cutTimeRange);
1453  //@ts-ignore
1454  wasmModule.HEAPU8.set(cutTimeRangeBuffer, splitReqBufferAddr);
1455  //@ts-ignore
1456  wasmModule._TraceStreamerSplitFileEx(cutTimeRangeBuffer.length);
1457  let cutFileSize = 0;
1458  let receiveFileResult = -1;
1459  while (cutFileSize < uint8Array.length) {
1460    const sliceLen = Math.min(uint8Array.length - cutFileSize, REQ_BUF_SIZE);
1461    const dataSlice = uint8Array.subarray(cutFileSize, cutFileSize + sliceLen);
1462    //@ts-ignore
1463    wasmModule.HEAPU8.set(dataSlice, splitReqBufferAddr);
1464    cutFileSize += sliceLen;
1465    try {
1466      if (cutFileSize >= uint8Array.length) {
1467        //@ts-ignore
1468        receiveFileResult = wasmModule._TraceStreamerReciveFileEx(sliceLen, 1);
1469      } else {
1470        //@ts-ignore
1471        receiveFileResult = wasmModule._TraceStreamerReciveFileEx(sliceLen, 0);
1472      }
1473    } catch (error) {
1474      self.postMessage(
1475        {
1476          id: e.data.id,
1477          action: e.data.action,
1478          cutStatus: false,
1479          msg: 'split failed',
1480          buffer: e.data.buffer,
1481        },
1482        // @ts-ignore
1483        [e.data.buffer]
1484      );
1485    }
1486  }
1487}
1488function cutFileCallBackFunc(resultBuffer: Array<Uint8Array>, uint8Array: Uint8Array, e: MessageEvent): Function {
1489  return (heapPtr: number, size: number, fileType: number, isEnd: number) => {
1490    //@ts-ignore
1491    let out: Uint8Array = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
1492    if (FileTypeEnum.data === fileType) {
1493      resultBuffer.push(out);
1494    } else if (FileTypeEnum.json === fileType) {
1495      let cutBuffer = cutFileBufferByOffSet(out, uint8Array);
1496      resultBuffer.push(cutBuffer);
1497    }
1498    if (isEnd) {
1499      //@ts-ignore
1500      const cutResultFileLength = resultBuffer.reduce((total, obj) => total + obj.length, 0);
1501      //@ts-ignore
1502      let cutBuffer = new Uint8Array(cutResultFileLength);
1503      let offset = 0;
1504      resultBuffer.forEach((item) => {
1505        //@ts-ignore
1506        cutBuffer.set(item, offset);
1507        //@ts-ignore
1508        offset += item.length;
1509      });
1510      resultBuffer.length = 0;
1511      self.postMessage(
1512        {
1513          id: e.data.id,
1514          action: e.data.action,
1515          cutStatus: true,
1516          msg: 'split success',
1517          buffer: e.data.buffer,
1518          cutBuffer: cutBuffer.buffer,
1519        },
1520        // @ts-ignore
1521        [e.data.buffer, cutBuffer.buffer]
1522      );
1523    }
1524  };
1525}
1526
1527function createView(sql: string): void {
1528  let array = enc.encode(sql);
1529  //@ts-ignore
1530  wasmModule.HEAPU8.set(array, reqBufferAddr);
1531  //@ts-ignore
1532  wasmModule._TraceStreamerSqlOperateEx(array.length);
1533}
1534
1535function query(name: string, sql: string, params: unknown): void {
1536  if (params) {
1537    Reflect.ownKeys(params).forEach((key: unknown) => {
1538      //@ts-ignore
1539      if (typeof params[key] === 'string') {
1540        //@ts-ignore
1541        sql = sql.replace(new RegExp(`\\${key}`, 'g'), `'${params[key]}'`);
1542      } else {
1543        //@ts-ignore
1544        sql = sql.replace(new RegExp(`\\${key}`, 'g'), params[key]);
1545      }
1546    });
1547  }
1548  let sqlUintArray = enc.encode(sql);
1549  //@ts-ignore
1550  wasmModule.HEAPU8.set(sqlUintArray, reqBufferAddr);
1551  //@ts-ignore
1552  wasmModule._TraceStreamerSqlQueryEx(sqlUintArray.length);
1553}
1554
1555function querySdk(name: string, sql: string, sdkParams: unknown, action: string): void {
1556  if (sdkParams) {
1557    Reflect.ownKeys(sdkParams).forEach((key: unknown) => {
1558      //@ts-ignore
1559      if (typeof sdkParams[key] === 'string') {
1560        //@ts-ignore
1561        sql = sql.replace(new RegExp(`\\${key}`, 'g'), `'${sdkParams[key]}'`);
1562      } else {
1563        //@ts-ignore
1564        sql = sql.replace(new RegExp(`\\${key}`, 'g'), sdkParams[key]);
1565      }
1566    });
1567  }
1568  let sqlUintArray = enc.encode(sql);
1569  let commentId = action.substring(action.lastIndexOf('-') + 1);
1570  let key = Number(commentId);
1571  let wasm = thirdWasmMap.get(key);
1572  if (wasm !== undefined) {
1573    let wasmModel = wasm.model;
1574    wasmModel.HEAPU8.set(sqlUintArray, wasm.bufferAddr);
1575    wasmModel._TraceStreamerSqlQueryEx(sqlUintArray.length);
1576  }
1577}
1578
1579function queryMetric(name: string): void {
1580  let metricArray = enc.encode(name);
1581  //@ts-ignore
1582  wasmModule.HEAPU8.set(metricArray, reqBufferAddr);
1583  //@ts-ignore
1584  wasmModule._TraceStreamerSqlMetricsQuery(metricArray.length);
1585}
1586
1587const DB_NAME = 'sp';
1588const DB_VERSION = 1;
1589const STORE_NAME = 'longTable';
1590
1591function openDB(): Promise<IDBDatabase> {
1592  return new Promise((resolve, reject) => {
1593    const openRequest = indexedDB.open(DB_NAME, DB_VERSION);
1594    openRequest.onerror = (): void => reject(openRequest.error);
1595    openRequest.onsuccess = (): void => {
1596      resolve(openRequest.result);
1597    };
1598  });
1599}
1600
1601function queryDataFromIndexeddb(getRequest: IDBRequest<IDBCursorWithValue | null>): Promise<unknown> {
1602  return new Promise((resolve, reject) => {
1603    let results: unknown[] = [];
1604    getRequest.onerror = (event): void => {
1605      // @ts-ignore
1606      reject(event.target.error);
1607    };
1608    getRequest.onsuccess = (event): void => {
1609      // @ts-ignore
1610      const cursor = event.target!.result;
1611      if (cursor) {
1612        results.push(cursor.value);
1613        cursor.continue();
1614      } else {
1615        // @ts-ignore
1616        resolve(results);
1617      }
1618    };
1619  });
1620}
1621
1622function addDataToIndexeddb(db: IDBDatabase, value: unknown, key?: IDBValidKey): Promise<unknown> {
1623  return new Promise((resolve, reject) => {
1624    const transaction = db.transaction(STORE_NAME, 'readwrite');
1625    const objectStore = transaction.objectStore(STORE_NAME);
1626    const request = objectStore.add(value, key);
1627    request.onsuccess = function (event): void {
1628      // @ts-ignore
1629      resolve(event.target.result);
1630    };
1631    request.onerror = (event): void => {
1632      reject(event);
1633    };
1634  });
1635}
1636