mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-11 01:59:58 +00:00
Finish app conversion and enforce code style
This commit is contained in:
@@ -25,25 +25,24 @@ export interface UpdateMessageData {
|
||||
export default class Media {
|
||||
private sessionId: number;
|
||||
private mediaSessionId: number;
|
||||
private _id: string;
|
||||
private referenceId: string;
|
||||
private session: Session;
|
||||
private channel: any;
|
||||
private _sendMessage: SendMessageCallback;
|
||||
private sendMessageCallback: SendMessageCallback;
|
||||
|
||||
constructor (sessionId: number
|
||||
, mediaSessionId: number
|
||||
, _id: string
|
||||
, parentSession: Session,
|
||||
_sendMessage: SendMessageCallback) {
|
||||
|
||||
this._id = _id;
|
||||
|
||||
this._sendMessage = _sendMessage;
|
||||
constructor (
|
||||
sessionId: number
|
||||
, mediaSessionId: number
|
||||
, referenceId: string
|
||||
, session: Session
|
||||
, sendMessageCallback: SendMessageCallback) {
|
||||
|
||||
this.sessionId = sessionId;
|
||||
this.mediaSessionId = mediaSessionId;
|
||||
this.referenceId = referenceId;
|
||||
this.session = session;
|
||||
this.sendMessageCallback = sendMessageCallback;
|
||||
|
||||
this.session = parentSession;
|
||||
this.session.createChannel(MEDIA_NAMESPACE);
|
||||
this.channel = this.session.channelMap.get(MEDIA_NAMESPACE);
|
||||
|
||||
@@ -54,11 +53,12 @@ export default class Media {
|
||||
const status = data.status[0];
|
||||
|
||||
const messageData = {
|
||||
currentTime: status.currentTime
|
||||
, _lastCurrentTime: Date.now() / 1000
|
||||
, customData: status.customData
|
||||
_lastCurrentTime: Date.now() / 1000
|
||||
, _volumeLevel: status.volume.level
|
||||
, _volumeMuted: status.volume.muted
|
||||
|
||||
, currentTime: status.currentTime
|
||||
, customData: status.customData
|
||||
, playbackRate: status.playbackRate
|
||||
, playerState: status.playerState
|
||||
, repeatMode: status.repeatMode
|
||||
@@ -81,7 +81,7 @@ export default class Media {
|
||||
});
|
||||
}
|
||||
|
||||
messageHandler (message: Message) {
|
||||
public messageHandler (message: Message) {
|
||||
switch (message.subject) {
|
||||
case "bridge:/media/sendMediaMessage": {
|
||||
let error = false;
|
||||
@@ -97,15 +97,15 @@ export default class Media {
|
||||
});
|
||||
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendMessage (subject: string, data: any = {}) {
|
||||
this._sendMessage({
|
||||
private sendMessage (subject: string, data: any = {}) {
|
||||
this.sendMessageCallback({
|
||||
subject
|
||||
, data
|
||||
, _id: this._id
|
||||
, _id: this.referenceId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
import { Client, ClientChannel } from "castv2";
|
||||
import uuid from "uuid";
|
||||
|
||||
import { Channel, Client } from "castv2";
|
||||
|
||||
import { Message
|
||||
, SendMessageCallback } from "./types";
|
||||
@@ -11,40 +13,39 @@ const NS_HEARTBEAT = "urn:x-cast:com.google.cast.tp.heartbeat";
|
||||
const NS_RECEIVER = "urn:x-cast:com.google.cast.receiver";
|
||||
|
||||
export default class Session {
|
||||
private _sendMessage: SendMessageCallback;
|
||||
public channelMap = new Map<string, Channel>();
|
||||
|
||||
private sendMessageCallback: SendMessageCallback;
|
||||
private sessionId: number;
|
||||
private _id: string;
|
||||
private referenceId: string;
|
||||
|
||||
private client: Client;
|
||||
private clientConnection: ClientChannel;
|
||||
private clientHeartbeat: ClientChannel;
|
||||
private clientReceiver: ClientChannel;
|
||||
private clientConnection: Channel;
|
||||
private clientHeartbeat: Channel;
|
||||
private clientReceiver: Channel;
|
||||
private clientHeartbeatIntervalId: NodeJS.Timer;
|
||||
|
||||
private isSessionCreated = false;
|
||||
|
||||
private clientId: string;
|
||||
private transportId: string;
|
||||
private transportConnection: ClientChannel;
|
||||
private transportConnection: Channel;
|
||||
private app: any;
|
||||
|
||||
constructor (
|
||||
host: string
|
||||
, port: number
|
||||
, appId: string
|
||||
, sessionId: number
|
||||
, sendMessageCallback: SendMessageCallback) {
|
||||
|
||||
public channelMap = new Map<string, ClientChannel>();
|
||||
|
||||
|
||||
constructor (host: string
|
||||
, port: number
|
||||
, appId: string
|
||||
, sessionId: number
|
||||
, _sendMessage: SendMessageCallback) {
|
||||
|
||||
this._sendMessage = _sendMessage;
|
||||
this.sendMessageCallback = sendMessageCallback;
|
||||
this.sessionId = sessionId;
|
||||
|
||||
this.client = new Client();
|
||||
|
||||
this.client.connect({ host, port }, () => {
|
||||
let transportHeartbeat: ClientChannel;
|
||||
let transportHeartbeat: Channel;
|
||||
|
||||
const sourceId = "sender-0";
|
||||
const destinationId = "receiver-0";
|
||||
@@ -63,6 +64,7 @@ export default class Session {
|
||||
if (transportHeartbeat) {
|
||||
transportHeartbeat.send({ type: "PING" });
|
||||
}
|
||||
|
||||
this.clientHeartbeat.send({ type: "PING" });
|
||||
}, 5000);
|
||||
|
||||
@@ -73,56 +75,58 @@ export default class Session {
|
||||
});
|
||||
|
||||
this.clientReceiver.on("message", (message: any) => {
|
||||
switch (message.type) {
|
||||
case "RECEIVER_STATUS": {
|
||||
this.sendMessage("shim:/session/updateStatus", message.status);
|
||||
if (message.type === "RECEIVER_STATUS") {
|
||||
this.sendMessage("shim:/session/updateStatus"
|
||||
, message.status);
|
||||
|
||||
if (!message.status.applications) return;
|
||||
if (!message.status.applications) {
|
||||
return;
|
||||
}
|
||||
|
||||
const receiverApp = message.status.applications[0];
|
||||
const receiverAppId = receiverApp.appId;
|
||||
const receiverApp = message.status.applications[0];
|
||||
const receiverAppId = receiverApp.appId;
|
||||
|
||||
this.app = receiverApp;
|
||||
this.app = receiverApp;
|
||||
|
||||
if (receiverAppId !== appId) {
|
||||
// Close session
|
||||
this.sendMessage("shim:/session/stopped");
|
||||
this.client.close();
|
||||
clearInterval(this.clientHeartbeatIntervalId);
|
||||
return;
|
||||
}
|
||||
if (receiverAppId !== appId) {
|
||||
// Close session
|
||||
this.sendMessage("shim:/session/stopped");
|
||||
this.client.close();
|
||||
clearInterval(this.clientHeartbeatIntervalId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.isSessionCreated) {
|
||||
this.isSessionCreated = true;
|
||||
if (!this.isSessionCreated) {
|
||||
this.isSessionCreated = true;
|
||||
|
||||
this.transportId = this.app.transportId;
|
||||
this.clientId = `client-${Math.floor(Math.random() * 10e5)}`;
|
||||
this.transportId = this.app.transportId;
|
||||
this.clientId =
|
||||
`client-${Math.floor(Math.random() * 10e5)}`;
|
||||
|
||||
this.transportConnection = this.client.createChannel(
|
||||
this.clientId, this.transportId, NS_CONNECTION, "JSON");
|
||||
transportHeartbeat = this.client.createChannel(
|
||||
this.clientId, this.transportId, NS_HEARTBEAT, "JSON");
|
||||
this.transportConnection = this.client.createChannel(
|
||||
this.clientId, this.transportId
|
||||
, NS_CONNECTION, "JSON");
|
||||
transportHeartbeat = this.client.createChannel(
|
||||
this.clientId, this.transportId
|
||||
, NS_HEARTBEAT, "JSON");
|
||||
|
||||
this.transportConnection.send({ type: "CONNECT" });
|
||||
this.transportConnection.send({ type: "CONNECT" });
|
||||
|
||||
this.sessionId = this.app.sessionId;
|
||||
this.sessionId = this.app.sessionId;
|
||||
|
||||
this.sendMessage("shim:/session/connected", {
|
||||
sessionId: this.app.sessionId
|
||||
, namespaces: this.app.namespaces
|
||||
, displayName: this.app.displayName
|
||||
, statusText: this.app.displayName
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
};
|
||||
this.sendMessage("shim:/session/connected", {
|
||||
sessionId: this.app.sessionId
|
||||
, namespaces: this.app.namespaces
|
||||
, displayName: this.app.displayName
|
||||
, statusText: this.app.displayName
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
messageHandler (message: Message) {
|
||||
public messageHandler (message: Message) {
|
||||
switch (message.subject) {
|
||||
case "bridge:/session/close":
|
||||
this.close();
|
||||
@@ -136,7 +140,7 @@ export default class Session {
|
||||
this._impl_sendMessage(
|
||||
message.data.namespace
|
||||
, message.data.message
|
||||
, message.data.messageId)
|
||||
, message.data.messageId);
|
||||
break;
|
||||
|
||||
case "bridge:/session/impl_setReceiverMuted":
|
||||
@@ -157,15 +161,7 @@ export default class Session {
|
||||
}
|
||||
}
|
||||
|
||||
sendMessage (subject: string, data: any = {}) {
|
||||
this._sendMessage({
|
||||
subject
|
||||
, data
|
||||
, _id: this._id
|
||||
});
|
||||
}
|
||||
|
||||
createChannel (namespace: string) {
|
||||
public createChannel (namespace: string) {
|
||||
if (!this.channelMap.has(namespace)) {
|
||||
this.channelMap.set(namespace
|
||||
, this.client.createChannel(
|
||||
@@ -173,25 +169,36 @@ export default class Session {
|
||||
}
|
||||
}
|
||||
|
||||
close () {
|
||||
public close () {
|
||||
this.clientConnection.send({ type: "CLOSE" });
|
||||
if (this.transportConnection) {
|
||||
this.transportConnection.send({ type: "CLOSE" });
|
||||
}
|
||||
}
|
||||
|
||||
private sendMessage (subject: string, data: any = {}) {
|
||||
this.sendMessageCallback({
|
||||
subject
|
||||
, data
|
||||
, _id: this.referenceId
|
||||
});
|
||||
}
|
||||
|
||||
_impl_addMessageListener (namespace: string) {
|
||||
private _impl_addMessageListener (namespace: string) {
|
||||
this.createChannel(namespace);
|
||||
this.channelMap.get(namespace).on("message", (data: any) => {
|
||||
this.sendMessage("shim:/session/impl_addMessageListener", {
|
||||
namespace: namespace
|
||||
namespace
|
||||
, data: JSON.stringify(data)
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
_impl_sendMessage (namespace: string, message: object, messageId: string) {
|
||||
private _impl_sendMessage (
|
||||
namespace: string
|
||||
, message: object
|
||||
, messageId: string) {
|
||||
|
||||
let error = false;
|
||||
|
||||
try {
|
||||
@@ -207,7 +214,8 @@ export default class Session {
|
||||
});
|
||||
}
|
||||
|
||||
_impl_setReceiverMuted (muted: boolean, volumeId: string) {
|
||||
private _impl_setReceiverMuted (muted: boolean, volumeId: string) {
|
||||
|
||||
let error = false;
|
||||
|
||||
try {
|
||||
@@ -226,7 +234,8 @@ export default class Session {
|
||||
});
|
||||
}
|
||||
|
||||
_impl_setReceiverVolumeLevel (newLevel: number, volumeId: string) {
|
||||
private _impl_setReceiverVolumeLevel (newLevel: number, volumeId: string) {
|
||||
|
||||
let error = false;
|
||||
|
||||
try {
|
||||
@@ -234,7 +243,7 @@ export default class Session {
|
||||
type: "SET_VOLUME"
|
||||
, volume: { level: newLevel }
|
||||
, requestId: 0
|
||||
})
|
||||
});
|
||||
} catch (err) {
|
||||
error = true;
|
||||
}
|
||||
@@ -245,7 +254,7 @@ export default class Session {
|
||||
});
|
||||
}
|
||||
|
||||
_impl_stop (stopId: string) {
|
||||
private _impl_stop (stopId: string) {
|
||||
let error = false;
|
||||
|
||||
try {
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
* - https://github.com/postlund/pyatv/blob/master/docs/airplay.rst
|
||||
*/
|
||||
|
||||
import nacl from "tweetnacl";
|
||||
import srp6a from "fast-srp-hap";
|
||||
import crypto from "crypto";
|
||||
import fetch from "node-fetch";
|
||||
import srp6a from "fast-srp-hap";
|
||||
import fetch, { Headers } from "node-fetch";
|
||||
import nacl from "tweetnacl";
|
||||
import bplist from "./bplist";
|
||||
|
||||
|
||||
@@ -22,7 +22,11 @@ const MIMETYPE_BPLIST = "application/x-apple-binary-plist";
|
||||
* Client ID and keypair
|
||||
*/
|
||||
export class AirPlayAuthCredentials {
|
||||
constructor (clientId, clientSk) {
|
||||
public clientId: string;
|
||||
public clientSk: Uint8Array;
|
||||
public clientPk: Uint8Array;
|
||||
|
||||
constructor (clientId: string, clientSk: Uint8Array) {
|
||||
if (clientId && clientSk) {
|
||||
this.clientId = clientId;
|
||||
this.clientSk = clientSk;
|
||||
@@ -40,11 +44,13 @@ export class AirPlayAuthCredentials {
|
||||
}
|
||||
|
||||
export class AirPlayAuth {
|
||||
constructor (address, credentials) {
|
||||
private address: string;
|
||||
private credentials: AirPlayAuthCredentials;
|
||||
private baseUrl: URL;
|
||||
|
||||
constructor (address: string, credentials: AirPlayAuthCredentials) {
|
||||
this.address = address;
|
||||
this.clientId = credentials.clientId;
|
||||
this.clientSk = credentials.clientSk;
|
||||
this.clientPk = credentials.clientPk;
|
||||
this.credentials = credentials;
|
||||
|
||||
this.baseUrl = new URL(`http://${this.address}:${AIRPLAY_PORT}`);
|
||||
}
|
||||
@@ -52,7 +58,7 @@ export class AirPlayAuth {
|
||||
/**
|
||||
* Begins pairing process.
|
||||
*/
|
||||
async beginPairing () {
|
||||
public async beginPairing () {
|
||||
return this.sendPostRequest("/pair-pin-start");
|
||||
}
|
||||
|
||||
@@ -61,7 +67,7 @@ export class AirPlayAuth {
|
||||
* beginPairing(). Coordinates the three pairing stages and
|
||||
* manages request responses.
|
||||
*/
|
||||
async finishPairing (pin) {
|
||||
public async finishPairing (pin: string) {
|
||||
// Stage 1 response
|
||||
const { pk: serverPk
|
||||
, salt: serverSalt } = await this.pairSetupPin1();
|
||||
@@ -72,11 +78,11 @@ export class AirPlayAuth {
|
||||
|
||||
// Create SRP client
|
||||
const srpClient = new srp6a.Client(
|
||||
srpParams // Params
|
||||
, serverSalt // Receiver salt
|
||||
, Buffer.from(this.clientId) // Username
|
||||
, Buffer.from(pin) // Password (receiver pin)
|
||||
, Buffer.from(this.clientSk)); // Client secret key
|
||||
srpParams // Params
|
||||
, serverSalt // Receiver salt
|
||||
, Buffer.from(this.credentials.clientId) // Username
|
||||
, Buffer.from(pin) // Password (receiver pin)
|
||||
, Buffer.from(this.credentials.clientSk)); // Client secret key
|
||||
|
||||
// Add receiver's public key
|
||||
srpClient.setB(serverPk);
|
||||
@@ -87,7 +93,7 @@ export class AirPlayAuth {
|
||||
, srpClient.computeM1()); // SRP proof
|
||||
|
||||
// Stage 3 response
|
||||
console.log(await this.pairSetupPin3(srpClient.computeK()));
|
||||
await this.pairSetupPin3(srpClient.computeK());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,12 +102,12 @@ export class AirPlayAuth {
|
||||
* Triggering the receiver passcode display and receiving
|
||||
* its public key / salt.
|
||||
*/
|
||||
async pairSetupPin1 () {
|
||||
public async pairSetupPin1 (): Promise<any> {
|
||||
const [ response ] = await this.sendPostRequestBplist(
|
||||
"/pair-setup-pin"
|
||||
, {
|
||||
method: "pin"
|
||||
, user: this.clientId
|
||||
, user: this.credentials.clientId
|
||||
});
|
||||
|
||||
return response;
|
||||
@@ -114,7 +120,10 @@ export class AirPlayAuth {
|
||||
* public keys, sending them to the receiver and receiving its
|
||||
* proof.
|
||||
*/
|
||||
async pairSetupPin2 (pk, proof) {
|
||||
public async pairSetupPin2 (
|
||||
pk: Buffer
|
||||
, proof: Buffer): Promise<any> {
|
||||
|
||||
const [ response ] = await this.sendPostRequestBplist(
|
||||
"/pair-setup-pin"
|
||||
, { pk, proof });
|
||||
@@ -129,7 +138,9 @@ export class AirPlayAuth {
|
||||
* secret hash and sending it to the receiver. Receiver then
|
||||
* responds confirming the pairing is complete.
|
||||
*/
|
||||
async pairSetupPin3 (sharedSecretHash) {
|
||||
public async pairSetupPin3 (
|
||||
sharedSecretHash: crypto.BinaryLike): Promise<any> {
|
||||
|
||||
// Create AES key
|
||||
const aesKey = crypto.createHash("sha512")
|
||||
.update("Pair-Setup-AES-Key")
|
||||
@@ -150,7 +161,7 @@ export class AirPlayAuth {
|
||||
const cipher = crypto.createCipheriv("aes-128-gcm", aesKey, aesIv);
|
||||
|
||||
// Encode client public key
|
||||
const epk = cipher.update(this.clientPk);
|
||||
const epk = cipher.update(this.credentials.clientPk);
|
||||
cipher.final();
|
||||
const authTag = cipher.getAuthTag();
|
||||
|
||||
@@ -166,7 +177,11 @@ export class AirPlayAuth {
|
||||
* Sends a POST request to receiver and returns the
|
||||
* response.
|
||||
*/
|
||||
async sendPostRequest (path, contentType, data) {
|
||||
public async sendPostRequest (
|
||||
path: string
|
||||
, contentType?: string
|
||||
, data?: Buffer | string): Promise<any> {
|
||||
|
||||
// Create URL from base receiver URL and path
|
||||
const requestUrl = new URL(path, this.baseUrl);
|
||||
|
||||
@@ -189,24 +204,26 @@ export class AirPlayAuth {
|
||||
throw new Error(`AirPlay request error: ${response.status}`);
|
||||
}
|
||||
|
||||
return await response.arrayBuffer();
|
||||
return await response.buffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes binary plist data, sends a POST request to
|
||||
* receiver, then decodes and returns the response.
|
||||
*/
|
||||
async sendPostRequestBplist (path, data) {
|
||||
public async sendPostRequestBplist (
|
||||
path: string
|
||||
, data?: object): Promise<any> {
|
||||
|
||||
// Convert data to compatible type
|
||||
const requestBody = data
|
||||
? bplist.create(data)
|
||||
: null;
|
||||
: undefined;
|
||||
|
||||
const responseArrayBuffer = await this.sendPostRequest(
|
||||
const response = await this.sendPostRequest(
|
||||
path, MIMETYPE_BPLIST, requestBody);
|
||||
|
||||
// Convert response data to Buffer for bplist-parser
|
||||
return bplist.parse.parseBuffer(
|
||||
Buffer.from(responseArrayBuffer));
|
||||
return bplist.parse.parseBuffer(response);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import create from "bplist-creator";
|
||||
import parse from "bplist-parser";
|
||||
import parse from "bplist-parser";
|
||||
|
||||
export default { create, parse };
|
||||
@@ -1,13 +1,14 @@
|
||||
import dnssd from "dnssd";
|
||||
|
||||
import http from "http";
|
||||
import events from "events";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import http from "http";
|
||||
import mime from "mime-types";
|
||||
import path from "path";
|
||||
|
||||
import * as transforms from "./transforms";
|
||||
import Media from "./Media";
|
||||
import Session from "./Session";
|
||||
import * as transforms from "./transforms";
|
||||
|
||||
import { Message } from "./types";
|
||||
|
||||
@@ -15,18 +16,21 @@ import { __applicationName
|
||||
, __applicationVersion } from "../package.json";
|
||||
|
||||
|
||||
// Increase listener limit
|
||||
events.EventEmitter.defaultMaxListeners = 50;
|
||||
|
||||
|
||||
const browser = new dnssd.Browser(dnssd.tcp("googlecast"));
|
||||
|
||||
// Local media server
|
||||
let httpServer: http.Server;
|
||||
|
||||
process.on("SIGTERM", () => {
|
||||
if (httpServer) httpServer.close();
|
||||
if (httpServer) {
|
||||
httpServer.close();
|
||||
}
|
||||
});
|
||||
|
||||
// Increase listener limit
|
||||
require("events").EventEmitter.defaultMaxListeners = 50;
|
||||
|
||||
// stdin -> stdout
|
||||
process.stdin
|
||||
.pipe(transforms.decode)
|
||||
@@ -40,7 +44,9 @@ process.stdin
|
||||
function sendMessage (message: object) {
|
||||
try {
|
||||
transforms.encode.write(message);
|
||||
} catch (err) {}
|
||||
} catch (err) {
|
||||
console.error("Failed to encode message");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,12 +108,12 @@ async function handleMessage (message: Message) {
|
||||
case "bridge:/getInfo": {
|
||||
const extensionVersion = message.data;
|
||||
return __applicationVersion;
|
||||
};
|
||||
}
|
||||
|
||||
case "bridge:/startDiscovery": {
|
||||
browser.start();
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
case "bridge:/startHttpServer": {
|
||||
const { filePath, port } = message.data;
|
||||
@@ -144,7 +150,7 @@ async function handleMessage (message: Message) {
|
||||
, "Content-Type": contentType
|
||||
});
|
||||
|
||||
fs.createReadStream(filePath).pipe(res)
|
||||
fs.createReadStream(filePath).pipe(res);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -155,12 +161,14 @@ async function handleMessage (message: Message) {
|
||||
});
|
||||
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
case "bridge:/stopHttpServer": {
|
||||
if (httpServer) httpServer.close();
|
||||
if (httpServer) {
|
||||
httpServer.close();
|
||||
}
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +188,7 @@ browser.on("serviceUp", (service: dnssd.Service) => {
|
||||
|
||||
browser.on("serviceDown", (service: dnssd.Service) => {
|
||||
transforms.encode.write({
|
||||
subject:"shim:/serviceDown"
|
||||
subject: "shim:/serviceDown"
|
||||
, data: {
|
||||
id: service.txt.id
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@ import { Transform } from "stream";
|
||||
import { Message } from "./types";
|
||||
|
||||
|
||||
interface ResponseHandlerFunction {
|
||||
(message: Message): Promise<any>
|
||||
}
|
||||
type ResponseHandlerFunction = (message: Message) => Promise<any>;
|
||||
|
||||
/**
|
||||
* Takes a handler function that implements the transform
|
||||
@@ -18,9 +16,9 @@ export const response = (handler: ResponseHandlerFunction) => new Transform({
|
||||
|
||||
, transform (chunk: Message, encoding, callback) {
|
||||
Promise.resolve(handler(chunk))
|
||||
.then(response => {
|
||||
if (response) {
|
||||
callback(null, response);
|
||||
.then(res => {
|
||||
if (res) {
|
||||
callback(null, res);
|
||||
} else {
|
||||
callback(null);
|
||||
}
|
||||
@@ -94,13 +92,13 @@ export const encode = new Transform({
|
||||
writableObjectMode: true
|
||||
|
||||
, transform (chunk, encoding, callback) {
|
||||
const message_length = Buffer.alloc(4);
|
||||
const messageLength = Buffer.alloc(4);
|
||||
const message = Buffer.from(JSON.stringify(chunk));
|
||||
|
||||
// Write message length
|
||||
message_length.writeUInt32LE(message.length, 0);
|
||||
messageLength.writeUInt32LE(message.length, 0);
|
||||
|
||||
// Output joined message length and content
|
||||
callback(null, Buffer.concat([message_length, message]));
|
||||
callback(null, Buffer.concat([messageLength, message]));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,6 +6,4 @@ export interface Message {
|
||||
_id?: string;
|
||||
}
|
||||
|
||||
export interface SendMessageCallback {
|
||||
(message: Message): void
|
||||
}
|
||||
export type SendMessageCallback = (message: Message) => void;
|
||||
|
||||
Reference in New Issue
Block a user