UNPKG

@litert/televoke

Version:
194 lines 6.92 kB
"use strict"; /** * Copyright 2025 Angus.Fenying <fenying@litert.org> * * 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 * * https://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. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.createJsonApiClient = createJsonApiClient; const Shared = require("../shared"); const cC = require("./Client.Constants"); const node_events_1 = require("node:events"); const Channel_impl_1 = require("../shared/Channel.impl"); const v2 = require("../shared/Encodings/v2"); const Utils_1 = require("../shared/Utils"); let channelIdCounter = Date.now(); class TvJsonApiClient extends node_events_1.EventEmitter { constructor(_connector, timeout, _streamManagerFactory) { super(); this._connector = _connector; this.timeout = timeout; this._streamManagerFactory = _streamManagerFactory; this._channel = null; this._connecting = null; this._onChannelClose = () => { this._channel?.off('close', this._onChannelClose) .off('push_message', this._onMessage); this._channel = null; this.emit('close'); }; this._onMessage = (msg) => { this.emit('push_message', msg); }; this._onError = (e) => { this.emit('error', e); }; } get streams() { const ret = this._channel?.streams; if (!ret) { throw new Shared.errors.channel_inactive(); } return ret; } get transporter() { return this._channel?.transporter ?? null; } get ended() { return false !== this._channel?.ended; } get finished() { return false !== this._channel?.finished; } get writable() { return false !== this._channel?.writable; } async _getChannel() { if (this._channel?.transporter?.writable) { // debugLog('televoke', 'Reusing existing channel.'); return this._channel; } if (this._connecting) { // debugLog('televoke', 'Waiting for previous connection to be established.'); return this._connecting; } try { // debugLog('televoke', 'Attempting to connect...'); return this._channel = await (this._connecting = this._connect()); } catch (e) { // debugLog('televoke', 'Attempts to connect failed.'); this._channel = null; this._connecting = null; throw e; } finally { // debugLog('televoke', 'Attempts to connect finished.'); this._connecting = null; } } async _connect() { this._channel = new TvClientChannel(await this._connector.connect(), this._streamManagerFactory, this.timeout) .on('close', this._onChannelClose) .on('error', this._onError) .on('push_message', this._onMessage); return this._channel; } async invoke(name, ...args) { try { const resp = await (await this._getChannel()).apiCall(name, JSON.stringify(args), cC.EArgsEncodings.JSON); return (0, Utils_1.buffer2json)(resp.body); } catch (e) { if (e instanceof Shared.errors.app_error) { let info; try { info = JSON.parse(e.message); } catch { throw e; } throw new Shared.TvErrorResponse(info); } throw e; } } async callApi(name, args, opts) { try { const resp = await (await this._getChannel()).apiCall(name, JSON.stringify(args), cC.EArgsEncodings.JSON, opts?.binChunks); return { result: (0, Utils_1.buffer2json)(resp.body), binChunks: resp.binChunks, }; } catch (e) { if (e instanceof Shared.errors.app_error) { let info; try { info = JSON.parse(e.message); } catch { throw e; } throw new Shared.TvErrorResponse(info); } throw e; } } close() { this._channel?.close(); // this._onChannelClose(); } async ping(msg) { return (await this._getChannel()).ping(msg); } async connect() { await this._getChannel(); } async sendBinaryChunk(streamId, index, chunk) { return (await this._getChannel()).sendBinaryChunk(streamId, index, chunk); } } class TvClientChannel extends Channel_impl_1.AbstractTvChannelV2 { constructor(transporter, streamManagerFactory, timeout = 60000) { super(channelIdCounter++, transporter, timeout, streamManagerFactory); } apiCall(name, argsBody, argsEncoding, extBinaryChunks) { if (!this.writable) { return Promise.reject(new Shared.errors.channel_inactive()); } const seq = this._seqCounter++; this.transporter.write(Channel_impl_1.encoder.encode({ 'typ': v2.EPacketType.REQUEST, 'cmd': v2.ECommand.API_CALL, 'seq': seq, 'ct': { 'name': name, 'body': argsBody, 'bodyEnc': argsEncoding, 'binChunks': extBinaryChunks, } })); return new Promise((resolve, reject) => { this._setTimeout(v2.ECommand.API_CALL, seq, (resp) => { if (resp.ct instanceof Shared.TelevokeError) { reject(resp.ct); return; } resolve(resp.ct); }); }); } } /** * Create a JSON-RPC client instance, over televoke2 protocol. * * @param connector The connector instance. * @param streamManagerFactory The stream manager factory function. [default: createSharedStreamManagerFactory()] * @param timeout The default timeout value of commands, in milliseconds. [default: 60000] * @returns The client instance. */ function createJsonApiClient(connector, streamManagerFactory = Shared.createSharedStreamManagerFactory(), timeout = 60000) { return new TvJsonApiClient(connector, timeout, streamManagerFactory); } //# sourceMappingURL=JsonApiClient.impl.js.map