UNPKG

androidtv-remote-slstn

Version:
275 lines (256 loc) 10 kB
import tls from "tls"; import { remoteMessageManager } from "./RemoteMessageManager.js"; import EventEmitter from "events"; class RemoteManager extends EventEmitter { constructor(host, port, certs) { super(); this.host = host; this.port = port; this.certs = certs; this.chunks = Buffer.from([]); this.error = null; } async start() { let isEmitedError = false; return new Promise((resolve, reject) => { let options = { key: this.certs.key, cert: this.certs.cert, port: this.port, host: this.host, rejectUnauthorized: false, }; console.debug("Start Remote Connect"); this.client = tls.connect(options, () => { //console.debug("Remote connected") }); this.client.on("timeout", () => { this.client.destroy(); if (!isEmitedError) { this.emit("error", { message: "Connection timeout" }); isEmitedError = true; } resolve({ state: "error", message: "Connection timeout" }); }); // Le ping est reçu toutes les 5 secondes this.client.setTimeout(10000); this.client.on("secureConnect", () => { console.debug(this.host + " Remote secureConnect"); resolve(true); }); this.client.on("data", (data) => { let buffer = Buffer.from(data); this.chunks = Buffer.concat([this.chunks, buffer]); if ( this.chunks.length > 0 && this.chunks.readInt8(0) === this.chunks.length - 1 ) { let message = remoteMessageManager.parse(this.chunks); if (!message.remotePingRequest) { //console.debug(this.host + " Receive : " + Array.from(this.chunks)); console.debug( this.host + " Receive : " + JSON.stringify(message.toJSON()) ); } if (message.remoteConfigure) { this.client.write( remoteMessageManager.createRemoteConfigure( 622, "Build.MODEL", "Build.MANUFACTURER", 1, "Build.VERSION.RELEASE" ) ); this.emit("ready"); } else if (message.remoteSetActive) { this.client.write(remoteMessageManager.createRemoteSetActive(622)); } else if (message.remotePingRequest) { this.client.write( remoteMessageManager.createRemotePingResponse( message.remotePingRequest.val1 ) ); } else if (message.remoteImeKeyInject) { this.emit( "current_app", message.remoteImeKeyInject.appInfo.appPackage ); } else if (message.remoteImeBatchEdit) { console.debug( "Receive IME BATCH EDIT" + message.remoteImeBatchEdit ); } else if (message.remoteImeShowRequest) { console.debug( "Receive IME SHOW REQUEST" + message.remoteImeShowRequest ); } else if (message.remoteVoiceBegin) { //console.debug("Receive VOICE BEGIN" + message.remoteVoiceBegin); } else if (message.remoteVoicePayload) { //console.debug("Receive VOICE PAYLOAD" + message.remoteVoicePayload); } else if (message.remoteVoiceEnd) { //console.debug("Receive VOICE END" + message.remoteVoiceEnd); } else if (message.remoteStart) { this.emit("powered", message.remoteStart.started); } else if (message.remoteSetVolumeLevel) { this.emit("volume", { level: message.remoteSetVolumeLevel.volumeLevel, maximum: message.remoteSetVolumeLevel.volumeMax, muted: message.remoteSetVolumeLevel.volumeMuted, }); //console.debug("Receive SET VOLUME LEVEL" + message.remoteSetVolumeLevel.toJSON().toString()); } else if (message.remoteSetPreferredAudioDevice) { //console.debug("Receive SET PREFERRED AUDIO DEVICE" + message.remoteSetPreferredAudioDevice); } else if (message.remoteError) { //console.debug("Receive REMOTE ERROR"); if (!isEmitedError) { this.emit("error", { message: message.remoteError }); isEmitedError = true; } resolve({ state: "error", message: message.remoteError }); } else { console.log("What else ?"); if (!isEmitedError) { this.emit("error", this.error); isEmitedError = true; } resolve({ state: "error", message: "Unknown error" }); } this.chunks = Buffer.from([]); } }); this.client.on("close", async (hasError) => { console.info(this.host + " Remote Connection closed ", hasError); if (hasError) { reject(this.error.code); if (this.error.code === "ECONNRESET") { this.emit("unpaired"); resolve({ state: "error", message: "Device is not paired" }); } else if (this.error.code === "ECONNREFUSED") { // L'appareil n'est pas encore prêt : on relance // await new Promise(resolve => setTimeout(resolve, 1000)); // await this.start().catch((error) => { // console.error(error); // }); if (!isEmitedError) { this.emit("error", { message: "Connection refused" }); isEmitedError = true; } resolve({ state: "error", message: "Connection refused" }); } else if (this.error.code === "EHOSTDOWN") { // L'appareil est down, on ne fait rien if (!isEmitedError) { this.emit("error", { message: "Host is down" }); isEmitedError = true; } resolve({ state: "error", message: "Host is down" }); } else if ( this.error.code === "ERR_SSL_SSLV3_ALERT_CERTIFICATE_UNKNOWN" ) { if (!isEmitedError) { this.emit("error", { message: "Certificate is revoked" }); isEmitedError = true; } resolve({ state: "error", message: "Certificate is revoked", }); } else { // Dans le doute on redémarre // await new Promise(resolve => setTimeout(resolve, 1000)); // await this.start().catch((error) => { // console.error(error); // }); if (!isEmitedError) { this.emit("error", this.error); isEmitedError = true; } resolve({ state: "error", message: "Unknown error" }); } } else { // Si pas d'erreur on relance. Si elle s'est éteinte alors une erreur empéchera de relancer encore // await new Promise((resolve) => setTimeout(resolve, 1000)); // await this.start().catch((error) => { // console.error(error); // }); if (this.error) { if (this.error.code === "ECONNRESET") { this.emit("unpaired"); resolve({ state: "error", message: "Device is not paired" }); } else if (this.error.code === "ECONNREFUSED") { // L'appareil n'est pas encore prêt : on relance // await new Promise(resolve => setTimeout(resolve, 1000)); // await this.start().catch((error) => { // console.error(error); // }); if (!isEmitedError) { this.emit("error", { message: "Connection refused" }); isEmitedError = true; } resolve({ state: "error", message: "Connection refused" }); } else if (this.error.code === "EHOSTDOWN") { // L'appareil est down, on ne fait rien if (!isEmitedError) { this.emit("error", { message: "Host is down" }); isEmitedError = true; } resolve({ state: "error", message: "Host is down" }); } else if ( this.error.code === "ERR_SSL_SSLV3_ALERT_CERTIFICATE_UNKNOWN" ) { if (!isEmitedError) { this.emit("error", { message: "Certificate is revoked" }); isEmitedError = true; } resolve({ state: "error", message: "Certificate is revoked", }); } else { // Dans le doute on redémarre // await new Promise(resolve => setTimeout(resolve, 1000)); // await this.start().catch((error) => { // console.error(error); // }); if (!isEmitedError) { this.emit("error", this.error); isEmitedError = true; } resolve({ state: "error", message: this.error.message }); } } else { console.log("Has no error"); resolve({ state: "success", message: "Has no error" }); } } }); this.client.on("error", (error) => { console.error(this.host, error); this.error = error; resolve({ state: "error", message: error.message }); }); }); } sendPower() { this.client.write( remoteMessageManager.createRemoteKeyInject( remoteMessageManager.RemoteDirection.SHORT, remoteMessageManager.RemoteKeyCode.KEYCODE_POWER ) ); } sendKey(key, direction) { this.client.write( remoteMessageManager.createRemoteKeyInject(direction, key) ); } sendAppLink(app_link) { this.client.write( remoteMessageManager.createRemoteRemoteAppLinkLaunchRequest(app_link) ); } stop() { this.client.destroy(); } } export { RemoteManager };