UNPKG

hdckit

Version:

A pure Node.js client for the OpenHarmony Device Connector

159 lines (158 loc) 5.24 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const node_net_1 = __importDefault(require("node:net")); const Emitter_1 = __importDefault(require("licia/Emitter")); const ChannelHandShake_1 = __importDefault(require("./ChannelHandShake")); const startWith_1 = __importDefault(require("licia/startWith")); const node_child_process_1 = require("node:child_process"); const node_util_1 = __importDefault(require("node:util")); const toStr_1 = __importDefault(require("licia/toStr")); const HANDSHAKE_MESSAGE = 'OHOS HDC'; class Connection extends Emitter_1.default { constructor(options) { super(); this.triedStarting = false; this.ended = false; this.options = options; } connect(connectKey) { const socket = node_net_1.default.connect(this.options); socket.setNoDelay(true); this.socket = socket; return new Promise((resolve, reject) => { socket.once('connect', async () => { try { await this.handshake(connectKey); resolve(null); } catch (e) { reject(e); } }); socket.once('error', reject); socket.once('end', () => { this.ended = true; this.socket = null; }); }) .catch((e) => { if (e.code === 'ECONNREFUSED' && !this.triedStarting) { this.triedStarting = true; return this.startServer().then(() => { return this.connect(connectKey); }); } else { this.end(); throw e; } }) .then(() => this); } end() { if (this.socket) { this.socket.end(); } } write(data) { return new Promise((resolve, reject) => { this.socket.write(data, (err) => { if (err) { reject(err); } else { resolve(null); } }); }); } readBytes(howMany) { const { socket } = this; let tryRead; let errorListener; let endListener; return new Promise((resolve, reject) => { tryRead = () => { if (howMany) { const chunk = socket.read(howMany); if (chunk) { howMany -= chunk.length; if (howMany === 0) { return resolve(chunk); } } if (this.ended) { return reject(new Error('ended')); } } else { return resolve(Buffer.alloc(0)); } }; endListener = () => { this.ended = true; return reject(new Error('ended')); }; errorListener = (err) => reject(err); socket.on('readable', tryRead); socket.on('error', errorListener); socket.on('end', endListener); tryRead(); }).finally(() => { socket.removeListener('readable', tryRead); socket.removeListener('error', errorListener); socket.removeListener('end', endListener); }); } readValue() { return this.readBytes(4).then((value) => { const length = value.readUInt32BE(0); return this.readBytes(length); }); } async readAll() { let all = Buffer.alloc(0); while (true) { try { const chunk = await this.readValue(); all = Buffer.concat([all, chunk]); } catch (e) { if (this.ended) { return all; } throw e; } } } async send(data) { const len = Buffer.alloc(4); len.writeUInt32BE(data.length, 0); await this.write(Buffer.concat([len, data])); } async handshake(connectKey) { const data = await this.readValue(); const channelHandShake = new ChannelHandShake_1.default(); channelHandShake.deserialize(data); if (!(0, startWith_1.default)(channelHandShake.banner.toString('utf8'), HANDSHAKE_MESSAGE)) { throw new Error('Channel Hello failed'); } if (connectKey) { channelHandShake.connectKey = connectKey; } await this.send(channelHandShake.serialize()); } async startServer() { const { port, bin } = this.options; return node_util_1.default.promisify(node_child_process_1.execFile)(bin, ['start'], { env: { ...process.env, OHOS_HDC_SERVER_PORT: (0, toStr_1.default)(port), }, }); } } exports.default = Connection;