UNPKG

appium-lg-webos-driver

Version:
373 lines 18 kB
"use strict"; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var _LGWSClient_instances, _LGWSClient_url, _LGWSClient_urlSecure, _LGWSClient_ws, _LGWSClient_saveClientKey, _LGWSClient_useSecureWebsocket, _LGWSClient_cmdNum, _LGWSClient_log, _LGWSClient_remoteClient, _LGWSClient_remoteKeyCooldown, _LGWSClient_keystore, _LGWSClient_valueBox, _LGWSClient_keystoreId, _LGWSClient_clientKey, _LGWSClient_receiveResponse, _LGWSClient_sendMessage, _LGWSClient_authPayload_get, _LGWSClient_getKeystore, _LGWSClient_updateAuthStatus; Object.defineProperty(exports, "__esModule", { value: true }); exports.LGWSClient = exports.WsEvent = void 0; const ws_1 = __importDefault(require("ws")); const bluebird_1 = __importDefault(require("bluebird")); const constants_1 = require("./constants"); const support_1 = require("appium/support"); const path_1 = __importDefault(require("path")); const lg_remote_client_1 = require("./lg-remote-client"); exports.WsEvent = ({ CONNECT: 'connect', CLOSE: 'close', ERROR: 'error', OPEN: 'open', MESSAGE: 'message', }); class LGWSClient { /** * * @param {import('../types').LGSocketClientOpts} opts */ constructor({ url, urlSecure, useSecureWebsocket, valueBox, deviceName, log = support_1.logger.getLogger('LGWsClient'), saveClientKey = true, remoteKeyCooldown, }) { _LGWSClient_instances.add(this); /** @type {string} */ _LGWSClient_url.set(this, void 0); /** @type {string} */ _LGWSClient_urlSecure.set(this, void 0); /** @type {WebSocket|undefined} */ _LGWSClient_ws.set(this, void 0); /** @type {boolean} */ _LGWSClient_saveClientKey.set(this, void 0); /** @type {boolean} */ _LGWSClient_useSecureWebsocket.set(this, void 0); _LGWSClient_cmdNum.set(this, 0); /** @type {import('@appium/types').AppiumLogger} */ _LGWSClient_log.set(this, void 0); /** @type {LGRemoteClient|undefined} */ _LGWSClient_remoteClient.set(this, void 0); /** @type {number|undefined} */ _LGWSClient_remoteKeyCooldown.set(this, void 0); /** * @type {import('./valuebox').ValueWrapper<string>} */ _LGWSClient_keystore.set(this, void 0); /** @type {import('./valuebox').ValueBox} */ _LGWSClient_valueBox.set(this, void 0); /** * Unique identifier for key based on device name. * Also doubles as a filename. * @type {string} */ _LGWSClient_keystoreId.set(this, void 0); /** @type {string|undefined} */ _LGWSClient_clientKey.set(this, void 0); __classPrivateFieldSet(this, _LGWSClient_valueBox, valueBox, "f"); __classPrivateFieldSet(this, _LGWSClient_url, url, "f"); __classPrivateFieldSet(this, _LGWSClient_urlSecure, urlSecure, "f"); __classPrivateFieldSet(this, _LGWSClient_useSecureWebsocket, useSecureWebsocket, "f"); __classPrivateFieldSet(this, _LGWSClient_log, log, "f"); __classPrivateFieldSet(this, _LGWSClient_saveClientKey, saveClientKey, "f"); __classPrivateFieldSet(this, _LGWSClient_remoteKeyCooldown, remoteKeyCooldown, "f"); __classPrivateFieldSet(this, _LGWSClient_keystoreId, `clientKey-${deviceName}.txt`, "f"); } /** * @returns {Promise<void>} */ async connect() { await new bluebird_1.default((res, rej) => { /** @type {WebSocket} */ let ws; const onOpen = () => { ws.removeListener(exports.WsEvent.ERROR, onError); res(ws); }; /** @param {Error} err */ const onError = (err) => { ws.removeListener(exports.WsEvent.OPEN, onOpen); rej(err); }; if (__classPrivateFieldGet(this, _LGWSClient_useSecureWebsocket, "f")) { ws = new ws_1.default(__classPrivateFieldGet(this, _LGWSClient_urlSecure, "f"), { rejectUnauthorized: false }).once(exports.WsEvent.OPEN, onOpen).once(exports.WsEvent.ERROR, onError); } else { ws = new ws_1.default(__classPrivateFieldGet(this, _LGWSClient_url, "f")).once(exports.WsEvent.OPEN, onOpen).once(exports.WsEvent.ERROR, onError); } __classPrivateFieldSet(this, _LGWSClient_ws, ws, "f"); }); } /** * @returns {Promise<void>} */ async disconnect() { await new bluebird_1.default(async (res, rej) => { const onClose = () => { __classPrivateFieldGet(this, _LGWSClient_ws, "f")?.removeListener(exports.WsEvent.ERROR, onError); res(); }; /** @param {Error} err */ const onError = (err) => { __classPrivateFieldGet(this, _LGWSClient_ws, "f")?.removeListener(exports.WsEvent.CLOSE, onClose); rej(err); }; __classPrivateFieldGet(this, _LGWSClient_ws, "f")?.once(exports.WsEvent.CLOSE, onClose); __classPrivateFieldGet(this, _LGWSClient_ws, "f")?.once(exports.WsEvent.ERROR, onError); if (__classPrivateFieldGet(this, _LGWSClient_remoteClient, "f")) { try { await __classPrivateFieldGet(this, _LGWSClient_remoteClient, "f").disconnect(); } catch (err) { __classPrivateFieldGet(this, _LGWSClient_log, "f").warn(`Could not cleanly shut down remote client; err was: ${err}`); } finally { __classPrivateFieldSet(this, _LGWSClient_remoteClient, undefined, "f"); } } __classPrivateFieldGet(this, _LGWSClient_ws, "f")?.close(); }); } /** * * @returns {Promise<string>} */ async authenticate() { if (__classPrivateFieldGet(this, _LGWSClient_saveClientKey, "f")) { try { const keystore = await __classPrivateFieldGet(this, _LGWSClient_instances, "m", _LGWSClient_getKeystore).call(this); __classPrivateFieldGet(this, _LGWSClient_log, "f").info(`Trying to read key from file on disk at ${path_1.default.join(__classPrivateFieldGet(this, _LGWSClient_valueBox, "f").dir, keystore.id)}`); __classPrivateFieldSet(this, _LGWSClient_clientKey, keystore.value, "f"); __classPrivateFieldGet(this, _LGWSClient_log, "f").info(`Success: key is '${__classPrivateFieldGet(this, _LGWSClient_clientKey, "f")}'`); } catch (ign) { __classPrivateFieldGet(this, _LGWSClient_log, "f").info(`Could not read key from disk`); } } const origClientKey = __classPrivateFieldGet(this, _LGWSClient_clientKey, "f"); if (!(await __classPrivateFieldGet(this, _LGWSClient_instances, "m", _LGWSClient_updateAuthStatus).call(this))) { const { type, payload } = /** @type {InboundMsg<AuthPayload>} */ (await __classPrivateFieldGet(this, _LGWSClient_instances, "m", _LGWSClient_receiveResponse).call(this)); if (type === constants_1.MsgType.REGISTERED) { __classPrivateFieldSet(this, _LGWSClient_clientKey, payload['client-key'], "f"); } if (!(await __classPrivateFieldGet(this, _LGWSClient_instances, "m", _LGWSClient_updateAuthStatus).call(this))) { throw new Error('Could not authenticate, please accept prompt'); } } if (__classPrivateFieldGet(this, _LGWSClient_saveClientKey, "f") && __classPrivateFieldGet(this, _LGWSClient_clientKey, "f") !== undefined && __classPrivateFieldGet(this, _LGWSClient_clientKey, "f") !== origClientKey) { __classPrivateFieldGet(this, _LGWSClient_log, "f").info(`Client key changed, writing it to disk`); const keystore = await __classPrivateFieldGet(this, _LGWSClient_instances, "m", _LGWSClient_getKeystore).call(this); await keystore.put(__classPrivateFieldGet(this, _LGWSClient_clientKey, "f")); } return /** @type {string} */ (__classPrivateFieldGet(this, _LGWSClient_clientKey, "f")); } /** * * @param {any} msg * @returns {msg is import('../types').RegisteredMsg} */ static isRegisteredMsg(msg) { return msg.type === constants_1.MsgType.REGISTERED; } /** * * @param {any} msg * @returns {msg is import('../types').PromptMsg} */ static isPromptMsg(msg) { return msg.type === constants_1.MsgType.RESPONSE && msg.payload?.pairingType === 'PROMPT'; } /** * * @returns {Promise<string>} */ async initialize() { await this.connect(); return await this.authenticate(); } /** * @template {import('./constants').MessageType} T * @template {SerializableObject|void} [P=void] * @template {SerializableObject} [R=any] * @param {T} type * @param {string} [uri] * @param {T extends 'register' ? AuthPayload : P} [payload] * @returns {Promise<InboundMsg<R>>} */ async command(type, uri, payload = /** @type {T extends 'register' ? AuthPayload : P} */ ({})) { var _a, _b; /** @type {OutboundMsg<T extends 'register' ? AuthPayload : P>} */ const msg = { id: `${type}_${__classPrivateFieldSet(this, _LGWSClient_cmdNum, (_b = __classPrivateFieldGet(this, _LGWSClient_cmdNum, "f"), _a = _b++, _b), "f"), _a}`, type, payload, }; if (uri) { msg.uri = uri; } const res = /** @type {InboundMsg<R>} */ (await __classPrivateFieldGet(this, _LGWSClient_instances, "m", _LGWSClient_sendMessage).call(this, msg)); if (res?.type === constants_1.MsgType.ERROR) { throw new Error(res?.error); } return res; } /** * @template {SerializableObject|void} [P=void] * @template {SerializableObject} [R=any] * @param {string} uri * @param {P} [payload] * @returns {Promise<R|undefined>} */ async request(uri, payload = /** @type {P} */ ({})) { if (!__classPrivateFieldGet(this, _LGWSClient_clientKey, "f")) { throw new Error(`Can't send request without client key set`); } const res = await this.command(constants_1.MsgType.REQUEST, uri, payload); return res?.payload; } // API commands async getListApps() { const uri = 'ssap://com.webos.applicationManager/listApps'; return await this.request(uri); } async getForegroundAppInfo() { const uri = 'ssap://com.webos.applicationManager/getForegroundAppInfo'; return await this.request(uri); } async getRemoteClient() { if (!__classPrivateFieldGet(this, _LGWSClient_remoteClient, "f")) { const uri = 'ssap://com.webos.service.networkinput/getPointerInputSocket'; const { socketPath } = await this.request(uri); __classPrivateFieldSet(this, _LGWSClient_remoteClient, new lg_remote_client_1.LGRemoteClient({ url: socketPath, log: __classPrivateFieldGet(this, _LGWSClient_log, "f"), keyCooldown: __classPrivateFieldGet(this, _LGWSClient_remoteKeyCooldown, "f"), }), "f"); await __classPrivateFieldGet(this, _LGWSClient_remoteClient, "f").connect(); } return __classPrivateFieldGet(this, _LGWSClient_remoteClient, "f"); } async getServiceList() { const res = await this.request('ssap://api/getServiceList'); return res?.services; } async getVolume() { const res = await this.request('ssap://audio/getVolume'); return res?.volumeStatus; } async volumeUp() { return await this.request('ssap://audio/volumeUp'); } async volumeDown() { return await this.request('ssap://audio/volumeDown'); } async mute() { return await this.request('ssap://audio/setMute', { mute: true }); } async unmute() { return await this.request('ssap://audio/setMute', { mute: false }); } async play() { return await this.request('ssap://media.controls/play'); } async stop() { return await this.request('ssap://media.controls/stop'); } async rewind() { return await this.request('ssap://media.controls/rewind'); } async fastForward() { return await this.request('ssap://media.controls/fastForward'); } async channelDown() { return await this.request('ssap://tv/channelDown'); } async channelUp() { return await this.request('ssap://tv/channelUp'); } } exports.LGWSClient = LGWSClient; _LGWSClient_url = new WeakMap(), _LGWSClient_urlSecure = new WeakMap(), _LGWSClient_ws = new WeakMap(), _LGWSClient_saveClientKey = new WeakMap(), _LGWSClient_useSecureWebsocket = new WeakMap(), _LGWSClient_cmdNum = new WeakMap(), _LGWSClient_log = new WeakMap(), _LGWSClient_remoteClient = new WeakMap(), _LGWSClient_remoteKeyCooldown = new WeakMap(), _LGWSClient_keystore = new WeakMap(), _LGWSClient_valueBox = new WeakMap(), _LGWSClient_keystoreId = new WeakMap(), _LGWSClient_clientKey = new WeakMap(), _LGWSClient_instances = new WeakSet(), _LGWSClient_receiveResponse = /** * @template {SerializableObject} [R=any] * @returns {Promise<InboundMsg<R>>} */ async function _LGWSClient_receiveResponse() { return await new bluebird_1.default((res, rej) => { /** @param {string} msg */ const onMsg = (msg) => { __classPrivateFieldGet(this, _LGWSClient_log, "f").debug(`Got response: ${msg}`); try { res(JSON.parse(msg)); } catch (err) { onError(/** @type {Error} */ (err)); } }; /** @param {Error} err */ const onError = (err) => { __classPrivateFieldGet(this, _LGWSClient_ws, "f")?.removeListener(exports.WsEvent.MESSAGE, onMsg); rej(err); }; __classPrivateFieldGet(this, _LGWSClient_ws, "f")?.once(exports.WsEvent.MESSAGE, onMsg); __classPrivateFieldGet(this, _LGWSClient_ws, "f")?.once(exports.WsEvent.ERROR, onError); }); }, _LGWSClient_sendMessage = /** * @template {SerializableObject|void} [P=void] * @template {SerializableObject} [R=any] * @param {OutboundMsg<P>} msgObj * @returns {Promise<InboundMsg<R>>} */ async function _LGWSClient_sendMessage(msgObj) { const msg = JSON.stringify(msgObj); __classPrivateFieldGet(this, _LGWSClient_log, "f").debug(`Sending message: ${msg}`); __classPrivateFieldGet(this, _LGWSClient_ws, "f")?.send(msg); return await __classPrivateFieldGet(this, _LGWSClient_instances, "m", _LGWSClient_receiveResponse).call(this); }, _LGWSClient_authPayload_get = function _LGWSClient_authPayload_get() { /** @type {AuthPayload} */ const payload = { ...constants_1.AUTH_PAYLOAD }; if (__classPrivateFieldGet(this, _LGWSClient_clientKey, "f")) { payload['client-key'] = __classPrivateFieldGet(this, _LGWSClient_clientKey, "f"); } return payload; }, _LGWSClient_getKeystore = /** * Gets / initializes the keystore based on the keystore ID * @see {@linkcode #keystoreId} * @returns {Promise<import('./valuebox').ValueWrapper<string>>} */ async function _LGWSClient_getKeystore() { return (__classPrivateFieldGet(this, _LGWSClient_keystore, "f") ?? (__classPrivateFieldSet(this, _LGWSClient_keystore, await __classPrivateFieldGet(this, _LGWSClient_valueBox, "f").createWrapper(__classPrivateFieldGet(this, _LGWSClient_keystoreId, "f")), "f"))); }, _LGWSClient_updateAuthStatus = /** * Resolver `true` if registered, `false` if not. * @returns {Promise<boolean>} */ async function _LGWSClient_updateAuthStatus() { const msg = await this.command(constants_1.MsgType.REGISTER, undefined, __classPrivateFieldGet(this, _LGWSClient_instances, "a", _LGWSClient_authPayload_get)); if (LGWSClient.isRegisteredMsg(msg)) { __classPrivateFieldSet(this, _LGWSClient_clientKey, msg.payload['client-key'], "f"); return true; } else if (LGWSClient.isPromptMsg(msg)) { return false; } throw new Error(`Could not determine auth status; client is not registered, but no prompt is available`); }; /** * @typedef {import('./constants').AuthPayload} AuthPayload * @typedef {import('../types').SerializableObject} SerializableObject */ /** * @template {SerializableObject} [P=any] * @typedef {import('../types').InboundMsg<P>} InboundMsg */ /** * @template {SerializableObject|void} [P=void] * @typedef {import('../types').OutboundMsg<P>} OutboundMsg */ //# sourceMappingURL=lg-socket-client.js.map