/** * Base-class for any MHub client. * * Derived classes add actual transport logic to connect to * e.g. a Node.JS websocket API, a browser version, or a version * specifically for testing. */ /// import * as events from "events"; import Message, { Headers } from "./message"; import * as protocol from "./protocol"; /** * Options to be passed to constructor. */ export interface BaseClientOptions { /** * Number of milliseconds of idleness (i.e. no data * transmitted or received) before sending a ping to * the server. If it doesn't respond within that same * interval, the connection is closed with an error. * Use 0 to disable. */ keepalive?: number; } export declare const defaultBaseClientOptions: BaseClientOptions; /** * Interface for coupling of MHub client to transport protocol * such as a WebSocket or raw TCP stream. * * Events expected from the interface: * @event open() Emitted when connection was established. * @event close() Emitted when connection was closed. * @event error(e: Error) Emitted when there was a connection, server or protocol error. * @event message(data: protocol.Response) Emitted when a message (object) was received. * Note: object needs to be deserialized already. Don't pass a string. */ export interface Connection extends events.EventEmitter { /** * Transmit data object. * @return Promise that resolves when transmit is accepted (i.e. not necessarily * arrived at other side, can be e.g. queued). */ send(data: protocol.Command): Promise; /** * Gracefully close connection, i.e. allow pending transmissions * to be completed. * @return Promise that resolves when connection is succesfully closed. */ close(): Promise; /** * Forcefully close connection. * @return Promise that resolves when connection is succesfully closed. */ terminate(): Promise; } export interface BaseClient { /** * Attach event handler for connection established event. */ on(event: "open", listener: () => void): this; /** * Attache event handler for connection closed event. */ on(event: "close", listener: () => void): this; /** * Attach event handler for error event. */ on(event: "error", listener: (error: Error) => void): this; /** * Attach event handler for receiving a new message. * If no explicit subscriptionId was passed during subscribe, string "default" is used. */ on(event: "message", listener: (message: Message, subscriptionId: string) => void): this; } /** * Abstract MHub client. * * Implements MHub client protocol, but does not implement the transport layer * such as WebSocket, raw TCP, etc. * * @event open() Emitted when connection was established. * @event close() Emitted when connection was closed. * @event error(e: Error) Emitted when there was a connection, server or protocol error. * @event message(m: Message, subscriptionId: string) Emitted when message was received (due to subscription). */ export declare abstract class BaseClient extends events.EventEmitter { private _options; private _socket; private _transactions; private _seqNo; private _idleTimer; private _connecting; private _closing; private _socketConstructor; private _connected; /** * Create new BaseClient. * @param options Protocol settings */ constructor(socketConstructor: () => Connection, options?: BaseClientOptions); /** * Connect to the MServer. * If connection is already active or pending, this is a no-op. * Note: a connection is already initiated when the constructor is called. */ connect(): Promise; /** * Disconnect from MServer. * Pending requests will be rejected with an error. * If already disconnected, this becomes a no-op. * * Note: any existing subscriptions will be lost. * * Optionally pass an error to signal abrupt failure, * forcefully terminating the connection. * The same error will be used to reject any pending * requests. * @param error (optional) Error to emit, reject transactions with, and * forcefully close connection. */ close(error?: Error): Promise; /** * Login to server using username/password. * * Warning: the username and password are sent in plain text. * Only use this on secure connections such as wss://. * * @param username Username. * @param password Password. */ login(username: string, password: string): Promise; /** * Subscribe to a node. * * Emits the "message" event when a message is received for this subscription. * First argument of that event is the message, second is the subscription id * (or "default" if no id was given). * * @param nodeName Name of node in MServer to subscribe to (e.g. "default") * @param pattern Optional pattern glob (e.g. "/some/foo*"). Matches all topics if omitted. * @param id Optional subscription ID sent back with all matching messages */ subscribe(nodeName: string, pattern?: string, id?: string): Promise; /** * Unsubscribe `pattern` (or all if omitted) from given `node` and `id`. * Subscription id "default" is used if `id` is omitted. * * @param nodeName Name of node in MServer to unsubscribe from (e.g. "default") * @param pattern Optional pattern glob (e.g. "/some/foo*"). Unsubscribes all (on `node` and `id`) * if omitted. * @param id Subscription ID, or "default" */ unsubscribe(nodeName: string, pattern?: string, id?: string): Promise; /** * Publish message to a node. * * @param nodeName Name of node in MServer to publish to (e.g. "default") * @param topic Message topic * @param data Message data * @param headers Message headers */ publish(nodeName: string, topic: string, data?: any, headers?: Headers): Promise; /** * Publish message to a node. * * @param nodeName Name of node in MServer to publish to (e.g. "default") * @param message Message object */ publish(nodeName: string, message: Message): Promise; /** * Ping server. * Mostly used to check whether connection is still alive. * Note that the client will automatically send pings in the * absence of other communication, so there should be no need to * manually send pings. * * @param timeout (optional) Timeout in milliseconds before rejecting * the promise with an error, or infinite if not given. */ ping(timeout?: number): Promise; /** * Defer calling of events to next tick, to prevent e.g. errors * in handlers from interfering with client state, and to * prevent hard-to-debug async weirdness. */ private _asyncEmit; private _handleSocketOpen; private _handleSocketError; private _handleSocketClose; private _handleSocketMessage; /** * (Re-)start idle timer and send pings when connection is idle * for too long. */ private _restartIdleTimer; private _stopIdleTimer; private _handleIdleTimeout; private _send; /** * Resolve pending transaction promise (either fulfill or reject with error). * Returns true when the given sequence number was actually found. */ private _release; /** * Compute next available sequence number. * Throws an error when no sequence number is available (too many * pending transactions). */ private _nextSeq; } export default BaseClient;