• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022-2023 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 */
15let rpc = requireNapi('rpc');
16let hilog = requireNapi('hilog');
17
18let domainID = 0xD001320;
19let TAG = 'JSENV';
20
21const EVENT_CALL_NOTIFY = 1;
22const REQUEST_SUCCESS = 0;
23
24const ERROR_CODE_INVALID_PARAM = 401;
25const ERROR_CODE_CALLER_RELEASED = 16200001;
26const ERROR_CODE_CLAAEE_INVALID = 16200002;
27const ERROR_CODE_INNER_ERROR = 16000050;
28
29const ERROR_MSG_INVALID_PARAM = 'Invalid input parameter.';
30const ERROR_MSG_CALLER_RELEASED = 'Caller released. The caller has been released.';
31const ERROR_MSG_CLAAEE_INVALID = 'The callee does not exist.';
32const ERROR_MSG_INNER_ERROR = 'Inner Error.';
33
34let errMap = new Map();
35errMap.set(ERROR_CODE_INVALID_PARAM, ERROR_MSG_INVALID_PARAM);
36errMap.set(ERROR_CODE_CALLER_RELEASED, ERROR_MSG_CALLER_RELEASED);
37errMap.set(ERROR_CODE_CLAAEE_INVALID, ERROR_MSG_CLAAEE_INVALID);
38errMap.set(ERROR_CODE_INNER_ERROR, ERROR_MSG_INNER_ERROR);
39
40class BusinessError extends Error {
41  constructor(code) {
42    let msg = '';
43    if (errMap.has(code)) {
44      msg = errMap.get(code);
45    } else {
46      msg = ERROR_MSG_INNER_ERROR;
47    }
48    super(msg);
49    this.code = code;
50  }
51}
52
53class ThrowInvalidParamError extends Error {
54  constructor(msg) {
55    let message = ERROR_MSG_INVALID_PARAM + msg;
56    super(message);
57    this.code = ERROR_CODE_INVALID_PARAM;
58  }
59}
60
61class Caller {
62  constructor(obj) {
63    hilog.sLogI(domainID, TAG, 'Caller::constructor obj is ' + typeof obj);
64    this.__call_obj__ = obj;
65    this.releaseState = false;
66  }
67
68  call(method, data) {
69    return new Promise(async (resolve, reject) => {
70      const checkError = this.callCheck(method, data);
71      if (checkError != null) {
72        reject(checkError);
73        return;
74      }
75
76      hilog.sLogI(domainID, TAG, 'Caller call msgData rpc.MessageSequence create');
77      let msgData = this.buildMsgData(method, data);
78      let msgReply = rpc.MessageSequence.create();
79
80      let retData = undefined;
81      try {
82        retData = await this.__call_obj__.callee.sendMessageRequest(EVENT_CALL_NOTIFY, msgData, msgReply,
83          rpc.MessageOption());
84        hilog.sLogI(domainID, TAG, 'Caller call msgData rpc.sendMessageRequest called');
85        if (retData.errCode !== 0) {
86          msgData.reclaim();
87          msgReply.reclaim();
88          hilog.sLogI(domainID, TAG, 'Caller call return errCode ' + retData.errCode);
89          reject(new BusinessError(retData.errCode));
90          return;
91        }
92      } catch (e) {
93        hilog.sLogI(domainID, TAG, 'Caller call msgData rpc.sendMessageRequest error ' + e);
94      }
95
96      try {
97        let retval = retData.reply.readInt();
98        let str = retData.reply.readString();
99        if (retval === REQUEST_SUCCESS && str === 'object') {
100          msgData.reclaim();
101          msgReply.reclaim();
102        } else {
103          hilog.sLogD(domainID, TAG,
104            'Caller call retval is [' + retval + '], str [' + str + ']');
105          msgData.reclaim();
106          msgReply.reclaim();
107          reject(new BusinessError(retval));
108          return;
109        }
110      } catch (e) {
111        hilog.sLogI(domainID, TAG, 'Caller call msgData sendMessageRequest retval error');
112        msgData.reclaim();
113        msgReply.reclaim();
114        reject(new BusinessError(ERROR_CODE_INNER_ERROR));
115        return;
116      }
117
118      hilog.sLogI(domainID, TAG, 'Caller call msgData sendMessageRequest end');
119      resolve(undefined);
120      return;
121    });
122  }
123
124  callWithResult(method, data) {
125    return new Promise(async (resolve, reject) => {
126      hilog.sLogI(domainID, TAG, 'Caller callWithResult method [' + method + ']');
127      const checkError = this.callCheck(method, data);
128      if (checkError != null) {
129        reject(checkError);
130        return;
131      }
132
133      hilog.sLogI(domainID, TAG, 'Caller callWithResult msgData rpc.MessageSequence create');
134      let msgData = this.buildMsgData(method, data);
135      let msgReply = rpc.MessageSequence.create();
136
137      let reply = undefined;
138      let retData = undefined;
139      try {
140        retData = await this.__call_obj__.callee.sendMessageRequest(EVENT_CALL_NOTIFY, msgData, msgReply,
141          rpc.MessageOption());
142        hilog.sLogI(domainID, TAG, 'Caller callWithResult msgData rpc.sendMessageRequest called');
143        if (retData.errCode !== 0) {
144          msgData.reclaim();
145          msgReply.reclaim();
146          hilog.sLogI(domainID, TAG, 'Caller callWithResult return errCode ' + retData.errCode);
147          reject(new BusinessError(retData.errCode));
148          return;
149        }
150      } catch (e) {
151        hilog.sLogI(domainID, TAG, 'Caller call msgData rpc.MessageSequence error ' + e);
152      }
153
154      try {
155        let retval = retData.reply.readInt();
156        let str = retData.reply.readString();
157        if (retval === REQUEST_SUCCESS && str === 'object') {
158          msgData.reclaim();
159          reply = retData.reply;
160        } else {
161          hilog.sLogI(domainID, TAG,
162            'Caller callWithResult retval is [' + retval + '], str [' + str + ']');
163          msgData.reclaim();
164          msgReply.reclaim();
165          reject(new BusinessError(retval));
166          return;
167        }
168      } catch (e) {
169        hilog.sLogI(domainID, TAG, 'Caller callWithResult msgData sendMessageRequest retval error');
170        msgData.reclaim();
171        msgReply.reclaim();
172        reject(new BusinessError(ERROR_CODE_INNER_ERROR));
173        return;
174      }
175
176      hilog.sLogI(domainID, TAG, 'Caller callWithResult msgData sendMessageRequest end');
177      resolve(reply);
178      return;
179    });
180  }
181
182  release() {
183    hilog.sLogI(domainID, TAG, 'Caller release js called.');
184    if (this.releaseState === true) {
185      hilog.sLogI(domainID, TAG, 'Caller release remoteObj releaseState is true');
186      throw new BusinessError(ERROR_CODE_CALLER_RELEASED);
187    }
188
189    if (this.__call_obj__.callee == null) {
190      hilog.sLogI(domainID, TAG, 'Caller release call remoteObj is released');
191      throw new BusinessError(ERROR_CODE_CLAAEE_INVALID);
192    }
193
194    this.releaseState = true;
195    this.__call_obj__.release();
196  }
197
198  onRelease(callback) {
199    hilog.sLogI(domainID, TAG, 'Caller onRelease jscallback called.');
200    if (typeof callback !== 'function') {
201      hilog.sLogI(domainID, TAG, 'Caller onRelease ' + typeof callback);
202      throw new ThrowInvalidParamError('Parameter error: Failed to get callback, must be a function.');
203    }
204
205    if (this.releaseState === true) {
206      hilog.sLogI(domainID, TAG, 'Caller onRelease remoteObj releaseState is true');
207      throw new BusinessError(ERROR_CODE_CALLER_RELEASED);
208    }
209
210    this.__call_obj__.onRelease(callback);
211  }
212
213  onRemoteStateChange(callback) {
214    hilog.sLogI(domainID, TAG, 'Caller onRemoteStateChange jscallback called.');
215    if (typeof callback !== 'function') {
216      hilog.sLogI(domainID, TAG, 'Caller onRemoteStateChange ' + typeof callback);
217      throw new ThrowInvalidParamError('Parameter error: Failed to get callback, must be a function.');
218    }
219
220    if (this.releaseState === true) {
221      hilog.sLogI(domainID, TAG, 'Caller onRemoteStateChange remoteObj releaseState is true');
222      throw new BusinessError(ERROR_CODE_CALLER_RELEASED);
223    }
224
225    this.__call_obj__.onRemoteStateChange(callback);
226  }
227
228  on(type, callback) {
229    hilog.sLogI(domainID, TAG, 'Caller onRelease jscallback called.');
230    if (typeof type !== 'string' || type !== 'release') {
231      hilog.sLogI(domainID, TAG,
232        'Caller onRelease error, input [type] is invalid.');
233      throw new ThrowInvalidParamError('Parameter error: Failed to get type, must be string type release.');
234    }
235
236    if (typeof callback !== 'function') {
237      hilog.sLogI(domainID, TAG, 'Caller onRelease error ' + typeof callback);
238      throw new ThrowInvalidParamError('Parameter error: Failed to get callback, must be a function.');
239    }
240
241    if (this.releaseState === true) {
242      hilog.sLogI(domainID, TAG, 'Caller onRelease error, remoteObj releaseState is true');
243      throw new BusinessError(ERROR_CODE_CALLER_RELEASED);
244    }
245
246    this.__call_obj__.onRelease(callback);
247  }
248
249  off(type, callback) {
250    if (typeof type !== 'string' || type !== 'release') {
251      hilog.sLogI(domainID, TAG,
252         'Caller onRelease error, input [type] is invalid.');
253      throw new ThrowInvalidParamError('Parameter error: Failed to get type, must be string type release.');
254    }
255
256    if (callback && typeof callback !== 'function') {
257      hilog.sLogI(domainID, TAG, 'Caller onRelease error ' + typeof callback);
258      throw new ThrowInvalidParamError('Parameter error: Failed to get callback, must be a function.');
259    }
260    // Empty
261  }
262
263  callCheck(method, data) {
264    if (typeof method !== 'string' || typeof data !== 'object') {
265      hilog.sLogI(domainID, TAG,
266        'Caller callCheck ' + typeof method + ' ' + typeof data);
267      return new ThrowInvalidParamError('Parameter error: Failed to get method or data, ' +
268        'method must be a string, data must be a rpc.Parcelable');
269    }
270
271    if (method === '' || data == null) {
272      hilog.sLogI(domainID, TAG,
273        'Caller callCheck ' + method + ', ' + data);
274      return new ThrowInvalidParamError('Parameter error: method or data is empty, Please check it.');
275    }
276
277    if (this.releaseState === true) {
278      hilog.sLogI(domainID, TAG, 'Caller callCheck this.callee release');
279      return new BusinessError(ERROR_CODE_CALLER_RELEASED);
280    }
281
282    if (this.__call_obj__.callee == null) {
283      hilog.sLogI(domainID, TAG, 'Caller callCheck this.callee is nullptr');
284      return new BusinessError(ERROR_CODE_CLAAEE_INVALID);
285    }
286    return null;
287  }
288
289  buildMsgData(method, data) {
290    let msgData = rpc.MessageSequence.create();
291    msgData.writeString(method);
292    msgData.writeParcelable(data);
293    return msgData;
294  }
295}
296
297export default Caller;
298