1/* 2 * Copyright (c) 2021 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 16/** 17 * Intercept callback from native and forward to user-defined callback. 18 * @param {*} args - Args. 19 * @param {boolean} [needPromise] - If asynchronous operations are needed. 20 * @return {Object} If promise are needed, return { args, promise }. Otherwise return args. 21 */ 22export function interceptCallback(args: any, needPromise?: boolean): object { 23 if (args.length === 0 && !needPromise) { 24 return args; 25 } 26 const first: object = args[0]; 27 const callbacks: object = {}; 28 let hasProperty: boolean = false; 29 if (typeof first === 'object' && 30 Object.prototype.toString.call(first).toLowerCase() === '[object object]' && 31 args.length === 1 32 ) { 33 for (const key in first) { 34 const value: Function = first[key]; 35 if (typeof value === 'function') { 36 callbacks[key] = value; 37 } else { 38 hasProperty = true; 39 } 40 } 41 } else { 42 hasProperty = true; 43 } 44 45 let promise: any; 46 const callbLength: number = Object.keys(callbacks).length; 47 if (needPromise) { 48 if (callbLength <= 0) { 49 promise = new PromiseRef(); 50 } 51 } 52 if (callbLength > 0 || promise) { 53 const callb = (msg: { method: string; arguments: any; }) => { 54 let func = callbacks[msg.method]; 55 const callbArgs: any = msg.arguments; 56 57 if (func !== undefined) { 58 func(...callbArgs); 59 } 60 61 // Always call complete(). 62 func = callbacks['complete']; 63 if (func !== undefined) { 64 func(...callbArgs); 65 } 66 if (promise) { 67 const data: any = callbArgs && 68 callbArgs.length > 0 69 ? callbArgs[0] 70 : undefined; 71 if ('success' === msg.method || 'callback' === msg.method) { 72 promise.resolve({ data }); 73 } else { 74 // 200 means common error ,100 :cancel. 75 const code: any = 76 'cancel' === msg.method 77 ? 100 78 : callbArgs && callbArgs.length > 1 79 ? callbArgs[1] 80 : 200; 81 promise.reject({ data, code }); 82 } 83 } 84 }; 85 callb.__onlyPromise = callbLength <= 0; 86 87 if (hasProperty) { 88 args.push(callb); 89 } else { 90 args = [callb]; 91 } 92 } 93 return needPromise ? { args, promise } : args; 94} 95 96/** 97 * This class provide a Promise object for asynchronous operation processing. 98 */ 99class PromiseRef { 100 private _promise: Promise<object>; 101 private _reject: Function; 102 private _resolve: Function; 103 104 constructor() { 105 this._promise = new Promise((resolve, reject) => { 106 this._reject = reject; 107 this._resolve = resolve; 108 }); 109 } 110 111 /** 112 * Promise of this PromiseRef. 113 * @type {Promise} 114 */ 115 public get promise() { 116 return this._promise; 117 } 118 119 public set promise(newPromise) { 120 this._promise = newPromise; 121 } 122 123 /** 124 * Reject function using the Promise object. 125 * @type {Promise} 126 */ 127 public get reject() { 128 return this._reject; 129 } 130 131 public set reject(data) { 132 this._reject = data; 133 } 134 135 /** 136 * Resolve function using the Promise object. 137 * @type {Promise} 138 */ 139 public get resolve() { 140 return this._resolve; 141 } 142 143 public set resolve(data) { 144 this._resolve = data; 145 } 146} 147