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 WorkFactory, { WorkerType } from '../WorkFactory'
17import worker from '@ohos.worker';
18import { HiLog } from '../../../../../../common'
19import buffer from '@ohos.buffer'
20
21const TAG = 'WorkerWrapper'
22
23export class WorkerMessage {
24  request: string;
25  callBackId: number;
26  type?: WorkerType;
27  param?: any;
28}
29
30/*
31 * WorkerWrapper
32 *
33 * Processes sending tasks to workers and receiving work processing results.
34 */
35export default class WorkerWrapper {
36  protected mWorker: worker.ThreadWorker = undefined;
37  private callBacks: Map<string, (result?: any) => void> = new Map();
38  private requestIndex: number = 0;
39  private workType: WorkerType;
40  private useWorker: boolean;
41
42  constructor(workType: WorkerType, useWorker: boolean) {
43    this.workType = workType;
44    this.useWorker = useWorker;
45    if (useWorker) {
46      this.initWorker();
47    }
48  }
49
50  async initWorker() {
51    HiLog.i(TAG, `WorkerWrapper initWorker ${WorkerType[this.getWorkerType()]}`)
52    let initWorker = await new worker.ThreadWorker('entry/ets/workers/base/Worker.ts', {
53      name: WorkerType[this.getWorkerType()]
54    });
55    let that = this;
56    initWorker.onexit = function (message) {
57      HiLog.w(TAG, 'onexit')
58      that.mWorker = undefined;
59    }
60    initWorker.onerror = function (e) {
61      HiLog.w(TAG, 'onerror:' + JSON.stringify(e))
62    }
63    initWorker.onmessageerror = function (e) {
64      HiLog.w(TAG, 'onmessageerror:' + JSON.stringify(e))
65    }
66    initWorker.onmessage = function (message) {
67      const buff = <ArrayBuffer> message.data;
68      const str = buffer.from(buff).toString();
69      let data = <WorkerMessage> JSON.parse(str)
70      HiLog.i(TAG, `onmessage ${data.request}`)
71      const key = that.getCallBackKey(data);
72      if (that.callBacks.has(key)) {
73        HiLog.i(TAG, `onmessage notify result.`)
74        const callback = that.callBacks.get(key);
75        if (callback) {
76          callback(data.param);
77        }
78        that.callBacks.delete(key);
79      }
80    }
81    this.mWorker = initWorker;
82    HiLog.i(TAG, `WorkerWrapper initWorker end`)
83  }
84
85  public getWorkerType(): WorkerType {
86    return this.workType;
87  }
88
89  /**
90   * SendRequest to worker thread.
91   *
92   * @param {string} request the request worker to do
93   * @param {Object} requestData  request param Data
94   * @param {Object} callBack Call back from worker
95   */
96  public async sendRequest(request: string, requestData?: any, callBack?: (result?: any) => void) {
97    HiLog.i(TAG, 'sendRequest in ' + request)
98    if (!this.useWorker) {
99      WorkFactory.getTask(this.getWorkerType()).runInWorker(request, callBack, requestData);
100    } else if (this.mWorker) {
101      const message = {
102        request: request,
103        callBackId: this.requestIndex,
104        type: this.getWorkerType(),
105        param: requestData
106      }
107      if (callBack) {
108        this.callBacks.set(this.getCallBackKey(message), callBack);
109      }
110      this.mWorker?.postMessage(message);
111      HiLog.d(TAG, `${this.getWorkerType()} ${request} send succ!`);
112      this.requestIndex++;
113    } else {
114      HiLog.w(TAG, `${this.getWorkerType()} ${request} send fail, worker has been closed!`);
115    }
116  }
117
118  /**
119   * Close  close worker thread.
120   */
121  public close() {
122    HiLog.i(TAG, `${this.getWorkerType()} worker close!`);
123    this.mWorker?.terminate();
124    this.mWorker = undefined;
125    this.callBacks.clear();
126  }
127
128  private getCallBackKey(message: WorkerMessage): string {
129    return message.request + message.callBackId;
130  }
131}
132