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
TypeScript
/// <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>;