Viewing File: /home/ubuntu/todaykat-frontend-base/node_modules/rpc-websockets/build-ts/lib/client.js

/**
 * "Client" wraps "ws" or a browser-implemented "WebSocket" library
 * according to the environment providing JSON RPC 2.0 support on top.
 * @module Client
 */
"use strict";
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
// @ts-ignore
import { EventEmitter } from "eventemitter3";
export default class CommonClient extends EventEmitter {
    /**
     * Instantiate a Client class.
     * @constructor
     * @param {webSocketFactory} webSocketFactory - factory method for WebSocket
     * @param {String} address - url to a websocket server
     * @param {Object} options - ws options object with reconnect parameters
     * @param {Function} generate_request_id - custom generation request Id
     * @return {CommonClient}
     */
    constructor(webSocketFactory, address = "ws://localhost:8080", _a = {}, generate_request_id) {
        var { autoconnect = true, reconnect = true, reconnect_interval = 1000, max_reconnects = 5 } = _a, rest_options = __rest(_a, ["autoconnect", "reconnect", "reconnect_interval", "max_reconnects"]);
        super();
        this.webSocketFactory = webSocketFactory;
        this.queue = {};
        this.rpc_id = 0;
        this.address = address;
        this.autoconnect = autoconnect;
        this.ready = false;
        this.reconnect = reconnect;
        this.reconnect_interval = reconnect_interval;
        this.max_reconnects = max_reconnects;
        this.rest_options = rest_options;
        this.current_reconnects = 0;
        this.generate_request_id = generate_request_id || (() => ++this.rpc_id);
        if (this.autoconnect)
            this._connect(this.address, Object.assign({ autoconnect: this.autoconnect, reconnect: this.reconnect, reconnect_interval: this.reconnect_interval, max_reconnects: this.max_reconnects }, this.rest_options));
    }
    /**
     * Connects to a defined server if not connected already.
     * @method
     * @return {Undefined}
     */
    connect() {
        if (this.socket)
            return;
        this._connect(this.address, Object.assign({ autoconnect: this.autoconnect, reconnect: this.reconnect, reconnect_interval: this.reconnect_interval, max_reconnects: this.max_reconnects }, this.rest_options));
    }
    /**
     * Calls a registered RPC method on server.
     * @method
     * @param {String} method - RPC method name
     * @param {Object|Array} params - optional method parameters
     * @param {Number} timeout - RPC reply timeout value
     * @param {Object} ws_opts - options passed to ws
     * @return {Promise}
     */
    call(method, params, timeout, ws_opts) {
        if (!ws_opts && "object" === typeof timeout) {
            ws_opts = timeout;
            timeout = null;
        }
        return new Promise((resolve, reject) => {
            if (!this.ready)
                return reject(new Error("socket not ready"));
            const rpc_id = this.generate_request_id(method, params);
            const message = {
                jsonrpc: "2.0",
                method: method,
                params: params || null,
                id: rpc_id
            };
            this.socket.send(JSON.stringify(message), ws_opts, (error) => {
                if (error)
                    return reject(error);
                this.queue[rpc_id] = { promise: [resolve, reject] };
                if (timeout) {
                    this.queue[rpc_id].timeout = setTimeout(() => {
                        delete this.queue[rpc_id];
                        reject(new Error("reply timeout"));
                    }, timeout);
                }
            });
        });
    }
    /**
     * Logins with the other side of the connection.
     * @method
     * @param {Object} params - Login credentials object
     * @return {Promise}
     */
    async login(params) {
        const resp = await this.call("rpc.login", params);
        if (!resp)
            throw new Error("authentication failed");
        return resp;
    }
    /**
     * Fetches a list of client's methods registered on server.
     * @method
     * @return {Array}
     */
    async listMethods() {
        return await this.call("__listMethods");
    }
    /**
     * Sends a JSON-RPC 2.0 notification to server.
     * @method
     * @param {String} method - RPC method name
     * @param {Object} params - optional method parameters
     * @return {Promise}
     */
    notify(method, params) {
        return new Promise((resolve, reject) => {
            if (!this.ready)
                return reject(new Error("socket not ready"));
            const message = {
                jsonrpc: "2.0",
                method: method,
                params: params || null
            };
            this.socket.send(JSON.stringify(message), (error) => {
                if (error)
                    return reject(error);
                resolve();
            });
        });
    }
    /**
     * Subscribes for a defined event.
     * @method
     * @param {String|Array} event - event name
     * @return {Undefined}
     * @throws {Error}
     */
    async subscribe(event) {
        if (typeof event === "string")
            event = [event];
        const result = await this.call("rpc.on", event);
        if (typeof event === "string" && result[event] !== "ok")
            throw new Error("Failed subscribing to an event '" + event + "' with: " + result[event]);
        return result;
    }
    /**
     * Unsubscribes from a defined event.
     * @method
     * @param {String|Array} event - event name
     * @return {Undefined}
     * @throws {Error}
     */
    async unsubscribe(event) {
        if (typeof event === "string")
            event = [event];
        const result = await this.call("rpc.off", event);
        if (typeof event === "string" && result[event] !== "ok")
            throw new Error("Failed unsubscribing from an event with: " + result);
        return result;
    }
    /**
     * Closes a WebSocket connection gracefully.
     * @method
     * @param {Number} code - socket close code
     * @param {String} data - optional data to be sent before closing
     * @return {Undefined}
     */
    close(code, data) {
        this.socket.close(code || 1000, data);
    }
    /**
     * Connection/Message handler.
     * @method
     * @private
     * @param {String} address - WebSocket API address
     * @param {Object} options - ws options object
     * @return {Undefined}
     */
    _connect(address, options) {
        this.socket = this.webSocketFactory(address, options);
        this.socket.addEventListener("open", () => {
            this.ready = true;
            this.emit("open");
            this.current_reconnects = 0;
        });
        this.socket.addEventListener("message", ({ data: message }) => {
            if (message instanceof ArrayBuffer)
                message = Buffer.from(message).toString();
            try {
                message = JSON.parse(message);
            }
            catch (error) {
                return;
            }
            // check if any listeners are attached and forward event
            if (message.notification && this.listeners(message.notification).length) {
                if (!Object.keys(message.params).length)
                    return this.emit(message.notification);
                const args = [message.notification];
                if (message.params.constructor === Object)
                    args.push(message.params);
                else
                    // using for-loop instead of unshift/spread because performance is better
                    for (let i = 0; i < message.params.length; i++)
                        args.push(message.params[i]);
                // run as microtask so that pending queue messages are resolved first
                // eslint-disable-next-line prefer-spread
                return Promise.resolve().then(() => { this.emit.apply(this, args); });
            }
            if (!this.queue[message.id]) {
                // general JSON RPC 2.0 events
                if (message.method && message.params) {
                    // run as microtask so that pending queue messages are resolved first
                    return Promise.resolve().then(() => {
                        this.emit(message.method, message.params);
                    });
                }
                return;
            }
            // reject early since server's response is invalid
            if ("error" in message === "result" in message)
                this.queue[message.id].promise[1](new Error("Server response malformed. Response must include either \"result\"" +
                    " or \"error\", but not both."));
            if (this.queue[message.id].timeout)
                clearTimeout(this.queue[message.id].timeout);
            if (message.error)
                this.queue[message.id].promise[1](message.error);
            else
                this.queue[message.id].promise[0](message.result);
            delete this.queue[message.id];
        });
        this.socket.addEventListener("error", (error) => this.emit("error", error));
        this.socket.addEventListener("close", ({ code, reason }) => {
            if (this.ready) // Delay close event until internal state is updated
                setTimeout(() => this.emit("close", code, reason), 0);
            this.ready = false;
            this.socket = undefined;
            if (code === 1000)
                return;
            this.current_reconnects++;
            if (this.reconnect && ((this.max_reconnects > this.current_reconnects) ||
                this.max_reconnects === 0))
                setTimeout(() => this._connect(address, options), this.reconnect_interval);
        });
    }
}
Back to Directory File Manager