1fb726d48Sopenharmony_ci/*
2fb726d48Sopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd.
3fb726d48Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4fb726d48Sopenharmony_ci * you may not use this file except in compliance with the License.
5fb726d48Sopenharmony_ci * You may obtain a copy of the License at
6fb726d48Sopenharmony_ci *
7fb726d48Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8fb726d48Sopenharmony_ci *
9fb726d48Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10fb726d48Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11fb726d48Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fb726d48Sopenharmony_ci * See the License for the specific language governing permissions and
13fb726d48Sopenharmony_ci * limitations under the License.
14fb726d48Sopenharmony_ci */
15fb726d48Sopenharmony_ci
16fb726d48Sopenharmony_ciimport { query } from './SqlLite';
17fb726d48Sopenharmony_ci
18fb726d48Sopenharmony_ciclass ProcedureThread {
19fb726d48Sopenharmony_ci  busy: boolean = false;
20fb726d48Sopenharmony_ci  isCancelled: boolean = false;
21fb726d48Sopenharmony_ci  id: number = -1; //@ts-ignore
22fb726d48Sopenharmony_ci  taskMap: unknown = {};
23fb726d48Sopenharmony_ci  name: string | undefined;
24fb726d48Sopenharmony_ci  worker?: Worker;
25fb726d48Sopenharmony_ci  constructor(worker: Worker) {
26fb726d48Sopenharmony_ci    this.worker = worker;
27fb726d48Sopenharmony_ci  }
28fb726d48Sopenharmony_ci  uuid(): string {
29fb726d48Sopenharmony_ci    // @ts-ignore
30fb726d48Sopenharmony_ci    return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
31fb726d48Sopenharmony_ci      (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16)
32fb726d48Sopenharmony_ci    );
33fb726d48Sopenharmony_ci  }
34fb726d48Sopenharmony_ci  //@ts-ignore
35fb726d48Sopenharmony_ci  queryFunc(type: string, args: unknown, transfer: unknown, handler: Function): void {
36fb726d48Sopenharmony_ci    this.busy = true;
37fb726d48Sopenharmony_ci    let id = this.uuid(); // @ts-ignore
38fb726d48Sopenharmony_ci    this.taskMap[id] = handler;
39fb726d48Sopenharmony_ci    let pam = {
40fb726d48Sopenharmony_ci      id: id,
41fb726d48Sopenharmony_ci      type: type,
42fb726d48Sopenharmony_ci      params: args,
43fb726d48Sopenharmony_ci    };
44fb726d48Sopenharmony_ci    if (transfer) {
45fb726d48Sopenharmony_ci      try {
46fb726d48Sopenharmony_ci        if (Array.isArray(transfer)) {
47fb726d48Sopenharmony_ci          if (transfer.length > 0) {
48fb726d48Sopenharmony_ci            this.worker!.postMessage(pam, [...transfer]);
49fb726d48Sopenharmony_ci          } else {
50fb726d48Sopenharmony_ci            this.worker!.postMessage(pam);
51fb726d48Sopenharmony_ci          }
52fb726d48Sopenharmony_ci        } else {
53fb726d48Sopenharmony_ci          // @ts-ignore
54fb726d48Sopenharmony_ci          this.worker!.postMessage(pam, [transfer]);
55fb726d48Sopenharmony_ci        }
56fb726d48Sopenharmony_ci      } catch (
57fb726d48Sopenharmony_ci        //@ts-ignore
58fb726d48Sopenharmony_ci        e: unknown
59fb726d48Sopenharmony_ci      ) {}
60fb726d48Sopenharmony_ci    } else {
61fb726d48Sopenharmony_ci      this.worker!.postMessage(pam);
62fb726d48Sopenharmony_ci    }
63fb726d48Sopenharmony_ci  }
64fb726d48Sopenharmony_ci
65fb726d48Sopenharmony_ci  cancel(): void {
66fb726d48Sopenharmony_ci    this.isCancelled = true;
67fb726d48Sopenharmony_ci    this.worker!.terminate();
68fb726d48Sopenharmony_ci  }
69fb726d48Sopenharmony_ci}
70fb726d48Sopenharmony_ci
71fb726d48Sopenharmony_ciclass ProcedurePool {
72fb726d48Sopenharmony_ci  static cpuCount = Math.floor((window.navigator.hardwareConcurrency || 4) / 2);
73fb726d48Sopenharmony_ci  maxThreadNumber: number = 1;
74fb726d48Sopenharmony_ci  works: Array<ProcedureThread> = [];
75fb726d48Sopenharmony_ci  timelineChange:
76fb726d48Sopenharmony_ci    | ((
77fb726d48Sopenharmony_ci        //@ts-ignore
78fb726d48Sopenharmony_ci        a: unknown
79fb726d48Sopenharmony_ci      ) => void)
80fb726d48Sopenharmony_ci    | undefined
81fb726d48Sopenharmony_ci    | null = null;
82fb726d48Sopenharmony_ci  cpusLen = ProcedurePool.build('cpu', 0);
83fb726d48Sopenharmony_ci  freqLen = ProcedurePool.build('freq', 0);
84fb726d48Sopenharmony_ci  processLen = ProcedurePool.build('process', 0);
85fb726d48Sopenharmony_ci  logicDataLen = ProcedurePool.build('logic', 2);
86fb726d48Sopenharmony_ci  names = [...this.cpusLen, ...this.processLen, ...this.freqLen];
87fb726d48Sopenharmony_ci  logicDataHandles = [...this.logicDataLen];
88fb726d48Sopenharmony_ci
89fb726d48Sopenharmony_ci  onComplete: Function | undefined; //任务完成回调
90fb726d48Sopenharmony_ci
91fb726d48Sopenharmony_ci  constructor(threadBuild: (() => ProcedureThread) | undefined = undefined) {
92fb726d48Sopenharmony_ci    this.init(threadBuild);
93fb726d48Sopenharmony_ci  }
94fb726d48Sopenharmony_ci
95fb726d48Sopenharmony_ci  static build(name: string, len: number): string[] {
96fb726d48Sopenharmony_ci    return [...Array(len).keys()].map((it) => `${name}${it}`);
97fb726d48Sopenharmony_ci  }
98fb726d48Sopenharmony_ci
99fb726d48Sopenharmony_ci  init(threadBuild: (() => ProcedureThread) | undefined = undefined): void {
100fb726d48Sopenharmony_ci    this.maxThreadNumber = this.names.length;
101fb726d48Sopenharmony_ci    for (let i = 0; i < this.maxThreadNumber; i++) {
102fb726d48Sopenharmony_ci      this.newThread();
103fb726d48Sopenharmony_ci    }
104fb726d48Sopenharmony_ci    for (let j = 0; j < this.logicDataHandles.length; j++) {
105fb726d48Sopenharmony_ci      this.logicDataThread();
106fb726d48Sopenharmony_ci    }
107fb726d48Sopenharmony_ci  }
108fb726d48Sopenharmony_ci
109fb726d48Sopenharmony_ci  newThread(): void {
110fb726d48Sopenharmony_ci    // @ts-ignore
111fb726d48Sopenharmony_ci    if (window.useWb) {
112fb726d48Sopenharmony_ci      return;
113fb726d48Sopenharmony_ci    }
114fb726d48Sopenharmony_ci    let newThread: ProcedureThread = new ProcedureThread(
115fb726d48Sopenharmony_ci      new Worker(new URL('./ui-worker/ProcedureWorker', import.meta.url), {
116fb726d48Sopenharmony_ci        type: 'module',
117fb726d48Sopenharmony_ci      })
118fb726d48Sopenharmony_ci    );
119fb726d48Sopenharmony_ci    newThread.name = this.names[this.works.length];
120fb726d48Sopenharmony_ci    newThread.worker!.onmessage = (event: MessageEvent): void => {
121fb726d48Sopenharmony_ci      newThread.busy = false;
122fb726d48Sopenharmony_ci      if ((event.data.type as string) === 'timeline-range-changed') {
123fb726d48Sopenharmony_ci        this.timelineChange?.(event.data.results);
124fb726d48Sopenharmony_ci        newThread.busy = false;
125fb726d48Sopenharmony_ci        return;
126fb726d48Sopenharmony_ci      } // @ts-ignore
127fb726d48Sopenharmony_ci      if (Reflect.has(newThread.taskMap, event.data.id)) {
128fb726d48Sopenharmony_ci        if (event.data) {
129fb726d48Sopenharmony_ci          // @ts-ignore
130fb726d48Sopenharmony_ci          let fun = newThread.taskMap[event.data.id];
131fb726d48Sopenharmony_ci          if (fun) {
132fb726d48Sopenharmony_ci            fun(event.data.results, event.data.hover);
133fb726d48Sopenharmony_ci          } // @ts-ignore
134fb726d48Sopenharmony_ci          Reflect.deleteProperty(newThread.taskMap, event.data.id);
135fb726d48Sopenharmony_ci        }
136fb726d48Sopenharmony_ci      }
137fb726d48Sopenharmony_ci      if (this.isIdle() && this.onComplete) {
138fb726d48Sopenharmony_ci        this.onComplete();
139fb726d48Sopenharmony_ci      }
140fb726d48Sopenharmony_ci    };
141fb726d48Sopenharmony_ci    newThread.worker!.onmessageerror = (e): void => {};
142fb726d48Sopenharmony_ci    newThread.worker!.onerror = (e): void => {};
143fb726d48Sopenharmony_ci    newThread.id = this.works.length;
144fb726d48Sopenharmony_ci    newThread.busy = false;
145fb726d48Sopenharmony_ci    this.works?.push(newThread);
146fb726d48Sopenharmony_ci  }
147fb726d48Sopenharmony_ci
148fb726d48Sopenharmony_ci  private logicDataThread(): void {
149fb726d48Sopenharmony_ci    // @ts-ignore
150fb726d48Sopenharmony_ci    if (window.useWb) {
151fb726d48Sopenharmony_ci      return;
152fb726d48Sopenharmony_ci    }
153fb726d48Sopenharmony_ci    let thread: ProcedureThread = new ProcedureThread(
154fb726d48Sopenharmony_ci      new Worker(new URL('./logic-worker/ProcedureLogicWorker', import.meta.url), {
155fb726d48Sopenharmony_ci        type: 'module',
156fb726d48Sopenharmony_ci      })
157fb726d48Sopenharmony_ci    );
158fb726d48Sopenharmony_ci    thread.name = this.logicDataHandles[this.works.length - this.names.length];
159fb726d48Sopenharmony_ci    this.sendMessage(thread);
160fb726d48Sopenharmony_ci    thread.worker!.onmessageerror = (e): void => {};
161fb726d48Sopenharmony_ci    thread.worker!.onerror = (e): void => {};
162fb726d48Sopenharmony_ci    thread.id = this.works.length;
163fb726d48Sopenharmony_ci    thread.busy = false;
164fb726d48Sopenharmony_ci    this.works?.push(thread);
165fb726d48Sopenharmony_ci  }
166fb726d48Sopenharmony_ci
167fb726d48Sopenharmony_ci  private sendMessage(thread: ProcedureThread): void {
168fb726d48Sopenharmony_ci    thread.worker!.onmessage = (event: MessageEvent): void => {
169fb726d48Sopenharmony_ci      thread.busy = false;
170fb726d48Sopenharmony_ci      if (event.data.isQuery) {
171fb726d48Sopenharmony_ci        query(event.data.type, event.data.sql, event.data.args, { action : 'exec-buf' }).then(
172fb726d48Sopenharmony_ci          (
173fb726d48Sopenharmony_ci            // @ts-ignore
174fb726d48Sopenharmony_ci            res: unknown
175fb726d48Sopenharmony_ci          ) => {
176fb726d48Sopenharmony_ci            thread.worker!.postMessage({
177fb726d48Sopenharmony_ci              type: event.data.type,
178fb726d48Sopenharmony_ci              params: {
179fb726d48Sopenharmony_ci                list: res,
180fb726d48Sopenharmony_ci              },
181fb726d48Sopenharmony_ci              id: event.data.id,
182fb726d48Sopenharmony_ci            });
183fb726d48Sopenharmony_ci          }
184fb726d48Sopenharmony_ci        );
185fb726d48Sopenharmony_ci        return;
186fb726d48Sopenharmony_ci      }
187fb726d48Sopenharmony_ci      if (event.data.isSending) {
188fb726d48Sopenharmony_ci        if (
189fb726d48Sopenharmony_ci          Reflect.has(
190fb726d48Sopenharmony_ci            // @ts-ignore
191fb726d48Sopenharmony_ci            thread.taskMap,
192fb726d48Sopenharmony_ci            event.data.id
193fb726d48Sopenharmony_ci          )
194fb726d48Sopenharmony_ci        ) {
195fb726d48Sopenharmony_ci          if (event.data) {
196fb726d48Sopenharmony_ci            // @ts-ignore
197fb726d48Sopenharmony_ci            let fun = thread.taskMap[event.data.id];
198fb726d48Sopenharmony_ci            if (fun) {
199fb726d48Sopenharmony_ci              fun(event.data.results, event.data.hover);
200fb726d48Sopenharmony_ci            }
201fb726d48Sopenharmony_ci            return;
202fb726d48Sopenharmony_ci          }
203fb726d48Sopenharmony_ci        }
204fb726d48Sopenharmony_ci      } // @ts-ignore
205fb726d48Sopenharmony_ci      if (Reflect.has(thread.taskMap, event.data.id)) {
206fb726d48Sopenharmony_ci        if (event.data) {
207fb726d48Sopenharmony_ci          // @ts-ignore
208fb726d48Sopenharmony_ci          let fun = thread.taskMap[event.data.id];
209fb726d48Sopenharmony_ci          if (fun) {
210fb726d48Sopenharmony_ci            fun(event.data.results, event.data.hover);
211fb726d48Sopenharmony_ci          } // @ts-ignore
212fb726d48Sopenharmony_ci          Reflect.deleteProperty(thread.taskMap, event.data.id);
213fb726d48Sopenharmony_ci        }
214fb726d48Sopenharmony_ci      }
215fb726d48Sopenharmony_ci      if (this.isIdle() && this.onComplete) {
216fb726d48Sopenharmony_ci        this.onComplete();
217fb726d48Sopenharmony_ci      }
218fb726d48Sopenharmony_ci    };
219fb726d48Sopenharmony_ci  }
220fb726d48Sopenharmony_ci
221fb726d48Sopenharmony_ci  close = (): void => {
222fb726d48Sopenharmony_ci    for (let thread of this.works) {
223fb726d48Sopenharmony_ci      thread.worker!.terminate();
224fb726d48Sopenharmony_ci    }
225fb726d48Sopenharmony_ci    this.works.length = 0;
226fb726d48Sopenharmony_ci  };
227fb726d48Sopenharmony_ci
228fb726d48Sopenharmony_ci  clearCache = (): void => {
229fb726d48Sopenharmony_ci    for (let thread of this.works) {
230fb726d48Sopenharmony_ci      thread.queryFunc('clear', {}, undefined, () => {});
231fb726d48Sopenharmony_ci    }
232fb726d48Sopenharmony_ci  };
233fb726d48Sopenharmony_ci
234fb726d48Sopenharmony_ci  submitWithName(name: string, type: string, args: unknown, transfer: unknown, handler: Function): unknown {
235fb726d48Sopenharmony_ci    let noBusyThreads = this.works.filter((it) => it.name === name);
236fb726d48Sopenharmony_ci    let thread: ProcedureThread | undefined;
237fb726d48Sopenharmony_ci    if (noBusyThreads.length > 0) {
238fb726d48Sopenharmony_ci      //取第一个空闲的线程进行任务
239fb726d48Sopenharmony_ci      thread = noBusyThreads[0];
240fb726d48Sopenharmony_ci      thread!.queryFunc(type, args, transfer, handler);
241fb726d48Sopenharmony_ci    }
242fb726d48Sopenharmony_ci    return thread;
243fb726d48Sopenharmony_ci  }
244fb726d48Sopenharmony_ci  // @ts-ignore
245fb726d48Sopenharmony_ci  submitWithNamePromise(name: string, type: string, args: unknown, transfer: unknown): Promise<unknown> {
246fb726d48Sopenharmony_ci    return new Promise((resolve, reject) => {
247fb726d48Sopenharmony_ci      let noBusyThreads = this.works.filter((it) => it.name === name);
248fb726d48Sopenharmony_ci      let thread: ProcedureThread | undefined;
249fb726d48Sopenharmony_ci      if (noBusyThreads.length > 0) {
250fb726d48Sopenharmony_ci        //取第一个空闲的线程进行任务
251fb726d48Sopenharmony_ci        thread = noBusyThreads[0]; // @ts-ignore
252fb726d48Sopenharmony_ci        thread!.queryFunc(type, args, transfer, (res: unknown, hover: unknown) => {
253fb726d48Sopenharmony_ci          resolve({
254fb726d48Sopenharmony_ci            res: res,
255fb726d48Sopenharmony_ci            hover: hover,
256fb726d48Sopenharmony_ci          });
257fb726d48Sopenharmony_ci        });
258fb726d48Sopenharmony_ci      }
259fb726d48Sopenharmony_ci    });
260fb726d48Sopenharmony_ci  }
261fb726d48Sopenharmony_ci
262fb726d48Sopenharmony_ci  isIdle(): boolean {
263fb726d48Sopenharmony_ci    return this.works.every((it) => !it.busy);
264fb726d48Sopenharmony_ci  }
265fb726d48Sopenharmony_ci}
266fb726d48Sopenharmony_ci
267fb726d48Sopenharmony_ciexport const procedurePool = new ProcedurePool();
268