• 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
16import { Utils as TraceUtil } from './component/trace/base/Utils';
17import { getThreadPoolTraceBufferCacheKey, threadPool } from './database/SqlLite';
18
19export enum TraceMode {
20  NORMAL,
21  LONG_TRACE,
22  DISTRIBUTED,
23}
24
25export const applicationHtml: string = `
26        <style>
27        :host{
28
29        }
30        .dark{
31        --dark-background: #272C34;
32        --dark-background1: #424851;
33        --dark-background2: #262f3c;
34        --dark-background3: #292D33;
35        --dark-background4: #323841;
36        --dark-background5: #333840;
37        --dark-background6: rgba(82,145,255,0.2);
38        --dark-background7: #494d52;
39        --dark-background8: #5291FF;
40        --dark-color: rgba(255,255,255,0.6);
41        --dark-color1: rgba(255,255,255,0.86);
42        --dark-color2: rgba(255,255,255,0.9);
43        --dark-border: #474F59;
44        --dark-color3:#4694C2;
45        --dark-color4:#5AADA0;
46        --dark-border1: #454E5A;
47        --bark-expansion:#0076FF;
48        --bark-prompt:#9e9e9e;
49        --dark-icon:#adafb3;
50        --dark-img: url('img/dark_pic.png');
51            background: #272C34;
52            color: #FFFFFF;
53        }
54        .root{
55            display: grid;
56            grid-template-rows: min-content 1fr;
57            grid-template-columns: min-content 1fr;
58            grid-template-areas: 'm s'
59                                 'm b';
60            height: 100vh;
61            width: 100vw;
62        }
63        .filedrag::after {
64             content: 'Drop the trace file to open it';
65             position: fixed;
66             z-index: 2001;
67             top: 0;
68             left: 0;
69             right: 0;
70             bottom: 0;
71             border: 5px dashed var(--dark-color1,#404854);
72             text-align: center;
73             font-size: 3rem;
74             line-height: 100vh;
75             background: rgba(255, 255, 255, 0.5);
76        }
77        .menu{
78            grid-area: m;
79            /*transition: all 0.2s;*/
80            box-shadow: 4px 0px 20px rgba(0,0,0,0.05);
81            z-index: 2000;
82        }
83        .search-vessel{
84            z-index: 999;
85            position: relative;
86            cursor: default;
87        }
88        .progress{
89            bottom: 0;
90            position: absolute;
91            height: 1px;
92            left: 0;
93            right: 0;
94        }
95
96        :host(:not([search])) .search-vessel  {
97           display: none;
98        }
99        :host(:not([search])) .search-vessel .search  {
100            background-color: var(--dark-background5,#F6F6F6);
101        }
102        .search{
103            grid-area: s;
104            background-color: var(--dark-background,#FFFFFF);
105            height: 48px;
106            display: flex;
107            justify-content: center;
108            align-items: center;
109
110        }
111        .search .search-bg{
112            background-color: var(--dark-background5,#fff);
113            border-radius: 40px;
114            padding: 3px 20px;
115            display: flex;
116            justify-content: center;
117            align-items: center;
118            border: 1px solid var(--dark-border,#c5c5c5);
119        }
120        lit-search input{
121            outline: none;
122            border: 0px;
123            background-color: transparent;
124            font-size: inherit;
125            color: var(--dark-color,#666666);
126            width: 30vw;
127            height: auto;
128            vertical-align:middle;
129            line-height:inherit;
130            height:inherit;
131            padding: 6px 6px 6px 6px};
132            max-height: inherit;
133            box-sizing: border-box;
134
135        }
136        ::placeholder { /* CSS 3 標準 */
137          color: #b5b7ba;
138          font-size: 1em;
139        }
140        lit-search input::placeholder {
141          color: #b5b7ba;
142          font-size: 1em;
143        }
144        .content{
145            grid-area: b;
146            background-color: #ffffff;
147            height: 100%;
148            overflow: auto;
149            position:relative;
150        }
151        .sheet{
152
153        }
154        .sidebar-button{
155            position: absolute;
156            top: 0;
157            left: 0;
158            background-color: var(--dark-background1,#FFFFFF);
159            height: 100%;
160            border-radius: 0 5px 5px 0;
161            width: 48px;
162            display: flex;
163            align-content: center;
164            justify-content: center;
165            cursor: pointer;
166        }
167        :host{
168            font-size: inherit;
169            display: inline-block;
170            transition: .3s;
171         }
172         :host([spin]){
173            animation: rotate 1.75s linear infinite;
174         }
175         @keyframes rotate {
176            to{
177                transform: rotate(360deg);
178            }
179         }
180         .icon{
181            display: block;
182            width: 1em;
183            height: 1em;
184            margin: auto;
185            fill: currentColor;
186            overflow: hidden;
187            font-size: 20px;
188            color: #1E4EEA;
189         }
190        :host([chart_filter]) .chart-filter {
191            display: grid;
192            grid-template-rows: min-content min-content min-content max-content auto;
193            overflow-y: clip;
194            height: 99%;
195            visibility: visible;
196            position: absolute;
197            width: 40%;
198            right: 0;
199            z-index: 1001;
200            top: 0;
201        }
202        :host([custom-color]) .custom-color {
203            display: grid;
204            grid-template-rows: min-content min-content min-content max-content auto;
205            overflow-y: auto;
206            height: 100%;
207            visibility: visible;
208            position: absolute;
209            width: 50%;
210            right: 0;
211            z-index: 1002;
212            top: 0;
213        }
214        .filter-config {
215            opacity: 1;
216            visibility: hidden;
217        }
218        .filter-config:hover {
219            opacity: 0.7;
220        }
221        .page-button[prohibit] {
222          cursor: none;
223        }
224        .page-button {
225            background: #D8D8D8;
226            border-radius: 12px;
227            width: 24px;
228            height: 24px;
229            margin-right: 12px;
230            display: flex;
231            justify-content: center;
232            align-items: center;
233        }
234        #preview-button:hover {
235          cursor: pointer;
236          background: #0A59F7;
237          color: #FFFFFF;
238          opacity: 1;
239        }
240        #next-button:hover {
241          cursor: pointer;
242          background: #0A59F7;
243          color: #FFFFFF;
244          opacity: 1;
245        }
246        .pagination:hover {
247          cursor: pointer;
248          background: #0A59F7;
249          color: #FFFFFF;
250          opacity: 1;
251        }
252        .confirm-button:hover {
253          cursor: pointer;
254          background: #0A59F7;
255          color: #FFFFFF;
256          opacity: 1;
257        }
258        .pagination {
259            background: #D8D8D8;
260            color: #000000;
261            border-radius: 12px;
262            width: 24px;
263            height: 24px;
264            margin-right: 12px;
265            display: flex;
266            justify-content: center;
267            align-items: center;
268            font-family: Helvetica;
269            font-size: 12px;
270            text-align: center;
271            line-height: 20px;
272            font-weight: 400;
273            opacity: 0.6;
274        }
275        .pagination[selected] {
276            background: #0A59F7;
277            color: #FFFFFF;
278            opacity: 1;
279        }
280        .page-jump-font {
281            opacity: 0.6;
282            font-family: Helvetica;
283            font-size: 12px;
284            color: #000000;
285            text-align: center;
286            line-height: 20px;
287            font-weight: 400;
288        }
289        .page-input {
290            background: #D8D8D8;
291            border-radius: 10px;
292            width: 40px;
293            height: 24px;
294            justify-content: center;
295            align-items: center;
296            text-align: center;
297            margin-right: 8px;
298            border: none;
299        }
300        .confirm-button {
301            font-family: Helvetica;
302            font-size: 12px;
303            color: #0A59F7;
304            text-align: center;
305            font-weight: 400;
306            border: 1px solid #0A59F7;
307            border-radius: 10px;
308            width: 64px;
309            height: 24px;
310            line-height: 24px;
311        }
312        .long_trace_page {
313            justify-content: center;
314            width: -webkit-fill-available;
315            margin-right: 5.2em;
316            align-items: center;
317            display: none;
318        }
319        .content-center-option {
320          justify-content: center;
321          width: -webkit-fill-available;
322          margin-right: 5.2em;
323          align-items: center;
324          width: auto;
325        }
326        .page-number-list {
327            display: flex;
328        }
329
330        #sp-ai-analysis {
331            top:75px;
332            right:0px;
333            position:absolute;
334            z-index:9999;
335            min-width:430px;
336            max-width:75%;
337            width:430px;
338            height:740px;
339            box-shadow:3px 0px 14px #000;
340            border-radius:8px;
341            background-color:#fff;
342            padding:10px 10px 30px 5px;
343            box-sizing:border-box;
344            visibility:hidden;
345        }
346        #sp-snapshot-view {
347            top:75px;
348            right:0px;
349            position:absolute;
350            z-index:2000;
351            width:25%;
352            height:90%;
353            box-shadow:3px 0px 14px #000;
354            background-color:#fff;
355            box-sizing:border-box;
356            visibility:hidden;
357        }
358        </style>
359        <div class="root" style="position: relative;">
360            <sp-bubble-ai style="visibility: visible; top:50%;right:2px;position: absolute;z-index: 10000" id="sp-bubbles" draggable ="true"></sp-bubble-ai>
361            <sp-advertisement style="bottom:2px;right:2px;position: absolute;z-index: 10086" id= "sp-advertisement"></sp-advertisement>
362            <lit-main-menu id="main-menu" class="menu" data=''></lit-main-menu>
363            <sp-keyboard style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0px;left:0px;right:0;bottom:0px;position:absolute;z-index: 8888" id="sp-keyboard">
364            </sp-keyboard>
365            <div class="search-vessel">
366                <div class="search" style="position: relative;">
367                    <div class="sidebar-button" style="width: 0">
368                        <svg class="icon" id="icon" aria-hidden="true" viewBox="0 0 1024 1024">
369                             <use id="use" xlink:href="./base-ui/icon.svg#icon-menu"></use>
370                        </svg>
371                    </div>
372                    <div class = "content-left-option" style="text-align: left;
373                      position: absolute;left: 5px ; cursor: pointer;top: 15px">
374                      <div title="Import Key Path" id="import-key-path" style="display: none ;text-align: left;cursor: pointer;">
375                        <input id="import-config" style="display: none;pointer-events: none" type="file" accept=".json" >
376                        <label style="width: 20px;height: 20px;cursor: pointer;" for="import-config">
377                            <lit-icon id="import-btn" name="copy-csv" style="pointer-events: none" size="20">
378                            </lit-icon>
379                        </label>
380                      </div>
381                      <lit-icon  id="close-key-path" name="close" title="Close Key Path" color='#fff' size="20" style="display: none;text-align: left;cursor: pointer;">
382                      </lit-icon>
383                    </div>
384                    <lit-search id="lit-search"></lit-search>
385                    <lit-search id="lit-record-search"></lit-search>
386                    <div class="content-center-option" style="display: ">
387                      <div class="long_trace_page" style="display: none;">
388                        <div class="page-button" id="preview-button">
389                          <img title="preview" src="img/preview.png"/>
390                        </div>
391                        <div class="page-number-list"></div>
392                        <div class="page-button" id="next-button" style="margin-right: 8px;">
393                           <img title="next" src="img/next.png"/>
394                        </div>
395                        <div class="page-jump-font" style="margin-right: 8px;">To</div>
396                        <input class="page-input" />
397                        <div class="confirm-button">Confirm</div>
398                      </div>
399                    </div>
400                </div>
401                <div class = "content-right-option" style="display: flex;flex-flow: nowrap;text-align: right;position: absolute;right: 1.2em;cursor: pointer;top: 17px"">
402                  <lit-icon class="export-record" title="Download Mark Trace" name="download" size="16" style="margin-left: 0.8em;"></lit-icon>
403                  <img class="cut-trace-file" title="Cut Trace File" src="img/menu-cut.svg" style="margin-left: 0.8em;">
404                  <img class="filter-config" title="Display Template" src="img/config_filter.png" style="margin-left: 0.8em;">
405                </div>
406                <lit-progress-bar class="progress"></lit-progress-bar>
407            </div>
408            <div id="app-content" class="content">
409                <sp-welcome style="visibility:visible;top:0px;left:0px;position:absolute;z-index: 100" id="sp-welcome">
410                </sp-welcome>
411                </sp-ai-analysis>
412                <sp-system-trace style="visibility:hidden;z-index: 101;" id="sp-system-trace">
413                </sp-system-trace>
414                <sp-record-trace record_template='false' style="overflow:auto;width:100%;height:100%;visibility:hidden;top:0px;left:0px;right:0;bottom:0px;position:absolute;z-index: 102" id="sp-record-trace">
415                </sp-record-trace>
416                <sp-scheduling-analysis style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0;left:0;right:0;bottom:0;position:absolute;" id="sp-scheduling-analysis"></sp-scheduling-analysis>
417                <sp-metrics style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0;left:0;right:0;bottom:0;position:absolute;z-index: 105" id="sp-metrics">
418                </sp-metrics>
419                <sp-query-sql style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0;left:0;right:0;bottom:0;position:absolute;z-index: 106" id="sp-query-sql">
420                </sp-query-sql>
421                <sp-info-and-stats style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0;left:0;right:0;bottom:0;position:absolute;z-index: 107" id="sp-info-and-stats">
422                </sp-info-and-stats>
423                <sp-convert-trace style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0;left:0;right:0;bottom:0;position:absolute;z-index: 107" id="sp-convert-trace">
424                </sp-convert-trace>
425                <sp-help style="width:100%;height:100%;overflow:hidden;visibility:hidden;top:0px;left:0px;right:0;bottom:0px;position:absolute;z-index: 103" id="sp-help">
426                </sp-help>
427                <sp-flags style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0px;left:0px;right:0;bottom:0px;position:absolute;z-index: 104" id="sp-flags">
428                </sp-flags>
429                <sp-third-party style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0px;left:0px;right:0;bottom:0px;position:absolute;z-index: 104" id="sp-third-party">
430                </sp-third-party>
431                <trace-row-config class="chart-filter" style="height:100%;top:0px;right:0;bottom:0px;position:absolute;z-index: 1001"></trace-row-config>
432                <custom-theme-color class="custom-color" style="height:100%;top:0px;right:0;bottom:0px;position:absolute;z-index: 1001"></custom-theme-color>
433            </div>
434                <sp-ai-analysis id="sp-ai-analysis" style="visibility:hidden;"></sp-ai-analysis>
435                <sp-snapshot-view id="sp-snapshot-view" style="visibility:hidden;"></sp-snapshot-view>
436        </div>
437        `;
438
439export function readTraceFileBuffer(): Promise<ArrayBuffer | undefined> {
440  return new Promise((resolve) => {
441    caches.match(getThreadPoolTraceBufferCacheKey('1')).then((res) => {
442      if (res) {
443        res.arrayBuffer().then((buffer) => {
444          resolve(buffer);
445        });
446      } else {
447        resolve(undefined);
448      }
449    });
450  });
451}
452
453export function clearTraceFileCache(): void {
454  caches.keys().then((keys) => {
455    keys.forEach((key) => {
456      if (key === getThreadPoolTraceBufferCacheKey('1')) {
457        caches.delete(key).then();
458      } else if (key.includes('/') && key.includes('-')) {
459        let splits = key.split('/');
460        let keyStr = splits[splits.length - 1];
461        let time = keyStr.split('-')[0];
462        let fileDate = new Date(parseInt(time));
463        if (fileDate.toLocaleDateString() !== new Date().toLocaleDateString()) {
464          //如果不是当天的缓存则删去缓存文件
465          caches.delete(key).then();
466        }
467      } else {
468        caches.delete(key).then();
469      }
470    });
471  });
472}
473
474export function postLog(filename: string, fileSize: string): void {
475  fetch(`https://${window.location.host.split(':')[0]}:${window.location.port}${window.location.pathname}logger`, {
476    method: 'POST',
477    headers: {
478      'Content-Type': 'application/json',
479    },
480    body: JSON.stringify({
481      fileName: filename,
482      fileSize: fileSize,
483    }),
484  })
485    .then((response) => response.json())
486    .then((data) => { })
487    .catch((error) => { });
488}
489
490export function indexedDataToBufferData(sourceData: unknown): ArrayBuffer {
491  let uintArrayLength = 0;
492  //@ts-ignore
493  let uintDataList = sourceData.map((item: unknown) => {
494    //@ts-ignore
495    let currentBufData = new Uint8Array(item.buf);
496    uintArrayLength += currentBufData.length;
497    return currentBufData;
498  });
499  let resultArrayBuffer = new ArrayBuffer(uintArrayLength);
500  let resultUintArray = new Uint8Array(resultArrayBuffer);
501  let offset = 0;
502  uintDataList.forEach((currentArray: Uint8Array) => {
503    resultUintArray.set(currentArray, offset);
504    offset += currentArray.length;
505  });
506  return resultArrayBuffer;
507}
508
509export function findFreeSizeAlgorithm(numbers: Array<number>, freeSize: number): Array<number> {
510  let closestSize = 0;
511  let currentSize = 0;
512  let finalIndex: Array<number> = [];
513  let currentSelectIndex: Array<number> = [];
514
515  function reBackFind(index: number): void {
516    if (index === numbers.length) {
517      const sumDifference = Math.abs(currentSize - freeSize);
518      if (currentSize <= freeSize && sumDifference < Math.abs(closestSize - freeSize)) {
519        closestSize = currentSize;
520        finalIndex = [...currentSelectIndex];
521      }
522      return;
523    }
524    currentSize += numbers[index];
525    currentSelectIndex.push(index);
526    reBackFind(index + 1);
527    currentSize -= numbers[index];
528    currentSelectIndex.pop();
529    reBackFind(index + 1);
530  }
531
532  reBackFind(0);
533  return finalIndex;
534}
535
536export function getCurrentDataTime(): string[] {
537  let current = new Date();
538  let year = '' + current.getFullYear();
539  let month = ('0' + (current.getMonth() + 1)).slice(-2);
540  let day = ('0' + current.getDate()).slice(-2);
541  let hours = ('0' + current.getHours()).slice(-2);
542  let minutes = ('0' + current.getMinutes()).slice(-2);
543  let seconds = ('0' + current.getSeconds()).slice(-2);
544  return [year, month, day, hours, minutes, seconds];
545}
546
547// 定义ZIP文件的文件头常量
548const ZIP_HEADER = [0x50, 0x4B, 0x03, 0x04];
549// 定义ZLIB文件的文件头常量
550const ZLIB_HEADER = [0x78, 0x9c];
551
552/**
553 * 验证Uint8Array实例并检查长度是否满足要求
554 * @param uint8Array 待验证的Uint8Array实例
555 * @param requiredLength 所需的最小长度
556 * @returns 如果uint8Array是一个Uint8Array实例且长度大于等于requiredLength,则返回true,否则返回false
557 */
558function validateUint8Array(uint8Array: Uint8Array, requiredLength: number): boolean {
559  return uint8Array instanceof Uint8Array && uint8Array.length >= requiredLength;
560}
561
562/**
563 * 检查Uint8Array是否表示一个ZIP文件
564 * @param uint8Array 待检查的Uint8Array实例
565 * @returns 如果uint8Array表示的是一个ZIP文件,则返回true,否则返回false
566 */
567export function isZipFile(uint8Array: Uint8Array): boolean {
568  if (!validateUint8Array(uint8Array, ZIP_HEADER.length)) {
569    return false;
570  }
571  for (let i = 0; i < ZIP_HEADER.length; i++) {
572    if (uint8Array[i] !== ZIP_HEADER[i]) {
573      return false;
574    }
575  }
576  return true;
577}
578
579/**
580 * 检查Uint8Array是否表示一个ZLIB文件
581 * @param uint8Array 待检查的Uint8Array实例
582 * @returns 如果uint8Array表示的是一个ZLIB文件,则返回true,否则返回false
583 */
584export function isZlibFile(uint8Array: Uint8Array): boolean {
585  if (!validateUint8Array(uint8Array, ZLIB_HEADER.length)) {
586    return false;
587  }
588  for (let i = 0; i < ZLIB_HEADER.length; i++) {
589    if (uint8Array[i] !== ZLIB_HEADER[i]) {
590      return false;
591    }
592  }
593  return true;
594}
595
596/**
597 * 外部交互,向外传输db文件
598 */
599export function addExportDBToParentEvent() {
600  window.addEventListener('message', e => {
601    if (e.data.name == 'exportDbToParent') {
602      threadPool.submit('download-db', '', {}, async (reqBufferDB: ArrayBuffer) => {
603        if (reqBufferDB && reqBufferDB.byteLength > 0) {
604          window.parent.postMessage({
605            name: `${(TraceUtil.currentTraceName || 'trace').split('.')[0]}.db`,
606            data: reqBufferDB
607          }, '*');
608        } else {
609          window.parent.postMessage({
610            name: `暂无数据`,
611            data: null
612          }, '*');
613        }
614      }, 'download-db');
615    }
616  });
617}
618
619export function loadTraceCompleteEvent() {
620  if (window?.parent) {
621      window.parent.postMessage({
622        name:'trace_load_complete',
623        data: null
624      }, '*');
625    }
626}