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