Split status listener handling into class

This commit is contained in:
hensm
2019-04-11 06:42:24 +01:00
parent 11f87d20ae
commit 158d792ec0
2 changed files with 95 additions and 100 deletions

80
app/src/StatusListener.ts Normal file
View File

@@ -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" });
});
}
}

View File

@@ -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<string, StatusListener>();
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<string, StatusListener>();
/**
* 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);
}