UNPKG

@bitrix24/b24jssdk

Version:

Bitrix24 REST API JavaScript SDK

211 lines (208 loc) 5.98 kB
/** * @package @bitrix24/b24jssdk * @version 1.0.1 * @copyright (c) 2026 Bitrix24 * @license MIT * @see https://github.com/bitrix24/b24jssdk * @see https://bitrix24.github.io/b24jssdk/ */ import { ErrorNotConnected, ErrorTimeout } from './errors.mjs'; import { Type } from '../tools/type.mjs'; import { Text } from '../tools/text.mjs'; import { ListRpcError } from '../types/pull.mjs'; import { LoggerFactory } from '../logger/logger-factory.mjs'; var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); const JSON_RPC_VERSION = "2.0"; class JsonRpc { static { __name(this, "JsonRpc"); } _logger; _connector; _idCounter = 0; _handlers = {}; _rpcResponseAwaiters = /* @__PURE__ */ new Map(); constructor(options) { this._logger = LoggerFactory.createNullLogger(); this._connector = options.connector; if (Type.isPlainObject(options.handlers)) { for (const method in options.handlers) { this.handle(method, options.handlers[method]); } } } setLogger(logger) { this._logger = logger; } getLogger() { return this._logger; } /** * @param {string} method * @param {function} handler */ handle(method, handler) { this._handlers[method] = handler; } /** * Sends RPC command to the server. * * @param {string} method Method name * @param {object} params * @param {int} timeout * @returns {Promise} */ async executeOutgoingRpcCommand(method, params, timeout = 5) { return new Promise((resolve, reject) => { const request = this.createRequest(method, params); if (!this._connector.send(JSON.stringify(request))) { reject(new ErrorNotConnected("websocket is not connected")); } const timeoutHandler = setTimeout(() => { this._rpcResponseAwaiters.delete(request.id); reject(new ErrorTimeout("no response")); }, timeout * 1e3); this._rpcResponseAwaiters.set(request.id, { resolve, reject, timeout: timeoutHandler }); }); } /** * Executes array or rpc commands. * Returns an array of promises, each promise will be resolved individually. * * @param {JsonRpcRequest[]} batch * @returns {Promise[]} */ // @ts-expect-error When we rewrite it to something more modern, then we'll remove this executeOutgoingRpcBatch(batch) { const requests = []; const promises = []; batch.forEach(({ method, params, id }) => { const request = this.createRequest(method, params, id); requests.push(request); promises.push( new Promise( (resolve, reject) => this._rpcResponseAwaiters.set(request.id, { resolve, reject }) ) ); }); this._connector.send(JSON.stringify(requests)); return promises; } processRpcResponse(response) { if ("id" in response && this._rpcResponseAwaiters.has(Number(response.id))) { const awaiter = this._rpcResponseAwaiters.get(Number(response.id)); if (awaiter) { if ("result" in response) { awaiter.resolve(response.result); } else if ("error" in response) { awaiter.reject(response?.error || "error"); } else { awaiter.reject("wrong response structure"); } clearTimeout(awaiter.timeout); this._rpcResponseAwaiters.delete(Number(response.id)); } return; } this.getLogger().error(`${Text.getDateForLog()}: Pull: Received rpc response with unknown id`, { response }); } parseJsonRpcMessage(message) { let decoded; try { decoded = JSON.parse(message); } catch (error) { this.getLogger().error( `${Text.getDateForLog()}: Pull: Could not decode json rpc message`, { error } ); return []; } if (Type.isArray(decoded)) { return this.executeIncomingRpcBatch(decoded); } else if (Type.isJsonRpcRequest(decoded)) { return this.executeIncomingRpcCommand(decoded); } else if (Type.isJsonRpcResponse(decoded)) { this.processRpcResponse(decoded); return []; } else { this.getLogger().error( `${Text.getDateForLog()}: Pull: unknown rpc packet`, { decoded } ); } return []; } /** * Executes RPC command, received from the server * * @param {string} method * @param {object} params * @returns {object} RpcCommandResult */ executeIncomingRpcCommand({ method, params }) { if (method in this._handlers) { return this._handlers[method].call(this, params || {}); } return { jsonrpc: JSON_RPC_VERSION, error: ListRpcError.MethodNotFound }; } executeIncomingRpcBatch(batch) { const result = []; for (const command of batch) { if ("jsonrpc" in command) { if ("method" in command) { const commandResult = this.executeIncomingRpcCommand(command); if (commandResult) { commandResult["jsonrpc"] = JSON_RPC_VERSION; commandResult["id"] = command["id"]; result.push(commandResult); } } else { this.processRpcResponse(command); } } else { this.getLogger().error( `${Text.getDateForLog()}: Pull: unknown rpc command in batch`, { command } ); result.push({ jsonrpc: JSON_RPC_VERSION, error: ListRpcError.InvalidRequest }); } } return result; } nextId() { return ++this._idCounter; } createPublishRequest(messageBatch) { return messageBatch.map((message) => this.createRequest("publish", message)); } createRequest(method, params, id) { if (!id) { id = this.nextId(); } return { jsonrpc: JSON_RPC_VERSION, method, params, id }; } } export { JsonRpc }; //# sourceMappingURL=json-rpc.mjs.map