UNPKG

pocket-messaging

Version:

A small cryptographic messaging library written in TypeScript both for browser and nodejs supporting TCP and WebSockets

204 lines (203 loc) 8.04 kB
/// <reference types="node" /> import { ClientInterface } from "pocket-sockets"; import EventEmitter from "eventemitter3"; import { SentMessage, Header, OutgoingQueue, IncomingQueue, EventType, SendReturn } from "./types"; export declare class Messaging { /** * Messages sent from here which are expecting replies. * */ protected pendingReply: { [msgId: string]: SentMessage; }; /** * Data read on socket and transformed to messages. */ protected incomingQueue: IncomingQueue; /** * Messages transformed and sent. */ protected outgoingQueue: OutgoingQueue; /** * The general event emitter for incoming messages and socket events. * Reply messages are not emitted using this object but are emitted on message specific event emitters. */ protected eventEmitter: EventEmitter; /** * The given client socket to communicate with. */ protected socket: ClientInterface; /** * Set to true if we have opened. */ protected _isOpened: boolean; /** * Set to true if we have closed. */ protected _isClosed: boolean; /** ID of the timeout in use for ping. */ protected pingTimeout: ReturnType<typeof setTimeout> | undefined; /** Milliseconds to wait between each ping. */ protected pingInterval: number; /** Keep track of pending ping, pong resets it. */ protected pingTimestamp: number; /** * How many messages we allow through. * 0 means cork it up * -1 means unlimited. */ protected dispatchLimit: number; protected isBusyOut: number; protected isBusyIn: number; protected instanceId: string; /** * @param socket the underlying socket to use. Socket must be in binary mode. * @param pingInterval in milliseconds, set to send frequent pings on the socket to detect silent disconnects. */ constructor(socket: ClientInterface, pingInterval?: number); getInstanceId(): string; /** * Remove a stored pending message so that it cannot receive any more replies. */ cancelPendingMessage: (msgId: Buffer) => void; /** * See if a specific msgId is pending a reply. * @param msgId the ID of the message to check if it is pending a reply. * @returns true if message identified by msgId is pending a reply. */ isMessagePending: (msgId: Buffer) => boolean; /** * This pauses all timeouts for a message until the next message arrives then timeouts are re-activated (if set initially ofc). * This could be useful when expecting a never ending stream of messages where chunks could be time apart. */ clearTimeout: (msgId: Buffer) => void; /** * Get the general event emitter object. * This is used to listen for incoming messages * and socket events such as close and error. */ getEventEmitter(): EventEmitter; /** * Open this Messaging for inbound data. * * Do not open it until you have hooked the event emitter * to not loose any incoming data. * * It is technically allowed to send data before opening, * but the Messaging should be opened very shortly after * sending so that replies can come through and so that * timeouts are processed properly. */ open(): void; isOpen(): boolean; isOpened(): boolean; isClosed(): boolean; /** * Close this Messaging object and it's socket. * */ close(): void; cork(): void; uncork(limit?: number): void; /** * Send message to remote. * * The returned EventEmitter can be hooked as eventEmitter.on("reply", fn) or * const data: ReplyEvent = await once(eventEmitter, "reply"); * Other events are "close" (CloseEvent) and "any" which trigger both for "reply", "close" and "error" (ErrorEvent). There is also "timeout" (TimeoutEvent). * * A timeouted message is removed from memory and a TIMEOUT is emitted. * * @param target: Buffer | string either set as routing target as string, or as message ID in reply to (as buffer). * The receiving Messaging instance will check if target matches a msg ID which is waiting for a reply and in such case the message till be emitted on that EventEmitter, * or else it will pass it to the router to see if it matches some route. * @param data: Buffer of data to be sent. Note that data (payload) cannot exceed MESSAGE_MAX_BYTES. * @param timeout milliseconds to wait for the first reply (defaults to -1) * -1 means we are not expecting a reply * 0 or greater means that we are expecting a reply, 0 means wait forever * @param stream set to true if expecting multiple replies (defaults to false) * This requires that timeout is set to 0 or greater * @param timeoutStream milliseconds to wait for secondary replies, 0 means forever (default). * Only relevant if expecting multiple replies (stream = true). * @return SendReturn | undefined * SendReturn.msgId is always set * SendReturn.eventEmitter property is set if expecting reply * undefined is returned as a silent error when the Messaging is closed and data cannot be sent again on this Messaging instance. * @throws on malformed input */ send(target: Buffer | string, data?: Buffer, timeout?: number, stream?: boolean, timeoutStream?: number): SendReturn | undefined; /** * Enable to send frequent pings on the socket. * This will help to detect silent disconnects. * @param pingInterval how many milliseconds to wait between each ping. * Default is 10000 (10 sec). 0 means disabled. */ enablePing(pingInterval?: number): void; disablePing(): void; /** * @returns the underlaying socket client. */ getClient(): ClientInterface; protected getNow(): number; static GenerateMsgId(): Buffer; /** * @throws on malformed input */ static EncodeHeader(header: Header): Buffer; /** * @throws on malformed input */ static DecodeHeader(buffer: Buffer): [Header, Buffer]; /** * Extract length as single buffer and modify the buffers array in place. * */ protected extractBuffer(buffers: Buffer[], length: number): Buffer | undefined; protected emitEvent(eventEmitters: EventEmitter[], eventType: EventType, arg?: any): void; protected getAllEventEmitters(): EventEmitter[]; /** * Notify all pending messages and the main emitter about an error. * * @param message the error message * */ protected emitError: (message: string) => void; /** * Notify all pending messages about the close. */ protected socketClose: (hadError: boolean) => void; /** * Send a ping to remote to force a disconnect event in the case * the socket has silently closed. * There is no reply expected on the ping. */ protected sendPing: () => void; /** * Buffer incoming raw data from the socket and process it. */ protected socketData: (data: Buffer | string) => void; protected processInqueue: () => Promise<void>; /** * Assemble messages from decrypted data and put to next queue. * */ protected assembleIncoming: () => boolean; /** * Dispatch messages on event emitters. * */ protected dispatchIncoming: () => void; protected processOutqueue: () => void; protected dispatchOutgoing: () => void; /** * Check every pending message to see which have timeouted. * */ protected checkTimeouts: () => void; protected getTimeoutedPendingMessages(): SentMessage[]; } /** * Mimicking the async/await once function from the nodejs events module. * Because EventEmitter3 module doesn't seem to support the async/await promise feature of nodejs events once() function. */ export declare function once(eventEmitter: EventEmitter, eventName: string | symbol): Promise<any>;