@scrypted/server 0.0.107 → 0.0.111
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.
Potentially problematic release.
This version of @scrypted/server might be problematic. Click here for more details.
- package/dist/event-registry.js +2 -2
- package/dist/event-registry.js.map +1 -1
- package/dist/http-interfaces.js +2 -2
- package/dist/http-interfaces.js.map +1 -1
- package/dist/plugin/listen-zero.js +13 -1
- package/dist/plugin/listen-zero.js.map +1 -1
- package/dist/plugin/plugin-api.js +2 -2
- package/dist/plugin/plugin-api.js.map +1 -1
- package/dist/plugin/plugin-device.js +1 -0
- package/dist/plugin/plugin-device.js.map +1 -1
- package/dist/plugin/plugin-host-api.js +10 -8
- package/dist/plugin/plugin-host-api.js.map +1 -1
- package/dist/plugin/plugin-host.js +36 -87
- package/dist/plugin/plugin-host.js.map +1 -1
- package/dist/plugin/plugin-http.js +100 -0
- package/dist/plugin/plugin-http.js.map +1 -0
- package/dist/plugin/plugin-lazy-remote.js +73 -0
- package/dist/plugin/plugin-lazy-remote.js.map +1 -0
- package/dist/plugin/plugin-npm-dependencies.js +16 -16
- package/dist/plugin/plugin-npm-dependencies.js.map +1 -1
- package/dist/plugin/plugin-remote-websocket.js +40 -34
- package/dist/plugin/plugin-remote-websocket.js.map +1 -1
- package/dist/plugin/plugin-remote.js +35 -26
- package/dist/plugin/plugin-remote.js.map +1 -1
- package/dist/plugin/system.js +11 -3
- package/dist/plugin/system.js.map +1 -1
- package/dist/rpc.js +57 -27
- package/dist/rpc.js.map +1 -1
- package/dist/runtime.js +45 -111
- package/dist/runtime.js.map +1 -1
- package/dist/scrypted-main.js +3 -0
- package/dist/scrypted-main.js.map +1 -1
- package/dist/services/plugin.js +2 -2
- package/dist/services/plugin.js.map +1 -1
- package/dist/state.js +2 -8
- package/dist/state.js.map +1 -1
- package/package.json +2 -2
- package/python/plugin-remote.py +4 -4
- package/python/rpc.py +68 -26
- package/src/event-registry.ts +5 -5
- package/src/http-interfaces.ts +3 -3
- package/src/plugin/listen-zero.ts +13 -0
- package/src/plugin/plugin-api.ts +5 -5
- package/src/plugin/plugin-device.ts +2 -1
- package/src/plugin/plugin-host-api.ts +11 -10
- package/src/plugin/plugin-host.ts +40 -95
- package/src/plugin/plugin-http.ts +117 -0
- package/src/plugin/plugin-lazy-remote.ts +70 -0
- package/src/plugin/plugin-npm-dependencies.ts +19 -18
- package/src/plugin/plugin-remote-websocket.ts +55 -60
- package/src/plugin/plugin-remote.ts +45 -38
- package/src/plugin/system.ts +15 -6
- package/src/rpc.ts +66 -26
- package/src/runtime.ts +55 -128
- package/src/scrypted-main.ts +4 -0
- package/src/services/plugin.ts +2 -2
- package/src/state.ts +4 -12
|
@@ -6,8 +6,7 @@ import { PluginAPI, PluginLogger, PluginRemote, PluginRemoteLoadZipOptions } fro
|
|
|
6
6
|
import { SystemManagerImpl } from './system';
|
|
7
7
|
import { RpcPeer, RPCResultError, PROPERTY_PROXY_ONEWAY_METHODS, PROPERTY_JSON_DISABLE_SERIALIZATION } from '../rpc';
|
|
8
8
|
import { BufferSerializer } from './buffer-serializer';
|
|
9
|
-
import {
|
|
10
|
-
import { createWebSocketClass } from './plugin-remote-websocket';
|
|
9
|
+
import { createWebSocketClass, WebSocketConnectCallbacks, WebSocketMethods } from './plugin-remote-websocket';
|
|
11
10
|
|
|
12
11
|
class DeviceLogger implements Logger {
|
|
13
12
|
nativeId: ScryptedNativeId;
|
|
@@ -262,14 +261,7 @@ class StorageImpl implements Storage {
|
|
|
262
261
|
}
|
|
263
262
|
}
|
|
264
263
|
|
|
265
|
-
|
|
266
|
-
end: any;
|
|
267
|
-
error: any;
|
|
268
|
-
data: any;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
export async function setupPluginRemote(peer: RpcPeer, api: PluginAPI, pluginId: string): Promise<PluginRemote> {
|
|
264
|
+
export async function setupPluginRemote(peer: RpcPeer, api: PluginAPI, pluginId: string, getSystemState: () => { [id: string]: { [property: string]: SystemDeviceState } }): Promise<PluginRemote> {
|
|
273
265
|
try {
|
|
274
266
|
// the host/remote connection can be from server to plugin (node to node),
|
|
275
267
|
// core plugin to web (node to browser).
|
|
@@ -277,16 +269,46 @@ export async function setupPluginRemote(peer: RpcPeer, api: PluginAPI, pluginId:
|
|
|
277
269
|
// but in plugin-host, mark Buffer as transport safe.
|
|
278
270
|
peer.addSerializer(Buffer, 'Buffer', new BufferSerializer());
|
|
279
271
|
const getRemote = await peer.getParam('getRemote');
|
|
280
|
-
|
|
272
|
+
const remote = await getRemote(api, pluginId);
|
|
273
|
+
|
|
274
|
+
await remote.setSystemState(getSystemState());
|
|
275
|
+
api.listen((id, eventDetails, eventData) => {
|
|
276
|
+
// ScryptedDevice events will be handled specially and repropagated by the remote.
|
|
277
|
+
if (eventDetails.eventInterface === ScryptedInterface.ScryptedDevice) {
|
|
278
|
+
if (eventDetails.property === ScryptedInterfaceProperty.id) {
|
|
279
|
+
// a change on the id property means device was deleted
|
|
280
|
+
remote.updateDeviceState(eventData, undefined);
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
// a change on anything else is a descriptor update
|
|
284
|
+
remote.updateDeviceState(id, getSystemState()[id]);
|
|
285
|
+
}
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (eventDetails.property) {
|
|
290
|
+
remote.notify(id, eventDetails.eventTime, eventDetails.eventInterface, eventDetails.property, getSystemState()[id]?.[eventDetails.property], eventDetails.changed);
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
remote.notify(id, eventDetails.eventTime, eventDetails.eventInterface, eventDetails.property, eventData, eventDetails.changed);
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
return remote;
|
|
281
298
|
}
|
|
282
299
|
catch (e) {
|
|
283
300
|
throw new RPCResultError(peer, 'error while retrieving PluginRemote', e);
|
|
284
301
|
}
|
|
285
302
|
}
|
|
286
303
|
|
|
304
|
+
export interface WebSocketCustomHandler {
|
|
305
|
+
id: string,
|
|
306
|
+
methods: WebSocketMethods;
|
|
307
|
+
}
|
|
308
|
+
|
|
287
309
|
export interface PluginRemoteAttachOptions {
|
|
288
310
|
createMediaManager?: (systemManager: SystemManager) => Promise<MediaManager>;
|
|
289
|
-
getServicePort?: (name: string) => Promise<number>;
|
|
311
|
+
getServicePort?: (name: string, ...args: any[]) => Promise<number>;
|
|
290
312
|
getDeviceConsole?: (nativeId?: ScryptedNativeId) => Console;
|
|
291
313
|
getPluginConsole?: () => Console;
|
|
292
314
|
getMixinConsole?: (id: string, nativeId?: ScryptedNativeId) => Console;
|
|
@@ -309,8 +331,9 @@ export function attachPluginRemote(peer: RpcPeer, options?: PluginRemoteAttachOp
|
|
|
309
331
|
const systemManager = new SystemManagerImpl();
|
|
310
332
|
const deviceManager = new DeviceManagerImpl(systemManager, getDeviceConsole, getMixinConsole);
|
|
311
333
|
const endpointManager = new EndpointManagerImpl();
|
|
312
|
-
const ioSockets: { [id: string]: WebSocketCallbacks } = {};
|
|
313
334
|
const mediaManager = await api.getMediaManager() || await createMediaManager(systemManager);
|
|
335
|
+
peer.params['mediaManager'] = mediaManager;
|
|
336
|
+
const ioSockets: { [id: string]: WebSocketConnectCallbacks } = {};
|
|
314
337
|
|
|
315
338
|
systemManager.api = api;
|
|
316
339
|
deviceManager.api = api;
|
|
@@ -383,11 +406,11 @@ export function attachPluginRemote(peer: RpcPeer, options?: PluginRemoteAttachOp
|
|
|
383
406
|
async updateDeviceState(id: string, state: { [property: string]: SystemDeviceState }) {
|
|
384
407
|
if (!state) {
|
|
385
408
|
delete systemManager.state[id];
|
|
386
|
-
systemManager.events.notify(
|
|
409
|
+
systemManager.events.notify(undefined, undefined, ScryptedInterface.ScryptedDevice, ScryptedInterfaceProperty.id, id, true);
|
|
387
410
|
}
|
|
388
411
|
else {
|
|
389
412
|
systemManager.state[id] = state;
|
|
390
|
-
systemManager.events.notify(id,
|
|
413
|
+
systemManager.events.notify(id, undefined, ScryptedInterface.ScryptedDevice, undefined, state, true);
|
|
391
414
|
}
|
|
392
415
|
},
|
|
393
416
|
|
|
@@ -432,32 +455,16 @@ export function attachPluginRemote(peer: RpcPeer, options?: PluginRemoteAttachOp
|
|
|
432
455
|
volume.writeFileSync(name, entry.getData());
|
|
433
456
|
}
|
|
434
457
|
|
|
435
|
-
function websocketConnect(url: string, protocols: any,
|
|
436
|
-
if (url.startsWith('io://')) {
|
|
437
|
-
const id = url.substring('
|
|
438
|
-
|
|
439
|
-
ioSockets[id] = {
|
|
440
|
-
data,
|
|
441
|
-
error,
|
|
442
|
-
end
|
|
443
|
-
};
|
|
444
|
-
|
|
445
|
-
connect(undefined, {
|
|
446
|
-
close: () => api.ioClose(id),
|
|
447
|
-
}, (message: string) => api.ioSend(id, message));
|
|
448
|
-
}
|
|
449
|
-
else if (url.startsWith('ws://')) {
|
|
450
|
-
const id = url.substring('ws://'.length);
|
|
458
|
+
function websocketConnect(url: string, protocols: any, callbacks: WebSocketConnectCallbacks) {
|
|
459
|
+
if (url.startsWith('io://') || url.startsWith('ws://')) {
|
|
460
|
+
const id = url.substring('xx://'.length);
|
|
451
461
|
|
|
452
|
-
ioSockets[id] =
|
|
453
|
-
data,
|
|
454
|
-
error,
|
|
455
|
-
end
|
|
456
|
-
};
|
|
462
|
+
ioSockets[id] = callbacks;
|
|
457
463
|
|
|
458
|
-
connect(undefined, {
|
|
464
|
+
callbacks.connect(undefined, {
|
|
459
465
|
close: () => api.ioClose(id),
|
|
460
|
-
|
|
466
|
+
send: (message: string) => api.ioSend(id, message),
|
|
467
|
+
});
|
|
461
468
|
}
|
|
462
469
|
else {
|
|
463
470
|
throw new Error('unsupported websocket');
|
package/src/plugin/system.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EventListenerOptions, EventDetails, EventListenerRegister, ScryptedDevice, ScryptedInterface, ScryptedInterfaceDescriptors, SystemDeviceState, SystemManager, ScryptedInterfaceProperty, ScryptedDeviceType, Logger } from "@scrypted/sdk/types";
|
|
2
2
|
import { PluginAPI } from "./plugin-api";
|
|
3
|
-
import { handleFunctionInvocations } from '../rpc';
|
|
3
|
+
import { handleFunctionInvocations, PROPERTY_PROXY_ONEWAY_METHODS } from '../rpc';
|
|
4
4
|
import { EventRegistry } from "../event-registry";
|
|
5
5
|
import { allInterfaceProperties, isValidInterfaceMethod } from "./descriptor";
|
|
6
6
|
|
|
@@ -56,7 +56,7 @@ class DeviceProxyHandler implements ProxyHandler<any>, ScryptedDevice {
|
|
|
56
56
|
return (this.device as any)[method](...argArray);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
listen(event: string | EventListenerOptions, callback: (eventSource: ScryptedDevice, eventDetails: EventDetails, eventData:
|
|
59
|
+
listen(event: string | EventListenerOptions, callback: (eventSource: ScryptedDevice, eventDetails: EventDetails, eventData: any) => void): EventListenerRegister {
|
|
60
60
|
return this.systemManager.listenDevice(this.id, event, callback);
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -92,6 +92,15 @@ class EventListenerRegisterImpl implements EventListenerRegister {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
function makeOneWayCallback<T>(input: T): T {
|
|
96
|
+
const f: any = input;
|
|
97
|
+
const oneways: string[] = f[PROPERTY_PROXY_ONEWAY_METHODS] || [];
|
|
98
|
+
if (!oneways.includes(null))
|
|
99
|
+
oneways.push(null);
|
|
100
|
+
f[PROPERTY_PROXY_ONEWAY_METHODS] = oneways;
|
|
101
|
+
return input;
|
|
102
|
+
}
|
|
103
|
+
|
|
95
104
|
export class SystemManagerImpl implements SystemManager {
|
|
96
105
|
api: PluginAPI;
|
|
97
106
|
state: {[id: string]: {[property: string]: SystemDeviceState}};
|
|
@@ -122,10 +131,10 @@ export class SystemManagerImpl implements SystemManager {
|
|
|
122
131
|
return this.getDeviceById(id);
|
|
123
132
|
}
|
|
124
133
|
}
|
|
125
|
-
listen(
|
|
126
|
-
return this.events.listen((id, eventDetails, eventData) =>
|
|
134
|
+
listen(callback: (eventSource: ScryptedDevice, eventDetails: EventDetails, eventData: any) => void): EventListenerRegister {
|
|
135
|
+
return this.events.listen(makeOneWayCallback((id, eventDetails, eventData) => callback(this.getDeviceById(id), eventDetails, eventData)));
|
|
127
136
|
}
|
|
128
|
-
listenDevice(id: string, options: string | EventListenerOptions, callback: (eventSource: ScryptedDevice, eventDetails: EventDetails, eventData:
|
|
137
|
+
listenDevice(id: string, options: string | EventListenerOptions, callback: (eventSource: ScryptedDevice, eventDetails: EventDetails, eventData: any) => void): EventListenerRegister {
|
|
129
138
|
let { event, watch } = (options || {}) as EventListenerOptions;
|
|
130
139
|
if (!event && typeof options === 'string')
|
|
131
140
|
event = options as string;
|
|
@@ -136,7 +145,7 @@ export class SystemManagerImpl implements SystemManager {
|
|
|
136
145
|
if (watch)
|
|
137
146
|
return this.events.listenDevice(id, event, (eventDetails, eventData) => callback(this.getDeviceById(id), eventDetails, eventData));
|
|
138
147
|
|
|
139
|
-
return new EventListenerRegisterImpl(this.api.listenDevice(id, options, (eventDetails, eventData) => callback(this.getDeviceById(id), eventDetails, eventData)))
|
|
148
|
+
return new EventListenerRegisterImpl(this.api.listenDevice(id, options, makeOneWayCallback((eventDetails, eventData) => callback(this.getDeviceById(id), eventDetails, eventData))));
|
|
140
149
|
}
|
|
141
150
|
|
|
142
151
|
async removeDevice(id: string) {
|
package/src/rpc.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import vm from 'vm';
|
|
2
2
|
|
|
3
|
+
const finalizerIdSymbol = Symbol('rpcFinalizerId');
|
|
4
|
+
|
|
3
5
|
function getDefaultTransportSafeArgumentTypes() {
|
|
4
6
|
const jsonSerializable = new Set<string>();
|
|
5
7
|
jsonSerializable.add(Number.name);
|
|
@@ -40,6 +42,7 @@ interface RpcOob extends RpcMessage {
|
|
|
40
42
|
|
|
41
43
|
interface RpcRemoteProxyValue {
|
|
42
44
|
__remote_proxy_id: string;
|
|
45
|
+
__remote_proxy_finalizer_id: string;
|
|
43
46
|
__remote_constructor_name: string;
|
|
44
47
|
__remote_proxy_props: any;
|
|
45
48
|
__remote_proxy_oneway_methods: string[];
|
|
@@ -52,6 +55,7 @@ interface RpcLocalProxyValue {
|
|
|
52
55
|
|
|
53
56
|
interface RpcFinalize extends RpcMessage {
|
|
54
57
|
__local_proxy_id: string;
|
|
58
|
+
__local_proxy_finalizer_id: string;
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
interface Deferred {
|
|
@@ -78,20 +82,17 @@ export const PROPERTY_PROXY_PROPERTIES = '__proxy_props';
|
|
|
78
82
|
export const PROPERTY_JSON_COPY_SERIALIZE_CHILDREN = '__json_copy_serialize_children';
|
|
79
83
|
|
|
80
84
|
class RpcProxy implements ProxyHandler<any> {
|
|
85
|
+
|
|
81
86
|
constructor(public peer: RpcPeer,
|
|
82
|
-
public
|
|
87
|
+
public entry: LocalProxiedEntry,
|
|
83
88
|
public constructorName: string,
|
|
84
89
|
public proxyProps: any,
|
|
85
90
|
public proxyOneWayMethods: string[]) {
|
|
86
|
-
this.peer = peer;
|
|
87
|
-
this.id = id;
|
|
88
|
-
this.constructorName = constructorName;
|
|
89
|
-
this.proxyProps = proxyProps;
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
get(target: any, p: PropertyKey, receiver: any): any {
|
|
93
94
|
if (p === '__proxy_id')
|
|
94
|
-
return this.id;
|
|
95
|
+
return this.entry.id;
|
|
95
96
|
if (p === '__proxy_constructor')
|
|
96
97
|
return this.constructorName;
|
|
97
98
|
if (p === '__proxy_peer')
|
|
@@ -114,8 +115,17 @@ class RpcProxy implements ProxyHandler<any> {
|
|
|
114
115
|
return new Proxy(() => p, this);
|
|
115
116
|
}
|
|
116
117
|
|
|
118
|
+
set(target: any, p: string | symbol, value: any, receiver: any): boolean {
|
|
119
|
+
if (p === finalizerIdSymbol)
|
|
120
|
+
this.entry.finalizerId = value;
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
|
|
117
124
|
apply(target: any, thisArg: any, argArray?: any): any {
|
|
118
|
-
|
|
125
|
+
// rpc objects can be functions. if the function is a oneway method,
|
|
126
|
+
// it will have a null in the oneway method list. this is because
|
|
127
|
+
// undefined is not JSON serializable.
|
|
128
|
+
const method = target() || null;
|
|
119
129
|
const args: any[] = [];
|
|
120
130
|
for (const arg of (argArray || [])) {
|
|
121
131
|
args.push(this.peer.serialize(arg));
|
|
@@ -124,7 +134,7 @@ class RpcProxy implements ProxyHandler<any> {
|
|
|
124
134
|
const rpcApply: RpcApply = {
|
|
125
135
|
type: "apply",
|
|
126
136
|
id: undefined,
|
|
127
|
-
proxyId: this.id,
|
|
137
|
+
proxyId: this.entry.id,
|
|
128
138
|
args,
|
|
129
139
|
method,
|
|
130
140
|
};
|
|
@@ -187,16 +197,21 @@ export interface RpcSerializer {
|
|
|
187
197
|
deserialize(serialized: any): any;
|
|
188
198
|
}
|
|
189
199
|
|
|
200
|
+
interface LocalProxiedEntry {
|
|
201
|
+
id: string;
|
|
202
|
+
finalizerId: string;
|
|
203
|
+
}
|
|
204
|
+
|
|
190
205
|
export class RpcPeer {
|
|
191
206
|
idCounter = 1;
|
|
192
207
|
onOob: (oob: any) => void;
|
|
193
208
|
params: { [name: string]: any } = {};
|
|
194
209
|
pendingResults: { [id: string]: Deferred } = {};
|
|
195
210
|
proxyCounter = 1;
|
|
196
|
-
localProxied = new Map<any,
|
|
211
|
+
localProxied = new Map<any, LocalProxiedEntry>();
|
|
197
212
|
localProxyMap: { [id: string]: any } = {};
|
|
198
213
|
remoteWeakProxies: { [id: string]: WeakRef<any> } = {};
|
|
199
|
-
finalizers = new FinalizationRegistry(
|
|
214
|
+
finalizers = new FinalizationRegistry(entry => this.finalize(entry as LocalProxiedEntry));
|
|
200
215
|
nameDeserializerMap = new Map<string, RpcSerializer>();
|
|
201
216
|
constructorSerializerMap = new Map<string, string>();
|
|
202
217
|
transportSafeArgumentTypes = getDefaultTransportSafeArgumentTypes();
|
|
@@ -238,10 +253,11 @@ export class RpcPeer {
|
|
|
238
253
|
this.constructorSerializerMap.set(ctr, name);
|
|
239
254
|
}
|
|
240
255
|
|
|
241
|
-
finalize(
|
|
242
|
-
delete this.remoteWeakProxies[id];
|
|
256
|
+
finalize(entry: LocalProxiedEntry) {
|
|
257
|
+
delete this.remoteWeakProxies[entry.id];
|
|
243
258
|
const rpcFinalize: RpcFinalize = {
|
|
244
|
-
__local_proxy_id: id,
|
|
259
|
+
__local_proxy_id: entry.id,
|
|
260
|
+
__local_proxy_finalizer_id: entry.finalizerId,
|
|
245
261
|
type: 'finalize',
|
|
246
262
|
}
|
|
247
263
|
this.send(rpcFinalize);
|
|
@@ -294,9 +310,12 @@ export class RpcPeer {
|
|
|
294
310
|
return ret;
|
|
295
311
|
}
|
|
296
312
|
|
|
297
|
-
const { __remote_proxy_id, __local_proxy_id, __remote_constructor_name, __serialized_value, __remote_proxy_props, __remote_proxy_oneway_methods } = value;
|
|
313
|
+
const { __remote_proxy_id, __remote_proxy_finalizer_id, __local_proxy_id, __remote_constructor_name, __serialized_value, __remote_proxy_props, __remote_proxy_oneway_methods } = value;
|
|
298
314
|
if (__remote_proxy_id) {
|
|
299
|
-
|
|
315
|
+
let proxy = this.remoteWeakProxies[__remote_proxy_id]?.deref();
|
|
316
|
+
if (!proxy)
|
|
317
|
+
proxy = this.newProxy(__remote_proxy_id, __remote_constructor_name, __remote_proxy_props, __remote_proxy_oneway_methods);
|
|
318
|
+
proxy[finalizerIdSymbol] = __remote_proxy_finalizer_id;
|
|
300
319
|
return proxy;
|
|
301
320
|
}
|
|
302
321
|
|
|
@@ -329,10 +348,13 @@ export class RpcPeer {
|
|
|
329
348
|
|
|
330
349
|
let __remote_constructor_name = value.__proxy_constructor || value.constructor?.name?.toString();
|
|
331
350
|
|
|
332
|
-
let
|
|
333
|
-
if (
|
|
351
|
+
let proxiedEntry = this.localProxied.get(value);
|
|
352
|
+
if (proxiedEntry) {
|
|
353
|
+
const __remote_proxy_finalizer_id = (this.proxyCounter++).toString();
|
|
354
|
+
proxiedEntry.finalizerId = __remote_proxy_finalizer_id;
|
|
334
355
|
const ret: RpcRemoteProxyValue = {
|
|
335
|
-
__remote_proxy_id:
|
|
356
|
+
__remote_proxy_id: proxiedEntry.id,
|
|
357
|
+
__remote_proxy_finalizer_id,
|
|
336
358
|
__remote_constructor_name,
|
|
337
359
|
__remote_proxy_props: value?.[PROPERTY_PROXY_PROPERTIES],
|
|
338
360
|
__remote_proxy_oneway_methods: value?.[PROPERTY_PROXY_ONEWAY_METHODS],
|
|
@@ -355,6 +377,7 @@ export class RpcPeer {
|
|
|
355
377
|
const serialized = serializer.serialize(value);
|
|
356
378
|
const ret: RpcRemoteProxyValue = {
|
|
357
379
|
__remote_proxy_id: undefined,
|
|
380
|
+
__remote_proxy_finalizer_id: undefined,
|
|
358
381
|
__remote_constructor_name,
|
|
359
382
|
__remote_proxy_props: value?.[PROPERTY_PROXY_PROPERTIES],
|
|
360
383
|
__remote_proxy_oneway_methods: value?.[PROPERTY_PROXY_ONEWAY_METHODS],
|
|
@@ -363,12 +386,17 @@ export class RpcPeer {
|
|
|
363
386
|
return ret;
|
|
364
387
|
}
|
|
365
388
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
389
|
+
const __remote_proxy_id = (this.proxyCounter++).toString();
|
|
390
|
+
proxiedEntry = {
|
|
391
|
+
id: __remote_proxy_id,
|
|
392
|
+
finalizerId: __remote_proxy_id,
|
|
393
|
+
};
|
|
394
|
+
this.localProxied.set(value, proxiedEntry);
|
|
395
|
+
this.localProxyMap[__remote_proxy_id] = value;
|
|
369
396
|
|
|
370
397
|
const ret: RpcRemoteProxyValue = {
|
|
371
|
-
__remote_proxy_id
|
|
398
|
+
__remote_proxy_id,
|
|
399
|
+
__remote_proxy_finalizer_id: __remote_proxy_id,
|
|
372
400
|
__remote_constructor_name,
|
|
373
401
|
__remote_proxy_props: value?.[PROPERTY_PROXY_PROPERTIES],
|
|
374
402
|
__remote_proxy_oneway_methods: value?.[PROPERTY_PROXY_ONEWAY_METHODS],
|
|
@@ -378,12 +406,16 @@ export class RpcPeer {
|
|
|
378
406
|
}
|
|
379
407
|
|
|
380
408
|
newProxy(proxyId: string, proxyConstructorName: string, proxyProps: any, proxyOneWayMethods: string[]) {
|
|
381
|
-
const
|
|
409
|
+
const localProxiedEntry: LocalProxiedEntry = {
|
|
410
|
+
id: proxyId,
|
|
411
|
+
finalizerId: undefined,
|
|
412
|
+
}
|
|
413
|
+
const rpc = new RpcProxy(this, localProxiedEntry, proxyConstructorName, proxyProps, proxyOneWayMethods);
|
|
382
414
|
const target = proxyConstructorName === 'Function' || proxyConstructorName === 'AsyncFunction' ? function () { } : rpc;
|
|
383
415
|
const proxy = new Proxy(target, rpc);
|
|
384
416
|
const weakref = new WeakRef(proxy);
|
|
385
417
|
this.remoteWeakProxies[proxyId] = weakref;
|
|
386
|
-
this.finalizers.register(rpc,
|
|
418
|
+
this.finalizers.register(rpc, localProxiedEntry);
|
|
387
419
|
global.gc?.();
|
|
388
420
|
return proxy;
|
|
389
421
|
}
|
|
@@ -460,8 +492,16 @@ export class RpcPeer {
|
|
|
460
492
|
case 'finalize': {
|
|
461
493
|
const rpcFinalize = message as RpcFinalize;
|
|
462
494
|
const local = this.localProxyMap[rpcFinalize.__local_proxy_id];
|
|
463
|
-
|
|
464
|
-
|
|
495
|
+
if (local) {
|
|
496
|
+
const localProxiedEntry = this.localProxied.get(local);
|
|
497
|
+
// if a finalizer id is specified, it must match.
|
|
498
|
+
if (rpcFinalize.__local_proxy_finalizer_id && rpcFinalize.__local_proxy_finalizer_id !== localProxiedEntry?.finalizerId) {
|
|
499
|
+
console.error(this.selfName, this.peerName, 'finalizer mismatch')
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
delete this.localProxyMap[rpcFinalize.__local_proxy_id];
|
|
503
|
+
this.localProxied.delete(local);
|
|
504
|
+
}
|
|
465
505
|
break;
|
|
466
506
|
}
|
|
467
507
|
case 'oob': {
|