UNPKG

@hms-networks/kolibri-js-client

Version:

Kolibri Consumer API client for building kolibri based applications

576 lines 27.7 kB
/* * Copyright 2021 HMS Industrial Networks AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http: //www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; import Url from 'url-parse'; import { Subscription } from './subscription'; import { KolibriConnection } from './kolibri_connection'; import { DefaultKolibriResponse, errorcode, errorFromCode, isJsonRpcError, isJsonRpcFailure, isJsonRpcRequest, isJsonRpcSuccess, isKolibriRpcError, isKolibriRpcRequest, isKolibriRpcSuccess, KolibriErrorResponse, KolibriRequestMethods, KolibriRpcErrorResponse, KolibriRpcSuccessResponse } from '@hms-networks/kolibri-js-core'; import { HttpsProxyAgent } from 'https-proxy-agent'; import { getRequestError } from '../error/kolibri_request_error'; var BaseClient = /** @class */ (function () { function BaseClient(config) { var _this = this; this.config = config; this.rpcId = 1; this.tId = 1; this.subscription = new Subscription(); this.writeTransactions = new Map(); this.consumerRpcs = new Map(); this.kolibriRpcs = new Map(); var urlStr = "".concat(config.host, "/").concat(config.project).concat(config.path); var brokerUrl = new Url(urlStr); if (config.port) { brokerUrl.set('port', config.port.toString()); } var connectionOptions = { url: brokerUrl, protocol: this.getKolibriProtocol(), tlsOptions: config.tls, reconnectOptions: config.reconnect, clientMessageListener: function (jsonrpc) { return _this.clientEventDispatcher(jsonrpc); } }; if (config.proxy) { var agent = new HttpsProxyAgent(config.proxy); connectionOptions.requestOptions = { agent: agent }; } this.connection = new KolibriConnection(connectionOptions); this.initBuildInConsumerRpcs(); this.registerKolibriRpc(KolibriRequestMethods.GetRpcInfoRequestMethod, this.handleGetRpcInfoRequest.bind(this)); if (this.config.auth) { this.loginParams = this.config.auth; } if (this.config.reconnect) { this.initReconnectHandler(); } this.connection.addOnDisconnectListener(function (event) { return __awaiter(_this, void 0, void 0, function () { var _a; return __generator(this, function (_b) { switch (_b.label) { case 0: return [4 /*yield*/, ((_a = this.onDisconnectListener) === null || _a === void 0 ? void 0 : _a.call(this, event))]; case 1: _b.sent(); return [2 /*return*/]; } }); }); }); } BaseClient.prototype.getNextRpcId = function () { return this.rpcId++; }; BaseClient.prototype.getNextTid = function () { return this.tId++; }; BaseClient.prototype.storeLoginData = function (params, result) { this.loginParams = params; this.loginResult = result; }; BaseClient.prototype.storeSubscribeData = function (params, result) { this.subscribeParams = params; this.subscribeResult = result; }; BaseClient.prototype.clearSubscribeData = function () { this.subscribeParams = undefined; this.subscribeResult = undefined; }; BaseClient.prototype.storeUserSubscribeData = function (params, result) { this.userSubscribeParams = params; this.userSubscribeResult = result; }; BaseClient.prototype.clearUserSubscribeData = function () { this.userSubscribeParams = undefined; this.userSubscribeResult = undefined; }; BaseClient.prototype.addOnUnsubscribed = function (listener) { this.subscription.onUnsubscribed = listener; }; BaseClient.prototype.addOnWriteListener = function (listener) { this.subscription.onWrite = listener; }; BaseClient.prototype.addOnUserNotifyListener = function (listener) { this.subscription.onUserNotify = listener; }; BaseClient.prototype.addOnErrorListener = function (listener) { this.subscription.onError = listener; }; BaseClient.prototype.addOnReconnectListener = function (listener) { this.onReconnectListener = listener; }; BaseClient.prototype.addOnDisconnectListener = function (listener) { this.onDisconnectListener = listener; }; BaseClient.prototype.connect = function () { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, this.connection.connect()]; }); }); }; BaseClient.prototype.disconnect = function () { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: this.rpcId = 1; this.tId = 1; this.connection.disableReconnect(); return [4 /*yield*/, this.connection.close()]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; BaseClient.prototype.sendKolibriRpcRequest = function (request) { return __awaiter(this, void 0, void 0, function () { var response; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.connection.sendRequest(request)]; case 1: response = _a.sent(); if (isKolibriRpcSuccess(response)) { return [2 /*return*/, response]; } else if (isKolibriRpcError(response)) { throw getRequestError(response.error.code, response.error.data); } else { throw new Error('Unknown response type!'); } return [2 /*return*/]; } }); }); }; BaseClient.prototype.sendKolibriRequest = function (kolibriRequest) { return __awaiter(this, void 0, void 0, function () { var response; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.connection.sendRequest(kolibriRequest)]; case 1: response = _a.sent(); if (isJsonRpcSuccess(response)) { return [2 /*return*/, response]; } else if (isJsonRpcFailure(response)) { throw getRequestError(response.error.code, response.error.data); } else { throw new Error('Unknown response type!'); } return [2 /*return*/]; } }); }); }; BaseClient.prototype.registerKolibriRpc = function (method, handler) { this.kolibriRpcs.set(method, handler.bind(this)); }; BaseClient.prototype.handleGetRpcInfoRequest = function (_args) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, Array.from(this.kolibriRpcs.keys())]; }); }); }; BaseClient.prototype.handleWriteRequest = function (request) { var _a, _b, _c, _d; return __awaiter(this, void 0, void 0, function () { var writeRequest, combinedWriteResult, response, e_1; var _this = this; return __generator(this, function (_e) { switch (_e.label) { case 0: writeRequest = request; combinedWriteResult = writeRequest.params.nodes .map(function (node) { var nodeProperties = _this.subscription.fetchSubscribedNode(node.path); if (!nodeProperties) return; return __assign(__assign({}, nodeProperties), node); }) .filter(function (elem) { return elem !== undefined; }); _e.label = 1; case 1: _e.trys.push([1, 3, , 4]); if (writeRequest.params.tid) { this.writeTransactions.set(writeRequest.params.tid, combinedWriteResult); } else if (combinedWriteResult.length !== 0) { (_b = (_a = this.subscription).onWrite) === null || _b === void 0 ? void 0 : _b.call(_a, combinedWriteResult); } response = new DefaultKolibriResponse(writeRequest.id, 0); return [4 /*yield*/, this.connection.sendResponse(response)]; case 2: _e.sent(); return [3 /*break*/, 4]; case 3: e_1 = _e.sent(); (_d = (_c = this.subscription).onError) === null || _d === void 0 ? void 0 : _d.call(_c, e_1); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); }; BaseClient.prototype.handleUnsubscribedRequest = function (request) { var _a, _b, _c, _d; return __awaiter(this, void 0, void 0, function () { var unsubscribedRequest, response, e_2; return __generator(this, function (_e) { switch (_e.label) { case 0: unsubscribedRequest = request; this.subscription.deleteSubscribedNodes(unsubscribedRequest.params); _e.label = 1; case 1: _e.trys.push([1, 3, , 4]); response = new DefaultKolibriResponse(request.id, 0); return [4 /*yield*/, this.connection.sendResponse(response)]; case 2: _e.sent(); (_b = (_a = this.subscription).onUnsubscribed) === null || _b === void 0 ? void 0 : _b.call(_a, unsubscribedRequest.params); return [3 /*break*/, 4]; case 3: e_2 = _e.sent(); (_d = (_c = this.subscription).onError) === null || _d === void 0 ? void 0 : _d.call(_c, e_2); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); }; BaseClient.prototype.handleUserNotifyRequest = function (request) { var _a, _b, _c, _d; return __awaiter(this, void 0, void 0, function () { var userNotifyRequest, response, e_3; return __generator(this, function (_e) { switch (_e.label) { case 0: userNotifyRequest = request; _e.label = 1; case 1: _e.trys.push([1, 3, , 4]); response = new DefaultKolibriResponse(request.id, 0); return [4 /*yield*/, this.connection.sendResponse(response)]; case 2: _e.sent(); (_b = (_a = this.subscription).onUserNotify) === null || _b === void 0 ? void 0 : _b.call(_a, userNotifyRequest.params); return [3 /*break*/, 4]; case 3: e_3 = _e.sent(); (_d = (_c = this.subscription).onError) === null || _d === void 0 ? void 0 : _d.call(_c, e_3); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); }; BaseClient.prototype.handleCommitRequest = function (request) { var _a, _b, _c, _d; return __awaiter(this, void 0, void 0, function () { var commitRequest, pendingWriteResult, response, e_4; return __generator(this, function (_e) { switch (_e.label) { case 0: commitRequest = request; pendingWriteResult = this.writeTransactions .get(commitRequest.params.tid); if (pendingWriteResult) { (_b = (_a = this.subscription).onWrite) === null || _b === void 0 ? void 0 : _b.call(_a, pendingWriteResult); } else { // could not match commit with pending transaction. Respond to broker anyway. } _e.label = 1; case 1: _e.trys.push([1, 3, 4, 5]); response = new DefaultKolibriResponse(commitRequest.id, 0); return [4 /*yield*/, this.connection.sendResponse(response)]; case 2: _e.sent(); return [3 /*break*/, 5]; case 3: e_4 = _e.sent(); (_d = (_c = this.subscription).onError) === null || _d === void 0 ? void 0 : _d.call(_c, e_4); return [3 /*break*/, 5]; case 4: this.writeTransactions.delete(commitRequest.params.tid); return [7 /*endfinally*/]; case 5: return [2 /*return*/]; } }); }); }; BaseClient.prototype.clientEventDispatcher = function (jsonrpc) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: if (!isJsonRpcRequest(jsonrpc)) { return [2 /*return*/]; } if (!isKolibriRpcRequest(jsonrpc)) return [3 /*break*/, 2]; return [4 /*yield*/, this.handleKolibriRpcRequest(jsonrpc)]; case 1: _a.sent(); return [3 /*break*/, 4]; case 2: return [4 /*yield*/, this.handleConsumerRpcRequest(jsonrpc)]; case 3: _a.sent(); _a.label = 4; case 4: return [2 /*return*/]; } }); }); }; BaseClient.prototype.handleConsumerRpcRequest = function (jsonrpc) { return __awaiter(this, void 0, void 0, function () { var handlerFunction, error, response; return __generator(this, function (_a) { switch (_a.label) { case 0: handlerFunction = this.consumerRpcs.get(jsonrpc.method); if (!!handlerFunction) return [3 /*break*/, 2]; error = errorFromCode(errorcode.METHOD_NOT_FOUND.code); error.data = jsonrpc.method; response = new /** @class */ (function (_super) { __extends(class_1, _super); function class_1() { return _super !== null && _super.apply(this, arguments) || this; } return class_1; }(KolibriErrorResponse))(jsonrpc.id, error); return [4 /*yield*/, this.connection.sendResponse(response)]; case 1: _a.sent(); return [2 /*return*/]; case 2: return [4 /*yield*/, handlerFunction(jsonrpc)]; case 3: _a.sent(); return [2 /*return*/]; } }); }); }; BaseClient.prototype.handleKolibriRpcRequest = function (jsonrpc) { return __awaiter(this, void 0, void 0, function () { var handlerFunction, response, error, result, e_5, ex_1, e_6; return __generator(this, function (_a) { switch (_a.label) { case 0: handlerFunction = this.kolibriRpcs.get(jsonrpc.method); if (!!handlerFunction) return [3 /*break*/, 2]; error = errorFromCode(errorcode.METHOD_NOT_FOUND.code); error.data = jsonrpc.method; response = new KolibriRpcErrorResponse(jsonrpc.id, jsonrpc._server, error); return [4 /*yield*/, this.connection.sendResponse(response)]; case 1: _a.sent(); return [2 /*return*/]; case 2: _a.trys.push([2, 4, , 9]); return [4 /*yield*/, handlerFunction(jsonrpc.params)]; case 3: result = _a.sent(); return [3 /*break*/, 9]; case 4: e_5 = _a.sent(); _a.label = 5; case 5: _a.trys.push([5, 7, , 8]); if (isJsonRpcError(e_5)) { response = new KolibriRpcErrorResponse(jsonrpc.id, jsonrpc._server, e_5); } else { response = new KolibriRpcErrorResponse(jsonrpc.id, jsonrpc._server, errorFromCode(errorcode.KOLIBRI_RPC_ERROR.code)); } return [4 /*yield*/, this.connection.sendResponse(response)]; case 6: _a.sent(); return [2 /*return*/]; case 7: ex_1 = _a.sent(); throw new Error('Failed to send error!'); case 8: return [3 /*break*/, 9]; case 9: _a.trys.push([9, 11, , 12]); response = new KolibriRpcSuccessResponse(jsonrpc.id, jsonrpc._server, result); return [4 /*yield*/, this.connection.sendResponse(response)]; case 10: _a.sent(); return [3 /*break*/, 12]; case 11: e_6 = _a.sent(); throw new Error('Failed to send result!'); case 12: return [2 /*return*/]; } }); }); }; BaseClient.prototype.initBuildInConsumerRpcs = function () { this.consumerRpcs.set(KolibriRequestMethods.WriteRequestMethod, this.handleWriteRequest.bind(this)); this.consumerRpcs.set(KolibriRequestMethods.UnsubscribedRequestMethod, this.handleUnsubscribedRequest.bind(this)); this.consumerRpcs.set(KolibriRequestMethods.UserNotifyRequestMethod, this.handleUserNotifyRequest.bind(this)); this.consumerRpcs.set(KolibriRequestMethods.CommitRequestMethod, this.handleCommitRequest.bind(this)); }; BaseClient.prototype.initReconnectHandler = function () { var _this = this; this.connection.addOnReconnectListener(function () { return __awaiter(_this, void 0, void 0, function () { var e_7, e_8; var _a, _b; return __generator(this, function (_c) { switch (_c.label) { case 0: _c.trys.push([0, 4, , 5]); return [4 /*yield*/, this.restoreLogin()]; case 1: _c.sent(); if (!((_a = this.config.reconnect) === null || _a === void 0 ? void 0 : _a.resumeSubscriptions)) return [3 /*break*/, 3]; // Restoring Subscriptions return [4 /*yield*/, this.restoreSubscriptions()]; case 2: // Restoring Subscriptions _c.sent(); _c.label = 3; case 3: return [3 /*break*/, 5]; case 4: e_7 = _c.sent(); throw new Error('Restoring client state failed!'); case 5: _c.trys.push([5, 7, , 8]); return [4 /*yield*/, ((_b = this.onReconnectListener) === null || _b === void 0 ? void 0 : _b.call(this))]; case 6: _c.sent(); return [3 /*break*/, 8]; case 7: e_8 = _c.sent(); return [3 /*break*/, 8]; case 8: return [2 /*return*/]; } }); }); }); }; BaseClient.prototype.restoreLogin = function () { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: if (!(this.loginParams && this.loginResult)) return [3 /*break*/, 2]; this.loginParams.client = this.loginResult.client; return [4 /*yield*/, this.login(this.loginParams)]; case 1: _a.sent(); return [3 /*break*/, 5]; case 2: if (!this.loginParams) return [3 /*break*/, 4]; return [4 /*yield*/, this.login(this.loginParams)]; case 3: _a.sent(); return [3 /*break*/, 5]; case 4: throw new Error('Unknown client state!'); case 5: return [2 /*return*/]; } }); }); }; BaseClient.prototype.restoreSubscriptions = function () { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: if (!(this.subscribeParams && this.subscribeResult)) return [3 /*break*/, 2]; return [4 /*yield*/, this.subscribe(this.subscribeParams)]; case 1: _a.sent(); _a.label = 2; case 2: if (!(this.userSubscribeParams && this.userSubscribeResult)) return [3 /*break*/, 4]; return [4 /*yield*/, this.userSubscribe(this.userSubscribeParams)]; case 3: _a.sent(); _a.label = 4; case 4: return [2 /*return*/]; } }); }); }; return BaseClient; }()); export { BaseClient }; //# sourceMappingURL=base_client.js.map