@scrypted/server 0.7.93 → 0.7.94
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/asynciterable-utils.d.ts +2 -0
- package/dist/asynciterable-utils.js +24 -0
- package/dist/asynciterable-utils.js.map +1 -0
- package/dist/cert.d.ts +6 -0
- package/dist/cert.js +75 -0
- package/dist/cert.js.map +1 -0
- package/dist/collection.d.ts +1 -0
- package/dist/collection.js +16 -0
- package/dist/collection.js.map +1 -0
- package/dist/db-types.d.ts +38 -0
- package/dist/db-types.js +45 -0
- package/dist/db-types.js.map +1 -0
- package/dist/event-registry.d.ts +19 -0
- package/dist/event-registry.js +92 -0
- package/dist/event-registry.js.map +1 -0
- package/dist/http-interfaces.d.ts +3 -0
- package/dist/http-interfaces.js +73 -0
- package/dist/http-interfaces.js.map +1 -0
- package/dist/infer-defaults.d.ts +11 -0
- package/dist/infer-defaults.js +119 -0
- package/dist/infer-defaults.js.map +1 -0
- package/dist/io.d.ts +22 -0
- package/dist/io.js +3 -0
- package/dist/io.js.map +1 -0
- package/dist/level.d.ts +110 -0
- package/dist/level.js +135 -0
- package/dist/level.js.map +1 -0
- package/dist/listen-zero.d.ts +13 -0
- package/dist/listen-zero.js +48 -0
- package/dist/listen-zero.js.map +1 -0
- package/dist/logger.d.ts +29 -0
- package/dist/logger.js +78 -0
- package/dist/logger.js.map +1 -0
- package/dist/media-helpers.d.ts +5 -0
- package/dist/media-helpers.js +89 -0
- package/dist/media-helpers.js.map +1 -0
- package/dist/mixin/mixin-cycle.d.ts +3 -0
- package/dist/mixin/mixin-cycle.js +32 -0
- package/dist/mixin/mixin-cycle.js.map +1 -0
- package/dist/plugin/acl.d.ts +16 -0
- package/dist/plugin/acl.js +83 -0
- package/dist/plugin/acl.js.map +1 -0
- package/dist/plugin/descriptor.d.ts +22 -0
- package/dist/plugin/descriptor.js +35 -0
- package/dist/plugin/descriptor.js.map +1 -0
- package/dist/plugin/media.d.ts +71 -0
- package/dist/plugin/media.js +420 -0
- package/dist/plugin/media.js.map +1 -0
- package/dist/plugin/mediaobject.d.ts +10 -0
- package/dist/plugin/mediaobject.js +26 -0
- package/dist/plugin/mediaobject.js.map +1 -0
- package/dist/plugin/plugin-api.d.ts +106 -0
- package/dist/plugin/plugin-api.js +120 -0
- package/dist/plugin/plugin-api.js.map +1 -0
- package/dist/plugin/plugin-console.d.ts +28 -0
- package/dist/plugin/plugin-console.js +291 -0
- package/dist/plugin/plugin-console.js.map +1 -0
- package/dist/plugin/plugin-debug.d.ts +4 -0
- package/dist/plugin/plugin-debug.js +3 -0
- package/dist/plugin/plugin-debug.js.map +1 -0
- package/dist/plugin/plugin-device.d.ts +54 -0
- package/dist/plugin/plugin-device.js +413 -0
- package/dist/plugin/plugin-device.js.map +1 -0
- package/dist/plugin/plugin-error.d.ts +2 -0
- package/dist/plugin/plugin-error.js +7 -0
- package/dist/plugin/plugin-error.js.map +1 -0
- package/dist/plugin/plugin-host-api.d.ts +43 -0
- package/dist/plugin/plugin-host-api.js +177 -0
- package/dist/plugin/plugin-host-api.js.map +1 -0
- package/dist/plugin/plugin-host.d.ts +45 -0
- package/dist/plugin/plugin-host.js +398 -0
- package/dist/plugin/plugin-host.js.map +1 -0
- package/dist/plugin/plugin-http.d.ts +18 -0
- package/dist/plugin/plugin-http.js +120 -0
- package/dist/plugin/plugin-http.js.map +1 -0
- package/dist/plugin/plugin-lazy-remote.d.ts +31 -0
- package/dist/plugin/plugin-lazy-remote.js +75 -0
- package/dist/plugin/plugin-lazy-remote.js.map +1 -0
- package/dist/plugin/plugin-npm-dependencies.d.ts +8 -0
- package/dist/plugin/plugin-npm-dependencies.js +103 -0
- package/dist/plugin/plugin-npm-dependencies.js.map +1 -0
- package/dist/plugin/plugin-remote-stats.d.ts +8 -0
- package/dist/plugin/plugin-remote-stats.js +30 -0
- package/dist/plugin/plugin-remote-stats.js.map +1 -0
- package/dist/plugin/plugin-remote-websocket.d.ts +29 -0
- package/dist/plugin/plugin-remote-websocket.js +152 -0
- package/dist/plugin/plugin-remote-websocket.js.map +1 -0
- package/dist/plugin/plugin-remote-worker.d.ts +5 -0
- package/dist/plugin/plugin-remote-worker.js +348 -0
- package/dist/plugin/plugin-remote-worker.js.map +1 -0
- package/dist/plugin/plugin-remote.d.ts +75 -0
- package/dist/plugin/plugin-remote.js +598 -0
- package/dist/plugin/plugin-remote.js.map +1 -0
- package/dist/plugin/plugin-repl.d.ts +2 -0
- package/dist/plugin/plugin-repl.js +74 -0
- package/dist/plugin/plugin-repl.js.map +1 -0
- package/dist/plugin/plugin-state-check.d.ts +1 -0
- package/dist/plugin/plugin-state-check.js +27 -0
- package/dist/plugin/plugin-state-check.js.map +1 -0
- package/dist/plugin/plugin-volume.d.ts +3 -0
- package/dist/plugin/plugin-volume.js +31 -0
- package/dist/plugin/plugin-volume.js.map +1 -0
- package/dist/plugin/runtime/child-process-worker.d.ts +20 -0
- package/dist/plugin/runtime/child-process-worker.js +42 -0
- package/dist/plugin/runtime/child-process-worker.js.map +1 -0
- package/dist/plugin/runtime/node-fork-worker.d.ts +9 -0
- package/dist/plugin/runtime/node-fork-worker.js +67 -0
- package/dist/plugin/runtime/node-fork-worker.js.map +1 -0
- package/dist/plugin/runtime/node-thread-worker.d.ts +20 -0
- package/dist/plugin/runtime/node-thread-worker.js +73 -0
- package/dist/plugin/runtime/node-thread-worker.js.map +1 -0
- package/dist/plugin/runtime/python-worker.d.ts +10 -0
- package/dist/plugin/runtime/python-worker.js +91 -0
- package/dist/plugin/runtime/python-worker.js.map +1 -0
- package/dist/plugin/runtime/runtime-worker.d.ts +26 -0
- package/dist/plugin/runtime/runtime-worker.js +3 -0
- package/dist/plugin/runtime/runtime-worker.js.map +1 -0
- package/dist/plugin/socket-serializer.d.ts +5 -0
- package/dist/plugin/socket-serializer.js +17 -0
- package/dist/plugin/socket-serializer.js.map +1 -0
- package/dist/plugin/system.d.ts +39 -0
- package/dist/plugin/system.js +216 -0
- package/dist/plugin/system.js.map +1 -0
- package/dist/rpc-buffer-serializer.d.ts +11 -0
- package/dist/rpc-buffer-serializer.js +30 -0
- package/dist/rpc-buffer-serializer.js.map +1 -0
- package/dist/rpc-serializer.d.ts +24 -0
- package/dist/rpc-serializer.js +144 -0
- package/dist/rpc-serializer.js.map +1 -0
- package/dist/rpc.d.ts +147 -0
- package/dist/rpc.js +689 -0
- package/dist/rpc.js.map +1 -0
- package/dist/runtime.d.ts +103 -0
- package/dist/runtime.js +815 -0
- package/dist/runtime.js.map +1 -0
- package/dist/scrypted-main-exports.d.ts +6 -0
- package/dist/scrypted-main-exports.js +57 -0
- package/dist/scrypted-main-exports.js.map +1 -0
- package/dist/scrypted-main.d.ts +1 -0
- package/dist/scrypted-main.js +8 -0
- package/dist/scrypted-main.js.map +1 -0
- package/dist/scrypted-plugin-main.d.ts +2 -0
- package/dist/scrypted-plugin-main.js +43 -0
- package/dist/scrypted-plugin-main.js.map +1 -0
- package/dist/scrypted-server-main.d.ts +6 -0
- package/dist/scrypted-server-main.js +559 -0
- package/dist/scrypted-server-main.js.map +1 -0
- package/dist/server-settings.d.ts +5 -0
- package/dist/server-settings.js +91 -0
- package/dist/server-settings.js.map +1 -0
- package/dist/services/addresses.d.ts +7 -0
- package/dist/services/addresses.js +43 -0
- package/dist/services/addresses.js.map +1 -0
- package/dist/services/alerts.d.ts +9 -0
- package/dist/services/alerts.js +27 -0
- package/dist/services/alerts.js.map +1 -0
- package/dist/services/cors.d.ts +18 -0
- package/dist/services/cors.js +18 -0
- package/dist/services/cors.js.map +1 -0
- package/dist/services/info.d.ts +5 -0
- package/dist/services/info.js +18 -0
- package/dist/services/info.js.map +1 -0
- package/dist/services/plugin.d.ts +46 -0
- package/dist/services/plugin.js +172 -0
- package/dist/services/plugin.js.map +1 -0
- package/dist/services/service-control.d.ts +8 -0
- package/dist/services/service-control.js +39 -0
- package/dist/services/service-control.js.map +1 -0
- package/dist/services/users.d.ts +19 -0
- package/dist/services/users.js +75 -0
- package/dist/services/users.js.map +1 -0
- package/dist/sleep.d.ts +1 -0
- package/dist/sleep.js +8 -0
- package/dist/sleep.js.map +1 -0
- package/dist/state.d.ts +39 -0
- package/dist/state.js +247 -0
- package/dist/state.js.map +1 -0
- package/dist/threading.d.ts +3 -0
- package/dist/threading.js +93 -0
- package/dist/threading.js.map +1 -0
- package/dist/usertoken.d.ts +11 -0
- package/dist/usertoken.js +52 -0
- package/dist/usertoken.js.map +1 -0
- package/package.json +2 -2
package/dist/rpc.js
ADDED
@@ -0,0 +1,689 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.getEvalSource = exports.RpcPeer = exports.RPCResultError = exports.startPeriodicGarbageCollection = void 0;
|
4
|
+
function startPeriodicGarbageCollection() {
|
5
|
+
if (!global.gc) {
|
6
|
+
console.warn('rpc peer garbage collection not available: global.gc is not exposed.');
|
7
|
+
}
|
8
|
+
let g;
|
9
|
+
try {
|
10
|
+
g = global;
|
11
|
+
}
|
12
|
+
catch (e) {
|
13
|
+
}
|
14
|
+
// periodically see if new objects were created or finalized,
|
15
|
+
// and collect gc if so.
|
16
|
+
let lastCollection = 0;
|
17
|
+
return setInterval(() => {
|
18
|
+
const now = Date.now();
|
19
|
+
const sinceLastCollection = now - lastCollection;
|
20
|
+
const remotesCreated = RpcPeer.remotesCreated;
|
21
|
+
RpcPeer.remotesCreated = 0;
|
22
|
+
const remotesCollected = RpcPeer.remotesCollected;
|
23
|
+
RpcPeer.remotesCollected = 0;
|
24
|
+
if (remotesCreated || remotesCollected || sinceLastCollection > 5 * 60 * 1000) {
|
25
|
+
lastCollection = now;
|
26
|
+
g?.gc?.();
|
27
|
+
}
|
28
|
+
}, 10000);
|
29
|
+
}
|
30
|
+
exports.startPeriodicGarbageCollection = startPeriodicGarbageCollection;
|
31
|
+
class RpcProxy {
|
32
|
+
peer;
|
33
|
+
entry;
|
34
|
+
constructorName;
|
35
|
+
proxyProps;
|
36
|
+
proxyOneWayMethods;
|
37
|
+
static iteratorMethods = new Set([
|
38
|
+
'next',
|
39
|
+
'throw',
|
40
|
+
'return',
|
41
|
+
]);
|
42
|
+
constructor(peer, entry, constructorName, proxyProps, proxyOneWayMethods) {
|
43
|
+
this.peer = peer;
|
44
|
+
this.entry = entry;
|
45
|
+
this.constructorName = constructorName;
|
46
|
+
this.proxyProps = proxyProps;
|
47
|
+
this.proxyOneWayMethods = proxyOneWayMethods;
|
48
|
+
}
|
49
|
+
toPrimitive() {
|
50
|
+
const peer = this.peer;
|
51
|
+
return `RpcProxy-${peer.selfName}:${peer.peerName}: ${this.constructorName}`;
|
52
|
+
}
|
53
|
+
get(target, p, receiver) {
|
54
|
+
if (p === Symbol.asyncIterator) {
|
55
|
+
if (!this.proxyProps?.[Symbol.asyncIterator.toString()])
|
56
|
+
return;
|
57
|
+
return () => {
|
58
|
+
return new Proxy(() => { }, this);
|
59
|
+
};
|
60
|
+
}
|
61
|
+
if (RpcProxy.iteratorMethods.has(p?.toString())) {
|
62
|
+
const asyncIteratorMethod = this.proxyProps?.[Symbol.asyncIterator.toString()]?.[p];
|
63
|
+
if (asyncIteratorMethod)
|
64
|
+
return new Proxy(() => asyncIteratorMethod, this);
|
65
|
+
}
|
66
|
+
if (p === RpcPeer.PROPERTY_PROXY_ID)
|
67
|
+
return this.entry.id;
|
68
|
+
if (p === '__proxy_constructor')
|
69
|
+
return this.constructorName;
|
70
|
+
if (p === '__proxy_peer')
|
71
|
+
return this.peer;
|
72
|
+
if (p === RpcPeer.PROPERTY_PROXY_PROPERTIES)
|
73
|
+
return this.proxyProps;
|
74
|
+
if (p === RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS)
|
75
|
+
return this.proxyOneWayMethods;
|
76
|
+
if (p === RpcPeer.PROPERTY_JSON_DISABLE_SERIALIZATION || p === RpcPeer.PROPERTY_JSON_COPY_SERIALIZE_CHILDREN)
|
77
|
+
return;
|
78
|
+
if (p === 'then')
|
79
|
+
return;
|
80
|
+
if (p === 'constructor')
|
81
|
+
return;
|
82
|
+
if (this.proxyProps?.[p] !== undefined)
|
83
|
+
return this.proxyProps?.[p];
|
84
|
+
const handled = RpcPeer.handleFunctionInvocations(this, target, p, receiver);
|
85
|
+
if (handled)
|
86
|
+
return handled;
|
87
|
+
return new Proxy(() => p, this);
|
88
|
+
}
|
89
|
+
set(target, p, value, receiver) {
|
90
|
+
if (p === RpcPeer.finalizerIdSymbol) {
|
91
|
+
this.entry.finalizerId = value;
|
92
|
+
}
|
93
|
+
else {
|
94
|
+
this.proxyProps ||= {};
|
95
|
+
this.proxyProps[p] = value;
|
96
|
+
}
|
97
|
+
return true;
|
98
|
+
}
|
99
|
+
apply(target, thisArg, argArray) {
|
100
|
+
const method = target() || null;
|
101
|
+
const oneway = this.proxyOneWayMethods?.includes?.(method);
|
102
|
+
if (Object.isFrozen(this.peer.pendingResults)) {
|
103
|
+
if (oneway)
|
104
|
+
return Promise.resolve();
|
105
|
+
return Promise.reject(new RPCResultError(this.peer, 'RpcPeer has been killed (apply) ' + target()));
|
106
|
+
}
|
107
|
+
// rpc objects can be functions. if the function is a oneway method,
|
108
|
+
// it will have a null in the oneway method list. this is because
|
109
|
+
// undefined is not JSON serializable.
|
110
|
+
const args = [];
|
111
|
+
const serializationContext = {};
|
112
|
+
for (const arg of (argArray || [])) {
|
113
|
+
args.push(this.peer.serialize(arg, serializationContext));
|
114
|
+
}
|
115
|
+
const rpcApply = {
|
116
|
+
type: "apply",
|
117
|
+
id: undefined,
|
118
|
+
proxyId: this.entry.id,
|
119
|
+
args,
|
120
|
+
method,
|
121
|
+
};
|
122
|
+
if (oneway) {
|
123
|
+
rpcApply.oneway = true;
|
124
|
+
// a oneway callable object doesn't need to be in the JSON payload.
|
125
|
+
if (method === null)
|
126
|
+
delete rpcApply.method;
|
127
|
+
this.peer.send(rpcApply, undefined, serializationContext);
|
128
|
+
return Promise.resolve();
|
129
|
+
}
|
130
|
+
const pendingResult = this.peer.createPendingResult((id, reject) => {
|
131
|
+
rpcApply.id = id;
|
132
|
+
this.peer.send(rpcApply, reject, serializationContext);
|
133
|
+
});
|
134
|
+
const asyncIterator = this.proxyProps?.[Symbol.asyncIterator.toString()];
|
135
|
+
if (!asyncIterator || (method !== asyncIterator.next && method !== asyncIterator.return))
|
136
|
+
return pendingResult;
|
137
|
+
return pendingResult
|
138
|
+
.then(value => {
|
139
|
+
if (method === asyncIterator.return) {
|
140
|
+
return {
|
141
|
+
done: true,
|
142
|
+
value: undefined,
|
143
|
+
};
|
144
|
+
}
|
145
|
+
return ({
|
146
|
+
value,
|
147
|
+
done: false,
|
148
|
+
});
|
149
|
+
})
|
150
|
+
.catch(e => {
|
151
|
+
if (e.name === 'StopAsyncIteration') {
|
152
|
+
return {
|
153
|
+
done: true,
|
154
|
+
value: undefined,
|
155
|
+
};
|
156
|
+
}
|
157
|
+
throw e;
|
158
|
+
});
|
159
|
+
}
|
160
|
+
}
|
161
|
+
// todo: error constructor adds a "cause" variable in Chrome 93, Node v??
|
162
|
+
class RPCResultError extends Error {
|
163
|
+
cause;
|
164
|
+
constructor(peer, message, cause, options) {
|
165
|
+
super(`${message}\n${peer.selfName}:${peer.peerName}`);
|
166
|
+
this.cause = cause;
|
167
|
+
if (options?.name) {
|
168
|
+
this.name = options?.name;
|
169
|
+
}
|
170
|
+
if (options?.stack) {
|
171
|
+
this.stack = `${cause?.stack || options.stack}\n${peer.peerName}:${peer.selfName}`;
|
172
|
+
}
|
173
|
+
}
|
174
|
+
}
|
175
|
+
exports.RPCResultError = RPCResultError;
|
176
|
+
function compileFunction(code, params, options) {
|
177
|
+
params = params || [];
|
178
|
+
const f = `(function(${params.join(',')}) {;${code};})`;
|
179
|
+
return eval(f);
|
180
|
+
}
|
181
|
+
try {
|
182
|
+
// @ts-ignore
|
183
|
+
const fr = FinalizationRegistry;
|
184
|
+
}
|
185
|
+
catch (e) {
|
186
|
+
window.WeakRef = class WeakRef {
|
187
|
+
target;
|
188
|
+
constructor(target) {
|
189
|
+
this.target = target;
|
190
|
+
}
|
191
|
+
deref() {
|
192
|
+
return this.target;
|
193
|
+
}
|
194
|
+
};
|
195
|
+
window.FinalizationRegistry = class FinalizationRegistry {
|
196
|
+
register() {
|
197
|
+
}
|
198
|
+
};
|
199
|
+
}
|
200
|
+
class RpcPeer {
|
201
|
+
selfName;
|
202
|
+
peerName;
|
203
|
+
send;
|
204
|
+
idCounter = 1;
|
205
|
+
params = {};
|
206
|
+
pendingResults = {};
|
207
|
+
proxyCounter = 1;
|
208
|
+
localProxied = new Map();
|
209
|
+
localProxyMap = new Map();
|
210
|
+
// @ts-ignore
|
211
|
+
remoteWeakProxies = {};
|
212
|
+
// @ts-ignore
|
213
|
+
finalizers = new FinalizationRegistry(entry => this.finalize(entry));
|
214
|
+
nameDeserializerMap = new Map();
|
215
|
+
onProxyTypeSerialization = new Map();
|
216
|
+
onProxySerialization;
|
217
|
+
constructorSerializerMap = new Map();
|
218
|
+
transportSafeArgumentTypes = RpcPeer.getDefaultTransportSafeArgumentTypes();
|
219
|
+
killed;
|
220
|
+
killedDeferred;
|
221
|
+
tags = {};
|
222
|
+
yieldedAsyncIterators = new Set();
|
223
|
+
static finalizerIdSymbol = Symbol('rpcFinalizerId');
|
224
|
+
static remotesCollected = 0;
|
225
|
+
static remotesCreated = 0;
|
226
|
+
static activeRpcPeer;
|
227
|
+
static isRpcProxy(value) {
|
228
|
+
return !!value?.[RpcPeer.PROPERTY_PROXY_ID];
|
229
|
+
}
|
230
|
+
static getDefaultTransportSafeArgumentTypes() {
|
231
|
+
const jsonSerializable = new Set();
|
232
|
+
jsonSerializable.add(Number.name);
|
233
|
+
jsonSerializable.add(String.name);
|
234
|
+
jsonSerializable.add(Object.name);
|
235
|
+
jsonSerializable.add(Boolean.name);
|
236
|
+
jsonSerializable.add(Array.name);
|
237
|
+
return jsonSerializable;
|
238
|
+
}
|
239
|
+
static handleFunctionInvocations(thiz, target, p, receiver) {
|
240
|
+
if (p === 'apply') {
|
241
|
+
return (thisArg, args) => {
|
242
|
+
return thiz.apply(target, thiz, args);
|
243
|
+
};
|
244
|
+
}
|
245
|
+
else if (p === 'call') {
|
246
|
+
return (thisArg, ...args) => {
|
247
|
+
return thiz.apply(target, thiz, args);
|
248
|
+
};
|
249
|
+
}
|
250
|
+
else if (p === 'toString' || p === Symbol.toPrimitive) {
|
251
|
+
return (thisArg, ...args) => {
|
252
|
+
return thiz.toPrimitive();
|
253
|
+
};
|
254
|
+
}
|
255
|
+
}
|
256
|
+
// static setProxyProperties(value: any, properties: any) {
|
257
|
+
// value[RpcPeer.PROPERTY_PROXY_PROPERTIES] = properties;
|
258
|
+
// }
|
259
|
+
// static getProxyProperties(value: any) {
|
260
|
+
// return value?.[RpcPeer.PROPERTY_PROXY_PROPERTIES];
|
261
|
+
// }
|
262
|
+
static getIteratorNext(target) {
|
263
|
+
if (!target[Symbol.asyncIterator])
|
264
|
+
return;
|
265
|
+
const proxyProps = target[this.PROPERTY_PROXY_PROPERTIES]?.[Symbol.asyncIterator.toString()];
|
266
|
+
return proxyProps?.next || 'next';
|
267
|
+
}
|
268
|
+
static prepareProxyProperties(value) {
|
269
|
+
let props = value?.[RpcPeer.PROPERTY_PROXY_PROPERTIES];
|
270
|
+
if (!value[Symbol.asyncIterator])
|
271
|
+
return props;
|
272
|
+
props ||= {};
|
273
|
+
if (!props[Symbol.asyncIterator.toString()]) {
|
274
|
+
props[Symbol.asyncIterator.toString()] = {
|
275
|
+
next: 'next',
|
276
|
+
throw: 'throw',
|
277
|
+
return: 'return',
|
278
|
+
};
|
279
|
+
}
|
280
|
+
return props;
|
281
|
+
}
|
282
|
+
static RPC_RESULT_ERROR_NAME = 'RPCResultError';
|
283
|
+
static PROPERTY_PROXY_ID = '__proxy_id';
|
284
|
+
static PROPERTY_PROXY_ONEWAY_METHODS = '__proxy_oneway_methods';
|
285
|
+
static PROPERTY_JSON_DISABLE_SERIALIZATION = '__json_disable_serialization';
|
286
|
+
static PROPERTY_PROXY_PROPERTIES = '__proxy_props';
|
287
|
+
static PROPERTY_JSON_COPY_SERIALIZE_CHILDREN = '__json_copy_serialize_children';
|
288
|
+
static PROBED_PROPERTIES = new Set([
|
289
|
+
'then',
|
290
|
+
'constructor',
|
291
|
+
'__proxy_id',
|
292
|
+
'__proxy_constructor',
|
293
|
+
'__proxy_peer',
|
294
|
+
RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS,
|
295
|
+
RpcPeer.PROPERTY_JSON_DISABLE_SERIALIZATION,
|
296
|
+
RpcPeer.PROPERTY_PROXY_PROPERTIES,
|
297
|
+
RpcPeer.PROPERTY_JSON_COPY_SERIALIZE_CHILDREN,
|
298
|
+
]);
|
299
|
+
constructor(selfName, peerName, send) {
|
300
|
+
this.selfName = selfName;
|
301
|
+
this.peerName = peerName;
|
302
|
+
this.send = send;
|
303
|
+
this.killed = new Promise((resolve, reject) => {
|
304
|
+
this.killedDeferred = { resolve, reject };
|
305
|
+
}).catch(e => e.message || 'Unknown Error');
|
306
|
+
}
|
307
|
+
static isTransportSafe(value) {
|
308
|
+
return !value || (!value[RpcPeer.PROPERTY_JSON_DISABLE_SERIALIZATION] && this.getDefaultTransportSafeArgumentTypes().has(value.constructor?.name));
|
309
|
+
}
|
310
|
+
isTransportSafe(value) {
|
311
|
+
return !value || (!value[RpcPeer.PROPERTY_JSON_DISABLE_SERIALIZATION] && this.transportSafeArgumentTypes.has(value.constructor?.name));
|
312
|
+
}
|
313
|
+
createPendingResult(cb) {
|
314
|
+
if (Object.isFrozen(this.pendingResults))
|
315
|
+
return Promise.reject(new RPCResultError(this, 'RpcPeer has been killed (createPendingResult)'));
|
316
|
+
const promise = new Promise((resolve, reject) => {
|
317
|
+
const id = (this.idCounter++).toString();
|
318
|
+
this.pendingResults[id] = { resolve, reject };
|
319
|
+
cb(id, e => reject(new RPCResultError(this, e.message, e)));
|
320
|
+
});
|
321
|
+
// todo: make this an option so rpc doesn't nuke the process if uncaught?
|
322
|
+
promise.catch(() => { });
|
323
|
+
return promise;
|
324
|
+
}
|
325
|
+
kill(message) {
|
326
|
+
if (Object.isFrozen(this.pendingResults))
|
327
|
+
return;
|
328
|
+
const error = new RPCResultError(this, message || 'peer was killed');
|
329
|
+
this.killedDeferred.reject(error);
|
330
|
+
for (const result of Object.values(this.pendingResults)) {
|
331
|
+
result.reject(error);
|
332
|
+
}
|
333
|
+
for (const y of this.yieldedAsyncIterators) {
|
334
|
+
y.throw(error);
|
335
|
+
}
|
336
|
+
this.yieldedAsyncIterators.clear();
|
337
|
+
this.pendingResults = Object.freeze({});
|
338
|
+
this.params = Object.freeze({});
|
339
|
+
this.remoteWeakProxies = Object.freeze({});
|
340
|
+
this.localProxyMap.clear();
|
341
|
+
this.localProxied.clear();
|
342
|
+
}
|
343
|
+
// need a name/constructor map due to babel name mangling? fix somehow?
|
344
|
+
addSerializer(ctr, name, serializer) {
|
345
|
+
this.nameDeserializerMap.set(name, serializer);
|
346
|
+
this.constructorSerializerMap.set(ctr, name);
|
347
|
+
}
|
348
|
+
finalize(entry) {
|
349
|
+
RpcPeer.remotesCollected++;
|
350
|
+
delete this.remoteWeakProxies[entry.id];
|
351
|
+
const rpcFinalize = {
|
352
|
+
__local_proxy_id: entry.id,
|
353
|
+
__local_proxy_finalizer_id: entry.finalizerId,
|
354
|
+
type: 'finalize',
|
355
|
+
};
|
356
|
+
this.send(rpcFinalize);
|
357
|
+
}
|
358
|
+
async getParam(param) {
|
359
|
+
return this.createPendingResult((id, reject) => {
|
360
|
+
const paramMessage = {
|
361
|
+
id,
|
362
|
+
type: 'param',
|
363
|
+
param,
|
364
|
+
};
|
365
|
+
this.send(paramMessage, reject);
|
366
|
+
});
|
367
|
+
}
|
368
|
+
evalLocal(script, filename, coercedParams) {
|
369
|
+
const params = Object.assign({}, this.params, coercedParams);
|
370
|
+
let compile;
|
371
|
+
try {
|
372
|
+
// prevent bundlers from trying to include non-existent vm module.
|
373
|
+
compile = module[`require`]('vm').compileFunction;
|
374
|
+
}
|
375
|
+
catch (e) {
|
376
|
+
compile = compileFunction;
|
377
|
+
}
|
378
|
+
const f = compile(script, Object.keys(params), {
|
379
|
+
filename,
|
380
|
+
});
|
381
|
+
const value = f(...Object.values(params));
|
382
|
+
return value;
|
383
|
+
}
|
384
|
+
/**
|
385
|
+
* @deprecated
|
386
|
+
* @param result
|
387
|
+
* @param e
|
388
|
+
*/
|
389
|
+
createErrorResult(result, e) {
|
390
|
+
result.result = this.serializeError(e);
|
391
|
+
result.throw = true;
|
392
|
+
result.message = e.message || 'no message';
|
393
|
+
result.stack = e.stack || 'no stack';
|
394
|
+
}
|
395
|
+
deserialize(value, deserializationContext) {
|
396
|
+
if (!value)
|
397
|
+
return value;
|
398
|
+
const copySerializeChildren = value[RpcPeer.PROPERTY_JSON_COPY_SERIALIZE_CHILDREN];
|
399
|
+
if (copySerializeChildren) {
|
400
|
+
const ret = {};
|
401
|
+
for (const [key, val] of Object.entries(value)) {
|
402
|
+
ret[key] = this.deserialize(val, deserializationContext);
|
403
|
+
}
|
404
|
+
return ret;
|
405
|
+
}
|
406
|
+
const { __remote_proxy_id, __remote_proxy_finalizer_id, __local_proxy_id, __remote_constructor_name, __serialized_value, __remote_proxy_props, __remote_proxy_oneway_methods } = value;
|
407
|
+
if (__remote_constructor_name === RpcPeer.RPC_RESULT_ERROR_NAME)
|
408
|
+
return this.deserializeError(__serialized_value);
|
409
|
+
if (__remote_proxy_id) {
|
410
|
+
let proxy = this.remoteWeakProxies[__remote_proxy_id]?.deref();
|
411
|
+
if (!proxy)
|
412
|
+
proxy = this.newProxy(__remote_proxy_id, __remote_constructor_name, __remote_proxy_props, __remote_proxy_oneway_methods);
|
413
|
+
proxy[RpcPeer.finalizerIdSymbol] = __remote_proxy_finalizer_id;
|
414
|
+
const deserializer = this.nameDeserializerMap.get(__remote_constructor_name);
|
415
|
+
if (deserializer) {
|
416
|
+
return deserializer.deserialize(proxy, deserializationContext);
|
417
|
+
}
|
418
|
+
return proxy;
|
419
|
+
}
|
420
|
+
if (__local_proxy_id) {
|
421
|
+
const ret = this.localProxyMap.get(__local_proxy_id);
|
422
|
+
if (!ret)
|
423
|
+
throw new RPCResultError(this, `invalid local proxy id ${__local_proxy_id}`);
|
424
|
+
return ret;
|
425
|
+
}
|
426
|
+
const deserializer = this.nameDeserializerMap.get(__remote_constructor_name);
|
427
|
+
if (deserializer) {
|
428
|
+
return deserializer.deserialize(__serialized_value, deserializationContext);
|
429
|
+
}
|
430
|
+
return value;
|
431
|
+
}
|
432
|
+
deserializeError(e) {
|
433
|
+
const { name, stack, message } = e;
|
434
|
+
return new RPCResultError(this, message, undefined, { name, stack });
|
435
|
+
}
|
436
|
+
serializeError(e) {
|
437
|
+
const __serialized_value = {
|
438
|
+
stack: e.stack || '[no stack]',
|
439
|
+
name: e.name || '[no name]',
|
440
|
+
message: e.message || '[no message]',
|
441
|
+
};
|
442
|
+
return {
|
443
|
+
// probably not safe to use constructor.name
|
444
|
+
__remote_constructor_name: RpcPeer.RPC_RESULT_ERROR_NAME,
|
445
|
+
__remote_proxy_id: undefined,
|
446
|
+
__remote_proxy_finalizer_id: undefined,
|
447
|
+
__remote_proxy_oneway_methods: undefined,
|
448
|
+
__remote_proxy_props: undefined,
|
449
|
+
__serialized_value,
|
450
|
+
};
|
451
|
+
}
|
452
|
+
serialize(value, serializationContext) {
|
453
|
+
if (value?.[RpcPeer.PROPERTY_JSON_COPY_SERIALIZE_CHILDREN] === true) {
|
454
|
+
const ret = {};
|
455
|
+
for (const [key, val] of Object.entries(value)) {
|
456
|
+
ret[key] = this.serialize(val, serializationContext);
|
457
|
+
}
|
458
|
+
return ret;
|
459
|
+
}
|
460
|
+
if (this.isTransportSafe(value)) {
|
461
|
+
return value;
|
462
|
+
}
|
463
|
+
let __remote_constructor_name = value.__proxy_constructor || value.constructor?.name?.toString();
|
464
|
+
if (value instanceof Error)
|
465
|
+
return this.serializeError(value);
|
466
|
+
const serializerMapName = this.constructorSerializerMap.get(value.constructor);
|
467
|
+
if (serializerMapName) {
|
468
|
+
__remote_constructor_name = serializerMapName;
|
469
|
+
const serializer = this.nameDeserializerMap.get(serializerMapName);
|
470
|
+
if (!serializer)
|
471
|
+
throw new Error('serializer not found for ' + serializerMapName);
|
472
|
+
const serialized = serializer.serialize(value, serializationContext);
|
473
|
+
const ret = {
|
474
|
+
__remote_proxy_id: undefined,
|
475
|
+
__remote_proxy_finalizer_id: undefined,
|
476
|
+
__remote_constructor_name,
|
477
|
+
__remote_proxy_props: RpcPeer.prepareProxyProperties(value),
|
478
|
+
__remote_proxy_oneway_methods: value?.[RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS],
|
479
|
+
__serialized_value: serialized,
|
480
|
+
};
|
481
|
+
return ret;
|
482
|
+
}
|
483
|
+
let proxiedEntry = this.localProxied.get(value);
|
484
|
+
if (proxiedEntry) {
|
485
|
+
const __remote_proxy_finalizer_id = (this.proxyCounter++).toString();
|
486
|
+
proxiedEntry.finalizerId = __remote_proxy_finalizer_id;
|
487
|
+
const ret = {
|
488
|
+
__remote_proxy_id: proxiedEntry.id,
|
489
|
+
__remote_proxy_finalizer_id,
|
490
|
+
__remote_constructor_name,
|
491
|
+
__remote_proxy_props: RpcPeer.prepareProxyProperties(value),
|
492
|
+
__remote_proxy_oneway_methods: value?.[RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS],
|
493
|
+
};
|
494
|
+
return ret;
|
495
|
+
}
|
496
|
+
const { __proxy_id, __proxy_peer } = value;
|
497
|
+
if (__proxy_id && __proxy_peer === this) {
|
498
|
+
const ret = {
|
499
|
+
__local_proxy_id: __proxy_id,
|
500
|
+
};
|
501
|
+
return ret;
|
502
|
+
}
|
503
|
+
this.onProxyTypeSerialization.get(__remote_constructor_name)?.(value);
|
504
|
+
const __remote_proxy_id = (this.proxyCounter++).toString();
|
505
|
+
proxiedEntry = {
|
506
|
+
id: __remote_proxy_id,
|
507
|
+
finalizerId: __remote_proxy_id,
|
508
|
+
};
|
509
|
+
this.localProxied.set(value, proxiedEntry);
|
510
|
+
this.localProxyMap.set(__remote_proxy_id, value);
|
511
|
+
const __remote_proxy_props = this.onProxySerialization ? this.onProxySerialization(value, __remote_proxy_id) : RpcPeer.prepareProxyProperties(value);
|
512
|
+
const ret = {
|
513
|
+
__remote_proxy_id,
|
514
|
+
__remote_proxy_finalizer_id: __remote_proxy_id,
|
515
|
+
__remote_constructor_name,
|
516
|
+
__remote_proxy_props,
|
517
|
+
__remote_proxy_oneway_methods: value?.[RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS],
|
518
|
+
};
|
519
|
+
return ret;
|
520
|
+
}
|
521
|
+
newProxy(proxyId, proxyConstructorName, proxyProps, proxyOneWayMethods) {
|
522
|
+
RpcPeer.remotesCreated++;
|
523
|
+
const localProxiedEntry = {
|
524
|
+
id: proxyId,
|
525
|
+
finalizerId: undefined,
|
526
|
+
};
|
527
|
+
const rpc = new RpcProxy(this, localProxiedEntry, proxyConstructorName, proxyProps, proxyOneWayMethods);
|
528
|
+
const target = proxyConstructorName === 'Function' || proxyConstructorName === 'AsyncFunction' ? function () { } : rpc;
|
529
|
+
const proxy = new Proxy(target, rpc);
|
530
|
+
// @ts-ignore
|
531
|
+
const weakref = new WeakRef(proxy);
|
532
|
+
this.remoteWeakProxies[proxyId] = weakref;
|
533
|
+
this.finalizers.register(rpc, localProxiedEntry);
|
534
|
+
return proxy;
|
535
|
+
}
|
536
|
+
handleMessage(message, deserializationContext) {
|
537
|
+
try {
|
538
|
+
RpcPeer.activeRpcPeer = this;
|
539
|
+
this.handleMessageInternal(message, deserializationContext);
|
540
|
+
}
|
541
|
+
finally {
|
542
|
+
RpcPeer.activeRpcPeer = undefined;
|
543
|
+
}
|
544
|
+
}
|
545
|
+
async handleMessageInternal(message, deserializationContext) {
|
546
|
+
if (Object.isFrozen(this.pendingResults))
|
547
|
+
return;
|
548
|
+
try {
|
549
|
+
switch (message.type) {
|
550
|
+
case 'param': {
|
551
|
+
const rpcParam = message;
|
552
|
+
const serializationContext = {};
|
553
|
+
let result;
|
554
|
+
try {
|
555
|
+
result = {
|
556
|
+
type: 'result',
|
557
|
+
id: rpcParam.id,
|
558
|
+
result: this.serialize(this.params[rpcParam.param], serializationContext)
|
559
|
+
};
|
560
|
+
}
|
561
|
+
catch (e) {
|
562
|
+
// console.error('failure', rpcApply.method, e);
|
563
|
+
this.createErrorResult(result, e);
|
564
|
+
}
|
565
|
+
this.send(result, undefined, serializationContext);
|
566
|
+
break;
|
567
|
+
}
|
568
|
+
case 'apply': {
|
569
|
+
const rpcApply = message;
|
570
|
+
const result = {
|
571
|
+
type: 'result',
|
572
|
+
id: rpcApply.id || '',
|
573
|
+
};
|
574
|
+
const serializationContext = {};
|
575
|
+
try {
|
576
|
+
const target = this.localProxyMap.get(rpcApply.proxyId);
|
577
|
+
if (!target)
|
578
|
+
throw new Error(`proxy id ${rpcApply.proxyId} not found`);
|
579
|
+
const args = [];
|
580
|
+
for (const arg of (rpcApply.args || [])) {
|
581
|
+
args.push(this.deserialize(arg, deserializationContext));
|
582
|
+
}
|
583
|
+
let value;
|
584
|
+
if (rpcApply.method) {
|
585
|
+
const method = target[rpcApply.method];
|
586
|
+
if (!method)
|
587
|
+
throw new Error(`target ${target?.constructor?.name} does not have method ${rpcApply.method}`);
|
588
|
+
const isIteratorNext = RpcPeer.getIteratorNext(target) === rpcApply.method;
|
589
|
+
if (isIteratorNext)
|
590
|
+
this.yieldedAsyncIterators.delete(target);
|
591
|
+
value = await target[rpcApply.method](...args);
|
592
|
+
if (isIteratorNext) {
|
593
|
+
if (value.done) {
|
594
|
+
const errorType = {
|
595
|
+
name: 'StopAsyncIteration',
|
596
|
+
message: undefined,
|
597
|
+
};
|
598
|
+
throw errorType;
|
599
|
+
}
|
600
|
+
else {
|
601
|
+
if (Object.isFrozen(this.pendingResults)) {
|
602
|
+
target.throw(new RPCResultError(this, 'RpcPeer has been killed (yield)'));
|
603
|
+
}
|
604
|
+
else {
|
605
|
+
this.yieldedAsyncIterators.add(target);
|
606
|
+
}
|
607
|
+
value = value.value;
|
608
|
+
}
|
609
|
+
}
|
610
|
+
}
|
611
|
+
else {
|
612
|
+
value = await target(...args);
|
613
|
+
}
|
614
|
+
result.result = this.serialize(value, serializationContext);
|
615
|
+
}
|
616
|
+
catch (e) {
|
617
|
+
// console.error('failure', rpcApply.method, e);
|
618
|
+
this.createErrorResult(result, e);
|
619
|
+
}
|
620
|
+
if (!rpcApply.oneway)
|
621
|
+
this.send(result, undefined, serializationContext);
|
622
|
+
break;
|
623
|
+
}
|
624
|
+
case 'result': {
|
625
|
+
// console.log(message)
|
626
|
+
const rpcResult = message;
|
627
|
+
const deferred = this.pendingResults[rpcResult.id];
|
628
|
+
delete this.pendingResults[rpcResult.id];
|
629
|
+
if (!deferred)
|
630
|
+
throw new Error(`unknown result ${rpcResult.id}`);
|
631
|
+
if ((rpcResult.message || rpcResult.stack) && !rpcResult.throw) {
|
632
|
+
const e = new RPCResultError(this, rpcResult.message || 'no message', undefined, {
|
633
|
+
name: rpcResult.result,
|
634
|
+
stack: rpcResult.stack,
|
635
|
+
});
|
636
|
+
deferred.reject(e);
|
637
|
+
return;
|
638
|
+
}
|
639
|
+
const deserialized = this.deserialize(rpcResult.result, deserializationContext);
|
640
|
+
if (rpcResult.throw)
|
641
|
+
deferred.reject(deserialized);
|
642
|
+
else
|
643
|
+
deferred.resolve(deserialized);
|
644
|
+
break;
|
645
|
+
}
|
646
|
+
case 'finalize': {
|
647
|
+
const rpcFinalize = message;
|
648
|
+
const local = this.localProxyMap.get(rpcFinalize.__local_proxy_id);
|
649
|
+
if (local) {
|
650
|
+
const localProxiedEntry = this.localProxied.get(local);
|
651
|
+
// if a finalizer id is specified, it must match.
|
652
|
+
if (rpcFinalize.__local_proxy_finalizer_id && rpcFinalize.__local_proxy_finalizer_id !== localProxiedEntry?.finalizerId) {
|
653
|
+
break;
|
654
|
+
}
|
655
|
+
this.localProxyMap.delete(rpcFinalize.__local_proxy_id);
|
656
|
+
this.localProxied.delete(local);
|
657
|
+
}
|
658
|
+
break;
|
659
|
+
}
|
660
|
+
default:
|
661
|
+
throw new Error(`unknown rpc message type ${message.type}`);
|
662
|
+
}
|
663
|
+
}
|
664
|
+
catch (e) {
|
665
|
+
console.error('unhandled rpc error', this.peerName, e);
|
666
|
+
return;
|
667
|
+
}
|
668
|
+
}
|
669
|
+
}
|
670
|
+
exports.RpcPeer = RpcPeer;
|
671
|
+
function getEvalSource() {
|
672
|
+
return `
|
673
|
+
(() => {
|
674
|
+
${RpcProxy}
|
675
|
+
|
676
|
+
${RpcPeer}
|
677
|
+
|
678
|
+
${startPeriodicGarbageCollection}
|
679
|
+
|
680
|
+
return {
|
681
|
+
startPeriodicGarbageCollection,
|
682
|
+
RpcPeer,
|
683
|
+
RpcProxy,
|
684
|
+
};
|
685
|
+
})();
|
686
|
+
`;
|
687
|
+
}
|
688
|
+
exports.getEvalSource = getEvalSource;
|
689
|
+
//# sourceMappingURL=rpc.js.map
|