@hms-networks/kolibri-js-client
Version:
Kolibri Consumer API client for building kolibri based applications
576 lines • 27.7 kB
JavaScript
/*
* 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