@scrypted/server 0.4.9 → 0.4.10

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.

@@ -166,15 +166,11 @@ export class SystemManagerImpl implements SystemManager {
166
166
  return this.events.listen(makeOneWayCallback((id, eventDetails, eventData) => callback(this.getDeviceById(id), eventDetails, eventData)));
167
167
  }
168
168
  listenDevice(id: string, options: string | EventListenerOptions, callback: EventListener): EventListenerRegister {
169
- let { event, watch } = (options || {}) as EventListenerOptions;
170
- if (!event && typeof options === 'string')
171
- event = options as string;
172
- if (!event)
173
- event = undefined;
169
+ let { watch } = (options || {}) as EventListenerOptions;
174
170
 
175
171
  // passive watching can be fast pathed to observe local state
176
172
  if (watch)
177
- return this.events.listenDevice(id, event, (eventDetails, eventData) => callback(this.getDeviceById(id), eventDetails, eventData));
173
+ return this.events.listenDevice(id, options, (eventDetails, eventData) => callback(this.getDeviceById(id), eventDetails, eventData));
178
174
 
179
175
  return new EventListenerRegisterImpl(this.api.listenDevice(id, options, makeOneWayCallback((eventDetails, eventData) => callback(this.getDeviceById(id), eventDetails, eventData))));
180
176
  }
package/src/rpc.ts CHANGED
@@ -154,6 +154,9 @@ class RpcProxy implements PrimitiveProxyHandler<any> {
154
154
 
155
155
  if (this.proxyOneWayMethods?.includes?.(method)) {
156
156
  rpcApply.oneway = true;
157
+ // a oneway callable object doesn't need to be in the JSON payload.
158
+ if (method === null)
159
+ delete rpcApply.method;
157
160
  this.peer.send(rpcApply, undefined, serializationContext);
158
161
  return Promise.resolve();
159
162
  }
@@ -70,6 +70,8 @@ export class PluginComponent {
70
70
  async kill(pluginId: string) {
71
71
  return this.scrypted.plugins[pluginId]?.kill();
72
72
  }
73
+ // TODO: Remove this, ScryptedPlugin exists now.
74
+ // 12/29/2022
73
75
  async getPackageJson(pluginId: string) {
74
76
  return this.scrypted.getPackageJson(pluginId);
75
77
  }
package/src/state.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { EventDetails, EventListenerOptions, EventListenerRegister, Refresh, ScryptedInterface, ScryptedInterfaceProperty, ScryptedNativeId, SystemDeviceState } from "@scrypted/types";
2
2
  import throttle from 'lodash/throttle';
3
3
  import { PluginDevice } from "./db-types";
4
- import { EventListenerRegisterImpl, EventRegistry } from "./event-registry";
5
- import { allInterfaceProperties, propertyInterfaces } from "./plugin/descriptor";
6
- import { RefreshSymbol } from "./plugin/plugin-device";
4
+ import { EventListenerRegisterImpl, EventRegistry, getMixinEventName } from "./event-registry";
5
+ import { propertyInterfaces } from "./plugin/descriptor";
6
+ import { QueryInterfaceSymbol, RefreshSymbol } from "./plugin/plugin-device";
7
7
  import { ScryptedRuntime } from "./runtime";
8
8
  import { sleep } from "./sleep";
9
9
 
@@ -34,25 +34,74 @@ export class ScryptedStateManager extends EventRegistry {
34
34
  this.scrypted = scrypted;
35
35
  }
36
36
 
37
- setPluginState(pluginId: string, nativeId: ScryptedNativeId, eventInterface: ScryptedInterface, property: string, value: any) {
38
- const device = this.scrypted.findPluginDevice(pluginId, nativeId);
37
+ async getImplementerId(pluginDevice: PluginDevice, eventInterface: ScryptedInterface | string) {
38
+ if (!eventInterface)
39
+ throw new Error(`ScryptedInterface is required`);
40
+
41
+ const device = this.scrypted.getDevice(pluginDevice._id);
39
42
  if (!device)
40
- throw new Error(`device not found for plugin id ${pluginId} native id ${nativeId}`);
41
- this.setPluginDeviceState(device, property, value, eventInterface);
43
+ throw new Error(`device ${pluginDevice._id} not found?`);
44
+
45
+ const implementerId: string = await (device as any)[QueryInterfaceSymbol](eventInterface);
46
+ return implementerId;
47
+ }
48
+
49
+ async notifyInterfaceEventFromMixin(pluginDevice: PluginDevice, eventInterface: ScryptedInterface | string, value: any, mixinId: string) {
50
+ // TODO: figure out how to clean this up this hack. For now,
51
+ // Settings interface is allowed to bubble from mixin devices..
52
+ if (eventInterface !== ScryptedInterface.Settings) {
53
+ const implementerId = await this.getImplementerId(pluginDevice, eventInterface);
54
+ if (implementerId !== mixinId) {
55
+ const event = getMixinEventName({
56
+ event: eventInterface,
57
+ mixinId,
58
+ });
59
+
60
+ this.notifyEventDetails(pluginDevice._id, {
61
+ eventId: undefined,
62
+ eventInterface,
63
+ eventTime: Date.now(),
64
+ mixinId,
65
+ }, value, event);
66
+
67
+ return;
68
+ }
69
+ }
70
+
71
+ this.notify(pluginDevice?._id, Date.now(), eventInterface, undefined, value);
72
+ }
73
+
74
+ async setPluginDeviceStateFromMixin(pluginDevice: PluginDevice, property: string, value: any, eventInterface: ScryptedInterface, mixinId: string) {
75
+ const implementerId = await this.getImplementerId(pluginDevice, eventInterface);
76
+ if (implementerId !== mixinId) {
77
+ const event = getMixinEventName({
78
+ event: eventInterface,
79
+ mixinId,
80
+ });
81
+ this.scrypted.getDeviceLogger(pluginDevice).log('i', `${property}: ${value} (mixin)`);
82
+ this.notifyEventDetails(pluginDevice._id, {
83
+ eventId: undefined,
84
+ eventInterface,
85
+ eventTime: Date.now(),
86
+ mixinId,
87
+ property,
88
+ }, value, event);
89
+ return false;
90
+ }
91
+
92
+ return this.setPluginDeviceState(pluginDevice, property, value, eventInterface);
42
93
  }
43
94
 
44
95
  setPluginDeviceState(device: PluginDevice, property: string, value: any, eventInterface?: ScryptedInterface) {
45
96
  eventInterface = eventInterface || propertyInterfaces[property];
46
97
  if (!eventInterface)
47
- throw new Error(`${property} is not a valid property`);
98
+ throw new Error(`eventInterface must be provided`);
48
99
 
49
100
  const changed = setState(device, property, value);
50
101
 
51
- const eventTime = device?.state?.[property]?.lastEventTime;
52
-
53
102
  if (eventInterface !== ScryptedInterface.ScryptedDevice) {
54
- if (this.notify(device?._id, eventTime, eventInterface, property, value, changed) && device) {
55
- this.scrypted.getDeviceLogger(device).log('i', `state change: ${property} ${value}`);
103
+ if (this.notify(device?._id, Date.now(), eventInterface, property, value, { changed }) && device) {
104
+ this.scrypted.getDeviceLogger(device).log('i', `${property}: ${value}`);
56
105
  }
57
106
  }
58
107
 
@@ -63,15 +112,18 @@ export class ScryptedStateManager extends EventRegistry {
63
112
  }
64
113
 
65
114
  updateDescriptor(device: PluginDevice) {
66
- this.notify(device._id, undefined, ScryptedInterface.ScryptedDevice, undefined, device.state, true);
115
+ this.notify(device._id, undefined, ScryptedInterface.ScryptedDevice, undefined, device.state, { changed: true });
67
116
  }
68
117
 
69
118
  removeDevice(id: string) {
70
- this.notify(undefined, undefined, ScryptedInterface.ScryptedDevice, ScryptedInterfaceProperty.id, id, true);
119
+ this.notify(undefined, undefined, ScryptedInterface.ScryptedDevice, ScryptedInterfaceProperty.id, id, { changed: true });
71
120
  }
72
121
 
73
- notifyInterfaceEvent(device: PluginDevice, eventInterface: ScryptedInterface | string, value: any) {
74
- this.notify(device?._id, Date.now(), eventInterface, undefined, value, true);
122
+ notifyInterfaceEvent(device: PluginDevice, eventInterface: ScryptedInterface | string, value: any, mixinId?: string) {
123
+ this.notify(device?._id, Date.now(), eventInterface, undefined, value, {
124
+ changed: true,
125
+ mixinId,
126
+ });
75
127
  }
76
128
 
77
129
  setState(id: string, property: string, value: any) {
@@ -214,12 +266,8 @@ export function setState(pluginDevice: PluginDevice, property: string, value: an
214
266
  if (!pluginDevice.state[property])
215
267
  pluginDevice.state[property] = {};
216
268
  const state = pluginDevice.state[property];
217
- const now = Date.now();
218
269
  const changed = !isSameValue(value, state.value);
219
- if (changed)
220
- state.stateTime = now;
221
270
  state.value = value;
222
- state.lastEventTime = now;
223
271
  return changed;
224
272
  }
225
273