From 6824c38fc6eb321ee191bfaaf004cfa521ec20fe Mon Sep 17 00:00:00 2001 From: Andrew Bulat Date: Thu, 23 Jan 2025 04:41:59 +0000 Subject: [PATCH] Emit lifecycle events on `LiveObject` Currently emits `deleted` upon receiving `OBJECT_DELETE` for the object DTP-1034 --- src/plugins/liveobjects/liveobject.ts | 41 ++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/plugins/liveobjects/liveobject.ts b/src/plugins/liveobjects/liveobject.ts index bb9216dd9..d0e083c6e 100644 --- a/src/plugins/liveobjects/liveobject.ts +++ b/src/plugins/liveobjects/liveobject.ts @@ -25,12 +25,23 @@ export interface SubscribeResponse { unsubscribe(): void; } +export enum LiveObjectLifecycleEvent { + deleted = 'deleted', +} + +export type LiveObjectLifecycleEventCallback = () => void; + +export interface OnLiveObjectLifecycleEventResponse { + off(): void; +} + export abstract class LiveObject< TData extends LiveObjectData = LiveObjectData, TUpdate extends LiveObjectUpdate = LiveObjectUpdate, > { protected _client: BaseClient; protected _subscriptions: EventEmitter; + protected _lifecycleEvents: EventEmitter; protected _objectId: string; /** * Represents an aggregated value for an object, which combines the initial value for an object from the create operation, @@ -56,6 +67,7 @@ export abstract class LiveObject< ) { this._client = this._liveObjects.getClient(); this._subscriptions = new this._client.EventEmitter(this._client.logger); + this._lifecycleEvents = new this._client.EventEmitter(this._client.logger); this._objectId = objectId; this._dataRef = this._getZeroValueData(); // use empty timeserials vector by default, so any future operation can be applied to this object @@ -94,6 +106,33 @@ export abstract class LiveObject< this._subscriptions.off(LiveObjectSubscriptionEvent.updated); } + on(event: LiveObjectLifecycleEvent, callback: LiveObjectLifecycleEventCallback): OnLiveObjectLifecycleEventResponse { + // no need to check channel modes for this public method + this._lifecycleEvents.on(event, callback); + + const off = () => { + this._lifecycleEvents.off(event, callback); + }; + + return { off }; + } + + off(event: LiveObjectLifecycleEvent, callback: LiveObjectLifecycleEventCallback): void { + // no need to check channel modes for this public method + + // prevent accidentally calling .off without any arguments on an EventEmitter and removing all callbacks + if (this._client.Utils.isNil(event) && this._client.Utils.isNil(callback)) { + return; + } + + this._lifecycleEvents.off(event, callback); + } + + offAll(): void { + // no need to check channel modes for this public method + this._lifecycleEvents.off(); + } + /** * @internal */ @@ -124,7 +163,7 @@ export abstract class LiveObject< this._tombstone = true; this._tombstonedAt = Date.now(); this._dataRef = this._getZeroValueData(); - // TODO: emit "deleted" event so that end users get notified about this object getting deleted + this._lifecycleEvents.emit(LiveObjectLifecycleEvent.deleted); } /**