mirror of
https://github.com/koush/scrypted.git
synced 2026-02-10 09:12:03 +00:00
105 lines
3.6 KiB
TypeScript
105 lines
3.6 KiB
TypeScript
import { EventDetails, EventListenerOptions, EventListenerRegister, ScryptedInterface } from "@scrypted/types";
|
|
|
|
export class EventListenerRegisterImpl implements EventListenerRegister {
|
|
removeListener: () => void;
|
|
|
|
constructor(removeListener: () => void) {
|
|
this.removeListener = removeListener;
|
|
}
|
|
}
|
|
|
|
export function getMixinEventName(options: string | EventListenerOptions) {
|
|
let { event, mixinId } = (options || {}) as EventListenerOptions;
|
|
if (!event && typeof options === 'string')
|
|
event = options as string;
|
|
if (!event)
|
|
event = undefined;
|
|
if (!mixinId)
|
|
return event;
|
|
let ret = `${event}-mixin-${mixinId}`;
|
|
return ret;
|
|
}
|
|
|
|
// todo: storage should only go to host plugin
|
|
const allowedEventInterfaces = new Set<string>([ScryptedInterface.ScryptedDevice, 'Logger', 'Storage'])
|
|
|
|
export class EventRegistry {
|
|
systemListeners = new Set<(id: string, eventDetails: EventDetails, eventData: any) => void>();
|
|
listeners: { [token: string]: Set<(eventDetails: EventDetails, eventData: any) => void> } = {};
|
|
|
|
listen(callback: (id: string, eventDetails: EventDetails, eventData: any) => void): EventListenerRegister {
|
|
const events = this.systemListeners;
|
|
events.add(callback);
|
|
return new EventListenerRegisterImpl(() => {
|
|
events.delete(callback);
|
|
callback = undefined;
|
|
});
|
|
}
|
|
|
|
listenDevice(id: string, options: string | EventListenerOptions, callback: (eventDetails: EventDetails, eventData: any) => void): EventListenerRegister {
|
|
let event = getMixinEventName(options)
|
|
const token = `${id}#${event}`;
|
|
let events = this.listeners[token];
|
|
if (!events) {
|
|
events = new Set();
|
|
this.listeners[token] = events;
|
|
}
|
|
|
|
events.add(callback);
|
|
return new EventListenerRegisterImpl(() => {
|
|
events.delete(callback);
|
|
callback = undefined;
|
|
});
|
|
}
|
|
|
|
notify(id: string | undefined, eventTime: number, eventInterface: string, property: string | undefined, value: any, options?: {
|
|
changed?: boolean;
|
|
mixinId?: string;
|
|
}): boolean {
|
|
const { changed, mixinId } = options || {};
|
|
// prevent property event noise
|
|
if (property && !changed)
|
|
return false;
|
|
|
|
const eventDetails: EventDetails = {
|
|
eventId: undefined,
|
|
eventInterface,
|
|
eventTime,
|
|
property,
|
|
mixinId,
|
|
};
|
|
|
|
return this.notifyEventDetails(id, eventDetails, value);
|
|
}
|
|
|
|
notifyEventDetails(id: string | undefined, eventDetails: EventDetails, value: any, eventInterface?: string) {
|
|
eventDetails.eventId ||= Math.random().toString(36).substring(2);
|
|
eventInterface ||= eventDetails.eventInterface;
|
|
|
|
// system listeners only get state changes.
|
|
// there are many potentially noisy stateless events, like
|
|
// object detection and settings changes.
|
|
if ((eventDetails.property && !eventDetails.mixinId) || allowedEventInterfaces.has(eventInterface)) {
|
|
for (const event of this.systemListeners) {
|
|
event(id, eventDetails, value);
|
|
}
|
|
}
|
|
|
|
const events = this.listeners[`${id}#${eventInterface}`];
|
|
if (events) {
|
|
for (const event of events) {
|
|
event(eventDetails, value);
|
|
}
|
|
}
|
|
|
|
const allEvents = this.listeners[`${id}#${undefined}`];
|
|
if (allEvents) {
|
|
for (const event of allEvents) {
|
|
event(eventDetails, value);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|