jaysonic
Version:
A feature rich JSON-RPC 1.0/2.0 compliant client and server library
333 lines (277 loc) • 14.5 kB
JavaScript
"use strict";
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); }
function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
/* eslint no-console: 0 */
var WsBrowserClientProtocol = require("../client/protocol/ws-browser");
/**
* Creates an instance of WsBrowserClientFactory.
*
* For websocket client use in the browser.
*
* @extends EventTarget
*/
var WsBrowserClientFactory = /*#__PURE__*/function (_EventTarget) {
_inherits(WsBrowserClientFactory, _EventTarget);
var _super = _createSuper(WsBrowserClientFactory);
/**
* @inheritdoc
* @param {Object} options Connection options for the factory class
* @param {string} [options.url="ws://127.0.0.1:8100"] IP of server to connect to
* @param {number} [options.version=2] JSON-RPC version to use (1|2)
* @param {string} [options.delimiter="\n"] Delimiter to use for requests
* @param {number} [options.timeout=30] Timeout for request response
* @param {number} [options.connectionTimeout=5000] Timeout for connection to server
* @param {number} [options.retries=2] Number of connection retry attempts
* @property {class} pcolInstance The [JsonRpcClientProtocol]{@link JsonRpcClientProtocol} instance
* @property {object} timeouts Key value pairs of request IDs to `setTimeout` instance
* @property {number} requestTimeout Same as `options.timeout`
* @property {number} remainingRetries Same as `options.retries`
* @property {number} connectionTimeout Same as `options.connectionTimeout`
* @property {string} url Same as `options.url`
*/
function WsBrowserClientFactory(options) {
var _this;
_classCallCheck(this, WsBrowserClientFactory);
_this = _super.call(this);
if (!(_assertThisInitialized(_this) instanceof WsBrowserClientFactory)) {
return _possibleConstructorReturn(_this, new WsBrowserClientFactory(options));
}
var defaults = {
url: "ws://127.0.0.1:8100",
version: 2,
delimiter: "\n",
timeout: 30,
connectionTimeout: 5000,
retries: 2
};
_this.options = _objectSpread(_objectSpread({}, defaults), options || {});
_this.pcolInstance = undefined;
_this.timeouts = {};
_this.url = _this.options.url;
_this.eventListenerList = {};
_this.requestTimeout = _this.options.timeout * 1000;
_this.remainingRetries = _this.options.retries;
_this.connectionTimeout = _this.options.connectionTimeout;
return _this;
}
/**
* Set the `pcolInstance` for the client factory
*
* @example
* this.pcolInstance = new WsBrowserClientProtocol()
*/
_createClass(WsBrowserClientFactory, [{
key: "buildProtocol",
value: function buildProtocol() {
this.pcolInstance = new WsBrowserClientProtocol(this, this.options.version, this.options.delimiter);
}
/**
* Calls `connect()` on protocol instance.
* @returns {function} pcolInstance.connect()
*/
}, {
key: "connect",
value: function connect() {
if (this.pcolInstance) {
// not having this caused MaxEventListeners error
return Promise.reject(Error("client already connected"));
}
this.buildProtocol();
return this.pcolInstance.connect();
}
/**
* Calls `end()` on protocol instance
*
*/
}, {
key: "end",
value: function end(cb) {
this.pcolInstance.end(cb);
}
/**
* Calls `message()` on the protocol instance
*
* @param {string} method Name of the method to use in the request
* @param {Array|JSON} params Params to send
* @param {boolean=} id If true it will use instances `message_id` for the request id, if false will generate a notification request
* @example
* client.message("hello", ["world"]) // returns {"jsonrpc": "2.0", "method": "hello", "params": ["world"], "id": 1}
* client.message("hello", ["world"], false) // returns {"jsonrpc": "2.0", "method": "hello", "params": ["world"]}
*/
}, {
key: "message",
value: function message(method, params, id) {
return this.pcolInstance.message(method, params, id);
}
/**
* Calls `send()` method on protocol instance
*
* Promise will resolve when a response has been received for the request.
*
* Promise will reject if the server responds with an error object, or if
* the response is not received within the set `requestTimeout`
*
* @param {string} method Name of the method to use in the request
* @param {Array|JSON} params Params to send
* @returns Promise
* @example
* client.send("hello", {"foo": "bar"})
*/
}, {
key: "send",
value: function send(method, params) {
return this.pcolInstance.send(method, params);
}
/**
* Calls `notify()` method on protocol instance
*
* Promise will resolve if the request was sucessfully sent, and reject if
* there was an error sending the request.
*
* @param {string} method Name of the method to use in the notification
* @param {Array|JSON} params Params to send
* @return Promise
* @example
* client.notify("hello", ["world"])
*/
}, {
key: "notify",
value: function notify(method, params) {
return this.pcolInstance.notify(method, params);
}
/**
* Calls `request()` method on protocol instance
*/
}, {
key: "request",
value: function request() {
return this.pcolInstance.request();
}
/**
* Calls `batch()` method on protocol instance
*
* @param {JSON[]} requests Valid JSON-RPC batch request array
*/
}, {
key: "batch",
value: function batch(requests) {
return this.pcolInstance.batch(requests);
}
/**
* Clears pending timeouts kept in `timeouts` for the provided request IDs.
*
* @param {string[]|number[]} ids Array of request IDs
*/
}, {
key: "cleanUp",
value: function cleanUp(ids) {
// clear pending timeouts for these request ids
clearTimeout(this.timeouts[ids]);
delete this.timeouts[ids];
}
/**
* Subscribe the function to the given event name
*
* @param {string} method Method to subscribe to
* @param {function} cb Name of callback function to invoke on event
*/
}, {
key: "subscribe",
value: function subscribe(method, cb) {
if (!this.eventListenerList[method]) {
this.eventListenerList[method] = [];
} // add listener to event tracking list
this.eventListenerList[method].push({
type: method,
listener: cb
});
this.addEventListener(method, cb);
}
/**
* Unsubscribe the function from the given event name
*
* @param {string} method Method to unsubscribe from
* @param {function} cb Name of function to remove
*/
}, {
key: "unsubscribe",
value: function unsubscribe(method, cb) {
// remove listener
this.removeEventListener(method, cb); // Find the event in the list and remove it
this._removeListener(method, cb); // if no more events of the removed event method are left,remove the group
if (this.eventListenerList[method].length === 0) {
delete this.eventListenerList[method];
}
}
/**
* Unsubscribe all functions from given event name
*
* @param {string} method Method to unsubscribe all listeners from
*/
}, {
key: "unsubscribeAll",
value: function unsubscribeAll(method) {
if (!this.eventListenerList[method]) {
this.eventListenerList[method] = [];
} // remove listener
for (var j = 0; j < this.eventListenerList[method].length; j += 1) {
var cb = this.eventListenerList[method][j].listener; // remove listener
this.removeEventListener(method, cb); // Find the event in the list and remove it
this._removeListener(method, cb);
}
delete this.eventListenerList[method];
}
/**
* Remmove the callback function from the given event listener
*
* @param {method} method Method name to remove listener for
* @param {function} cb Function name to remove listener
* @private
*/
}, {
key: "_removeListener",
value: function _removeListener(method, cb) {
if (!this.eventListenerList[method]) {
this.eventListenerList[method] = [];
}
for (var i = 0; i < this.eventListenerList[method].length; i += 1) {
if (this.eventListenerList[method][i].listener === cb) {
this.eventListenerList[method].splice(i, 1);
break;
}
}
}
/**
* Get the list of event listeners attached to the given event name.
*
* @param {string} name The name of the event to retrieve listeners for
* @returns {function|function[]}
*/
}, {
key: "getEventListeners",
value: function getEventListeners(name) {
// return requested listeners by name or all them
if (name === undefined) {
return this.eventListenerList;
}
return this.eventListenerList[name];
}
}]);
return WsBrowserClientFactory;
}( /*#__PURE__*/_wrapNativeSuper(EventTarget));
module.exports = WsBrowserClientFactory;