From 0f6053ce08e58e4b0d7f2de2a6e245555877cfbb Mon Sep 17 00:00:00 2001 From: Mikunj Date: Wed, 27 May 2020 11:05:30 +1000 Subject: [PATCH] Add events to MessageQueueInterface. Added strict typings for events. --- ts/session/sending/MessageQueue.ts | 10 +++- ts/session/sending/MessageQueueInterface.ts | 12 +++-- ts/session/sending/index.ts | 7 +-- ts/session/utils/TypedEmitter.ts | 53 +++++++++++++++++++++ ts/session/utils/index.ts | 2 + 5 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 ts/session/utils/TypedEmitter.ts create mode 100644 ts/session/utils/index.ts diff --git a/ts/session/sending/MessageQueue.ts b/ts/session/sending/MessageQueue.ts index 5eeaa2426..274640ac4 100644 --- a/ts/session/sending/MessageQueue.ts +++ b/ts/session/sending/MessageQueue.ts @@ -1,13 +1,19 @@ -import { MessageQueueInterface } from './MessageQueueInterface'; +import { EventEmitter } from 'events'; +import { + MessageQueueInterface, + MessageQueueInterfaceEvents, +} from './MessageQueueInterface'; import { OpenGroupMessage, OutgoingContentMessage } from '../messages/outgoing'; -import { JobQueue } from '../utils/JobQueue'; import { PendingMessageCache } from './PendingMessageCache'; +import { JobQueue, TypedEventEmitter } from '../utils'; export class MessageQueue implements MessageQueueInterface { + public readonly events: TypedEventEmitter; private readonly jobQueues: Map = new Map(); private readonly cache: PendingMessageCache; constructor() { + this.events = new EventEmitter(); this.cache = new PendingMessageCache(); this.processAllPending(); } diff --git a/ts/session/sending/MessageQueueInterface.ts b/ts/session/sending/MessageQueueInterface.ts index a231ad02c..553b25ed0 100644 --- a/ts/session/sending/MessageQueueInterface.ts +++ b/ts/session/sending/MessageQueueInterface.ts @@ -1,13 +1,19 @@ import { OpenGroupMessage, OutgoingContentMessage } from '../messages/outgoing'; +import { RawMessage } from '../types/RawMessage'; +import { TypedEventEmitter } from '../utils'; // TODO: add all group messages here, replace OutgoingContentMessage with them type GroupMessageType = OpenGroupMessage | OutgoingContentMessage; + +export interface MessageQueueInterfaceEvents { + success: (message: RawMessage) => void; + fail: (message: RawMessage, error: Error) => void; +} + export interface MessageQueueInterface { + events: TypedEventEmitter; sendUsingMultiDevice(user: string, message: OutgoingContentMessage): void; send(device: string, message: OutgoingContentMessage): void; sendToGroup(message: GroupMessageType): void; sendSyncMessage(message: OutgoingContentMessage): void; - // TODO: Find a good way to handle events in this - // E.g if we do queue.onMessageSent() we want to also be able to stop listening to the event - // TODO: implement events here } diff --git a/ts/session/sending/index.ts b/ts/session/sending/index.ts index 69ca9153b..f6cf299b6 100644 --- a/ts/session/sending/index.ts +++ b/ts/session/sending/index.ts @@ -1,5 +1,6 @@ +// TS 3.8 supports export * as X from 'Y' import * as MessageSender from './MessageSender'; -import { MessageQueue } from './MessageQueue'; -import { MessageQueueInterface } from './MessageQueueInterface'; +export { MessageSender }; -export { MessageSender, MessageQueue, MessageQueueInterface }; +export * from './MessageQueue'; +export * from './MessageQueueInterface'; diff --git a/ts/session/utils/TypedEmitter.ts b/ts/session/utils/TypedEmitter.ts new file mode 100644 index 000000000..a6a27f200 --- /dev/null +++ b/ts/session/utils/TypedEmitter.ts @@ -0,0 +1,53 @@ +// Code from https://github.com/andywer/typed-emitter + +type Arguments = [T] extends [(...args: infer U) => any] + ? U + : [T] extends [void] ? [] : [T]; + +/** + * Type-safe event emitter. + * + * Use it like this: + * + * interface MyEvents { + * error: (error: Error) => void + * message: (from: string, content: string) => void + * } + * + * const myEmitter = new EventEmitter() as TypedEmitter + * + * myEmitter.on("message", (from, content) => { + * // ... + * }) + * + * myEmitter.emit("error", "x") // <- Will catch this type error + * + * or + * + * class MyEmitter extends EventEmitter implements TypedEventEmitter + */ +export interface TypedEventEmitter { + addListener(event: E, listener: Events[E]): this; + on(event: E, listener: Events[E]): this; + once(event: E, listener: Events[E]): this; + prependListener(event: E, listener: Events[E]): this; + prependOnceListener( + event: E, + listener: Events[E] + ): this; + + off(event: E, listener: Events[E]): this; + removeAllListeners(event?: E): this; + removeListener(event: E, listener: Events[E]): this; + + emit( + event: E, + ...args: Arguments + ): boolean; + eventNames(): Array; + listeners(event: E): Array; + listenerCount(event: E): number; + + getMaxListeners(): number; + setMaxListeners(maxListeners: number): this; +} diff --git a/ts/session/utils/index.ts b/ts/session/utils/index.ts new file mode 100644 index 000000000..a33d528ba --- /dev/null +++ b/ts/session/utils/index.ts @@ -0,0 +1,2 @@ +export * from './TypedEmitter'; +export * from './JobQueue';