@scrypted/server 0.1.10 → 0.1.13
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/plugin/descriptor.js +23 -18
- package/dist/plugin/descriptor.js.map +1 -1
- package/dist/plugin/media.js +5 -3
- package/dist/plugin/media.js.map +1 -1
- package/dist/plugin/plugin-api.js +3 -0
- package/dist/plugin/plugin-api.js.map +1 -1
- package/dist/plugin/plugin-device.js +24 -14
- package/dist/plugin/plugin-device.js.map +1 -1
- package/dist/plugin/plugin-host-api.js +13 -4
- package/dist/plugin/plugin-host-api.js.map +1 -1
- package/dist/plugin/plugin-host.js +8 -1
- package/dist/plugin/plugin-host.js.map +1 -1
- package/dist/plugin/plugin-volume.js +2 -1
- package/dist/plugin/plugin-volume.js.map +1 -1
- package/dist/plugin/system.js +40 -4
- package/dist/plugin/system.js.map +1 -1
- package/dist/rpc.js +11 -0
- package/dist/rpc.js.map +1 -1
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +1 -1
- package/dist/scrypted-server-main.js +1 -0
- package/dist/scrypted-server-main.js.map +1 -1
- package/dist/state.js +10 -19
- package/dist/state.js.map +1 -1
- package/package.json +3 -2
- package/src/plugin/descriptor.ts +24 -18
- package/src/plugin/media.ts +5 -3
- package/src/plugin/plugin-api.ts +7 -1
- package/src/plugin/plugin-device.ts +31 -23
- package/src/plugin/plugin-host-api.ts +16 -7
- package/src/plugin/plugin-host.ts +8 -1
- package/src/plugin/plugin-volume.ts +2 -1
- package/src/plugin/system.ts +51 -13
- package/src/rpc.ts +11 -0
- package/src/runtime.ts +1 -1
- package/src/scrypted-server-main.ts +1 -0
- package/src/state.ts +15 -26
@@ -1,15 +1,14 @@
|
|
1
|
-
import { DeviceProvider,
|
2
|
-
import
|
1
|
+
import { DeviceProvider, EventListener, EventListenerOptions, EventListenerRegister, MixinProvider, ScryptedDevice, ScryptedDeviceType, ScryptedInterface, ScryptedInterfaceDescriptors, ScryptedInterfaceProperty } from "@scrypted/types";
|
2
|
+
import fs from 'fs';
|
3
|
+
import path from 'path';
|
3
4
|
import { PluginDevice } from "../db-types";
|
4
|
-
import { MixinProvider } from "@scrypted/types";
|
5
|
-
import { RpcPeer, PrimitiveProxyHandler } from "../rpc";
|
6
|
-
import { getState } from "../state";
|
7
5
|
import { getDisplayType } from "../infer-defaults";
|
8
|
-
import {
|
9
|
-
import {
|
6
|
+
import { PrimitiveProxyHandler, RpcPeer } from "../rpc";
|
7
|
+
import { ScryptedRuntime } from "../runtime";
|
10
8
|
import { sleep } from "../sleep";
|
11
|
-
import
|
12
|
-
import
|
9
|
+
import { getState } from "../state";
|
10
|
+
import { allInterfaceProperties, getInterfaceMethods, getPropertyInterfaces } from "./descriptor";
|
11
|
+
import { PluginError } from "./plugin-error";
|
13
12
|
|
14
13
|
interface MixinTable {
|
15
14
|
mixinProviderId: string;
|
@@ -17,7 +16,8 @@ interface MixinTable {
|
|
17
16
|
}
|
18
17
|
|
19
18
|
interface MixinTableEntry {
|
20
|
-
interfaces: Set<string
|
19
|
+
interfaces: Set<string>;
|
20
|
+
methods?: Set<string>;
|
21
21
|
allInterfaces: string[];
|
22
22
|
proxy: any;
|
23
23
|
error?: Error;
|
@@ -244,9 +244,10 @@ export class PluginDeviceProxyHandler implements PrimitiveProxyHandler<any>, Scr
|
|
244
244
|
|
245
245
|
const implementer = await (mixinProvider as any)[QueryInterfaceSymbol](ScryptedInterface.MixinProvider);
|
246
246
|
const host = this.scrypted.getPluginHostForDeviceId(implementer);
|
247
|
+
const propertyInterfaces = getPropertyInterfaces(host.api.descriptors || ScryptedInterfaceDescriptors);
|
247
248
|
// todo: remove this and pass the setter directly.
|
248
249
|
const deviceState = await host.remote.createDeviceState(this.id,
|
249
|
-
async (property, value) => this.scrypted.stateManager.setPluginDeviceState(pluginDevice, property, value));
|
250
|
+
async (property, value) => this.scrypted.stateManager.setPluginDeviceState(pluginDevice, property, value, propertyInterfaces[property]));
|
250
251
|
const mixinProxy = await mixinProvider.getMixin(wrappedProxy, previousInterfaces as ScryptedInterface[], deviceState);
|
251
252
|
if (!mixinProxy)
|
252
253
|
throw new PluginError(`mixin provider ${mixinId} did not return mixin for ${this.id}`);
|
@@ -283,7 +284,7 @@ export class PluginDeviceProxyHandler implements PrimitiveProxyHandler<any>, Scr
|
|
283
284
|
}
|
284
285
|
|
285
286
|
get(target: any, p: PropertyKey, receiver: any): any {
|
286
|
-
if (p
|
287
|
+
if (RpcPeer.PROBED_PROPERTIES.has(p))
|
287
288
|
return;
|
288
289
|
const handled = RpcPeer.handleFunctionInvocations(this, target, p, receiver);
|
289
290
|
if (handled)
|
@@ -300,9 +301,6 @@ export class PluginDeviceProxyHandler implements PrimitiveProxyHandler<any>, Scr
|
|
300
301
|
if (p === RefreshSymbol || p === QueryInterfaceSymbol)
|
301
302
|
return new Proxy(() => p, this);
|
302
303
|
|
303
|
-
if (!isValidInterfaceMethod(pluginDevice.state.interfaces.value, prop))
|
304
|
-
return;
|
305
|
-
|
306
304
|
if (ScryptedInterfaceDescriptors[ScryptedInterface.ScryptedDevice].methods.includes(prop))
|
307
305
|
return (this as any)[p].bind(this);
|
308
306
|
|
@@ -339,11 +337,7 @@ export class PluginDeviceProxyHandler implements PrimitiveProxyHandler<any>, Scr
|
|
339
337
|
}
|
340
338
|
|
341
339
|
async applyMixin(method: string, argArray?: any): Promise<any> {
|
342
|
-
const
|
343
|
-
if (!iface)
|
344
|
-
throw new PluginError(`unknown method ${method}`);
|
345
|
-
|
346
|
-
const found = await this.findMixin(iface);
|
340
|
+
const found = await this.findMethod(method);
|
347
341
|
if (found) {
|
348
342
|
const { mixin, entry } = found;
|
349
343
|
const { proxy } = entry;
|
@@ -355,6 +349,23 @@ export class PluginDeviceProxyHandler implements PrimitiveProxyHandler<any>, Scr
|
|
355
349
|
throw new PluginError(`${method} not implemented`)
|
356
350
|
}
|
357
351
|
|
352
|
+
async findMethod(method: string) {
|
353
|
+
for (const mixin of this.mixinTable) {
|
354
|
+
const entry = await mixin.entry;
|
355
|
+
if (!entry.methods) {
|
356
|
+
const pluginDevice = this.scrypted.findPluginDeviceById(mixin.mixinProviderId || this.id);
|
357
|
+
const plugin = this.scrypted.plugins[pluginDevice.pluginId];
|
358
|
+
let methods = new Set<string>(getInterfaceMethods(ScryptedInterfaceDescriptors, entry.interfaces))
|
359
|
+
if (plugin.api.descriptors)
|
360
|
+
methods = new Set<string>([...methods, ...getInterfaceMethods(plugin.api.descriptors, entry.interfaces)]);
|
361
|
+
entry.methods = methods;
|
362
|
+
}
|
363
|
+
if (entry.methods.has(method)) {
|
364
|
+
return { mixin, entry };
|
365
|
+
}
|
366
|
+
}
|
367
|
+
}
|
368
|
+
|
358
369
|
async findMixin(iface: string) {
|
359
370
|
for (const mixin of this.mixinTable) {
|
360
371
|
const entry = await mixin.entry;
|
@@ -407,9 +418,6 @@ export class PluginDeviceProxyHandler implements PrimitiveProxyHandler<any>, Scr
|
|
407
418
|
return this.scrypted.getPackageJson(pluginDevice.pluginId);
|
408
419
|
}
|
409
420
|
|
410
|
-
if (!isValidInterfaceMethod(pluginDevice.state.interfaces.value, method))
|
411
|
-
throw new PluginError(`device ${this.id} does not support method ${method}`);
|
412
|
-
|
413
421
|
if (method === 'refresh') {
|
414
422
|
const refreshInterface = argArray[0];
|
415
423
|
const userInitiated = argArray[1];
|
@@ -1,17 +1,20 @@
|
|
1
|
-
import {
|
2
|
-
import
|
1
|
+
import { Device, DeviceManifest, EventDetails, EventListenerOptions, EventListenerRegister, HttpRequest, MediaManager, ScryptedDevice, ScryptedInterfaceDescriptor, ScryptedInterfaceProperty, ScryptedNativeId } from '@scrypted/types';
|
2
|
+
import debounce from 'lodash/debounce';
|
3
3
|
import { Plugin } from '../db-types';
|
4
|
-
import { PluginAPI, PluginAPIManagedListeners } from './plugin-api';
|
5
4
|
import { Logger } from '../logger';
|
5
|
+
import { RpcPeer } from '../rpc';
|
6
|
+
import { ScryptedRuntime } from '../runtime';
|
6
7
|
import { getState } from '../state';
|
8
|
+
import { getPropertyInterfaces } from './descriptor';
|
9
|
+
import { PluginAPI, PluginAPIManagedListeners } from './plugin-api';
|
7
10
|
import { PluginHost } from './plugin-host';
|
8
|
-
import debounce from 'lodash/debounce';
|
9
|
-
import { RpcPeer } from '../rpc';
|
10
|
-
import { propertyInterfaces } from './descriptor';
|
11
11
|
import { checkProperty } from './plugin-state-check';
|
12
12
|
|
13
13
|
export class PluginHostAPI extends PluginAPIManagedListeners implements PluginAPI {
|
14
14
|
pluginId: string;
|
15
|
+
typesVersion: string;
|
16
|
+
descriptors: { [scryptedInterface: string]: ScryptedInterfaceDescriptor };
|
17
|
+
propertyInterfaces: ReturnType<typeof getPropertyInterfaces>;
|
15
18
|
|
16
19
|
[RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS] = [
|
17
20
|
'onMixinEvent',
|
@@ -116,7 +119,7 @@ export class PluginHostAPI extends PluginAPIManagedListeners implements PluginAP
|
|
116
119
|
|
117
120
|
async setState(nativeId: ScryptedNativeId, key: string, value: any) {
|
118
121
|
checkProperty(key, value);
|
119
|
-
this.scrypted.stateManager.setPluginState(this.pluginId, nativeId, key, value);
|
122
|
+
this.scrypted.stateManager.setPluginState(this.pluginId, nativeId, this.propertyInterfaces?.[key], key, value);
|
120
123
|
}
|
121
124
|
|
122
125
|
async setStorage(nativeId: ScryptedNativeId, storage: { [key: string]: string }) {
|
@@ -179,4 +182,10 @@ export class PluginHostAPI extends PluginAPIManagedListeners implements PluginAP
|
|
179
182
|
logger.log('i', 'plugin restart was requested');
|
180
183
|
return this.restartDebounced();
|
181
184
|
}
|
185
|
+
|
186
|
+
async setScryptedInterfaceDescriptors(typesVersion: string, descriptors: { [scryptedInterface: string]: ScryptedInterfaceDescriptor }): Promise<void> {
|
187
|
+
this.typesVersion = typesVersion;
|
188
|
+
this.descriptors = descriptors;
|
189
|
+
this.propertyInterfaces = getPropertyInterfaces(descriptors);
|
190
|
+
}
|
182
191
|
}
|
@@ -333,7 +333,14 @@ export class PluginHost {
|
|
333
333
|
});
|
334
334
|
|
335
335
|
this.worker.on('rpc', (message, sendHandle) => {
|
336
|
-
|
336
|
+
const socket = sendHandle as net.Socket;
|
337
|
+
const { pluginId } = message;
|
338
|
+
const host = this.scrypted.plugins[pluginId];
|
339
|
+
if (!host) {
|
340
|
+
socket.destroy();
|
341
|
+
return;
|
342
|
+
}
|
343
|
+
host.createRpcPeer(socket);
|
337
344
|
});
|
338
345
|
|
339
346
|
this.peer.params.updateStats = (stats: any) => {
|
@@ -1,8 +1,9 @@
|
|
1
|
+
import os from 'os';
|
1
2
|
import path from 'path';
|
2
3
|
import mkdirp from 'mkdirp';
|
3
4
|
|
4
5
|
export function getScryptedVolume() {
|
5
|
-
const volumeDir = process.env.SCRYPTED_VOLUME || path.join(
|
6
|
+
const volumeDir = process.env.SCRYPTED_VOLUME || path.join(os.homedir(), '.scrypted', 'volume');
|
6
7
|
return volumeDir;
|
7
8
|
}
|
8
9
|
|
package/src/plugin/system.ts
CHANGED
@@ -1,16 +1,14 @@
|
|
1
|
-
import {
|
2
|
-
import { PluginAPI } from "./plugin-api";
|
3
|
-
import { PrimitiveProxyHandler, RpcPeer } from '../rpc';
|
1
|
+
import { EventListener, EventListenerOptions, EventListenerRegister, Logger, ScryptedDevice, ScryptedDeviceType, ScryptedInterface, ScryptedInterfaceDescriptor, ScryptedInterfaceDescriptors, ScryptedInterfaceProperty, SystemDeviceState, SystemManager } from "@scrypted/types";
|
4
2
|
import { EventRegistry } from "../event-registry";
|
5
|
-
import {
|
6
|
-
|
3
|
+
import { PrimitiveProxyHandler, RpcPeer } from '../rpc';
|
4
|
+
import { getInterfaceMethods, getInterfaceProperties, getPropertyInterfaces, isValidInterfaceMethod, propertyInterfaces } from "./descriptor";
|
5
|
+
import { PluginAPI } from "./plugin-api";
|
7
6
|
|
8
7
|
function newDeviceProxy(id: string, systemManager: SystemManagerImpl) {
|
9
8
|
const handler = new DeviceProxyHandler(id, systemManager);
|
10
9
|
return new Proxy(handler, handler);
|
11
10
|
}
|
12
11
|
|
13
|
-
|
14
12
|
class DeviceProxyHandler implements PrimitiveProxyHandler<any>, ScryptedDevice {
|
15
13
|
device: Promise<ScryptedDevice>;
|
16
14
|
constructor(public id: string, public systemManager: SystemManagerImpl) {
|
@@ -20,6 +18,31 @@ class DeviceProxyHandler implements PrimitiveProxyHandler<any>, ScryptedDevice {
|
|
20
18
|
return `ScryptedDevice-${this.id}`
|
21
19
|
}
|
22
20
|
|
21
|
+
ownKeys(target: any): ArrayLike<string | symbol> {
|
22
|
+
const interfaces = new Set<string>(this.systemManager.state[this.id].interfaces.value);
|
23
|
+
const methods = getInterfaceMethods(this.systemManager.descriptors || ScryptedInterfaceDescriptors, interfaces);
|
24
|
+
const properties = getInterfaceProperties(this.systemManager.descriptors || ScryptedInterfaceDescriptors, interfaces);
|
25
|
+
return [...methods, ...properties];
|
26
|
+
}
|
27
|
+
|
28
|
+
getOwnPropertyDescriptor(target: any, p: string | symbol): PropertyDescriptor {
|
29
|
+
const interfaces = new Set<string>(this.systemManager.state[this.id].interfaces.value);
|
30
|
+
const methods = getInterfaceMethods(this.systemManager.descriptors || ScryptedInterfaceDescriptors, interfaces);
|
31
|
+
const prop = p.toString();
|
32
|
+
if (methods.includes(prop)) {
|
33
|
+
return {
|
34
|
+
configurable: true,
|
35
|
+
};
|
36
|
+
}
|
37
|
+
const properties = getInterfaceProperties(this.systemManager.descriptors || ScryptedInterfaceDescriptors, interfaces);
|
38
|
+
if (properties.includes(prop)) {
|
39
|
+
return {
|
40
|
+
configurable: true,
|
41
|
+
value: this.systemManager.state[this.id][prop]?.value
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
23
46
|
get(target: any, p: PropertyKey, receiver: any): any {
|
24
47
|
if (p === 'id')
|
25
48
|
return this.id;
|
@@ -28,11 +51,16 @@ class DeviceProxyHandler implements PrimitiveProxyHandler<any>, ScryptedDevice {
|
|
28
51
|
if (handled)
|
29
52
|
return handled;
|
30
53
|
|
31
|
-
|
54
|
+
const interfaces = new Set<string>(this.systemManager.state[this.id].interfaces.value);
|
55
|
+
const prop = p.toString();
|
56
|
+
const isValidProperty = this.systemManager.propertyInterfaces?.[prop] || propertyInterfaces[prop];
|
57
|
+
|
58
|
+
// this will also return old properties that should not exist on a device. ie, a disabled mixin provider.
|
59
|
+
// should this change?
|
60
|
+
if (isValidProperty)
|
32
61
|
return (this.systemManager.state[this.id] as any)?.[p]?.value;
|
33
62
|
|
34
|
-
|
35
|
-
if (!isValidInterfaceMethod(this.systemManager.state[this.id].interfaces.value, prop))
|
63
|
+
if (!isValidInterfaceMethod(this.systemManager.descriptors || ScryptedInterfaceDescriptors, interfaces, prop))
|
36
64
|
return;
|
37
65
|
|
38
66
|
if (ScryptedInterfaceDescriptors[ScryptedInterface.ScryptedDevice].methods.includes(prop))
|
@@ -41,7 +69,7 @@ class DeviceProxyHandler implements PrimitiveProxyHandler<any>, ScryptedDevice {
|
|
41
69
|
return new Proxy(() => p, this);
|
42
70
|
}
|
43
71
|
|
44
|
-
|
72
|
+
ensureDevice() {
|
45
73
|
if (!this.device)
|
46
74
|
this.device = this.systemManager.api.getDeviceById(this.id);
|
47
75
|
return this.device;
|
@@ -101,15 +129,18 @@ function makeOneWayCallback<T>(input: T): T {
|
|
101
129
|
|
102
130
|
export class SystemManagerImpl implements SystemManager {
|
103
131
|
api: PluginAPI;
|
104
|
-
state: {[id: string]: {[property: string]: SystemDeviceState}};
|
105
|
-
deviceProxies: {[id: string]: ScryptedDevice} = {};
|
132
|
+
state: { [id: string]: { [property: string]: SystemDeviceState } };
|
133
|
+
deviceProxies: { [id: string]: ScryptedDevice } = {};
|
106
134
|
log: Logger;
|
107
135
|
events = new EventRegistry();
|
136
|
+
typesVersion: string;
|
137
|
+
descriptors: { [scryptedInterface: string]: ScryptedInterfaceDescriptor };
|
138
|
+
propertyInterfaces: ReturnType<typeof getPropertyInterfaces>;
|
108
139
|
|
109
140
|
getDeviceState(id: string) {
|
110
141
|
return this.state[id];
|
111
142
|
}
|
112
|
-
getSystemState(): {[id: string]: {[property: string]: SystemDeviceState}} {
|
143
|
+
getSystemState(): { [id: string]: { [property: string]: SystemDeviceState } } {
|
113
144
|
return this.state;
|
114
145
|
}
|
115
146
|
|
@@ -155,4 +186,11 @@ export class SystemManagerImpl implements SystemManager {
|
|
155
186
|
getComponent(id: string): Promise<any> {
|
156
187
|
return this.api.getComponent(id);
|
157
188
|
}
|
189
|
+
|
190
|
+
setScryptedInterfaceDescriptors(typesVersion: string, descriptors: { [scryptedInterface: string]: ScryptedInterfaceDescriptor }): Promise<void> {
|
191
|
+
this.typesVersion = typesVersion;
|
192
|
+
this.descriptors = descriptors;
|
193
|
+
this.propertyInterfaces = getPropertyInterfaces(descriptors);
|
194
|
+
return this.api.setScryptedInterfaceDescriptors(typesVersion, descriptors);
|
195
|
+
}
|
158
196
|
}
|
package/src/rpc.ts
CHANGED
@@ -246,6 +246,17 @@ export class RpcPeer {
|
|
246
246
|
static readonly PROPERTY_JSON_DISABLE_SERIALIZATION = '__json_disable_serialization';
|
247
247
|
static readonly PROPERTY_PROXY_PROPERTIES = '__proxy_props';
|
248
248
|
static readonly PROPERTY_JSON_COPY_SERIALIZE_CHILDREN = '__json_copy_serialize_children';
|
249
|
+
static readonly PROBED_PROPERTIES = new Set<any>([
|
250
|
+
'then',
|
251
|
+
'constructor',
|
252
|
+
'__proxy_id',
|
253
|
+
'__proxy_constructor',
|
254
|
+
'__proxy_peer',
|
255
|
+
RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS,
|
256
|
+
RpcPeer.PROPERTY_JSON_DISABLE_SERIALIZATION,
|
257
|
+
RpcPeer.PROPERTY_PROXY_PROPERTIES,
|
258
|
+
RpcPeer.PROPERTY_JSON_COPY_SERIALIZE_CHILDREN,
|
259
|
+
]);
|
249
260
|
|
250
261
|
constructor(public selfName: string, public peerName: string, public send: (message: RpcMessage, reject?: (e: Error) => void, serializationContext?: any) => void) {
|
251
262
|
}
|
package/src/runtime.ts
CHANGED
@@ -225,6 +225,7 @@ async function start() {
|
|
225
225
|
});
|
226
226
|
|
227
227
|
console.log('#######################################################');
|
228
|
+
console.log(`Scrypted Volume : ${volumeDir}`);
|
228
229
|
console.log(`Scrypted Server (Local) : https://localhost:${SCRYPTED_SECURE_PORT}/`);
|
229
230
|
for (const address of getHostAddresses(true, true)) {
|
230
231
|
console.log(`Scrypted Server (Remote) : https://${address}:${SCRYPTED_SECURE_PORT}/`);
|
package/src/state.ts
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
import {
|
2
|
-
import { ScryptedNativeId, EventDetails, EventListenerOptions, EventListenerRegister, Refresh, ScryptedInterface, ScryptedInterfaceProperty, SystemDeviceState } from "@scrypted/types";
|
3
|
-
import { RefreshSymbol } from "./plugin/plugin-device";
|
1
|
+
import { EventDetails, EventListenerOptions, EventListenerRegister, Refresh, ScryptedInterface, ScryptedInterfaceProperty, ScryptedNativeId, SystemDeviceState } from "@scrypted/types";
|
4
2
|
import throttle from 'lodash/throttle';
|
5
|
-
import { sleep } from "./sleep";
|
6
|
-
import { EventListenerRegisterImpl, EventRegistry } from "./event-registry";
|
7
3
|
import { PluginDevice } from "./db-types";
|
4
|
+
import { EventListenerRegisterImpl, EventRegistry } from "./event-registry";
|
8
5
|
import { allInterfaceProperties, propertyInterfaces } from "./plugin/descriptor";
|
6
|
+
import { RefreshSymbol } from "./plugin/plugin-device";
|
7
|
+
import { ScryptedRuntime } from "./runtime";
|
8
|
+
import { sleep } from "./sleep";
|
9
9
|
|
10
10
|
export class ScryptedStateManager extends EventRegistry {
|
11
11
|
scrypted: ScryptedRuntime;
|
@@ -34,41 +34,30 @@ export class ScryptedStateManager extends EventRegistry {
|
|
34
34
|
this.scrypted = scrypted;
|
35
35
|
}
|
36
36
|
|
37
|
-
setPluginState(pluginId: string, nativeId: ScryptedNativeId, property: string, value: any) {
|
37
|
+
setPluginState(pluginId: string, nativeId: ScryptedNativeId, eventInterface: ScryptedInterface, property: string, value: any) {
|
38
38
|
const device = this.scrypted.findPluginDevice(pluginId, nativeId);
|
39
39
|
if (!device)
|
40
40
|
throw new Error(`device not found for plugin id ${pluginId} native id ${nativeId}`);
|
41
|
-
this.setPluginDeviceState(device, property, value);
|
41
|
+
this.setPluginDeviceState(device, property, value, eventInterface);
|
42
42
|
}
|
43
43
|
|
44
|
-
setPluginDeviceState(device: PluginDevice, property: string, value: any) {
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
// this currently doesn't work because inherited properties are not detected.
|
49
|
-
// ie, MediaPlayer implements StartStop and Pause
|
50
|
-
// if (!isValidInterfaceProperty(device.state.interfaces.value, property))
|
51
|
-
// throw new Error(`interface for property ${property} not implemented`);
|
52
|
-
if (!allInterfaceProperties.includes(property))
|
44
|
+
setPluginDeviceState(device: PluginDevice, property: string, value: any, eventInterface?: ScryptedInterface) {
|
45
|
+
eventInterface = eventInterface || propertyInterfaces[property];
|
46
|
+
if (!eventInterface)
|
53
47
|
throw new Error(`${property} is not a valid property`);
|
54
48
|
|
55
49
|
const changed = setState(device, property, value);
|
56
50
|
|
57
|
-
this.notifyPropertyEvent(device, property, value, changed);
|
58
|
-
|
59
|
-
this.upserts.add(device._id);
|
60
|
-
this.upsertThrottle();
|
61
|
-
|
62
|
-
return changed;
|
63
|
-
}
|
64
|
-
|
65
|
-
notifyPropertyEvent(device: PluginDevice, property: string, value: any, changed?: boolean) {
|
66
51
|
const eventTime = device?.state?.[property]?.lastEventTime;
|
67
|
-
const eventInterface = propertyInterfaces[property];
|
68
52
|
|
69
53
|
if (this.notify(device?._id, eventTime, eventInterface, property, value, changed) && device) {
|
70
54
|
this.scrypted.getDeviceLogger(device).log('i', `state change: ${property} ${value}`);
|
71
55
|
}
|
56
|
+
|
57
|
+
this.upserts.add(device._id);
|
58
|
+
this.upsertThrottle();
|
59
|
+
|
60
|
+
return changed;
|
72
61
|
}
|
73
62
|
|
74
63
|
updateDescriptor(device: PluginDevice) {
|