diff --git a/src/components/intent.ts b/src/components/intent.ts index 67973483..6ab0d3fe 100644 --- a/src/components/intent.ts +++ b/src/components/intent.ts @@ -125,6 +125,7 @@ export class Intent { ensureClientSyncingCallback: () => Promise; }; private readyPromise?: Promise; + private readonly debouncedRequests = new Map>(); /** * Create an entity which can fulfil the intent of a given user. @@ -865,6 +866,31 @@ export class Intent { } } + /** + * Debounce a request to the intent + * @param requestKey A unique key name for the request. E.g. "bridge-channel-id" + * @param fnName A function on this object. E.g. "joinRoom" + * @param args Args to pass to the function. + * @returns A object containing the promise and a function to clear the value. + */ + public debounceRequest(requestKey: string, fnName: keyof Intent, ...args: unknown[]) + : { promise: Promise, clear?: () => void } { + if (fnName === "debounceRequest") { + throw Error('Cannot debounce this function'); + } + const key = `${fnName}:${requestKey}`; + const existing = this.debouncedRequests.get(key); + if (existing) { + return { promise: existing as Promise }; + } + const promise = this[fnName](...args); + this.debouncedRequests.set(key, promise); + return { + promise, + clear: () => { this.debouncedRequests.delete(key) } + }; + } + // Guard a function which returns a promise which may reject if the user is not // in the room. If the promise rejects, join the room and retry the function. private async _joinGuard(roomId: string, promiseFn: () => Promise): Promise {