@scrypted/server 0.0.134 → 0.0.135

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 (53) hide show
  1. package/.vscode/settings.json +1 -1
  2. package/dist/event-registry.js +1 -1
  3. package/dist/event-registry.js.map +1 -1
  4. package/dist/infer-defaults.js +1 -1
  5. package/dist/infer-defaults.js.map +1 -1
  6. package/dist/media-helpers.js +9 -25
  7. package/dist/media-helpers.js.map +1 -1
  8. package/dist/plugin/descriptor.js +1 -1
  9. package/dist/plugin/descriptor.js.map +1 -1
  10. package/dist/plugin/media.js +207 -101
  11. package/dist/plugin/media.js.map +1 -1
  12. package/dist/plugin/plugin-device.js +1 -1
  13. package/dist/plugin/plugin-device.js.map +1 -1
  14. package/dist/plugin/plugin-host-api.js +1 -1
  15. package/dist/plugin/plugin-host-api.js.map +1 -1
  16. package/dist/plugin/plugin-host.js +15 -6
  17. package/dist/plugin/plugin-host.js.map +1 -1
  18. package/dist/plugin/plugin-remote.js +1 -1
  19. package/dist/plugin/plugin-remote.js.map +1 -1
  20. package/dist/plugin/system.js +1 -1
  21. package/dist/plugin/system.js.map +1 -1
  22. package/dist/runtime.js +9 -3
  23. package/dist/runtime.js.map +1 -1
  24. package/dist/services/plugin.js +1 -1
  25. package/dist/services/plugin.js.map +1 -1
  26. package/dist/state.js +1 -1
  27. package/dist/state.js.map +1 -1
  28. package/package.json +5 -5
  29. package/python/plugin-remote.py +5 -5
  30. package/src/db-types.ts +1 -1
  31. package/src/event-registry.ts +1 -1
  32. package/src/http-interfaces.ts +1 -1
  33. package/src/infer-defaults.ts +1 -1
  34. package/src/media-helpers.ts +6 -27
  35. package/src/plugin/descriptor.ts +1 -1
  36. package/src/plugin/media.ts +232 -116
  37. package/src/plugin/plugin-api.ts +1 -1
  38. package/src/plugin/plugin-console.ts +1 -1
  39. package/src/plugin/plugin-device.ts +2 -2
  40. package/src/plugin/plugin-host-api.ts +1 -1
  41. package/src/plugin/plugin-host.ts +17 -7
  42. package/src/plugin/plugin-http.ts +1 -1
  43. package/src/plugin/plugin-lazy-remote.ts +1 -1
  44. package/src/plugin/plugin-remote-worker.ts +1 -1
  45. package/src/plugin/plugin-remote.ts +1 -1
  46. package/src/plugin/plugin-repl.ts +1 -1
  47. package/src/plugin/system.ts +1 -1
  48. package/src/runtime.ts +11 -3
  49. package/src/services/plugin.ts +1 -1
  50. package/src/state.ts +1 -1
  51. package/dist/convert.js +0 -117
  52. package/dist/convert.js.map +0 -1
  53. package/src/convert.ts +0 -122
@@ -1,6 +1,6 @@
1
1
  import { RpcPeer } from '../rpc';
2
2
  import AdmZip from 'adm-zip';
3
- import { Device, EngineIOHandler } from '@scrypted/sdk/types'
3
+ import { Device, EngineIOHandler } from '@scrypted/types'
4
4
  import { ScryptedRuntime } from '../runtime';
5
5
  import { Plugin } from '../db-types';
6
6
  import io, { Socket } from 'engine.io';
@@ -27,6 +27,8 @@ import rimraf from 'rimraf';
27
27
 
28
28
  export class PluginHost {
29
29
  static sharedWorker: child_process.ChildProcess;
30
+ static sharedWorkerImmediateRestart = false;
31
+
30
32
  worker: child_process.ChildProcess;
31
33
  peer: RpcPeer;
32
34
  pluginId: string;
@@ -51,6 +53,9 @@ export class PluginHost {
51
53
  kill() {
52
54
  this.killed = true;
53
55
  this.api.removeListeners();
56
+ // things might get a bit race prone, so clear out the shared worker before killing.
57
+ if (this.worker === PluginHost.sharedWorker)
58
+ PluginHost.sharedWorker = undefined;
54
59
  this.worker.kill('SIGKILL');
55
60
  this.io.close();
56
61
  for (const s of Object.values(this.ws)) {
@@ -254,7 +259,7 @@ export class PluginHost {
254
259
  // stdin, stdout, stderr, peer in, peer out
255
260
  stdio: ['pipe', 'pipe', 'pipe', 'pipe', 'pipe'],
256
261
  env: Object.assign({
257
- PYTHONPATH: path.join(process.cwd(), 'node_modules/@scrypted/sdk'),
262
+ PYTHONPATH: path.join(process.cwd(), 'node_modules/@scrypted/types'),
258
263
  }, process.env, env),
259
264
  });
260
265
 
@@ -293,17 +298,22 @@ export class PluginHost {
293
298
  Object.keys(this.packageJson.optionalDependencies || {}).length === 0;
294
299
  if (useSharedWorker) {
295
300
  if (!PluginHost.sharedWorker) {
296
- PluginHost.sharedWorker = child_process.fork(require.main.filename, ['child', '@scrypted/shared'], {
301
+ const worker = child_process.fork(require.main.filename, ['child', '@scrypted/shared'], {
297
302
  stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
298
303
  env: Object.assign({}, process.env, env),
299
304
  serialization: 'advanced',
300
305
  execArgv,
301
306
  });
307
+ PluginHost.sharedWorker = worker;
302
308
  PluginHost.sharedWorker.setMaxListeners(100);
303
- PluginHost.sharedWorker.on('close', () => PluginHost.sharedWorker = undefined);
304
- PluginHost.sharedWorker.on('error', () => PluginHost.sharedWorker = undefined);
305
- PluginHost.sharedWorker.on('exit', () => PluginHost.sharedWorker = undefined);
306
- PluginHost.sharedWorker.on('disconnect', () => PluginHost.sharedWorker = undefined);
309
+ const clearSharedWorker = () => {
310
+ if (worker === PluginHost.sharedWorker)
311
+ PluginHost.sharedWorker = undefined;
312
+ };
313
+ PluginHost.sharedWorker.on('close', () => clearSharedWorker);
314
+ PluginHost.sharedWorker.on('error', () => clearSharedWorker);
315
+ PluginHost.sharedWorker.on('exit', () => clearSharedWorker);
316
+ PluginHost.sharedWorker.on('disconnect', () => clearSharedWorker);
307
317
  }
308
318
  PluginHost.sharedWorker.send({
309
319
  type: 'start',
@@ -1,6 +1,6 @@
1
1
  import { Request, Response, Router } from 'express';
2
2
  import bodyParser from 'body-parser';
3
- import { HttpRequest } from '@scrypted/sdk/types';
3
+ import { HttpRequest } from '@scrypted/types';
4
4
  import WebSocket, { Server as WebSocketServer } from "ws";
5
5
  import { ServerResponse } from 'http';
6
6
 
@@ -1,4 +1,4 @@
1
- import { ScryptedNativeId, SystemDeviceState } from '@scrypted/sdk/types'
1
+ import { ScryptedNativeId, SystemDeviceState } from '@scrypted/types'
2
2
  import { PluginRemote, PluginRemoteLoadZipOptions } from './plugin-api';
3
3
 
4
4
  /**
@@ -1,5 +1,5 @@
1
1
  import { RpcMessage, RpcPeer } from '../rpc';
2
- import { SystemManager, DeviceManager, ScryptedNativeId } from '@scrypted/sdk/types'
2
+ import { SystemManager, DeviceManager, ScryptedNativeId } from '@scrypted/types'
3
3
  import { attachPluginRemote, PluginReader } from './plugin-remote';
4
4
  import { PluginAPI } from './plugin-api';
5
5
  import { MediaManagerImpl } from './media';
@@ -1,7 +1,7 @@
1
1
  import AdmZip from 'adm-zip';
2
2
  import { Volume } from 'memfs';
3
3
  import path from 'path';
4
- import { ScryptedNativeId, DeviceManager, Logger, Device, DeviceManifest, DeviceState, EndpointManager, SystemDeviceState, ScryptedStatic, SystemManager, MediaManager, ScryptedMimeTypes, ScryptedInterface, ScryptedInterfaceProperty, HttpRequest } from '@scrypted/sdk/types'
4
+ import { ScryptedNativeId, DeviceManager, Logger, Device, DeviceManifest, DeviceState, EndpointManager, SystemDeviceState, ScryptedStatic, SystemManager, MediaManager, ScryptedMimeTypes, ScryptedInterface, ScryptedInterfaceProperty, HttpRequest } from '@scrypted/types'
5
5
  import { PluginAPI, PluginLogger, PluginRemote, PluginRemoteLoadZipOptions } from './plugin-api';
6
6
  import { SystemManagerImpl } from './system';
7
7
  import { RpcPeer, RPCResultError, PROPERTY_PROXY_ONEWAY_METHODS, PROPERTY_JSON_DISABLE_SERIALIZATION } from '../rpc';
@@ -2,7 +2,7 @@ import { listenZero } from './listen-zero';
2
2
  import { Server } from 'net';
3
3
  import { once } from 'events';
4
4
  import repl from 'repl';
5
- import { ScryptedStatic } from '@scrypted/sdk';
5
+ import { ScryptedStatic } from '@scrypted/types';
6
6
 
7
7
  export async function createREPLServer(scrypted: ScryptedStatic, params: any, plugin: any): Promise<number> {
8
8
  const { deviceManager, systemManager } = scrypted;
@@ -1,4 +1,4 @@
1
- import { EventListenerOptions, EventDetails, EventListenerRegister, ScryptedDevice, ScryptedInterface, ScryptedInterfaceDescriptors, SystemDeviceState, SystemManager, ScryptedInterfaceProperty, ScryptedDeviceType, Logger } from "@scrypted/sdk/types";
1
+ import { EventListenerOptions, EventDetails, EventListenerRegister, ScryptedDevice, ScryptedInterface, ScryptedInterfaceDescriptors, SystemDeviceState, SystemManager, ScryptedInterfaceProperty, ScryptedDeviceType, Logger } from "@scrypted/types";
2
2
  import { PluginAPI } from "./plugin-api";
3
3
  import { handleFunctionInvocations, PrimitiveProxyHandler, PROPERTY_PROXY_ONEWAY_METHODS } from '../rpc';
4
4
  import { EventRegistry } from "../event-registry";
package/src/runtime.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Level } from './level';
2
2
  import { PluginHost } from './plugin/plugin-host';
3
- import { ScryptedNativeId, Device, EngineIOHandler, HttpRequest, HttpRequestHandler, OauthClient, PushHandler, ScryptedDevice, ScryptedInterface, ScryptedInterfaceProperty } from '@scrypted/sdk/types';
3
+ import { ScryptedNativeId, Device, EngineIOHandler, HttpRequest, HttpRequestHandler, OauthClient, PushHandler, ScryptedDevice, ScryptedInterface, ScryptedInterfaceProperty } from '@scrypted/types';
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';
@@ -353,6 +353,11 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
353
353
  const existing = this.plugins[pluginId];
354
354
  if (existing) {
355
355
  delete this.plugins[pluginId];
356
+
357
+ if (existing.worker === PluginHost.sharedWorker) {
358
+ PluginHost.sharedWorkerImmediateRestart = true;
359
+ setTimeout(() => PluginHost.sharedWorkerImmediateRestart = false, 10000);
360
+ }
356
361
  existing.kill();
357
362
  }
358
363
  }
@@ -491,11 +496,14 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
491
496
  }
492
497
 
493
498
  setupPluginHostAutoRestart(pluginHost: PluginHost) {
499
+ const usingSharedWorker = pluginHost.worker === PluginHost.sharedWorker;
500
+
494
501
  pluginHost.worker.once('exit', () => {
495
502
  if (pluginHost.killed)
496
503
  return;
497
504
  pluginHost.kill();
498
- console.error('plugin unexpectedly exited, restarting in 1 minute', pluginHost.pluginId);
505
+ const timeout = usingSharedWorker && PluginHost.sharedWorkerImmediateRestart ? 0 : 60000;
506
+ console.error(`plugin unexpectedly exited, restarting in ${timeout}ms`, pluginHost.pluginId);
499
507
  setTimeout(async () => {
500
508
  const existing = this.plugins[pluginHost.pluginId];
501
509
  if (existing !== pluginHost) {
@@ -515,7 +523,7 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
515
523
  catch (e) {
516
524
  console.error('error restarting plugin', plugin._id, e);
517
525
  }
518
- }, 60000);
526
+ }, timeout);
519
527
  });
520
528
  }
521
529
 
@@ -1,4 +1,4 @@
1
- import { ScryptedInterfaceProperty, ScryptedNativeId } from "@scrypted/sdk/types";
1
+ import { ScryptedInterfaceProperty, ScryptedNativeId } from "@scrypted/types";
2
2
  import { ScryptedRuntime } from "../runtime";
3
3
  import { Plugin } from '../db-types';
4
4
  import { getState } from "../state";
package/src/state.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ScryptedRuntime } from "./runtime";
2
- import { ScryptedNativeId, EventDetails, EventListenerOptions, EventListenerRegister, Refresh, ScryptedInterface, ScryptedInterfaceProperty, SystemDeviceState } from "@scrypted/sdk/types";
2
+ import { ScryptedNativeId, EventDetails, EventListenerOptions, EventListenerRegister, Refresh, ScryptedInterface, ScryptedInterfaceProperty, SystemDeviceState } from "@scrypted/types";
3
3
  import { RefreshSymbol } from "./plugin/plugin-device";
4
4
  import throttle from 'lodash/throttle';
5
5
  import { sleep } from "./sleep";
package/dist/convert.js DELETED
@@ -1,117 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.convert = exports.ensureBuffer = void 0;
7
- const types_1 = require("@scrypted/sdk/types");
8
- const node_dijkstra_1 = __importDefault(require("node-dijkstra"));
9
- const whatwg_mimetype_1 = __importDefault(require("whatwg-mimetype"));
10
- const axios_1 = __importDefault(require("axios"));
11
- const https_1 = __importDefault(require("https"));
12
- function typeMatches(target, candidate) {
13
- // candidate will accept anything
14
- if (candidate === '*')
15
- return true;
16
- return target === candidate;
17
- }
18
- function mimeMatches(target, candidate) {
19
- return typeMatches(target.type, candidate.type) && typeMatches(target.subtype, candidate.subtype);
20
- }
21
- const httpsAgent = new https_1.default.Agent({
22
- rejectUnauthorized: false
23
- });
24
- async function ensureBuffer(data) {
25
- if (typeof data === 'string') {
26
- const ab = await axios_1.default.get(data, {
27
- responseType: 'arraybuffer',
28
- httpsAgent,
29
- });
30
- return Buffer.from(ab.data);
31
- }
32
- return Buffer.from(data);
33
- }
34
- exports.ensureBuffer = ensureBuffer;
35
- async function convert(converters, mediaObject, toMimeType) {
36
- // console.log('converting', mediaObject.mimeType, toMimeType);
37
- const mediaMime = new whatwg_mimetype_1.default(mediaObject.mimeType);
38
- const outputMime = new whatwg_mimetype_1.default(toMimeType);
39
- if (mimeMatches(mediaMime, outputMime)) {
40
- return {
41
- mimeType: outputMime.essence,
42
- data: await mediaObject.getData(),
43
- };
44
- }
45
- const converterIds = new Map();
46
- const converterReverseids = new Map();
47
- let id = 0;
48
- for (const converter of converters) {
49
- const cid = (id++).toString();
50
- converterIds.set(converter, cid);
51
- converterReverseids.set(cid, converter);
52
- }
53
- const nodes = {};
54
- const mediaNode = {};
55
- nodes['mediaObject'] = mediaNode;
56
- nodes['output'] = {};
57
- for (const converter of converters) {
58
- try {
59
- const inputMime = new whatwg_mimetype_1.default(converter.fromMimeType);
60
- const convertedMime = new whatwg_mimetype_1.default(converter.toMimeType);
61
- const targetId = converterIds.get(converter);
62
- const node = nodes[targetId] = {};
63
- for (const candidate of converters) {
64
- try {
65
- const candidateMime = new whatwg_mimetype_1.default(candidate.fromMimeType);
66
- if (!mimeMatches(convertedMime, candidateMime))
67
- continue;
68
- const candidateId = converterIds.get(candidate);
69
- node[candidateId] = 1;
70
- }
71
- catch (e) {
72
- console.warn('skipping converter due to error', e);
73
- }
74
- }
75
- if (mimeMatches(mediaMime, inputMime)) {
76
- mediaNode[targetId] = 1;
77
- }
78
- if (mimeMatches(convertedMime, outputMime)) {
79
- node['output'] = 1;
80
- }
81
- }
82
- catch (e) {
83
- console.warn('skipping converter due to error', e);
84
- }
85
- }
86
- const graph = new node_dijkstra_1.default();
87
- for (const id of Object.keys(nodes)) {
88
- graph.addNode(id, nodes[id]);
89
- }
90
- const route = graph.path('mediaObject', 'output');
91
- if (!route || !route.length)
92
- throw new Error('no converter found');
93
- // pop off the mediaObject start node, no conversion necessary.
94
- route.shift();
95
- // also remove the output node.
96
- route.splice(route.length - 1);
97
- let value = await mediaObject.getData();
98
- let valueMime = new whatwg_mimetype_1.default(mediaObject.mimeType);
99
- for (const node of route) {
100
- const converter = converterReverseids.get(node);
101
- const targetMime = new whatwg_mimetype_1.default(converter.toMimeType);
102
- const inputMime = new whatwg_mimetype_1.default(converter.fromMimeType);
103
- if (typeof value === 'string' && !inputMime.parameters.has(types_1.ScryptedMimeTypes.AcceptUrlParameter)) {
104
- value = await ensureBuffer(value);
105
- }
106
- value = await converter.convert(value, valueMime.essence);
107
- const type = targetMime.type === '*' ? valueMime.type : targetMime.type;
108
- const subtype = targetMime.subtype === '*' ? valueMime.subtype : targetMime.subtype;
109
- valueMime = new whatwg_mimetype_1.default(`${type}/${subtype}`);
110
- }
111
- return {
112
- data: value,
113
- mimeType: valueMime.essence,
114
- };
115
- }
116
- exports.convert = convert;
117
- //# sourceMappingURL=convert.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"convert.js","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"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"}
package/src/convert.ts DELETED
@@ -1,122 +0,0 @@
1
- import { BufferConverter, ScryptedMimeTypes } from '@scrypted/sdk/types';
2
- import Graph from 'node-dijkstra';
3
- import MimeType from 'whatwg-mimetype';
4
- import { MediaObjectRemote } from './plugin/plugin-api';
5
- import axios from 'axios';
6
- import https from 'https';
7
-
8
- function typeMatches(target: string, candidate: string): boolean {
9
- // candidate will accept anything
10
- if (candidate === '*')
11
- return true;
12
- return target === candidate;
13
- }
14
-
15
- function mimeMatches(target: MimeType, candidate: MimeType) {
16
- return typeMatches(target.type, candidate.type) && typeMatches(target.subtype, candidate.subtype);
17
- }
18
-
19
- const httpsAgent = new https.Agent({
20
- rejectUnauthorized: false
21
- })
22
-
23
- export async function ensureBuffer(data: Buffer | string): Promise<Buffer> {
24
- if (typeof data === 'string') {
25
- const ab = await axios.get(data as string, {
26
- responseType: 'arraybuffer',
27
- httpsAgent,
28
- });
29
- return Buffer.from(ab.data);
30
- }
31
- return Buffer.from(data);
32
- }
33
-
34
- export async function convert(converters: BufferConverter[], mediaObject: MediaObjectRemote, toMimeType: string): Promise<{ data: Buffer | string, mimeType: string }> {
35
- // console.log('converting', mediaObject.mimeType, toMimeType);
36
- const mediaMime = new MimeType(mediaObject.mimeType);
37
- const outputMime = new MimeType(toMimeType);
38
-
39
- if (mimeMatches(mediaMime, outputMime)) {
40
- return {
41
- mimeType: outputMime.essence,
42
- data: await mediaObject.getData(),
43
- }
44
- }
45
-
46
- const converterIds = new Map<BufferConverter, string>();
47
- const converterReverseids = new Map<string, BufferConverter>();
48
- let id = 0;
49
- for (const converter of converters) {
50
- const cid = (id++).toString();
51
- converterIds.set(converter, cid);
52
- converterReverseids.set(cid, converter);
53
- }
54
-
55
- const nodes: any = {};
56
- const mediaNode: any = {};
57
- nodes['mediaObject'] = mediaNode;
58
- nodes['output'] = {};
59
- for (const converter of converters) {
60
- try {
61
- const inputMime = new MimeType(converter.fromMimeType);
62
- const convertedMime = new MimeType(converter.toMimeType);
63
- const targetId = converterIds.get(converter);
64
- const node: any = nodes[targetId] = {};
65
- for (const candidate of converters) {
66
- try {
67
- const candidateMime = new MimeType(candidate.fromMimeType);
68
- if (!mimeMatches(convertedMime, candidateMime))
69
- continue;
70
- const candidateId = converterIds.get(candidate);
71
- node[candidateId] = 1;
72
- }
73
- catch (e) {
74
- console.warn('skipping converter due to error', e)
75
- }
76
- }
77
-
78
- if (mimeMatches(mediaMime, inputMime)) {
79
- mediaNode[targetId] = 1;
80
- }
81
- if (mimeMatches(convertedMime, outputMime)) {
82
- node['output'] = 1;
83
- }
84
- }
85
- catch (e) {
86
- console.warn('skipping converter due to error', e)
87
- }
88
- }
89
-
90
- const graph = new Graph();
91
- for (const id of Object.keys(nodes)) {
92
- graph.addNode(id, nodes[id]);
93
- }
94
-
95
- const route = graph.path('mediaObject', 'output') as Array<string>;
96
- if (!route || !route.length)
97
- throw new Error('no converter found');
98
- // pop off the mediaObject start node, no conversion necessary.
99
- route.shift();
100
- // also remove the output node.
101
- route.splice(route.length - 1);
102
- let value = await mediaObject.getData();
103
- let valueMime = new MimeType(mediaObject.mimeType);
104
- for (const node of route) {
105
- const converter = converterReverseids.get(node);
106
- const targetMime = new MimeType(converter.toMimeType);
107
- const inputMime = new MimeType(converter.fromMimeType);
108
-
109
- if (typeof value === 'string' && !inputMime.parameters.has(ScryptedMimeTypes.AcceptUrlParameter)) {
110
- value = await ensureBuffer(value);
111
- }
112
- value = await converter.convert(value, valueMime.essence);
113
- const type = targetMime.type === '*' ? valueMime.type : targetMime.type;
114
- const subtype = targetMime.subtype === '*' ? valueMime.subtype : targetMime.subtype;
115
- valueMime = new MimeType(`${type}/${subtype}`);
116
- }
117
-
118
- return {
119
- data: value,
120
- mimeType: valueMime.essence,
121
- };
122
- }