@zimi/remote 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021-2022 @zimi/utils authors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,184 @@
1
+ # @zimi/remote
2
+
3
+ 像调用本地函数一样调用远端的函数
4
+
5
+ - 本地可以是浏览器、服务器,甚至一些受限的 `js` 子集
6
+ - 远端可以是任何语言,如 `Java`
7
+ - 对远端响应的数据格式也不严格限制
8
+
9
+ ## install
10
+ ```
11
+ pnpm i @zimi/remote
12
+ ```
13
+
14
+ ## examples
15
+
16
+ ### iframe 与父级通信
17
+
18
+ ```ts
19
+ // 1. 声明各自能提供的函数类型
20
+ // type.d.ts
21
+
22
+ // 父级能提供的函数
23
+ export type FuncsFromParent = {
24
+ plus: (data: [number, number]) => Promise<number>
25
+ }
26
+
27
+ // 子级能提供的函数
28
+ export type FuncsFromChild = {
29
+ multiply: (data: [number, number]) => Promise<number>
30
+ }
31
+ ```
32
+
33
+ ```ts
34
+ // 2. 父级 remote 初始化
35
+ // parent.ts
36
+
37
+ import { Remote, createIframeAdaptor } from '@zimi/remote'
38
+
39
+ function getOpWindow() {
40
+ return (document.getElementById('child-iframe') as HTMLIFrameElement | null)?.contentWindow
41
+ }
42
+
43
+ // 我们提供了生成 iframe adaptor 的工具函数
44
+ // 你也可以参考实现自己的 adaptor, 没多少代码
45
+ const adaptor = createIframeAdaptor({
46
+ onEmit: (data) => {
47
+ getOpWindow()?.postMessage(data, '*')
48
+ },
49
+ })
50
+
51
+ const remote = new Remote<FuncsFromParent, FuncsFromChild>(adaptor, {
52
+ deviceId: 'parent',
53
+ })
54
+
55
+ // 父级注册自己能提供的函数
56
+ remote.register('plus', async ([a, b]) => a + b)
57
+ ```
58
+
59
+ ```ts
60
+ // 3. 子级 remote 初始化
61
+ // child-iframe.ts
62
+
63
+ import { Remote, createIframeAdaptor } from '@zimi/remote'
64
+
65
+ function getOpWindow() {
66
+ return window.top
67
+ }
68
+
69
+ // 我们提供了生成 iframe adaptor 的工具函数
70
+ // 你也可以参考实现自己的 adaptor, 没多少代码
71
+ const adaptor = createIframeAdaptor({
72
+ onEmit: (data) => {
73
+ getOpWindow()?.postMessage(data, '*')
74
+ },
75
+ })
76
+
77
+ const remote = new Remote<FuncsFromChild, FuncsFromParent>(adaptor, {
78
+ // 当涉及到多子级时,可以通过该 deviceId 来区分彼此,
79
+ // 达到与不同子级通信的效果
80
+ deviceId: 'child',
81
+ })
82
+
83
+ // 子级注册自己能提供的函数
84
+ remote.register('multiply', async ([a, b]) => a * b)
85
+ ```
86
+
87
+ ```ts
88
+ // 好了,现在你可以父子间随意通信了
89
+
90
+ // 对方所有函数都被代理到 remote._.xxx 上了
91
+
92
+ // parent.ts
93
+ // 父级中可以直接调用子级的函数
94
+ // 有严格的类型与提示
95
+ await remote._.multiply([3, 2])
96
+
97
+ await remote._.multiply([3, 2], {
98
+ // 每个函数可以单独指定超时时间,超时后会抛出 RemoteTimeoutError
99
+ timeoutMs: 1000,
100
+ // 每个函数可以指定调用特定目标所有的函数(需要在 adaptor onEmit 中根据 targetDeviceId 往不同设备发送消息)
101
+ targetDeviceId: 'child-2'
102
+ })
103
+
104
+ // 调用对方未注册的函数,会抛出 RemoteNotFoundError
105
+ await remote._.notRegisteredFunc()
106
+
107
+ // 当对方函数发生运行时错误时,会抛出 RemoteError
108
+ // 以上所有 error 都继承自 Error
109
+ ```
110
+
111
+ ### 浏览器与服务器通信
112
+
113
+ ```ts
114
+ // 对方怎么写我们就不管了,假设对方返回的数据格式为:
115
+ interface JavaResponse {
116
+ // 假设 code >= 300 为错误;code < 300 为成功
117
+ code: number
118
+ // 响应的数据
119
+ data: unknown
120
+ // 可能存在的错误信息
121
+ errorMsg?: string
122
+ }
123
+ ```
124
+
125
+ 此时 adaptor 的 onEmit 函数稍微有些复杂,它需要解析服务端响应的数据,并封装为我们需要的格式:
126
+
127
+ ```ts
128
+ const adaptor = createHttpAdaptor({
129
+ onEmit: async (data) => {
130
+ // 这里只是简单示意,使用者可以根据自己的情况构造 request
131
+ const res = await fetch(`https://xxx.com/api/${data.name}`, {
132
+ method: 'POST',
133
+ body: JSON.stringify(data.data),
134
+ headers: {
135
+ 'Content-Type': 'application/json',
136
+ },
137
+ })
138
+ // 下面相当于我们代 server 端封装了一下数据
139
+ // callbackName 是一定会有的,此处只是为了类型安全
140
+ const callbackName = data.callbackName ?? 'IMPOSSIBLE_NO_CALLBACK_NAME'
141
+ const adaptorData: AdaptorPackageData = {
142
+ // 由于我们代 server 抛出事件
143
+ // 所以这里的 deviceId 和 targetDeviceId 是相反的
144
+ deviceId: data.targetDeviceId,
145
+ targetDeviceId: data.deviceId,
146
+ name: callbackName,
147
+ // 我们在下面根据不同情况来填充 data
148
+ data: null,
149
+ }
150
+ if (!res.ok) {
151
+ adaptorData.data = response.error(new RemoteError('network error'))
152
+ } else {
153
+ const json = (await res.json()) as {
154
+ code: number
155
+ data: unknown
156
+ errorMsg?: string
157
+ }
158
+ if (json.code < 300) {
159
+ adaptorData.data = response.success(json.data)
160
+ } else {
161
+ const error = new RemoteError(`server error: ${json.errorMsg}`)
162
+ // RemoteError 也接受 code, 你可以把服务端响应的错误码挂到其上,便于业务上区分处理
163
+ error.code = json.code
164
+ adaptorData.data = response.error(error)
165
+ }
166
+ }
167
+ // 一定要抛出 every 事件,remote 包基于此处理远端的响应
168
+ remoteEventManager.emit(remoteEventManager.EVERY_EVENT_NAME, adaptorData)
169
+ remoteEventManager.emit(callbackName, adaptorData)
170
+ },
171
+ })
172
+
173
+ // 由于服务端不会调用我们,所以我们无需提供函数,自然也无需调用 remote.register 注册函数
174
+ const remote = new Remote<{}, FuncsFromHttp>(adaptor, {
175
+ deviceId: 'client',
176
+ })
177
+
178
+ // 使用方法同前
179
+ await remote._.xxx(anyData)
180
+ ```
181
+
182
+ ### 与其他端通信(如 websocket)略
183
+
184
+ 你可以看看 `iframe adaptor` / `http adaptor` 源码,包含空行也就 30 行,依葫芦画瓢很轻易就能写一个。
@@ -0,0 +1,13 @@
1
+ import EventEmitter from 'eventemitter3';
2
+ import type { Adaptor, AdaptorPackageData } from '../adaptor';
3
+ declare class RemoteEventManager extends EventEmitter<{
4
+ [key: string]: [AdaptorPackageData];
5
+ }> {
6
+ EVERY_EVENT_NAME: string;
7
+ onEvery(fn: (data: AdaptorPackageData) => void): void;
8
+ }
9
+ export declare const remoteEventManager: RemoteEventManager;
10
+ export declare function createHttpAdaptor({ onEmit, }: {
11
+ onEmit: (data: AdaptorPackageData) => void;
12
+ }): Adaptor;
13
+ export {};
@@ -0,0 +1,26 @@
1
+ import EventEmitter from 'eventemitter3';
2
+ class RemoteEventManager extends EventEmitter {
3
+ constructor() {
4
+ super(...arguments);
5
+ Object.defineProperty(this, "EVERY_EVENT_NAME", {
6
+ enumerable: true,
7
+ configurable: true,
8
+ writable: true,
9
+ value: '__remote_every__'
10
+ });
11
+ }
12
+ onEvery(fn) {
13
+ this.on(this.EVERY_EVENT_NAME, fn);
14
+ }
15
+ }
16
+ export const remoteEventManager = new RemoteEventManager();
17
+ export function createHttpAdaptor({ onEmit, }) {
18
+ const adaptor = {
19
+ every: remoteEventManager.onEvery.bind(remoteEventManager),
20
+ once: remoteEventManager.once.bind(remoteEventManager),
21
+ off: remoteEventManager.off.bind(remoteEventManager),
22
+ emit: onEmit,
23
+ };
24
+ return adaptor;
25
+ }
26
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/adaptors/http.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAA;AAIxC,MAAM,kBAAmB,SAAQ,YAE/B;IAFF;;QAGE;;;;mBAAmB,kBAAkB;WAAA;IAKvC,CAAC;IAHC,OAAO,CAAC,EAAsC;QAC5C,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAA;IACpC,CAAC;CACF;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,kBAAkB,EAAE,CAAA;AAE1D,MAAM,UAAU,iBAAiB,CAAC,EAChC,MAAM,GAGP;IACC,MAAM,OAAO,GAAY;QACvB,KAAK,EAAE,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC;QAC1D,IAAI,EAAE,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC;QACtD,GAAG,EAAE,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC;QACpD,IAAI,EAAE,MAAM;KACb,CAAA;IAED,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Adaptor, AdaptorPackageData } from '../adaptor';
2
+ export declare function createIframeAdaptor({ onEmit, }: {
3
+ onEmit: (data: AdaptorPackageData) => void;
4
+ }): Adaptor;
@@ -0,0 +1,38 @@
1
+ import EventEmitter from 'eventemitter3';
2
+ import { isRemoteAdaptorData } from '../remote';
3
+ class RemoteEventManager extends EventEmitter {
4
+ constructor() {
5
+ super();
6
+ Object.defineProperty(this, "EVERY_EVENT_NAME", {
7
+ enumerable: true,
8
+ configurable: true,
9
+ writable: true,
10
+ value: '__remote_every__'
11
+ });
12
+ if (typeof window === 'undefined') {
13
+ return;
14
+ }
15
+ window.addEventListener('message', (event) => {
16
+ const { data } = event;
17
+ if (isRemoteAdaptorData(data)) {
18
+ this.emit(data.name, data);
19
+ // 一定要抛出 every 事件,remote 包基于此处理远端的响应
20
+ this.emit(this.EVERY_EVENT_NAME, data);
21
+ }
22
+ });
23
+ }
24
+ onEvery(fn) {
25
+ this.on(this.EVERY_EVENT_NAME, fn);
26
+ }
27
+ }
28
+ export function createIframeAdaptor({ onEmit, }) {
29
+ const remoteEventManager = new RemoteEventManager();
30
+ const adaptor = {
31
+ every: remoteEventManager.onEvery.bind(remoteEventManager),
32
+ once: remoteEventManager.once.bind(remoteEventManager),
33
+ off: remoteEventManager.off.bind(remoteEventManager),
34
+ emit: onEmit,
35
+ };
36
+ return adaptor;
37
+ }
38
+ //# sourceMappingURL=iframe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iframe.js","sourceRoot":"","sources":["../../src/adaptors/iframe.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAI/C,MAAM,kBAAmB,SAAQ,YAE/B;IAGA;QACE,KAAK,EAAE,CAAA;QAHT;;;;mBAAmB,kBAAkB;WAAA;QAInC,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;YACjC,OAAM;SACP;QACD,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;YAC3C,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAA;YACtB,IAAI,mBAAmB,CAAC,IAAI,CAAC,EAAE;gBAC7B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;gBAC1B,oCAAoC;gBACpC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAA;aACvC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,CAAC,EAAsC;QAC5C,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAA;IACpC,CAAC;CACF;AAED,MAAM,UAAU,mBAAmB,CAAC,EAClC,MAAM,GAGP;IACC,MAAM,kBAAkB,GAAG,IAAI,kBAAkB,EAAE,CAAA;IAEnD,MAAM,OAAO,GAAY;QACvB,KAAK,EAAE,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC;QAC1D,IAAI,EAAE,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC;QACtD,GAAG,EAAE,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC;QACpD,IAAI,EAAE,MAAM;KACb,CAAA;IAED,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { Remote, isRemoteAdaptorData } from './remote';
2
+ export type { AdaptorPackageData, Adaptor } from './adaptor';
3
+ export { RemoteError, RemoteNotFoundError, RemoteTimeoutError, response, } from './response';
4
+ export { createIframeAdaptor } from './adaptors/iframe';
5
+ export { createHttpAdaptor, remoteEventManager } from './adaptors/http';
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { Remote, isRemoteAdaptorData } from './remote';
2
+ export { RemoteError, RemoteNotFoundError, RemoteTimeoutError, response, } from './response';
3
+ export { createIframeAdaptor } from './adaptors/iframe';
4
+ export { createHttpAdaptor, remoteEventManager } from './adaptors/http';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAEtD,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,QAAQ,GACT,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,79 @@
1
+ import type { Adaptor, AdaptorPackageData } from './adaptor';
2
+ type LogFunc = (...data: unknown[]) => void;
3
+ type RemoteCallableFunc = (data: any) => Promise<any>;
4
+ interface RemoteFuncRecords {
5
+ [key: string]: RemoteCallableFunc;
6
+ }
7
+ type FuncMapWithConfig<T extends RemoteFuncRecords> = {
8
+ [K in keyof T]: T[K] extends (data: infer Arg) => Promise<infer Ret> ? (data: Arg, config?: {
9
+ timeoutMs?: number;
10
+ targetDeviceId?: string;
11
+ }) => Promise<Ret> : never;
12
+ };
13
+ type RegisteredFunc<T extends RemoteCallableFunc> = T extends (data: infer Arg) => infer Ret ? (data: Arg, ctx: {
14
+ /**
15
+ * 对方的设备 id
16
+ */
17
+ deviceId: string;
18
+ }) => Ret : never;
19
+ export declare class Remote<
20
+ /**
21
+ * MF means my functions
22
+ */
23
+ MF extends RemoteFuncRecords,
24
+ /**
25
+ * OF means others functions
26
+ */
27
+ OF extends RemoteFuncRecords> {
28
+ private adaptor;
29
+ debug: boolean;
30
+ private log;
31
+ /**
32
+ * (调用对方函数时的)默认超时时间,单位 ms
33
+ * @default 30000
34
+ */
35
+ private defaultTimeoutMs;
36
+ private map;
37
+ private deviceIdValue;
38
+ /**
39
+ * 设备 id 应该唯一,用于区分不同设备。
40
+ * 你可以在任何时候修改(更新)它。
41
+ * @default ''
42
+ */
43
+ get deviceId(): string;
44
+ set deviceId(deviceId: string);
45
+ constructor(adaptor: Adaptor, config?: {
46
+ /**
47
+ * 设备 id 应该唯一,用于区分不同设备。
48
+ * 你可以在任何时候修改(更新)它。
49
+ * @default ''
50
+ */
51
+ deviceId?: string;
52
+ /**
53
+ * (调用对方函数时的)默认超时时间,单位 ms
54
+ * @default 30000
55
+ */
56
+ defaultTimeoutMs?: number;
57
+ debug?: boolean;
58
+ /**
59
+ * 格式化 AdaptorPackageData 的函数,
60
+ * 用于调试时输出日志。
61
+ * @default JSON.stringify
62
+ */
63
+ log?: LogFunc;
64
+ });
65
+ /**
66
+ * 调用其他端的方法;会等待对方响应。
67
+ * 不能直接使用该方法,应该使用 proxy。
68
+ * @WARNING 不能用于响应其他端。
69
+ */
70
+ private callAsync;
71
+ /**
72
+ * 注册方法,供对方调用;
73
+ */
74
+ register<K extends keyof MF>(name: K, callback: RegisteredFunc<MF[K]>): void;
75
+ _: FuncMapWithConfig<OF>;
76
+ self: MF;
77
+ }
78
+ export declare function isRemoteAdaptorData(data: unknown): data is AdaptorPackageData;
79
+ export {};
package/dist/remote.js ADDED
@@ -0,0 +1,192 @@
1
+ import { RemoteError, RemoteNotFoundError, RemoteTimeoutError, response, } from './response';
2
+ const RESPONSE_PREFIX = '_response_';
3
+ function defaultLog(...data) {
4
+ if (!this.debug) {
5
+ return;
6
+ }
7
+ console.log(`[remote of ${this.deviceId}]`, ...data);
8
+ }
9
+ export class Remote {
10
+ /**
11
+ * 设备 id 应该唯一,用于区分不同设备。
12
+ * 你可以在任何时候修改(更新)它。
13
+ * @default ''
14
+ */
15
+ get deviceId() {
16
+ return this.deviceIdValue;
17
+ }
18
+ set deviceId(deviceId) {
19
+ this.log(`deviceId set: from "${this.deviceIdValue}" to "${deviceId}"`);
20
+ this.deviceIdValue = deviceId;
21
+ }
22
+ constructor(adaptor, config) {
23
+ var _a, _b, _c, _d;
24
+ Object.defineProperty(this, "adaptor", {
25
+ enumerable: true,
26
+ configurable: true,
27
+ writable: true,
28
+ value: adaptor
29
+ });
30
+ Object.defineProperty(this, "debug", {
31
+ enumerable: true,
32
+ configurable: true,
33
+ writable: true,
34
+ value: false
35
+ });
36
+ Object.defineProperty(this, "log", {
37
+ enumerable: true,
38
+ configurable: true,
39
+ writable: true,
40
+ value: void 0
41
+ });
42
+ /**
43
+ * (调用对方函数时的)默认超时时间,单位 ms
44
+ * @default 30000
45
+ */
46
+ Object.defineProperty(this, "defaultTimeoutMs", {
47
+ enumerable: true,
48
+ configurable: true,
49
+ writable: true,
50
+ value: 30000
51
+ });
52
+ Object.defineProperty(this, "map", {
53
+ enumerable: true,
54
+ configurable: true,
55
+ writable: true,
56
+ value: {}
57
+ });
58
+ Object.defineProperty(this, "deviceIdValue", {
59
+ enumerable: true,
60
+ configurable: true,
61
+ writable: true,
62
+ value: ''
63
+ });
64
+ Object.defineProperty(this, "_", {
65
+ enumerable: true,
66
+ configurable: true,
67
+ writable: true,
68
+ value: new Proxy({}, {
69
+ get: (_, k) => this.callAsync.bind(this, k),
70
+ })
71
+ });
72
+ Object.defineProperty(this, "self", {
73
+ enumerable: true,
74
+ configurable: true,
75
+ writable: true,
76
+ value: new Proxy({}, {
77
+ get: (_, k) => { var _a; return (_a = this.map[k]) === null || _a === void 0 ? void 0 : _a.callback; },
78
+ })
79
+ });
80
+ this.debug = (_a = config === null || config === void 0 ? void 0 : config.debug) !== null && _a !== void 0 ? _a : this.debug;
81
+ this.defaultTimeoutMs = (_b = config === null || config === void 0 ? void 0 : config.defaultTimeoutMs) !== null && _b !== void 0 ? _b : this.defaultTimeoutMs;
82
+ this.log = (_c = config === null || config === void 0 ? void 0 : config.log) !== null && _c !== void 0 ? _c : defaultLog.bind(this);
83
+ this.deviceId = (_d = config === null || config === void 0 ? void 0 : config.deviceId) !== null && _d !== void 0 ? _d : this.deviceId;
84
+ adaptor.every(async (e) => {
85
+ var _a;
86
+ const { deviceId: selfDeviceId } = this;
87
+ const { name, data, deviceId: targetDeviceId, callbackName } = e;
88
+ const callback = (_a = this.map[name]) === null || _a === void 0 ? void 0 : _a.callback;
89
+ if (!callback) {
90
+ if (name.startsWith(RESPONSE_PREFIX)) {
91
+ // 这是响应,会在 callAsync once 中处理,这儿不用处理
92
+ this.log('[every] response received: ', e);
93
+ return;
94
+ }
95
+ this.log('callback not found: ', name);
96
+ if (callbackName) {
97
+ adaptor.emit({
98
+ deviceId: selfDeviceId,
99
+ targetDeviceId,
100
+ name: callbackName,
101
+ data: response.error(new RemoteNotFoundError(`callback not found: ${name}`)),
102
+ });
103
+ }
104
+ return;
105
+ }
106
+ if (!callbackName) {
107
+ this.log('should not respond: ', e);
108
+ void callback(data, { deviceId: targetDeviceId });
109
+ return;
110
+ }
111
+ this.log(`callback: ${name}; respondName: ${callbackName}; data: `, data);
112
+ try {
113
+ const ret = await callback(data, { deviceId: targetDeviceId });
114
+ this.log('callback return: ', ret);
115
+ adaptor.emit({
116
+ deviceId: selfDeviceId,
117
+ targetDeviceId,
118
+ name: callbackName,
119
+ data: response.success(ret),
120
+ });
121
+ }
122
+ catch (error) {
123
+ this.log('callback error: ', error);
124
+ adaptor.emit({
125
+ deviceId: selfDeviceId,
126
+ targetDeviceId,
127
+ name: callbackName,
128
+ data: response.error(RemoteError.fromError(error)),
129
+ });
130
+ }
131
+ });
132
+ }
133
+ /**
134
+ * 调用其他端的方法;会等待对方响应。
135
+ * 不能直接使用该方法,应该使用 proxy。
136
+ * @WARNING 不能用于响应其他端。
137
+ */
138
+ callAsync(name, data, config) {
139
+ var _a;
140
+ const timeoutMs = (_a = config === null || config === void 0 ? void 0 : config.timeoutMs) !== null && _a !== void 0 ? _a : this.defaultTimeoutMs;
141
+ const { deviceId } = this;
142
+ const randomStr = Math.random().toString(36).slice(2);
143
+ // 本条消息的响应名
144
+ const responseName = `${RESPONSE_PREFIX}-${name}-${deviceId}-${randomStr}`;
145
+ return new Promise((resolve, reject) => {
146
+ var _a;
147
+ let timer;
148
+ this.log(`callAsync ${name}: waiting for response: ${responseName}`);
149
+ const callback = (e) => {
150
+ var _a;
151
+ clearTimeout(timer);
152
+ this.log(`response received: ${responseName}`, e);
153
+ if (RemoteError.isRemoteError(e.data)) {
154
+ reject(RemoteError.fromError(e.data));
155
+ }
156
+ else {
157
+ resolve((_a = e.data) === null || _a === void 0 ? void 0 : _a.data);
158
+ }
159
+ };
160
+ this.adaptor.once(responseName, callback);
161
+ timer = setTimeout(() => {
162
+ this.log(`timeout: ${responseName}`);
163
+ this.adaptor.off(responseName, callback);
164
+ reject(new RemoteTimeoutError(`timeout: ${name}`));
165
+ }, timeoutMs);
166
+ this.adaptor.emit({
167
+ deviceId,
168
+ targetDeviceId: (_a = config === null || config === void 0 ? void 0 : config.targetDeviceId) !== null && _a !== void 0 ? _a : '',
169
+ name,
170
+ data,
171
+ callbackName: responseName,
172
+ });
173
+ });
174
+ }
175
+ /**
176
+ * 注册方法,供对方调用;
177
+ */
178
+ register(name, callback) {
179
+ this.map[name] = { callback };
180
+ }
181
+ }
182
+ export function isRemoteAdaptorData(data) {
183
+ return (!!data &&
184
+ typeof data === 'object' &&
185
+ 'deviceId' in data &&
186
+ 'name' in data &&
187
+ typeof data.deviceId === 'string' &&
188
+ typeof data.name === 'string' &&
189
+ !!data.deviceId &&
190
+ !!data.name);
191
+ }
192
+ //# sourceMappingURL=remote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.js","sourceRoot":"","sources":["../src/remote.ts"],"names":[],"mappings":"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"}