kodi-api
Version:
A complete implementation of Kodi JSON-RPC calls in an easy-to-use Javascript/TypeScript client.
97 lines (96 loc) • 3.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebSocketClient = void 0;
const rpc_websocket_client_1 = require("rpc-websocket-client");
const uuid_1 = require("uuid");
/** Custom class for web socket interactions with JSON-RPC. */
class WebSocketClient {
constructor(options = {}) {
const config = {
host: 'localhost',
port: 9090,
closeOnRequest: true,
...options
};
this.closeOnRequest = config.closeOnRequest;
this.connected = false;
this.url = 'ws://' + config.host + ':' + config.port.toString() + '/jsonrpc';
this.nextId = '';
}
/** Closely matches the type from Jayson/promise import. */
async request(method, params, id) {
if (!this.connected)
await this.connect(this.url);
if (typeof id === 'string')
this.nextId = id;
const result = await this.io.call(method, params);
if (this.closeOnRequest)
await this.disconnect();
return {
id: typeof id === 'string' ? id : this.lastId,
jsonrpc: '2.0',
result
};
}
/** Custom unique ID function following internal state. */
id() {
// If no `nextId` was cached, generate a unique id.
if (this.nextId === '') {
const id = uuid_1.v4();
this.lastId = id;
return id;
}
// Use the cached id, and reset `nextId` when done.
const id = this.nextId;
this.lastId = id;
this.nextId = '';
return id;
}
/** Manage custom connection logic. */
async connect(url) {
this.io = new rpc_websocket_client_1.RpcWebSocketClient();
this.io.onOpen(() => {
this.connected = true;
});
this.io.onClose(() => {
this.connected = false;
});
this.io.customId(() => this.id());
if (typeof url === 'string') {
await this.io.connect(url);
}
else {
await this.io.connect(this.url);
}
if (typeof this.io.ws === 'object') {
const onmessage = this.io.ws.onmessage;
this.io.ws.onmessage = (e) => {
// Handle syntax errors due to intermittent issues with non-string/non-JSON data on Kodi web socket.
try {
onmessage(e);
}
catch (err) {
for (const handler of this.io.onErrorResponse) {
handler(err);
}
}
};
}
}
/** Manage graceful disconnect from web socket. */
async disconnect() {
const close = new Promise((resolve, reject) => {
let ioHandler = (e) => { };
if (typeof this.io.ws.onclose === 'function') {
ioHandler = this.io.ws.onclose;
}
this.io.ws.onclose = (e) => {
ioHandler(e);
resolve(void 0);
};
this.io.ws.close();
});
return await close;
}
}
exports.WebSocketClient = WebSocketClient;