• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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    // @ts-ignore
311      saveTraceFileBuffer(ffrtFileCacheKey, arr.buffer);
312    }
313  };
314  let tlvResultCallback = (heapPtr: number, size: number, type: number, isEnd: number): void => {
315    //@ts-ignore
316    let out: Uint8Array = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
317    //@ts-ignore
318    protoDataMap.set(type, BatchSphData.decode(out).values);
319  };
320  //@ts-ignore
321  let fn1 = wasmModule.addFunction(callback, 'viii');
322  //@ts-ignore
323  let fn2 = wasmModule.addFunction(ffrtConvertCallback, 'viii');
324  //@ts-ignore
325  let tlvResultFun = wasmModule.addFunction(tlvResultCallback, 'viiii');
326  //@ts-ignore
327  wasmModule._TraceStreamerSetLogLevel(currentTSLogLevel);
328  //@ts-ignore
329  reqBufferAddr = wasmModule._Initialize(REQ_BUF_SIZE, fn1, tlvResultFun, fn2);
330}
331
332function parseThirdWasmByOpenAction(e: MessageEvent): void {
333  let parseConfig = e.data.parseConfig;
334  if (parseConfig !== '') {
335    let parseConfigArray = enc.encode(parseConfig);
336    //@ts-ignore
337    let parseConfigAddr = wasmModule._InitializeParseConfig(parseConfigArray.length);
338    //@ts-ignore
339    wasmModule.HEAPU8.set(parseConfigArray, parseConfigAddr);
340    //@ts-ignore
341    wasmModule._TraceStreamerParserConfigEx(parseConfigArray.length);
342  }
343  let wasmConfigStr = e.data.wasmConfig;
344  if (wasmConfigStr !== '' && wasmConfigStr.indexOf('WasmFiles') !== -1) {
345    let wasmConfig = JSON.parse(wasmConfigStr);
346    let wasmConfigs = wasmConfig.WasmFiles;
347    let itemArray = wasmConfigs.map((item: unknown) => {
348      //@ts-ignore
349      return item.componentId + ';' + item.pluginName;
350    });
351    let thirdWasmStr: string = itemArray.join(';');
352    let configUintArray = enc.encode(thirdWasmStr + ';');
353    //@ts-ignore
354    wasmModule.HEAPU8.set(configUintArray, reqBufferAddr);
355    //@ts-ignore
356    wasmModule._TraceStreamerInitThirdPartyConfig(configUintArray.length);
357    let first = true;
358    let sendDataCallback = (heapPtr: number, size: number, componentID: number): void => {
359      if (componentID === 100) {
360        if (first) {
361          first = false;
362          //@ts-ignore
363          headUnitArray = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
364        }
365        return;
366      }
367      let configs = wasmConfigs.filter((wasmConfig: unknown) => {
368        //@ts-ignore
369        return wasmConfig.componentId === componentID;
370      });
371      if (configs.length > 0) {
372        let config = configs[0];
373        let model = thirdWasmMap.get(componentID);
374        if (!model && config.componentId === componentID) {
375          importScripts(config.wasmJsName);
376          setThirdWasmMap(config, heapPtr, size, componentID);
377        } else {
378          let mm = model.model;
379          //@ts-ignore
380          let out: Uint8Array = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
381          mm.HEAPU8.set(out, model.bufferAddr);
382          mm._ParserData(out.length, componentID);
383        }
384      }
385    };
386    //@ts-ignore
387    let fn1 = wasmModule.addFunction(sendDataCallback, 'viii');
388    //@ts-ignore
389    wasmModule._TraceStreamerSetThirdPartyDataDealer(fn1, REQ_BUF_SIZE);
390  }
391}
392
393function isCommonData(dataType: number): boolean {
394  return (
395    dataType === CONTENT_TYPE_CMDLINES ||
396    dataType === CONTENT_TYPE_TGIDS ||
397    dataType === CONTENT_TYPE_HEADER_PAGE ||
398    dataType === CONTENT_TYPE_PRINTK_FORMATS ||
399    dataType === CONTENT_TYPE_KALLSYMS
400  );
401}
402
403function parseRawTraceByOpenAction(e: MessageEvent, wrSize: number, r2: number, uint8Array: Uint8Array): number {
404  let commonDataOffsetList: Array<{ startOffset: number; endOffset: number }> = []; // common Data
405  let offset = 12;
406  let tlvTypeLength = 4;
407  let headArray = uint8Array.slice(0, offset);
408  let commonTotalLength = 0;
409  while (offset < uint8Array.length) {
410    let commonDataOffset = { startOffset: offset, endOffset: offset };
411    let dataTypeData = e.data.buffer.slice(offset, offset + tlvTypeLength);
412    offset += tlvTypeLength;
413    let dataType = Array.from(new Uint32Array(dataTypeData));
414    let currentLData = e.data.buffer.slice(offset, offset + tlvTypeLength);
415    offset += tlvTypeLength;
416    let currentVLength = Array.from(new Uint32Array(currentLData));
417    offset += currentVLength[0];
418    commonDataOffset.endOffset = offset;
419    if (isCommonData(dataType[0])) {
420      commonTotalLength += commonDataOffset.endOffset - commonDataOffset.startOffset;
421      commonDataOffsetList.push(commonDataOffset);
422    }
423  }
424  let frontData = new Uint8Array(headArray.byteLength + commonTotalLength); // HeadArray
425  frontData.set(headArray, 0);
426  let lengthOffset = headArray.byteLength;
427  commonDataOffsetList.forEach((item) => {
428    let commonData = uint8Array.slice(item.startOffset, item.endOffset);
429    frontData.set(commonData, lengthOffset);
430    lengthOffset += commonData.byteLength;
431  });
432  let freeData = uint8Array.slice(12);
433  let final = new Uint8Array(frontData.length + freeData.length);
434  final.set(frontData);
435  final.set(freeData, frontData.length);
436  wrSize = 0;
437  while (wrSize < final.length) {
438    const sliceLen = Math.min(final.length - wrSize, REQ_BUF_SIZE);
439    const dataSlice = final.subarray(wrSize, wrSize + sliceLen);
440    //@ts-ignore
441    wasmModule.HEAPU8.set(dataSlice, reqBufferAddr);
442    wrSize += sliceLen;
443    //@ts-ignore
444    r2 = wasmModule._TraceStreamerParseDataEx(sliceLen, wrSize === final.length ? 1 : 0);
445    if (r2 === -1) {
446      break;
447    }
448  }
449  return r2;
450}
451
452function parseNormalTraceByOpenAction(wrSize: number, r2: number, uint8Array: Uint8Array): number {
453  while (wrSize < uint8Array.length) {
454    const sliceLen = Math.min(uint8Array.length - wrSize, REQ_BUF_SIZE);
455    const dataSlice = uint8Array.subarray(wrSize, wrSize + sliceLen);
456    //@ts-ignore
457    wasmModule.HEAPU8.set(dataSlice, reqBufferAddr);
458    wrSize += sliceLen;
459    //@ts-ignore
460    r2 = wasmModule._TraceStreamerParseDataEx(sliceLen, wrSize === uint8Array.length ? 1 : 0);
461    if (r2 === -1) {
462      break;
463    }
464  }
465  return r2;
466}
467
468function setThirdWasmMap(config: unknown, heapPtr: number, size: number, componentID: number): void {
469  //@ts-ignore
470  let thirdMode = initThirdWASM(config.wasmName);
471  //@ts-ignore
472  let configPluginName = config.pluginName;
473  let pluginNameUintArray = enc.encode(configPluginName);
474  //@ts-ignore
475  let pluginNameBuffer = thirdMode._InitPluginName(pluginNameUintArray.length);
476  //@ts-ignore
477  thirdMode.HEAPU8.set(pluginNameUintArray, pluginNameBuffer);
478  //@ts-ignore
479  thirdMode._TraceStreamerGetPluginNameEx(configPluginName.length);
480  let thirdQueryDataCallBack = (heapPtr: number, size: number, isEnd: number, isConfig: number): void => {
481    if (isConfig === 1) {
482      //@ts-ignore
483      let out: Uint8Array = thirdMode.HEAPU8.slice(heapPtr, heapPtr + size);
484      thirdJsonResult.set(componentID, {
485        jsonConfig: dec.decode(out),
486        //@ts-ignore
487        disPlayName: config.disPlayName,
488        //@ts-ignore
489        pluginName: config.pluginName,
490      });
491    } else {
492      //@ts-ignore
493      let out: Uint8Array = thirdMode.HEAPU8.slice(heapPtr, heapPtr + size);
494      bufferSlice.push(out);
495      if (isEnd === 1) {
496        arr = merged();
497        bufferSlice.length = 0;
498      }
499    }
500  };
501  //@ts-ignore
502  let fn = thirdMode.addFunction(thirdQueryDataCallBack, 'viiii');
503  //@ts-ignore
504  let thirdreqBufferAddr = thirdMode._Init(fn, REQ_BUF_SIZE);
505  initTraceRange(thirdMode);
506  //@ts-ignore
507  thirdMode._TraceStreamerInJsonConfig();
508  //@ts-ignore
509  thirdMode.HEAPU8.set(headUnitArray, thirdreqBufferAddr);
510  //@ts-ignore
511  thirdMode._ParserData(headUnitArray!.length, 100);
512  //@ts-ignore
513  let out: Uint8Array = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
514  //@ts-ignore
515  thirdMode.HEAPU8.set(out, thirdreqBufferAddr);
516  //@ts-ignore
517  thirdMode._ParserData(out.length, componentID);
518  thirdWasmMap.set(componentID, {
519    model: thirdMode,
520    bufferAddr: thirdreqBufferAddr,
521  });
522}
523
524function postMessageByOpenAction(r2: number, e: MessageEvent): void {
525  if (r2 === -1) {
526    // @ts-ignore
527    self.postMessage({
528      id: e.data.id,
529      action: e.data.action,
530      init: false,
531      msg: 'parse data error',
532    });
533    return;
534  }
535  // @ts-ignore
536  if (temp_init_sql_list && temp_init_sql_list.length > 0) {
537    // @ts-ignore
538    temp_init_sql_list.forEach((item, index) => {
539      createView(item);
540      // @ts-ignore
541      self.postMessage({ id: e.data.id, ready: true, index: index + 1 });
542    });
543  }
544
545  self.postMessage(
546    {
547      id: e.data.id,
548      action: e.data.action,
549      init: true,
550      msg: 'ok',
551      configSqlMap: thirdJsonResult,
552      buffer: e.data.buffer,
553      fileKey: ffrtFileCacheKey,
554    },
555    // @ts-ignore
556    [e.data.buffer]
557  );
558}
559
560function initTraceRange(thirdMode: unknown): void {
561  let updateTraceTimeCallBack = (heapPtr: number, size: number): void => {
562    //@ts-ignore
563    let out: Uint8Array = thirdMode.HEAPU8.slice(heapPtr, heapPtr + size);
564    //@ts-ignore
565    wasmModule.HEAPU8.set(out, reqBufferAddr);
566    //@ts-ignore
567    wasmModule._UpdateTraceTime(out.length);
568  };
569  //@ts-ignore
570  let traceRangeFn = thirdMode.addFunction(updateTraceTimeCallBack, 'vii');
571  //@ts-ignore
572  thirdMode._InitTraceRange(traceRangeFn, 1024);
573}
574
575function onmessageByExecAction(e: MessageEvent): void {
576  query(e.data.name, e.data.sql, e.data.params);
577  let jsonArray = convertJSON();
578  // @ts-ignore
579  self.postMessage({
580    id: e.data.id,
581    action: e.data.action,
582    results: jsonArray,
583  });
584}
585
586function onmessageByExecProtoAction(e: MessageEvent): void {
587  let typeLength = 4;
588  execProtoForWorker(e.data, (sql: string) => {
589    let sqlUintArray = enc.encode(sql);
590    if (e.data.params.trafic !== TraficEnum.ProtoBuffer) {
591      //@ts-ignore
592      wasmModule.HEAPU8.set(sqlUintArray, reqBufferAddr);
593      //@ts-ignore
594      wasmModule._TraceStreamerSqlQueryEx(sqlUintArray.length);
595      let jsonArray = convertJSON();
596      return jsonArray;
597    } else {
598      let allArray = new Uint8Array(typeLength + sqlUintArray.length);
599      allArray[0] = e.data.name;
600      allArray.set(sqlUintArray, typeLength);
601      //@ts-ignore
602      wasmModule.HEAPU8.set(allArray, reqBufferAddr);
603      //@ts-ignore
604      wasmModule._TraceStreamerSqlQueryToProtoCallback(allArray.length);
605      let finalArrayBuffer = [];
606      if (protoDataMap.has(e.data.name)) {
607        //@ts-ignore
608        finalArrayBuffer = protoDataMap.get(e.data.name);
609        protoDataMap.delete(e.data.name);
610      }
611      return finalArrayBuffer;
612    }
613  });
614}
615
616function onmessageByExecBufAction(e: MessageEvent): void {
617  query(e.data.name, e.data.sql, e.data.params);
618  self.postMessage(
619    { id: e.data.id, action: e.data.action, results: arr!.buffer },
620    // @ts-ignore
621    [arr.buffer]
622  );
623}
624
625function onmessageByExecSdkAction(e: MessageEvent): void {
626  querySdk(e.data.name, e.data.sql, e.data.params, e.data.action);
627  let jsonArray = convertJSON();
628  // @ts-ignore
629  self.postMessage({
630    id: e.data.id,
631    action: e.data.action,
632    results: jsonArray,
633  });
634}
635
636function onmessageByExecMetricAction(e: MessageEvent): void {
637  queryMetric(e.data.sql);
638  let metricResult = dec.decode(arr);
639  // @ts-ignore
640  self.postMessage({
641    id: e.data.id,
642    action: e.data.action,
643    results: metricResult,
644  });
645}
646
647function onmessageByInitPortAction(e: MessageEvent): void {
648  let port = e.ports[0];
649  port.onmessage = (me): void => {
650    query(me.data.action, me.data.sql, me.data.params);
651    let msg = {
652      id: me.data.id,
653      action: me.data.action,
654      results: arr!.buffer,
655    };
656    port.postMessage(msg, [arr!.buffer]);
657  };
658}
659
660function onmessageByDownloadDBAction(e: MessageEvent): void {
661  let bufferSliceUint: Array<Uint8Array> = [];
662  let mergedUint = (): Uint8Array => {
663    let length = 0;
664    bufferSliceUint.forEach((item) => {
665      length += item.length;
666    });
667    let mergedArray = new Uint8Array(length);
668    let offset = 0;
669    bufferSliceUint.forEach((item) => {
670      mergedArray.set(item, offset);
671      offset += item.length;
672    });
673    return mergedArray;
674  };
675  let getDownloadDb = (heapPtr: number, size: number, isEnd: number): void => {
676    //@ts-ignore
677    let out: Uint8Array = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
678    bufferSliceUint.push(out);
679    if (isEnd === 1) {
680      let arr: Uint8Array = mergedUint();
681      self.postMessage({
682        id: e.data.id,
683        action: e.data.action,
684        results: arr,
685      });
686    }
687  };
688  //@ts-ignore
689  let fn1 = wasmModule.addFunction(getDownloadDb, 'viii');
690  //@ts-ignore
691  wasmModule._WasmExportDatabase(fn1);
692}
693
694function onmessageByUploadSoAction(e: MessageEvent): void {
695  uploadSoActionId = e.data.id;
696  const fileList = e.data.params as Array<File>;
697  failedArray.length = 0;
698  if (fileList) {
699    fileList.sort((a, b) => b.size - a.size);
700    soFileList = fileList;
701    uploadFileIndex = 0;
702    if (!uploadSoCallbackFn) {
703      //@ts-ignore
704      uploadSoCallbackFn = wasmModule.addFunction(uploadSoCallBack, 'viii');
705    }
706    uploadSoFile(soFileList[uploadFileIndex]).then();
707  }
708}
709
710async function saveDataToIndexDB(
711  currentChunk: Uint8Array,
712  currentChunkOffset: number,
713  fileType: string,
714  timStamp: number,
715  pageNum: number,
716  saveIndex: number,
717  saveStartOffset: number
718): Promise<void> {
719  let freeArray = currentChunk.slice(0, currentChunkOffset);
720  await addDataToIndexeddb(indexDB, {
721    buf: freeArray,
722    id: `${fileType}_new_${timStamp}_${pageNum}_${saveIndex}`,
723    fileType: `${fileType}_new`,
724    pageNum: pageNum,
725    startOffset: saveStartOffset,
726    endOffset: saveStartOffset + maxSize,
727    index: saveIndex,
728    timStamp: timStamp,
729  });
730}
731
732function cutLongTraceCallBackHandle(
733  traceFileType: string,
734  currentPageNum: number,
735  heapPtr: number,
736  size: number,
737  dataType: number,
738  newCutFilePageInfo: Map<
739    string,
740    {
741      traceFileType: string;
742      dataArray: [{ data: Uint8Array | Array<{ offset: number; size: number }>; dataTypes: string }];
743    }
744  >
745): void {
746  let key = `${traceFileType}_${currentPageNum}`;
747  //@ts-ignore
748  let out: Uint8Array = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
749  if (DataTypeEnum.data === dataType) {
750    if (traceFileType === 'arkts') {
751      arkTsData.push(out);
752      arkTsDataSize += size;
753    } else {
754      if (newCutFilePageInfo.has(key)) {
755        let newVar = newCutFilePageInfo.get(key);
756        newVar?.dataArray.push({ data: out, dataTypes: 'data' });
757      } else {
758        newCutFilePageInfo.set(key, {
759          traceFileType: traceFileType,
760          dataArray: [{ data: out, dataTypes: 'data' }],
761        });
762      }
763    }
764  } else if (DataTypeEnum.json === dataType) {
765    let cutFilePageInfo = newCutFilePageInfo.get(key);
766    if (cutFilePageInfo) {
767      let jsonStr: string = dec.decode(out);
768      let jsonObj = JSON.parse(jsonStr);
769      let valueArray: Array<{ offset: number; size: number }> = jsonObj.value;
770      cutFilePageInfo.dataArray.push({ data: valueArray, dataTypes: 'json' });
771    }
772  }
773}
774
775function initSplitLongTraceModuleAndFun(
776  headArray: Uint8Array,
777  cutFileCallBack: (heapPtr: number, size: number, dataType: number, isEnd: number) => void
778): number {
779  //@ts-ignore
780  splitReqBufferAddr = wasmModule._InitializeSplitFile(wasmModule.addFunction(cutFileCallBack, 'viiii'), REQ_BUF_SIZE);
781  //@ts-ignore
782  wasmModule.HEAPU8.set(headArray, splitReqBufferAddr);
783  //@ts-ignore
784  wasmModule._TraceStreamerGetLongTraceTimeSnapEx(headArray.length);
785  return splitReqBufferAddr;
786}
787
788async function handleDataTypeBySplitLongTrace(
789  receiveData: { data: Uint8Array | Array<{ offset: number; size: number }>; dataTypes: string },
790  currentChunkOffset: number,
791  currentChunk: Uint8Array,
792  fileType: string,
793  timStamp: number,
794  pageNum: number,
795  saveIndex: number,
796  saveStartOffset: number
797): Promise<[number, number, number, Uint8Array]> {
798  let receiveDataArray = receiveData.data as Uint8Array;
799  if (currentChunkOffset + receiveDataArray.length > maxSize) {
800    let freeSize = maxSize - currentChunkOffset;
801    let freeSaveData = receiveDataArray.slice(0, freeSize);
802    currentChunk.set(freeSaveData, currentChunkOffset);
803    await addDataToIndexeddb(indexDB, {
804      buf: currentChunk,
805      id: `${fileType}_new_${timStamp}_${pageNum}_${saveIndex}`,
806      fileType: `${fileType}_new`,
807      pageNum: pageNum,
808      startOffset: saveStartOffset,
809      endOffset: saveStartOffset + maxSize,
810      index: saveIndex,
811      timStamp: timStamp,
812    });
813    saveStartOffset += maxSize;
814    saveIndex++;
815    currentChunk = new Uint8Array(maxSize);
816    let remnantArray = receiveDataArray.slice(freeSize);
817    currentChunkOffset = 0;
818    currentChunk.set(remnantArray, currentChunkOffset);
819    currentChunkOffset += remnantArray.length;
820  } else {
821    currentChunk.set(receiveDataArray, currentChunkOffset);
822    currentChunkOffset += receiveDataArray.length;
823  }
824  return [currentChunkOffset, saveIndex, saveStartOffset, currentChunk];
825}
826
827async function saveAllDataByLongTrace(
828  range: IDBKeyRange,
829  nowCutInfoList: Array<unknown>,
830  searchDataInfo: {
831    fileType: string;
832    index: number;
833    pageNum: number;
834    startOffsetSize: number;
835    endOffsetSize: number;
836  }[],
837  currentChunkOffset: number,
838  currentChunk: Uint8Array,
839  fileType: string,
840  timStamp: number,
841  pageNum: number,
842  saveIndex: number,
843  saveStartOffset: number
844): Promise<[number, number, number, Uint8Array]> {
845  let transaction = indexDB.transaction(STORE_NAME, 'readonly');
846  let store = transaction.objectStore(STORE_NAME);
847  let index = store.index('QueryCompleteFile');
848  const getRequest = index.openCursor(range);
849  let queryAllData = await queryDataFromIndexeddb(getRequest);
850  let mergeData = indexedDataToBufferData(queryAllData);
851  for (let cutOffsetObjIndex = 0; cutOffsetObjIndex < nowCutInfoList.length; cutOffsetObjIndex++) {
852    let cutUseOffsetObj = nowCutInfoList[cutOffsetObjIndex];
853    //@ts-ignore
854    let endOffset = cutUseOffsetObj.offset + cutUseOffsetObj.size;
855    let sliceData = mergeData.slice(
856      //@ts-ignore
857      cutUseOffsetObj.offset - searchDataInfo[0].startOffsetSize,
858      endOffset - searchDataInfo[0].startOffsetSize
859    );
860    let sliceDataLength = sliceData.length;
861    if (currentChunkOffset + sliceDataLength >= maxSize) {
862      let handleCurrentData = new Uint8Array(currentChunkOffset + sliceDataLength);
863      let freeSaveArray = currentChunk.slice(0, currentChunkOffset);
864      handleCurrentData.set(freeSaveArray, 0);
865      handleCurrentData.set(sliceData, freeSaveArray.length);
866      let newSliceDataLength: number = Math.ceil(handleCurrentData.length / maxSize);
867      for (let newSliceIndex = 0; newSliceIndex < newSliceDataLength; newSliceIndex++) {
868        let newSliceSize = newSliceIndex * maxSize;
869        let number = Math.min(newSliceSize + maxSize, handleCurrentData.length);
870        let saveArray = handleCurrentData.slice(newSliceSize, number);
871        if (newSliceIndex === newSliceDataLength - 1 && number - newSliceSize < maxSize) {
872          currentChunk = new Uint8Array(maxSize);
873          currentChunkOffset = 0;
874          currentChunk.set(saveArray, currentChunkOffset);
875          currentChunkOffset += saveArray.length;
876        } else {
877          await addDataToIndexeddb(indexDB, {
878            buf: saveArray,
879            id: `${fileType}_new_${timStamp}_${pageNum}_${saveIndex}`,
880            fileType: `${fileType}_new`,
881            pageNum: pageNum,
882            startOffset: saveStartOffset,
883            endOffset: saveStartOffset + maxSize,
884            index: saveIndex,
885            timStamp: timStamp,
886          });
887          saveStartOffset += maxSize;
888          saveIndex++;
889        }
890      }
891    } else {
892      currentChunk.set(sliceData, currentChunkOffset);
893      currentChunkOffset += sliceDataLength;
894    }
895  }
896  return [currentChunkOffset, saveIndex, saveStartOffset, currentChunk];
897}
898
899async function handleJsonTypeBySplitLongTrace(
900  receiveData: { data: Uint8Array | Array<{ offset: number; size: number }>; dataTypes: string },
901  allIndexDataList: Array<{
902    fileType: string;
903    index: number;
904    pageNum: number;
905    startOffsetSize: number;
906    endOffsetSize: number;
907  }>,
908  fileType: string,
909  timStamp: number,
910  currentChunkOffset: number,
911  currentChunk: Uint8Array,
912  pageNum: number,
913  saveIndex: number,
914  saveStartOffset: number
915): Promise<[number, number, number, Uint8Array]> {
916  let needCutMessage = receiveData.data as Array<{ offset: number; size: number }>;
917  let startOffset = needCutMessage[0].offset;
918  let nowCutInfoList: Array<{
919    offset: number;
920    size: number;
921  }> = [];
922  let isBeforeCutFinish = false;
923  for (let needCutIndex = 0; needCutIndex < needCutMessage.length; needCutIndex++) {
924    let cutInfo = needCutMessage[needCutIndex];
925    if (isBeforeCutFinish) {
926      startOffset = cutInfo.offset;
927      isBeforeCutFinish = false;
928      nowCutInfoList.length = 0;
929    }
930    if (cutInfo.offset + cutInfo.size - startOffset >= maxSize * 10 || needCutIndex === needCutMessage.length - 1) {
931      nowCutInfoList.push(cutInfo);
932      //@ts-ignore
933      let nowStartCutOffset = nowCutInfoList[0].offset;
934      let nowEndCutOffset = cutInfo.offset + cutInfo.size;
935      let searchDataInfo = allIndexDataList.filter(
936        (value: {
937          fileType: string;
938          index: number;
939          pageNum: number;
940          startOffsetSize: number;
941          endOffsetSize: number;
942        }) => {
943          return (
944            value.fileType === fileType &&
945            value.startOffsetSize <= nowEndCutOffset &&
946            value.endOffsetSize >= nowStartCutOffset
947          );
948        }
949      );
950      let startIndex = searchDataInfo[0].index;
951      let endIndex = searchDataInfo[searchDataInfo.length - 1].index;
952      let range = IDBKeyRange.bound(
953        [timStamp, fileType, 0, startIndex],
954        [timStamp, fileType, 0, endIndex],
955        false,
956        false
957      );
958      [currentChunkOffset, saveIndex, saveStartOffset, currentChunk] = await saveAllDataByLongTrace(
959        range,
960        nowCutInfoList,
961        searchDataInfo,
962        currentChunkOffset,
963        currentChunk,
964        fileType,
965        timStamp,
966        pageNum,
967        saveIndex,
968        saveStartOffset
969      );
970      isBeforeCutFinish = true;
971    } else {
972      nowCutInfoList.push(cutInfo);
973    }
974  }
975  return [currentChunkOffset, saveIndex, saveStartOffset, currentChunk];
976}
977
978async function handleAllTypeDataByLongTrace(
979  newCutFilePageInfo: Map<
980    string,
981    {
982      traceFileType: string;
983      dataArray: [
984        {
985          data: Uint8Array | Array<{ offset: number; size: number }>;
986          dataTypes: string;
987        }
988      ];
989    }
990  >,
991  timStamp: number,
992  allIndexDataList: Array<{
993    fileType: string;
994    index: number;
995    pageNum: number;
996    startOffsetSize: number;
997    endOffsetSize: number;
998  }>
999): Promise<void> {
1000  for (const [fileTypePageNum, fileMessage] of newCutFilePageInfo) {
1001    let fileTypePageNumArr = fileTypePageNum.split('_');
1002    let fileType = fileTypePageNumArr[0];
1003    let pageNum = Number(fileTypePageNumArr[1]);
1004    let saveIndex = 0;
1005    let saveStartOffset = 0;
1006    let dataArray = fileMessage.dataArray;
1007    let currentChunk = new Uint8Array(maxSize);
1008    let currentChunkOffset = 0;
1009    for (let fileDataIndex = 0; fileDataIndex < dataArray.length; fileDataIndex++) {
1010      let receiveData = dataArray[fileDataIndex];
1011      if (receiveData.dataTypes === 'data') {
1012    // @ts-ignore
1013        [currentChunkOffset, saveIndex, saveStartOffset, currentChunk] = await handleDataTypeBySplitLongTrace(
1014          receiveData,
1015          currentChunkOffset,
1016          currentChunk,
1017          fileType,
1018          timStamp,
1019          pageNum,
1020          saveIndex,
1021          saveStartOffset
1022        );
1023      } else {
1024        if (receiveData.data.length > 0) {
1025    // @ts-ignore
1026          [currentChunkOffset, saveIndex, saveStartOffset, currentChunk] = await handleJsonTypeBySplitLongTrace(
1027            receiveData,
1028            allIndexDataList,
1029            fileType,
1030            timStamp,
1031            currentChunkOffset,
1032            currentChunk,
1033            pageNum,
1034            saveIndex,
1035            saveStartOffset
1036          );
1037        }
1038      }
1039    }
1040    if (currentChunkOffset !== 0) {
1041      await saveDataToIndexDB(
1042        currentChunk,
1043        currentChunkOffset,
1044        fileType,
1045        timStamp,
1046        pageNum,
1047        saveIndex,
1048        saveStartOffset
1049      );
1050      saveStartOffset += maxSize;
1051      saveIndex++;
1052    }
1053  }
1054}
1055
1056async function onmessageByLongTraceAction(e: MessageEvent): Promise<void> {
1057  await initWASM();
1058  let result = {};
1059  let headArray = e.data.params.headArray;
1060  let timStamp = e.data.params.timeStamp;
1061  let allIndexDataList = e.data.params.splitDataList;
1062  let splitFileInfos = e.data.params.splitFileInfo as Array<{
1063    fileType: string;
1064    startIndex: number;
1065    endIndex: number;
1066    size: number;
1067  }>;
1068  let maxPageNum = headArray.length / 1024;
1069  let currentPageNum = 0;
1070  let splitReqBufferAddr: number;
1071  if (splitFileInfos) {
1072    let splitFileInfo = splitFileInfos.filter((splitFileInfo) => splitFileInfo.fileType !== 'trace');
1073    if (splitFileInfo && splitFileInfo.length > 0) {
1074      let traceFileType: string = '';
1075      indexDB = await openDB();
1076      let newCutFilePageInfo: Map<
1077        string,
1078        {
1079          traceFileType: string;
1080          dataArray: [{ data: Uint8Array | Array<{ offset: number; size: number }>; dataTypes: string }];
1081        }
1082      > = new Map();
1083      let cutFileCallBack = (heapPtr: number, size: number, dataType: number, isEnd: number): void => {
1084        cutLongTraceCallBackHandle(traceFileType, currentPageNum, heapPtr, size, dataType, newCutFilePageInfo);
1085      };
1086      splitReqBufferAddr = initSplitLongTraceModuleAndFun(headArray, cutFileCallBack);
1087      for (let fileIndex = 0; fileIndex < splitFileInfo.length; fileIndex++) {
1088        let fileInfo = splitFileInfo[fileIndex];
1089        traceFileType = fileInfo.fileType;
1090        for (let pageNum = 0; pageNum < maxPageNum; pageNum++) {
1091          currentPageNum = pageNum;
1092          await splitFileAndSave(timStamp, fileInfo, pageNum, splitReqBufferAddr);
1093          await initWASM();
1094          splitReqBufferAddr = initSplitLongTraceModuleAndFun(headArray, cutFileCallBack);
1095        }
1096      }
1097      await handleAllTypeDataByLongTrace(newCutFilePageInfo, timStamp, allIndexDataList);
1098    }
1099  }
1100  self.postMessage({
1101    id: e.data.id,
1102    action: e.data.action,
1103    results: result,
1104  });
1105  return;
1106}
1107
1108self.onmessage = async (e: MessageEvent): Promise<void> => {
1109  currentAction = e.data.action;
1110  currentActionId = e.data.id;
1111  if (e.data.action === 'reset') {
1112    clear();
1113  } else if (e.data.action === 'open') {
1114    await onmessageByOpenAction(e);
1115  } else if (e.data.action === 'exec') {
1116    onmessageByExecAction(e);
1117  } else if (e.data.action === 'exec-proto') {
1118    onmessageByExecProtoAction(e);
1119  } else if (e.data.action === 'exec-buf') {
1120    onmessageByExecBufAction(e);
1121  } else if (e.data.action.startsWith('exec-sdk')) {
1122    onmessageByExecSdkAction(e);
1123  } else if (e.data.action.startsWith('exec-metric')) {
1124    onmessageByExecMetricAction(e);
1125  } else if (e.data.action === 'init-port') {
1126    onmessageByInitPortAction(e);
1127  } else if (e.data.action === 'download-db') {
1128    onmessageByDownloadDBAction(e);
1129  } else if (e.data.action === 'upload-so') {
1130    onmessageByUploadSoAction(e);
1131  } else if (e.data.action === 'cut-file') {
1132    cutFileByRange(e);
1133  } else if (e.data.action === 'long_trace') {
1134    await onmessageByLongTraceAction(e);
1135  }
1136};
1137
1138function indexedDataToBufferData(sourceData: unknown): Uint8Array {
1139  let uintArrayLength = 0;
1140  //@ts-ignore
1141  let uintDataList = sourceData.map((item: unknown) => {
1142    //@ts-ignore
1143    let currentBufData = new Uint8Array(item.buf);
1144    uintArrayLength += currentBufData.length;
1145    return currentBufData;
1146  });
1147  let resultUintArray = new Uint8Array(uintArrayLength);
1148  let offset = 0;
1149  uintDataList.forEach((currentArray: Uint8Array) => {
1150    resultUintArray.set(currentArray, offset);
1151    offset += currentArray.length;
1152  });
1153  return resultUintArray;
1154}
1155
1156async function splitFileAndSaveArkTs(
1157  currentChunkOffset: number,
1158  currentChunk: Uint8Array,
1159  fileType: string,
1160  pageNum: number,
1161  saveStartOffset: number,
1162  saveIndex: number,
1163  timStamp: number
1164): Promise<void> {
1165  for (let arkTsAllDataIndex = 0; arkTsAllDataIndex < arkTsData.length; arkTsAllDataIndex++) {
1166    let currentArkTsData = arkTsData[arkTsAllDataIndex];
1167    let freeSize = maxSize - currentChunkOffset;
1168    if (currentArkTsData.length > freeSize) {
1169      let freeSaveData = currentArkTsData.slice(0, freeSize);
1170      currentChunk.set(freeSaveData, currentChunkOffset);
1171      let arg2 = setArg(currentChunk, fileType, pageNum, saveStartOffset, saveIndex, timStamp);
1172      await addDataToIndexeddb(indexDB, arg2);
1173      saveStartOffset += maxSize;
1174      saveIndex++;
1175      let remnantData = currentArkTsData.slice(freeSize);
1176      let remnantDataLength: number = Math.ceil(remnantData.length / maxSize);
1177      for (let newSliceIndex = 0; newSliceIndex < remnantDataLength; newSliceIndex++) {
1178        let newSliceSize = newSliceIndex * maxSize;
1179        let number = Math.min(newSliceSize + maxSize, remnantData.length);
1180        let saveArray = remnantData.slice(newSliceSize, number);
1181        if (newSliceIndex === remnantDataLength - 1 && number - newSliceSize < maxSize) {
1182          currentChunk = new Uint8Array(maxSize);
1183          currentChunkOffset = 0;
1184          currentChunk.set(saveArray, currentChunkOffset);
1185          currentChunkOffset += saveArray.length;
1186        } else {
1187          let arg2 = setArg(saveArray, fileType, pageNum, saveStartOffset, saveIndex, timStamp);
1188          await addDataToIndexeddb(indexDB, arg2);
1189          saveStartOffset += maxSize;
1190          saveIndex++;
1191        }
1192      }
1193    } else {
1194      currentChunk.set(currentArkTsData, currentChunkOffset);
1195      currentChunkOffset += currentArkTsData.length;
1196    }
1197  }
1198}
1199
1200const splitFileAndSave = async (
1201  timStamp: number,
1202  fileInfo: {
1203    fileType: string;
1204    startIndex: number;
1205    endIndex: number;
1206    size: number;
1207  },
1208  pageNum: number,
1209  splitBufAddr?: number
1210): Promise<void> => {
1211  let fileType = fileInfo.fileType;
1212  let fileSize = fileInfo.size;
1213  let startIndex = fileInfo.startIndex;
1214  let endIndex = fileInfo.endIndex;
1215  let queryStartIndex = startIndex;
1216  let queryEndIndex = startIndex;
1217  let saveIndex = 0;
1218  let saveStartOffset = 0;
1219  let current = new Uint8Array(maxSize);
1220  let currentOffset = 0;
1221  let resSize = 0;
1222  do {
1223    queryEndIndex = queryStartIndex + 9;
1224    if (queryEndIndex > endIndex) {
1225      queryEndIndex = endIndex;
1226    }
1227    let range = getRange(timStamp, fileType, queryStartIndex, queryEndIndex);
1228    let res = await getIndexedDBQueryData(indexDB, range);
1229    queryStartIndex = queryEndIndex + 1;
1230    //@ts-ignore
1231    for (let i = 0; i < res.length; i++) {
1232      //@ts-ignore
1233      let arrayBuffer = res[i];
1234      let uint8Array = new Uint8Array(arrayBuffer.buf);
1235      let cutFileSize = 0;
1236      while (cutFileSize < uint8Array.length) {
1237        [cutFileSize, resSize] = splitLongTrace(pageNum, fileSize, resSize, cutFileSize, uint8Array, splitBufAddr);
1238        if (arkTsDataSize > 0 && fileType === 'arkts') {
1239          splitFileAndSaveArkTs(currentOffset, current, fileType, pageNum, saveStartOffset, saveIndex, timStamp);
1240        }
1241      }
1242    }
1243  } while (queryEndIndex < endIndex);
1244  if (fileType === 'arkts' && currentOffset > 0) {
1245    let remnantArray = new Uint8Array(currentOffset);
1246    let remnantChunk = current.slice(0, currentOffset);
1247    remnantArray.set(remnantChunk, 0);
1248    let arg2 = setArg(remnantArray, fileType, pageNum, saveStartOffset, saveIndex, timStamp);
1249    await addDataToIndexeddb(indexDB, arg2);
1250    arkTsDataSize = 0;
1251    arkTsData.length = 0;
1252  }
1253};
1254
1255async function getIndexedDBQueryData(db: IDBDatabase, range: IDBKeyRange): Promise<unknown> {
1256  const transaction = db.transaction(STORE_NAME, 'readonly');
1257  const store = transaction.objectStore(STORE_NAME);
1258  const index = store.index('QueryCompleteFile');
1259  const getRequest = index.openCursor(range);
1260  return await queryDataFromIndexeddb(getRequest);
1261}
1262
1263function splitLongTrace(
1264  pageNum: number,
1265  fileSize: number,
1266  resultFileSize: number,
1267  cutFileSize: number,
1268  uint8Array: Uint8Array,
1269  splitReqBufferAddr?: number
1270): [number, number] {
1271  const sliceLen = Math.min(uint8Array.length - cutFileSize, REQ_BUF_SIZE);
1272  const dataSlice = uint8Array.subarray(cutFileSize, cutFileSize + sliceLen);
1273  //@ts-ignore
1274  wasmModule.HEAPU8.set(dataSlice, splitReqBufferAddr);
1275  cutFileSize += sliceLen;
1276  resultFileSize += sliceLen;
1277  if (resultFileSize >= fileSize) {
1278    //@ts-ignore
1279    wasmModule._TraceStreamerLongTraceSplitFileEx(sliceLen, 1, pageNum);
1280  } else {
1281    //@ts-ignore
1282    wasmModule._TraceStreamerLongTraceSplitFileEx(sliceLen, 0, pageNum);
1283  }
1284  return [cutFileSize, resultFileSize];
1285}
1286
1287function setArg(
1288  remnantArray: Uint8Array,
1289  fileType: string,
1290  pageNum: number,
1291  saveStartOffset: number,
1292  saveIndex: number,
1293  timStamp: number
1294): unknown {
1295  return {
1296    buf: remnantArray,
1297    id: `${fileType}_new_${timStamp}_${pageNum}_${saveIndex}`,
1298    fileType: `${fileType}_new`,
1299    pageNum: pageNum,
1300    startOffset: saveStartOffset,
1301    endOffset: saveStartOffset + maxSize,
1302    index: saveIndex,
1303    timStamp: timStamp,
1304  };
1305}
1306function getRange(timStamp: number, fileType: string, queryStartIndex: number, queryEndIndex: number): IDBKeyRange {
1307  return IDBKeyRange.bound(
1308    [timStamp, fileType, 0, queryStartIndex],
1309    [timStamp, fileType, 0, queryEndIndex],
1310    false,
1311    false
1312  );
1313}
1314
1315enum DataTypeEnum {
1316  data,
1317  json,
1318}
1319
1320let uploadSoActionId: string = '';
1321let uploadFileIndex: number = 0;
1322let uploadSoCallbackFn: Function;
1323let soFileList: Array<File | null> = [];
1324const failedArray: Array<string> = [];
1325const uploadSoFile = async (file: File | null): Promise<void> => {
1326  if (file) {
1327    let fileNameBuffer: Uint8Array | null = enc.encode(file.webkitRelativePath);
1328    let fileNameLength = fileNameBuffer.length;
1329    //@ts-ignore
1330    let addr = wasmModule._InitFileName(uploadSoCallbackFn, fileNameBuffer.length);
1331    //@ts-ignore
1332    wasmModule.HEAPU8.set(fileNameBuffer, addr);
1333    let writeSize = 0;
1334    let upRes = -1;
1335    while (writeSize < file.size) {
1336      let sliceLen = Math.min(file.size - writeSize, REQ_BUF_SIZE);
1337      let blob: Blob | null = file.slice(writeSize, writeSize + sliceLen);
1338      let buffer: ArrayBuffer | null = await blob.arrayBuffer();
1339      let data: Uint8Array | null = new Uint8Array(buffer);
1340      let size = file.size;
1341      //@ts-ignore
1342      wasmModule.HEAPU8.set(data, reqBufferAddr);
1343      writeSize += sliceLen;
1344      //@ts-ignore
1345      upRes = wasmModule._TraceStreamerDownloadELFEx(size, fileNameLength, sliceLen, 1);
1346      data = null;
1347      buffer = null;
1348      blob = null;
1349    }
1350    file = null;
1351    soFileList[uploadFileIndex] = null;
1352    fileNameBuffer = null;
1353  }
1354};
1355
1356const uploadSoCallBack = (heapPtr: number, size: number, isFinish: number): void => {
1357  //@ts-ignore
1358  let out: Uint8Array | null = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
1359  if (out) {
1360    let res = dec.decode(out);
1361    out = null;
1362    if (res.includes('ok') || res.includes('failed')) {
1363      if (res.includes('failed')) {
1364        failedArray.push(soFileList[uploadFileIndex]!.name);
1365      }
1366      if (uploadFileIndex < soFileList.length - 1) {
1367        uploadSoFile(soFileList[uploadFileIndex + 1]).then();
1368      }
1369      uploadFileIndex++;
1370    }
1371    if (uploadFileIndex === soFileList.length) {
1372      soFileList.length = 0;
1373      const result = failedArray.length === 0 ? 'ok' : 'failed';
1374      self.postMessage({
1375        id: uploadSoActionId,
1376        action: 'upload-so',
1377        results: { result: result, failedArray: failedArray },
1378      });
1379    }
1380  }
1381};
1382
1383let splitReqBufferAddr = -1;
1384
1385enum FileTypeEnum {
1386  data,
1387  json,
1388}
1389
1390function isRawTrace(uint8Array: Uint8Array): boolean {
1391  let rowTraceStr = Array.from(new Uint16Array(uint8Array.buffer.slice(0, 2)));
1392  return rowTraceStr[0] === 57161;
1393}
1394
1395function cutFileBufferByOffSet(out: Uint8Array, uint8Array: Uint8Array): Uint8Array {
1396  let jsonStr: string = dec.decode(out);
1397  let jsonObj = JSON.parse(jsonStr);
1398  let valueArray: Array<{ type: number; offset: number; size: number }> = jsonObj.value;
1399  let cutBuffer: Uint8Array;
1400  if (isRawTrace(uint8Array)) {
1401    let commDataSize = 0;
1402    let otherDataSize = 0;
1403    valueArray.forEach((item) => {
1404      const type = item.type;
1405      if (type === 0) {
1406        commDataSize += item.size;
1407      } else {
1408        otherDataSize += item.size;
1409        otherDataSize += 8;
1410      }
1411    });
1412    cutBuffer = new Uint8Array(commDataSize + otherDataSize);
1413    let commOffset = 0;
1414    let tlvOffset = commDataSize;
1415    valueArray.forEach((item) => {
1416      if (item.type !== 0) {
1417        let typeArray = new Uint32Array(1);
1418        typeArray[0] = item.type;
1419        cutBuffer.set(new Uint8Array(typeArray.buffer), tlvOffset);
1420        tlvOffset += typeArray.byteLength;
1421        let lengthArray = new Uint32Array(1);
1422        lengthArray[0] = item.size;
1423        cutBuffer.set(new Uint8Array(lengthArray.buffer), tlvOffset);
1424        tlvOffset += typeArray.byteLength;
1425        const dataSlice = uint8Array.subarray(item.offset, item.offset + item.size);
1426        cutBuffer.set(dataSlice, tlvOffset);
1427        tlvOffset += item.size;
1428      } else {
1429        const dataSlice = uint8Array.subarray(item.offset, item.offset + item.size);
1430        cutBuffer.set(dataSlice, commOffset);
1431        commOffset += item.size;
1432      }
1433    });
1434  } else {
1435    const sum = valueArray.reduce((total, obj) => total + obj.size, 0);
1436    cutBuffer = new Uint8Array(sum);
1437    let offset = 0;
1438    valueArray.forEach((item, index) => {
1439      const dataSlice = uint8Array.subarray(item.offset, item.offset + item.size);
1440      cutBuffer.set(dataSlice, offset);
1441      offset += item.size;
1442    });
1443  }
1444  return cutBuffer;
1445}
1446
1447function cutFileByRange(e: MessageEvent): void {
1448  let cutLeftTs = e.data.leftTs;
1449  let cutRightTs = e.data.rightTs;
1450  let uint8Array = new Uint8Array(e.data.buffer);
1451  let resultBuffer: Array<Uint8Array> = [];
1452  let cutFileCallBack = cutFileCallBackFunc(resultBuffer, uint8Array, e);
1453  //@ts-ignore
1454  splitReqBufferAddr = wasmModule._InitializeSplitFile(wasmModule.addFunction(cutFileCallBack, 'viiii'), REQ_BUF_SIZE);
1455  let cutTimeRange = `${cutLeftTs};${cutRightTs};`;
1456  let cutTimeRangeBuffer = enc.encode(cutTimeRange);
1457  //@ts-ignore
1458  wasmModule.HEAPU8.set(cutTimeRangeBuffer, splitReqBufferAddr);
1459  //@ts-ignore
1460  wasmModule._TraceStreamerSplitFileEx(cutTimeRangeBuffer.length);
1461  let cutFileSize = 0;
1462  let receiveFileResult = -1;
1463  while (cutFileSize < uint8Array.length) {
1464    const sliceLen = Math.min(uint8Array.length - cutFileSize, REQ_BUF_SIZE);
1465    const dataSlice = uint8Array.subarray(cutFileSize, cutFileSize + sliceLen);
1466    //@ts-ignore
1467    wasmModule.HEAPU8.set(dataSlice, splitReqBufferAddr);
1468    cutFileSize += sliceLen;
1469    try {
1470      if (cutFileSize >= uint8Array.length) {
1471        //@ts-ignore
1472        receiveFileResult = wasmModule._TraceStreamerReciveFileEx(sliceLen, 1);
1473      } else {
1474        //@ts-ignore
1475        receiveFileResult = wasmModule._TraceStreamerReciveFileEx(sliceLen, 0);
1476      }
1477    } catch (error) {
1478      self.postMessage(
1479        {
1480          id: e.data.id,
1481          action: e.data.action,
1482          cutStatus: false,
1483          msg: 'split failed',
1484          buffer: e.data.buffer,
1485        },
1486        // @ts-ignore
1487        [e.data.buffer]
1488      );
1489    }
1490  }
1491}
1492function cutFileCallBackFunc(resultBuffer: Array<Uint8Array>, uint8Array: Uint8Array, e: MessageEvent): Function {
1493  return (heapPtr: number, size: number, fileType: number, isEnd: number) => {
1494    //@ts-ignore
1495    let out: Uint8Array = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size);
1496    if (FileTypeEnum.data === fileType) {
1497      resultBuffer.push(out);
1498    } else if (FileTypeEnum.json === fileType) {
1499      let cutBuffer = cutFileBufferByOffSet(out, uint8Array);
1500      resultBuffer.push(cutBuffer);
1501    }
1502    if (isEnd) {
1503      //@ts-ignore
1504      const cutResultFileLength = resultBuffer.reduce((total, obj) => total + obj.length, 0);
1505      //@ts-ignore
1506      let cutBuffer = new Uint8Array(cutResultFileLength);
1507      let offset = 0;
1508      resultBuffer.forEach((item) => {
1509        //@ts-ignore
1510        cutBuffer.set(item, offset);
1511        //@ts-ignore
1512        offset += item.length;
1513      });
1514      resultBuffer.length = 0;
1515      self.postMessage(
1516        {
1517          id: e.data.id,
1518          action: e.data.action,
1519          cutStatus: true,
1520          msg: 'split success',
1521          buffer: e.data.buffer,
1522          cutBuffer: cutBuffer.buffer,
1523        },
1524        // @ts-ignore
1525        [e.data.buffer, cutBuffer.buffer]
1526      );
1527    }
1528  };
1529}
1530
1531function createView(sql: string): void {
1532  let array = enc.encode(sql);
1533  //@ts-ignore
1534  wasmModule.HEAPU8.set(array, reqBufferAddr);
1535  //@ts-ignore
1536  wasmModule._TraceStreamerSqlOperateEx(array.length);
1537}
1538
1539function query(name: string, sql: string, params: unknown): void {
1540  if (params) {
1541    Reflect.ownKeys(params).forEach((key: unknown) => {
1542      //@ts-ignore
1543      if (typeof params[key] === 'string') {
1544        //@ts-ignore
1545        sql = sql.replace(new RegExp(`\\${key}`, 'g'), `'${params[key]}'`);
1546      } else {
1547        //@ts-ignore
1548        sql = sql.replace(new RegExp(`\\${key}`, 'g'), params[key]);
1549      }
1550    });
1551  }
1552  let sqlUintArray = enc.encode(sql);
1553  //@ts-ignore
1554  wasmModule.HEAPU8.set(sqlUintArray, reqBufferAddr);
1555  //@ts-ignore
1556  wasmModule._TraceStreamerSqlQueryEx(sqlUintArray.length);
1557}
1558
1559function querySdk(name: string, sql: string, sdkParams: unknown, action: string): void {
1560  if (sdkParams) {
1561    Reflect.ownKeys(sdkParams).forEach((key: unknown) => {
1562      //@ts-ignore
1563      if (typeof sdkParams[key] === 'string') {
1564        //@ts-ignore
1565        sql = sql.replace(new RegExp(`\\${key}`, 'g'), `'${sdkParams[key]}'`);
1566      } else {
1567        //@ts-ignore
1568        sql = sql.replace(new RegExp(`\\${key}`, 'g'), sdkParams[key]);
1569      }
1570    });
1571  }
1572  let sqlUintArray = enc.encode(sql);
1573  let commentId = action.substring(action.lastIndexOf('-') + 1);
1574  let key = Number(commentId);
1575  let wasm = thirdWasmMap.get(key);
1576  if (wasm !== undefined) {
1577    let wasmModel = wasm.model;
1578    wasmModel.HEAPU8.set(sqlUintArray, wasm.bufferAddr);
1579    wasmModel._TraceStreamerSqlQueryEx(sqlUintArray.length);
1580  }
1581}
1582
1583function queryMetric(name: string): void {
1584  let metricArray = enc.encode(name);
1585  //@ts-ignore
1586  wasmModule.HEAPU8.set(metricArray, reqBufferAddr);
1587  //@ts-ignore
1588  wasmModule._TraceStreamerSqlMetricsQuery(metricArray.length);
1589}
1590
1591const DB_NAME = 'sp';
1592const DB_VERSION = 1;
1593const STORE_NAME = 'longTable';
1594
1595function openDB(): Promise<IDBDatabase> {
1596  return new Promise((resolve, reject) => {
1597    const openRequest = indexedDB.open(DB_NAME, DB_VERSION);
1598    openRequest.onerror = (): void => reject(openRequest.error);
1599    openRequest.onsuccess = (): void => {
1600      resolve(openRequest.result);
1601    };
1602  });
1603}
1604
1605function queryDataFromIndexeddb(getRequest: IDBRequest<IDBCursorWithValue | null>): Promise<unknown> {
1606  return new Promise((resolve, reject) => {
1607    let results: unknown[] = [];
1608    getRequest.onerror = (event): void => {
1609      // @ts-ignore
1610      reject(event.target.error);
1611    };
1612    getRequest.onsuccess = (event): void => {
1613      // @ts-ignore
1614      const cursor = event.target!.result;
1615      if (cursor) {
1616        results.push(cursor.value);
1617        cursor.continue();
1618      } else {
1619        // @ts-ignore
1620        resolve(results);
1621      }
1622    };
1623  });
1624}
1625
1626function addDataToIndexeddb(db: IDBDatabase, value: unknown, key?: IDBValidKey): Promise<unknown> {
1627  return new Promise((resolve, reject) => {
1628    const transaction = db.transaction(STORE_NAME, 'readwrite');
1629    const objectStore = transaction.objectStore(STORE_NAME);
1630    const request = objectStore.add(value, key);
1631    request.onsuccess = function (event): void {
1632      // @ts-ignore
1633      resolve(event.target.result);
1634    };
1635    request.onerror = (event): void => {
1636      reject(event);
1637    };
1638  });
1639}
1640