1/*
2 * Copyright (c) 2021-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 worker from '@ohos.worker';
17import Log from '../default/Log';
18import BundleManager from '../default/abilitymanager/bundleManager';
19import { Want } from 'ability/want';
20import Constants, { ItemComponentData, obtainMsg, RootConfigInfo } from './common/Constants';
21import ServiceExtensionContext from 'application/ServiceExtensionContext';
22import PluginSourceLoaderPatch from './sourceloader/PluginSourceLoaderPatch'
23
24export interface PluginWorkerListener {
25  initFinish(): void;
26  onItemAdd(data: ItemComponentData): void;
27  onItemRemove(data: ItemComponentData): void;
28};
29
30const TAG = 'PluginDataSourceAdapter';
31
32export default class PluginDataSourceAdapter {
33  mContext: ServiceExtensionContext;
34  mWorker;
35  mName: string;
36  mListener: PluginWorkerListener;
37  mWant: Want;
38  mPluginSourceLoaderPatch: PluginSourceLoaderPatch;
39  mModuleName: string;
40
41  constructor(name: string, context: ServiceExtensionContext, listener: PluginWorkerListener, moduleName: string) {
42    Log.showDebug(TAG, `constructor, name: ${name}`);
43    this.mName = name;
44    this.mContext = context;
45    this.mListener = listener;
46    this.mModuleName = moduleName;
47    const WORKER_JS_URL = this.mModuleName + '/ets/workers/PluginDataSourceWorker.js';
48    this.mWorker = new worker.Worker(WORKER_JS_URL, {
49      type: 'classic',
50      name: this.mName,
51    });
52
53    this.mWorker.onmessage = this.onMessage.bind(this);
54    this.mWorker.onmessageerror = this.onMessageError.bind(this);
55    this.mWorker.onexit = this.onExit.bind(this);
56    this.mWorker.onerror = this.onError.bind(this);
57  }
58
59  setWant(want: Want): void{
60    this.mWant = want;
61  }
62
63  initDataSource(configs: RootConfigInfo): void {
64    Log.showDebug(TAG, `name: ${this.mName}, initDataSource, configs: ${JSON.stringify(configs)}`);
65    this.mWorker.postMessage(obtainMsg(Constants.INIT_CONFIG, configs));
66    if (configs.loaderConfig.PluginSourceLoader) {
67      this.mPluginSourceLoaderPatch = new PluginSourceLoaderPatch(this.mWant, this);
68    }
69  }
70
71  loadData(userId: number): void {
72    Log.showDebug(TAG, `name: ${this.mName}, loadData`);
73    this.mWorker.postMessage(obtainMsg(Constants.LOAD_DATA, userId));
74  }
75
76  clearAll(): void {
77    Log.showDebug(TAG, `name: ${this.mName}, clearAll`);
78    this.mWorker.postMessage(obtainMsg(Constants.CLEAR_ALL, {}));
79    this.mPluginSourceLoaderPatch?.clearAll();
80  }
81
82  onMessage(msg: { data }): void {
83    Log.showDebug(TAG, `name: ${this.mName}, onMessage, msg: ${JSON.stringify(msg)}`);
84    let data = msg.data;
85    switch (data.action) {
86      case Constants.INIT_FINISH:
87        this.onInitFinish();
88        break;
89      case Constants.ADD_ITEM:
90        this.onItemAdd(data.data);
91        break;
92      case Constants.REMOVE_ITEM:
93        this.onItemRemove(data.data);
94        break;
95      case Constants.LOAD_PLUGIN_COMPONENT_DATA:
96        this.onLoadPluginComponentData(data.data).then(() => {
97        }).catch(err => {
98        });
99        break;
100      default:
101        Log.showError(TAG, `name: ${this.mName}, unknown type: ${data.action}`);
102    }
103  }
104
105  onInitFinish(): void {
106    Log.showDebug(TAG, `name: ${this.mName}, onInitFinish`);
107    this.mListener.initFinish();
108  }
109
110  async onItemAdd(itemData: ItemComponentData): Promise<void> {
111    Log.showDebug(TAG, `name: ${this.mName}, onItemAdd, itemData: ${JSON.stringify(itemData)}`);
112    itemData.label && (itemData.label = decodeURIComponent(itemData.label));
113    if (itemData.label && itemData.iconUrl) {
114      this.mListener.onItemAdd(itemData);
115      return;
116    }
117    Promise.all([
118      itemData.iconUrl ?? BundleManager.getMediaBase64({bundleName: itemData.bundleName, moduleName: itemData.moduleName, id: itemData.abilityIconId}),
119      itemData.label ?? BundleManager.getString({bundleName: itemData.bundleName, moduleName: itemData.moduleName, id: itemData.abilityLabelId}),
120    ])
121      .then(([iconValue, labelValue]) => {
122        iconValue && (itemData.iconUrl = iconValue);
123        labelValue && (itemData.label = labelValue);
124        this.mListener.onItemAdd(itemData);
125      })
126      .catch((err) => Log.showError(TAG, `name: ${this.mName}, Can't get bundle info, err: ${JSON.stringify(err)}`));
127  }
128
129  onItemRemove(itemData: ItemComponentData): void {
130    Log.showDebug(TAG, `name: ${this.mName}, onItemRemove, itemData: ${JSON.stringify(itemData)}`);
131    this.mListener.onItemRemove(itemData);
132  }
133
134  async onLoadPluginComponentData(itemData: ItemComponentData): Promise<void> {
135    Log.showDebug(TAG, `name: ${this.mName}, onLoadPluginComponentData, itemData: ${JSON.stringify(itemData)}`);
136    let ret = await this.mPluginSourceLoaderPatch?.requestPluginComponentData(itemData);
137    this.mWorker.postMessage(obtainMsg(Constants.UPDATE_PLUGIN_COMPONENT_DATA, ret));
138  }
139
140  async onUpdatePluginComponentData(pluginComponentData: ItemComponentData): Promise<void> {
141    Log.showDebug(TAG, `name: ${this.mName}, onUpdatePluginComponentData, pluginComponentData: ${JSON.stringify(pluginComponentData)}`);
142    this.mWorker.postMessage(obtainMsg(Constants.UPDATE_PLUGIN_COMPONENT_DATA, pluginComponentData));
143  }
144
145  onMessageError(event): void {
146    Log.showDebug(TAG, `name: ${this.mName}, mWorker.onmessageerror, event: ${JSON.stringify(event)}`);
147  }
148
149  onExit(code: number): void {
150    Log.showDebug(TAG, `name: ${this.mName}, mWorker.onexit, code: ${code}`);
151  }
152
153  onError(err): void {
154    Log.showDebug(TAG, `name: ${this.mName}, mWorker.onerror, err: ${JSON.stringify(err)}`);
155  }
156}
157