Move app StatusListener to discovery module

This commit is contained in:
hensm
2021-04-28 07:02:46 +01:00
parent f44d142631
commit 298a833ebb
2 changed files with 112 additions and 98 deletions

View File

@@ -1,86 +0,0 @@
"use strict";
import { Channel, Client } from "castv2";
import { EventEmitter } from "events";
import { NS_CONNECTION
, NS_HEARTBEAT
, NS_RECEIVER } from "./Session";
/**
* 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?: NodeJS.Timeout;
constructor(host: string, port: number) {
super();
this.client = new Client();
this.client.connect({ host, port }, this.onConnect.bind(this));
this.client.on("close", () => {
clearInterval(this.clientHeartbeatIntervalId!);
});
this.client.on("error", () => {
clearInterval(this.clientHeartbeatIntervalId!);
});
}
/**
* Closes status listener connection.
*/
public deregister(): void {
if (this.clientReceiver) {
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": {
this.emit("receiverStatus", data.status);
break;
}
case "MEDIA_STATUS": {
this.emit("mediaStatus", 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" });
}, 5000);
}
}

View File

@@ -1,5 +1,8 @@
"use strict"; "use strict";
import { EventEmitter } from "events";
import { Channel, Client } from "castv2";
import mdns from "mdns"; import mdns from "mdns";
import { sendMessage } from "../lib/nativeMessaging"; import { sendMessage } from "../lib/nativeMessaging";
@@ -7,7 +10,9 @@ import { sendMessage } from "../lib/nativeMessaging";
import { ReceiverStatus } from "../types"; import { ReceiverStatus } from "../types";
import { Message } from "../messaging"; import { Message } from "../messaging";
import StatusListener from "./chromecast/StatusListener"; import { NS_CONNECTION
, NS_HEARTBEAT
, NS_RECEIVER } from "./chromecast/Session";
interface CastTxtRecord { interface CastTxtRecord {
@@ -29,28 +34,36 @@ const browser = mdns.createBrowser(mdns.tcp("googlecast"), {
}); });
function onBrowserServiceUp(service: mdns.Service) { function onBrowserServiceUp(service: mdns.Service) {
// Ignore without txt record // Ignore without txt record / name
if (!service.txtRecord) { if (!service.txtRecord || !service.name) {
return; return;
} }
const txtRecord = service.txtRecord as CastTxtRecord; const txtRecord = service.txtRecord as CastTxtRecord;
sendMessage({ sendMessage({
subject: "main:receiverDeviceUp" subject: "main:receiverDeviceUp"
, data: { , data: {
receiverDevice: { receiverDevice: {
host: service.addresses[0] host: service.addresses[0]
, port: service.port , port: service.port
, id: txtRecord.id , id: service.name
, friendlyName: txtRecord.fn , friendlyName: txtRecord.fn
} }
} }
}); });
} }
function onBrowserServiceDown(_service: mdns.Service) { function onBrowserServiceDown(service: mdns.Service) {
// TODO: Fix service down detection // Ignore without name
if (!service.name) {
return;
}
const txtRecord = service.txtRecord as CastTxtRecord;
sendMessage({
subject: "main:receiverDeviceDown"
, data: { receiverDeviceId: service.name }
});
} }
browser.on("serviceUp", onBrowserServiceUp); browser.on("serviceUp", onBrowserServiceUp);
@@ -73,7 +86,7 @@ export function startDiscovery(options: InitializeOptions) {
const statusListeners = new Map<string, StatusListener>(); const statusListeners = new Map<string, StatusListener>();
function onStatusBrowserServiceUp(service: mdns.Service) { function onStatusBrowserServiceUp(service: mdns.Service) {
if (!service.txtRecord) { if (!service.name) {
return; return;
} }
@@ -81,23 +94,110 @@ export function startDiscovery(options: InitializeOptions) {
service.addresses[0], service.port); service.addresses[0], service.port);
listener.on("receiverStatus", (status: ReceiverStatus) => { listener.on("receiverStatus", (status: ReceiverStatus) => {
if (!service.name) {
return;
}
sendMessage({ sendMessage({
subject: "main:receiverDeviceUpdated" subject: "main:receiverDeviceUpdated"
, data: { , data: {
receiverDeviceId: service.txtRecord.id receiverDeviceId: service.name
, status , status
} }
}); });
}); });
statusListeners.set(service.txtRecord.id, listener); statusListeners.set(service.name, listener);
} }
function onStatusBrowserServiceDown(_service: mdns.Service) { function onStatusBrowserServiceDown(service: mdns.Service) {
// TODO: Fix service down detection if (!service.name) {
return;
}
const listener = statusListeners.get(service.name);
listener?.deregister();
} }
} }
export function stopDiscovery() { export function stopDiscovery() {
browser.stop(); browser.stop();
} }
/**
* 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?: NodeJS.Timeout;
constructor(host: string, port: number) {
super();
this.client = new Client();
this.client.connect({ host, port }, this.onConnect.bind(this));
this.client.on("close", () => {
clearInterval(this.clientHeartbeatIntervalId!);
});
this.client.on("error", () => {
clearInterval(this.clientHeartbeatIntervalId!);
});
}
/**
* Closes status listener connection.
*/
public deregister(): void {
if (this.clientReceiver) {
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": {
this.emit("receiverStatus", data.status);
break;
}
case "MEDIA_STATUS": {
this.emit("mediaStatus", 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" });
}, 5000);
}
}