From 158d792ec0ccd8e3d086efb7e8b933aa0ae0fe71 Mon Sep 17 00:00:00 2001 From: hensm Date: Thu, 11 Apr 2019 06:42:24 +0100 Subject: [PATCH] Split status listener handling into class --- app/src/StatusListener.ts | 80 ++++++++++++++++++++++++++ app/src/main.ts | 115 +++++--------------------------------- 2 files changed, 95 insertions(+), 100 deletions(-) create mode 100644 app/src/StatusListener.ts diff --git a/app/src/StatusListener.ts b/app/src/StatusListener.ts new file mode 100644 index 0000000..2e292ae --- /dev/null +++ b/app/src/StatusListener.ts @@ -0,0 +1,80 @@ +"use strict"; + +import { Channel, Client } from "castv2"; +import { EventEmitter } from "events"; + +const NS_CONNECTION = "urn:x-cast:com.google.cast.tp.connection"; +const NS_HEARTBEAT = "urn:x-cast:com.google.cast.tp.heartbeat"; +const NS_RECEIVER = "urn:x-cast:com.google.cast.receiver"; + + +/** + * Creates a connection to a receiver device and forwards + * RECEIVER_STATUS updates to the extension. + */ +export default class StatusListener extends EventEmitter { + private client: Client; + private clientReceiver: Channel; + private clientHeartbeatIntervalId: number; + + constructor ( + private host: string + , private port: number) { + + super(); + + this.client = new Client(); + this.client.connect({ host, port }, this.onConnect.bind(this)); + + this.client.on("close", () => { + clearInterval(this.clientHeartbeatIntervalId); + }); + } + + /** + * Closes status listener connection. + */ + public deregister (): void { + this.clientReceiver.send({ type: "CLOSE" }); + this.client.close(); + } + + + private onConnect (): void { + const sourceId = "sender-0"; + const destinationId = "receiver-0"; + + const clientConnection = this.client.createChannel( + sourceId, destinationId, NS_CONNECTION, "JSON"); + const clientHeartbeat = this.client.createChannel( + sourceId, destinationId, NS_HEARTBEAT, "JSON"); + const clientReceiver = this.client.createChannel( + sourceId, destinationId, NS_RECEIVER, "JSON"); + + clientReceiver.on("message", data => { + switch (data.type) { + case "CLOSE": { + this.client.close(); + break; + } + + case "RECEIVER_STATUS": { + // Send update message + this.emit("statusUpdate", data.status); + + break; + } + } + }); + + clientConnection.send({ type: "CONNECT" }); + clientHeartbeat.send({ type: "PING" }); + clientReceiver.send({ type: "GET_STATUS", requestId: 1 }); + + this.clientReceiver = clientReceiver; + + this.clientHeartbeatIntervalId = setInterval(() => { + clientHeartbeat.send({ type: "PING" }); + }); + } +} diff --git a/app/src/main.ts b/app/src/main.ts index 350a9ae..cead592 100755 --- a/app/src/main.ts +++ b/app/src/main.ts @@ -8,21 +8,15 @@ import path from "path"; import Media from "./Media"; import Session from "./Session"; +import StatusListener from "./StatusListener"; import * as transforms from "./transforms"; -import { Channel, Client } from "castv2"; - import { Message } from "./types"; import { __applicationName , __applicationVersion } from "../package.json"; -const NS_CONNECTION = "urn:x-cast:com.google.cast.tp.connection"; -const NS_HEARTBEAT = "urn:x-cast:com.google.cast.tp.heartbeat"; -const NS_RECEIVER = "urn:x-cast:com.google.cast.receiver"; - - // Increase listener limit events.EventEmitter.defaultMaxListeners = 50; @@ -188,13 +182,24 @@ async function handleMessage (message: Message) { } function initialize (options: InitializeOptions) { + const statusListeners = new Map(); + browser.on("serviceUp", (service: dnssd.Service) => { const address = service.addresses[0]; const port = service.port; const id = service.txt.id; if (options.shouldWatchStatus) { - registerStatusListener(address, port, id); + const listener = new StatusListener(address, port); + + listener.on("statusUpdate", (status: any) => { + sendMessage({ + subject: "main:/receiverStatusUpdate" + , data: { id, status } + }); + }); + + statusListeners.set(id, listener); } transforms.encode.write({ @@ -210,8 +215,8 @@ function initialize (options: InitializeOptions) { browser.on("serviceDown", (service: dnssd.Service) => { const id = service.txt.id; - if (options.shouldWatchStatus) { - deregisterStatusListener(id); + if (options.shouldWatchStatus && statusListeners.has(id)) { + statusListeners.get(id).deregister(); } transforms.encode.write({ @@ -222,93 +227,3 @@ function initialize (options: InitializeOptions) { browser.start(); } - - -interface StatusListener { - client: Client; - clientReceiver: Channel; -} - -// Map of client connections -const statusListeners = new Map(); - -/** - * Creates a connection to a receiver device and forwards - * RECEIVER_STATUS updates to the extension. - */ -function registerStatusListener ( - host: string - , port: number - , id: string) { - - const client = new Client(); - - const sourceId = "sender-0"; - const destinationId = "receiver-0"; - - let heartbeatIntervalId: number; - - client.connect({ host, port }, () => { - const clientConnection = client.createChannel( - sourceId, destinationId, NS_CONNECTION, "JSON"); - const clientHeartbeat = client.createChannel( - sourceId, destinationId, NS_HEARTBEAT, "JSON"); - const clientReceiver = client.createChannel( - sourceId, destinationId, NS_RECEIVER, "JSON"); - - - clientReceiver.on("message", data => { - switch (data.type) { - case "CLOSE": { - client.close(); - break; - } - - case "RECEIVER_STATUS": { - // Send update message - transforms.encode.write({ - subject: "main:/receiverStatusUpdate" - , data: { - id - , status: data.status - } - }); - - break; - } - } - }); - - clientConnection.send({ type: "CONNECT" }); - clientHeartbeat.send({ type: "PING" }); - clientReceiver.send({ type: "GET_STATUS", requestId: 1 }); - - heartbeatIntervalId = setInterval(() => { - clientHeartbeat.send({ type: "PING" }); - }); - - statusListeners.set(id, { - client - , clientReceiver - }); - }); - - client.on("close", () => { - clearInterval(heartbeatIntervalId); - }); -} - -/** - * Closes status listener connection for a given receiver - * device. - */ -function deregisterStatusListener (id: string) { - const { client, clientReceiver } = statusListeners.get(id); - - // Cleanup - clientReceiver.send({ type: "CLOSE" }); - client.close(); - - // Remove from map - statusListeners.delete(id); -}