@scrypted/server 0.0.105 → 0.0.109

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.

Files changed (49) hide show
  1. package/dist/http-interfaces.js +2 -2
  2. package/dist/http-interfaces.js.map +1 -1
  3. package/dist/plugin/listen-zero.js +13 -1
  4. package/dist/plugin/listen-zero.js.map +1 -1
  5. package/dist/plugin/plugin-device.js +11 -2
  6. package/dist/plugin/plugin-device.js.map +1 -1
  7. package/dist/plugin/plugin-host-api.js +8 -7
  8. package/dist/plugin/plugin-host-api.js.map +1 -1
  9. package/dist/plugin/plugin-host.js +36 -87
  10. package/dist/plugin/plugin-host.js.map +1 -1
  11. package/dist/plugin/plugin-http.js +100 -0
  12. package/dist/plugin/plugin-http.js.map +1 -0
  13. package/dist/plugin/plugin-lazy-remote.js +73 -0
  14. package/dist/plugin/plugin-lazy-remote.js.map +1 -0
  15. package/dist/plugin/plugin-npm-dependencies.js +16 -16
  16. package/dist/plugin/plugin-npm-dependencies.js.map +1 -1
  17. package/dist/plugin/plugin-remote-websocket.js +40 -34
  18. package/dist/plugin/plugin-remote-websocket.js.map +1 -1
  19. package/dist/plugin/plugin-remote.js +35 -26
  20. package/dist/plugin/plugin-remote.js.map +1 -1
  21. package/dist/rpc.js +53 -26
  22. package/dist/rpc.js.map +1 -1
  23. package/dist/runtime.js +45 -111
  24. package/dist/runtime.js.map +1 -1
  25. package/dist/scrypted-main.js +3 -0
  26. package/dist/scrypted-main.js.map +1 -1
  27. package/dist/services/plugin.js +2 -2
  28. package/dist/services/plugin.js.map +1 -1
  29. package/dist/state.js +2 -8
  30. package/dist/state.js.map +1 -1
  31. package/package.json +2 -2
  32. package/python/plugin-remote.py +4 -4
  33. package/python/rpc.py +68 -26
  34. package/src/http-interfaces.ts +3 -3
  35. package/src/plugin/listen-zero.ts +13 -0
  36. package/src/plugin/plugin-api.ts +1 -1
  37. package/src/plugin/plugin-device.ts +11 -2
  38. package/src/plugin/plugin-host-api.ts +9 -8
  39. package/src/plugin/plugin-host.ts +40 -95
  40. package/src/plugin/plugin-http.ts +117 -0
  41. package/src/plugin/plugin-lazy-remote.ts +70 -0
  42. package/src/plugin/plugin-npm-dependencies.ts +19 -18
  43. package/src/plugin/plugin-remote-websocket.ts +55 -60
  44. package/src/plugin/plugin-remote.ts +45 -38
  45. package/src/rpc.ts +62 -25
  46. package/src/runtime.ts +55 -128
  47. package/src/scrypted-main.ts +4 -0
  48. package/src/services/plugin.ts +2 -2
  49. package/src/state.ts +2 -10
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 id: string,
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,6 +115,12 @@ 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
  const method = target();
119
126
  const args: any[] = [];
@@ -124,7 +131,7 @@ class RpcProxy implements ProxyHandler<any> {
124
131
  const rpcApply: RpcApply = {
125
132
  type: "apply",
126
133
  id: undefined,
127
- proxyId: this.id,
134
+ proxyId: this.entry.id,
128
135
  args,
129
136
  method,
130
137
  };
@@ -187,16 +194,21 @@ export interface RpcSerializer {
187
194
  deserialize(serialized: any): any;
188
195
  }
189
196
 
197
+ interface LocalProxiedEntry {
198
+ id: string;
199
+ finalizerId: string;
200
+ }
201
+
190
202
  export class RpcPeer {
191
203
  idCounter = 1;
192
204
  onOob: (oob: any) => void;
193
205
  params: { [name: string]: any } = {};
194
206
  pendingResults: { [id: string]: Deferred } = {};
195
207
  proxyCounter = 1;
196
- localProxied = new Map<any, string>();
208
+ localProxied = new Map<any, LocalProxiedEntry>();
197
209
  localProxyMap: { [id: string]: any } = {};
198
210
  remoteWeakProxies: { [id: string]: WeakRef<any> } = {};
199
- finalizers = new FinalizationRegistry(id => this.finalize(id as string));
211
+ finalizers = new FinalizationRegistry(entry => this.finalize(entry as LocalProxiedEntry));
200
212
  nameDeserializerMap = new Map<string, RpcSerializer>();
201
213
  constructorSerializerMap = new Map<string, string>();
202
214
  transportSafeArgumentTypes = getDefaultTransportSafeArgumentTypes();
@@ -238,10 +250,11 @@ export class RpcPeer {
238
250
  this.constructorSerializerMap.set(ctr, name);
239
251
  }
240
252
 
241
- finalize(id: string) {
242
- delete this.remoteWeakProxies[id];
253
+ finalize(entry: LocalProxiedEntry) {
254
+ delete this.remoteWeakProxies[entry.id];
243
255
  const rpcFinalize: RpcFinalize = {
244
- __local_proxy_id: id,
256
+ __local_proxy_id: entry.id,
257
+ __local_proxy_finalizer_id: entry.finalizerId,
245
258
  type: 'finalize',
246
259
  }
247
260
  this.send(rpcFinalize);
@@ -294,9 +307,12 @@ export class RpcPeer {
294
307
  return ret;
295
308
  }
296
309
 
297
- const { __remote_proxy_id, __local_proxy_id, __remote_constructor_name, __serialized_value, __remote_proxy_props, __remote_proxy_oneway_methods } = value;
310
+ 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
311
  if (__remote_proxy_id) {
299
- const proxy = this.remoteWeakProxies[__remote_proxy_id]?.deref() || this.newProxy(__remote_proxy_id, __remote_constructor_name, __remote_proxy_props, __remote_proxy_oneway_methods);
312
+ let proxy = this.remoteWeakProxies[__remote_proxy_id]?.deref();
313
+ if (!proxy)
314
+ proxy = this.newProxy(__remote_proxy_id, __remote_constructor_name, __remote_proxy_props, __remote_proxy_oneway_methods);
315
+ proxy[finalizerIdSymbol] = __remote_proxy_finalizer_id;
300
316
  return proxy;
301
317
  }
302
318
 
@@ -329,10 +345,13 @@ export class RpcPeer {
329
345
 
330
346
  let __remote_constructor_name = value.__proxy_constructor || value.constructor?.name?.toString();
331
347
 
332
- let proxyId = this.localProxied.get(value);
333
- if (proxyId) {
348
+ let proxiedEntry = this.localProxied.get(value);
349
+ if (proxiedEntry) {
350
+ const __remote_proxy_finalizer_id = (this.proxyCounter++).toString();
351
+ proxiedEntry.finalizerId = __remote_proxy_finalizer_id;
334
352
  const ret: RpcRemoteProxyValue = {
335
- __remote_proxy_id: proxyId,
353
+ __remote_proxy_id: proxiedEntry.id,
354
+ __remote_proxy_finalizer_id,
336
355
  __remote_constructor_name,
337
356
  __remote_proxy_props: value?.[PROPERTY_PROXY_PROPERTIES],
338
357
  __remote_proxy_oneway_methods: value?.[PROPERTY_PROXY_ONEWAY_METHODS],
@@ -355,6 +374,7 @@ export class RpcPeer {
355
374
  const serialized = serializer.serialize(value);
356
375
  const ret: RpcRemoteProxyValue = {
357
376
  __remote_proxy_id: undefined,
377
+ __remote_proxy_finalizer_id: undefined,
358
378
  __remote_constructor_name,
359
379
  __remote_proxy_props: value?.[PROPERTY_PROXY_PROPERTIES],
360
380
  __remote_proxy_oneway_methods: value?.[PROPERTY_PROXY_ONEWAY_METHODS],
@@ -363,12 +383,17 @@ export class RpcPeer {
363
383
  return ret;
364
384
  }
365
385
 
366
- proxyId = (this.proxyCounter++).toString();
367
- this.localProxied.set(value, proxyId);
368
- this.localProxyMap[proxyId] = value;
386
+ const __remote_proxy_id = (this.proxyCounter++).toString();
387
+ proxiedEntry = {
388
+ id: __remote_proxy_id,
389
+ finalizerId: __remote_proxy_id,
390
+ };
391
+ this.localProxied.set(value, proxiedEntry);
392
+ this.localProxyMap[__remote_proxy_id] = value;
369
393
 
370
394
  const ret: RpcRemoteProxyValue = {
371
- __remote_proxy_id: proxyId,
395
+ __remote_proxy_id,
396
+ __remote_proxy_finalizer_id: __remote_proxy_id,
372
397
  __remote_constructor_name,
373
398
  __remote_proxy_props: value?.[PROPERTY_PROXY_PROPERTIES],
374
399
  __remote_proxy_oneway_methods: value?.[PROPERTY_PROXY_ONEWAY_METHODS],
@@ -378,12 +403,16 @@ export class RpcPeer {
378
403
  }
379
404
 
380
405
  newProxy(proxyId: string, proxyConstructorName: string, proxyProps: any, proxyOneWayMethods: string[]) {
381
- const rpc = new RpcProxy(this, proxyId, proxyConstructorName, proxyProps, proxyOneWayMethods);
406
+ const localProxiedEntry: LocalProxiedEntry = {
407
+ id: proxyId,
408
+ finalizerId: undefined,
409
+ }
410
+ const rpc = new RpcProxy(this, localProxiedEntry, proxyConstructorName, proxyProps, proxyOneWayMethods);
382
411
  const target = proxyConstructorName === 'Function' || proxyConstructorName === 'AsyncFunction' ? function () { } : rpc;
383
412
  const proxy = new Proxy(target, rpc);
384
413
  const weakref = new WeakRef(proxy);
385
414
  this.remoteWeakProxies[proxyId] = weakref;
386
- this.finalizers.register(rpc, proxyId);
415
+ this.finalizers.register(rpc, localProxiedEntry);
387
416
  global.gc?.();
388
417
  return proxy;
389
418
  }
@@ -460,8 +489,16 @@ export class RpcPeer {
460
489
  case 'finalize': {
461
490
  const rpcFinalize = message as RpcFinalize;
462
491
  const local = this.localProxyMap[rpcFinalize.__local_proxy_id];
463
- delete this.localProxyMap[rpcFinalize.__local_proxy_id];
464
- this.localProxied.delete(local);
492
+ if (local) {
493
+ const localProxiedEntry = this.localProxied.get(local);
494
+ // if a finalizer id is specified, it must match.
495
+ if (rpcFinalize.__local_proxy_finalizer_id && rpcFinalize.__local_proxy_finalizer_id !== localProxiedEntry?.finalizerId) {
496
+ console.error(this.selfName, this.peerName, 'finalizer mismatch')
497
+ break;
498
+ }
499
+ delete this.localProxyMap[rpcFinalize.__local_proxy_id];
500
+ this.localProxied.delete(local);
501
+ }
465
502
  break;
466
503
  }
467
504
  case 'oob': {
package/src/runtime.ts CHANGED
@@ -4,9 +4,8 @@ import { ScryptedNativeId, Device, EngineIOHandler, HttpRequest, HttpRequestHand
4
4
  import { PluginDeviceProxyHandler } from './plugin/plugin-device';
5
5
  import { Plugin, PluginDevice, ScryptedAlert } from './db-types';
6
6
  import { getState, ScryptedStateManager, setState } from './state';
7
- import { Request, Response, Router } from 'express';
7
+ import { Request, Response } from 'express';
8
8
  import { createResponseInterface } from './http-interfaces';
9
- import bodyParser from 'body-parser';
10
9
  import http, { ServerResponse } from 'http';
11
10
  import https from 'https';
12
11
  import express from 'express';
@@ -15,7 +14,7 @@ import { getDisplayName, getDisplayRoom, getDisplayType, getProvidedNameOrDefaul
15
14
  import { URL } from "url";
16
15
  import qs from "query-string";
17
16
  import { PluginComponent } from './services/plugin';
18
- import { Server as WebSocketServer } from "ws";
17
+ import WebSocket, { Server as WebSocketServer } from "ws";
19
18
  import axios from 'axios';
20
19
  import tar from 'tar';
21
20
  import { once } from 'events';
@@ -30,6 +29,7 @@ import io from 'engine.io';
30
29
  import { spawn as ptySpawn } from 'node-pty';
31
30
  import rimraf from 'rimraf';
32
31
  import { getPluginVolume } from './plugin/plugin-volume';
32
+ import { PluginHttp } from './plugin/plugin-http';
33
33
 
34
34
  interface DeviceProxyPair {
35
35
  handler: PluginDeviceProxyHandler;
@@ -39,13 +39,17 @@ interface DeviceProxyPair {
39
39
  const MIN_SCRYPTED_CORE_VERSION = 'v0.0.146';
40
40
  const PLUGIN_DEVICE_STATE_VERSION = 2;
41
41
 
42
- export class ScryptedRuntime {
42
+ interface HttpPluginData {
43
+ pluginHost: PluginHost;
44
+ pluginDevice: PluginDevice
45
+ }
46
+
47
+ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
43
48
  datastore: Level;
44
49
  plugins: { [id: string]: PluginHost } = {};
45
50
  pluginDevices: { [id: string]: PluginDevice } = {};
46
51
  devices: { [id: string]: DeviceProxyPair } = {};
47
52
  stateManager = new ScryptedStateManager(this);
48
- app: Router;
49
53
  logger = new Logger(this, '', 'Scrypted');
50
54
  devicesLogger = this.logger.getLogger('device', 'Devices');
51
55
  wss = new WebSocketServer({ noServer: true });
@@ -55,30 +59,12 @@ export class ScryptedRuntime {
55
59
  });
56
60
 
57
61
  constructor(datastore: Level, insecure: http.Server, secure: https.Server, app: express.Application) {
62
+ super(app);
58
63
  this.datastore = datastore;
59
64
  this.app = app;
60
65
 
61
66
  app.disable('x-powered-by');
62
67
 
63
- app.all(['/endpoint/@:owner/:pkg/public/engine.io/*', '/endpoint/:pkg/public/engine.io/*'], (req, res) => {
64
- this.endpointHandler(req, res, true, true, this.handleEngineIOEndpoint.bind(this))
65
- });
66
-
67
- app.all(['/endpoint/@:owner/:pkg/engine.io/*', '/endpoint/@:owner/:pkg/engine.io/*'], (req, res) => {
68
- this.endpointHandler(req, res, false, true, this.handleEngineIOEndpoint.bind(this))
69
- });
70
-
71
- // stringify all http endpoints
72
- app.all(['/endpoint/@:owner/:pkg/public', '/endpoint/@:owner/:pkg/public/*', '/endpoint/:pkg', '/endpoint/:pkg/*'], bodyParser.text() as any);
73
-
74
- app.all(['/endpoint/@:owner/:pkg/public', '/endpoint/@:owner/:pkg/public/*', '/endpoint/:pkg/public', '/endpoint/:pkg/public/*'], (req, res) => {
75
- this.endpointHandler(req, res, true, false, this.handleRequestEndpoint.bind(this))
76
- });
77
-
78
- app.all(['/endpoint/@:owner/:pkg', '/endpoint/@:owner/:pkg/*', '/endpoint/:pkg', '/endpoint/:pkg/*'], (req, res) => {
79
- this.endpointHandler(req, res, false, false, this.handleRequestEndpoint.bind(this))
80
- });
81
-
82
68
  app.get('/web/oauth/callback', (req, res) => {
83
69
  this.oauthCallback(req, res);
84
70
  });
@@ -190,7 +176,7 @@ export class ScryptedRuntime {
190
176
  }
191
177
  }
192
178
 
193
- async getPluginForEndpoint(endpoint: string) {
179
+ async getPluginForEndpoint(endpoint: string): Promise<HttpPluginData> {
194
180
  let pluginHost = this.plugins[endpoint] ?? this.getPluginHostForDeviceId(endpoint);
195
181
  if (endpoint === '@scrypted/core') {
196
182
  // enforce a minimum version on @scrypted/core
@@ -254,110 +240,55 @@ export class ScryptedRuntime {
254
240
  this.shellio.handleRequest(req, res);
255
241
  }
256
242
 
257
- async endpointHandler(req: Request, res: Response, isPublicEndpoint: boolean, isEngineIOEndpoint: boolean,
258
- handler: (req: Request, res: Response, endpointRequest: HttpRequest, pluginHost: PluginHost, pluginDevice: PluginDevice) => void) {
259
-
260
- const isUpgrade = req.headers.connection?.toLowerCase() === 'upgrade';
261
-
262
- const end = (code: number, message: string) => {
263
- if (isUpgrade) {
264
- const socket = res.socket;
265
- socket.write(`HTTP/1.1 ${code} ${message}\r\n` +
266
- '\r\n');
267
- socket.destroy();
268
- }
269
- else {
270
- res.status(code);
271
- res.send(message);
272
- }
273
- };
274
-
275
- if (!isPublicEndpoint && !res.locals.username) {
276
- end(401, 'Not Authorized');
277
- return;
278
- }
279
-
280
- const { owner, pkg } = req.params;
281
- let endpoint = pkg;
282
- if (owner)
283
- endpoint = `@${owner}/${endpoint}`;
284
-
285
- const { pluginHost, pluginDevice } = await this.getPluginForEndpoint(endpoint);
243
+ async getEndpointPluginData(endpoint: string, isUpgrade: boolean, isEngineIOEndpoint: boolean): Promise<HttpPluginData> {
244
+ const ret = await this.getPluginForEndpoint(endpoint);
245
+ const { pluginDevice } = ret;
286
246
 
287
247
  // check if upgrade requests can be handled. must be websocket.
288
248
  if (isUpgrade) {
289
- if (req.headers.upgrade?.toLowerCase() !== 'websocket' || !pluginDevice?.state.interfaces.value.includes(ScryptedInterface.EngineIOHandler)) {
290
- end(404, 'Not Found');
249
+ if (!pluginDevice?.state.interfaces.value.includes(ScryptedInterface.EngineIOHandler)) {
291
250
  return;
292
251
  }
293
252
  }
294
253
  else {
295
254
  if (!isEngineIOEndpoint && !pluginDevice?.state.interfaces.value.includes(ScryptedInterface.HttpRequestHandler)) {
296
- end(404, 'Not Found');
297
255
  return;
298
256
  }
299
257
  }
300
258
 
301
- let rootPath = `/endpoint/${endpoint}`;
302
- if (isPublicEndpoint)
303
- rootPath += '/public'
304
-
305
- const body = req.body && typeof req.body !== 'string' ? JSON.stringify(req.body) : req.body;
259
+ return ret;
260
+ }
306
261
 
307
- const httpRequest: HttpRequest = {
308
- body,
309
- headers: req.headers,
310
- method: req.method,
311
- rootPath,
312
- url: req.url,
313
- isPublicEndpoint,
314
- username: res.locals.username,
315
- };
262
+ async handleWebSocket(endpoint: string, httpRequest: HttpRequest, ws: WebSocket, pluginData: HttpPluginData): Promise<void> {
263
+ const { pluginDevice } = pluginData;
316
264
 
317
- if (isEngineIOEndpoint && !isUpgrade && isPublicEndpoint) {
318
- res.header("Access-Control-Allow-Origin", '*');
265
+ const handler = this.getDevice<EngineIOHandler>(pluginDevice._id);
266
+ const id = 'ws-' + this.wsAtomic++;
267
+ const pluginHost = this.plugins[endpoint] ?? this.getPluginHostForDeviceId(endpoint);
268
+ if (!pluginHost) {
269
+ ws.close();
270
+ return;
319
271
  }
272
+ pluginHost.ws[id] = ws;
320
273
 
321
- if (!isEngineIOEndpoint && isUpgrade) {
322
- this.wss.handleUpgrade(req, req.socket, (req as any).upgradeHead, async (ws) => {
323
- try {
324
- const handler = this.getDevice<EngineIOHandler>(pluginDevice._id);
325
- const id = 'ws-' + this.wsAtomic++;
326
- const pluginHost = this.plugins[endpoint] ?? this.getPluginHostForDeviceId(endpoint);
327
- if (!pluginHost) {
328
- ws.close();
329
- return;
330
- }
331
- pluginHost.ws[id] = ws;
332
-
333
- ws.on('message', async (message) => {
334
- try {
335
- pluginHost.remote.ioEvent(id, 'message', message)
336
- }
337
- catch (e) {
338
- ws.close();
339
- }
340
- });
341
- ws.on('close', async (reason) => {
342
- try {
343
- pluginHost.remote.ioEvent(id, 'close');
344
- }
345
- catch (e) {
346
- }
347
- delete pluginHost.ws[id];
348
- });
349
-
350
- await handler.onConnection(httpRequest, `ws://${id}`);
351
- }
352
- catch (e) {
353
- console.error('websocket plugin error', e);
354
- ws.close();
355
- }
356
- });
357
- }
358
- else {
359
- handler(req, res, httpRequest, pluginHost, pluginDevice);
360
- }
274
+ ws.on('message', async (message) => {
275
+ try {
276
+ pluginHost.remote.ioEvent(id, 'message', message)
277
+ }
278
+ catch (e) {
279
+ ws.close();
280
+ }
281
+ });
282
+ ws.on('close', async (reason) => {
283
+ try {
284
+ pluginHost.remote.ioEvent(id, 'close');
285
+ }
286
+ catch (e) {
287
+ }
288
+ delete pluginHost.ws[id];
289
+ });
290
+
291
+ await handler.onConnection(httpRequest, `ws://${id}`);
361
292
  }
362
293
 
363
294
  async getComponent(componentId: string): Promise<any> {
@@ -381,7 +312,9 @@ export class ScryptedRuntime {
381
312
  }
382
313
  }
383
314
 
384
- async handleEngineIOEndpoint(req: Request, res: ServerResponse, endpointRequest: HttpRequest, pluginHost: PluginHost, pluginDevice: PluginDevice) {
315
+ async handleEngineIOEndpoint(req: Request, res: ServerResponse, endpointRequest: HttpRequest, pluginData: HttpPluginData) {
316
+ const { pluginHost, pluginDevice } = pluginData;
317
+
385
318
  (req as any).scrypted = {
386
319
  endpointRequest,
387
320
  pluginDevice,
@@ -392,21 +325,15 @@ export class ScryptedRuntime {
392
325
  pluginHost.io.handleRequest(req, res);
393
326
  }
394
327
 
395
- async handleRequestEndpoint(req: Request, res: Response, endpointRequest: HttpRequest, pluginHost: PluginHost, pluginDevice: PluginDevice) {
396
- try {
397
- const handler = this.getDevice<HttpRequestHandler>(pluginDevice._id);
398
- if (handler.interfaces.includes(ScryptedInterface.EngineIOHandler) && req.headers.connection === 'upgrade' && req.headers.upgrade?.toLowerCase() === 'websocket') {
399
- this.wss.handleUpgrade(req, req.socket, null, ws => {
400
- console.log(ws);
401
- });
402
- }
403
- handler.onRequest(endpointRequest, createResponseInterface(res, pluginHost));
404
- }
405
- catch (e) {
406
- res.status(500);
407
- res.send(e.toString());
408
- console.error(e);
328
+ async handleRequestEndpoint(req: Request, res: Response, endpointRequest: HttpRequest, pluginData: HttpPluginData) {
329
+ const { pluginHost, pluginDevice } = pluginData;
330
+ const handler = this.getDevice<HttpRequestHandler>(pluginDevice._id);
331
+ if (handler.interfaces.includes(ScryptedInterface.EngineIOHandler) && req.headers.connection === 'upgrade' && req.headers.upgrade?.toLowerCase() === 'websocket') {
332
+ this.wss.handleUpgrade(req, req.socket, null, ws => {
333
+ console.log(ws);
334
+ });
409
335
  }
336
+ handler.onRequest(endpointRequest, createResponseInterface(res, pluginHost.zip));
410
337
  }
411
338
 
412
339
  killPlugin(plugin: Plugin) {
@@ -116,6 +116,10 @@ else {
116
116
  const db = level(dbPath);
117
117
  await db.open();
118
118
 
119
+ if (process.env.SCRYPTED_RESET_ALL_USERS === 'true') {
120
+ await db.removeAll(ScryptedUser);
121
+ }
122
+
119
123
  let certSetting = await db.tryGet(Settings, 'certificate') as Settings;
120
124
 
121
125
  if (certSetting?.value?.version !== CURRENT_SELF_SIGNED_CERTIFICATE_VERSION) {
@@ -120,7 +120,7 @@ export class PluginComponent {
120
120
  console.log('done updating plugins');
121
121
  }
122
122
 
123
- async getRemoteServicePort(pluginId: string, name: string): Promise<number> {
123
+ async getRemoteServicePort(pluginId: string, name: string, ...args: any[]): Promise<number> {
124
124
  if (name === 'console') {
125
125
  const consoleServer = await this.scrypted.plugins[pluginId].consoleServer;
126
126
  return consoleServer.readPort;
@@ -129,6 +129,6 @@ export class PluginComponent {
129
129
  const consoleServer = await this.scrypted.plugins[pluginId].consoleServer;
130
130
  return consoleServer.writePort;
131
131
  }
132
- return this.scrypted.plugins[pluginId].remote.getServicePort(name);
132
+ return this.scrypted.plugins[pluginId].remote.getServicePort(name, ...args);
133
133
  }
134
134
  }
package/src/state.ts CHANGED
@@ -72,23 +72,15 @@ export class ScryptedStateManager extends EventRegistry {
72
72
  }
73
73
 
74
74
  updateDescriptor(device: PluginDevice) {
75
- for (const plugin of Object.values(this.scrypted.plugins)) {
76
- plugin.remote?.updateDeviceState(device._id, device.state);
77
- }
75
+ this.notify(device._id, undefined, ScryptedInterface.ScryptedDevice, undefined, device.state, true);
78
76
  }
79
77
 
80
78
  removeDevice(id: string) {
81
- for (const plugin of Object.values(this.scrypted.plugins)) {
82
- plugin.remote?.updateDeviceState(id, undefined);
83
- }
84
-
85
79
  this.notify(undefined, undefined, ScryptedInterface.ScryptedDevice, ScryptedInterfaceProperty.id, id, true);
86
80
  }
87
81
 
88
82
  notifyInterfaceEvent(device: PluginDevice, eventInterface: ScryptedInterface | string, value: any) {
89
- const eventTime = Date.now();
90
-
91
- this.notify(device?._id, eventTime, eventInterface, undefined, value, true);
83
+ this.notify(device?._id, Date.now(), eventInterface, undefined, value, true);
92
84
  }
93
85
 
94
86
  setState(id: string, property: string, value: any) {