mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-08 08:39:59 +00:00
Improve app message types
This commit is contained in:
@@ -4,8 +4,8 @@ import castv2 from "castv2";
|
||||
|
||||
import Session from "./Session";
|
||||
|
||||
import { Message } from "../../types";
|
||||
import { sendMessage } from "../../lib/messaging"
|
||||
import { Message } from "../../messaging";
|
||||
import { sendMessage } from "../../lib/nativeMessaging"
|
||||
|
||||
|
||||
const NS_MEDIA = "urn:x-cast:com.google.cast.media";
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
import { Channel, Client } from "castv2";
|
||||
|
||||
import { Message } from "../../types";
|
||||
import { sendMessage } from "../../lib/messaging";
|
||||
import { Message } from "../../messaging";
|
||||
import { sendMessage } from "../../lib/nativeMessaging";
|
||||
|
||||
|
||||
export const NS_CONNECTION = "urn:x-cast:com.google.cast.tp.connection";
|
||||
|
||||
@@ -4,7 +4,7 @@ import mdns from "mdns";
|
||||
|
||||
import StatusListener from "./chromecast/StatusListener";
|
||||
import { ReceiverStatus } from "../types";
|
||||
import { sendMessage } from "../lib/messaging";
|
||||
import { sendMessage } from "../lib/nativeMessaging";
|
||||
|
||||
|
||||
interface CastTxtRecord {
|
||||
@@ -44,7 +44,7 @@ function onBrowserServiceUp (service: mdns.Service) {
|
||||
});
|
||||
}
|
||||
|
||||
function onBrowserServiceDown (service: mdns.Service) {
|
||||
function onBrowserServiceDown (_service: mdns.Service) {
|
||||
// TODO: Fix service down detection
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ export function startDiscovery (options: InitializeOptions) {
|
||||
statusListeners.set(id, listener);
|
||||
}
|
||||
|
||||
function onStatusBrowserServiceDown (service: mdns.Service) {
|
||||
function onStatusBrowserServiceDown (_service: mdns.Service) {
|
||||
// TODO: Fix service down detection
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import stream from "stream";
|
||||
|
||||
import mime from "mime-types";
|
||||
|
||||
import { sendMessage } from "../lib/messaging";
|
||||
import { sendMessage } from "../lib/nativeMessaging";
|
||||
import { convertSrtToVtt } from "../lib/subtitles";
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import child_process from "child_process";
|
||||
import path from "path";
|
||||
|
||||
import { sendMessage } from "../lib/messaging";
|
||||
import { sendMessage } from "../lib/nativeMessaging";
|
||||
|
||||
|
||||
function fatal (message: string) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
import { decodeTransform, encodeTransform } from "./lib/messaging";
|
||||
import { Message } from "./types";
|
||||
import { decodeTransform, encodeTransform } from "./lib/nativeMessaging";
|
||||
import { Message } from "./messaging";
|
||||
|
||||
import { handleSessionMessage, handleMediaMessage, stopReceiverApp }
|
||||
from "./components/chromecast";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
import { DecodeTransform, EncodeTransform } from "../../transforms";
|
||||
import { Message } from "../types";
|
||||
import { Message } from "../messaging";
|
||||
|
||||
|
||||
export const decodeTransform = new DecodeTransform();
|
||||
172
app/src/bridge/messaging.ts
Normal file
172
app/src/bridge/messaging.ts
Normal file
@@ -0,0 +1,172 @@
|
||||
"use strict";
|
||||
|
||||
import { Receiver
|
||||
, ReceiverSelectionCast
|
||||
, ReceiverSelectionStop
|
||||
, ReceiverStatus } from "./types";
|
||||
|
||||
|
||||
type MessageDefinitions = {
|
||||
"shim:serviceUp": { id: Receiver["id"] }
|
||||
, "shim:serviceDown": { id: Receiver["id"] }
|
||||
|
||||
, "shim:launchApp": { receiver: Receiver }
|
||||
|
||||
// Session messages
|
||||
, "shim:session/stopped": {}
|
||||
, "shim:session/connected": {
|
||||
sessionId: string
|
||||
, namespaces: Array<{ name: string }>
|
||||
, displayName: string
|
||||
, statusText: string
|
||||
}
|
||||
, "shim:session/updateStatus": { volume: any /* Volume */ }
|
||||
, "shim:session/impl_addMessageListener": {
|
||||
namespace: string
|
||||
, data: string
|
||||
}
|
||||
, "shim:session/impl_sendMessage": {
|
||||
messageId: string
|
||||
, error: boolean
|
||||
}
|
||||
, "shim:session/impl_setReceiverMuted": {
|
||||
volumeId: string
|
||||
, error: boolean
|
||||
}
|
||||
, "shim:session/impl_setReceiverVolumeLevel": {
|
||||
volumeId: string
|
||||
, error: boolean
|
||||
}
|
||||
, "shim:session/impl_stop": {
|
||||
stopId: string
|
||||
, error: boolean
|
||||
}
|
||||
|
||||
// Bridge session messages
|
||||
, "bridge:session/initialize": {
|
||||
address: string
|
||||
, port: number
|
||||
, appId: string
|
||||
, sessionId: string
|
||||
, _id: string
|
||||
}
|
||||
, "bridge:session/close": {}
|
||||
, "bridge:session/impl_leave": {
|
||||
id: string
|
||||
, _id: string
|
||||
}
|
||||
, "bridge:session/impl_sendMessage": {
|
||||
namespace: string
|
||||
, message: any
|
||||
, messageId: string
|
||||
, _id: string
|
||||
}
|
||||
, "bridge:session/impl_setReceiverMuted": {
|
||||
muted: boolean
|
||||
, volumeId: string
|
||||
, _id: string
|
||||
}
|
||||
, "bridge:session/impl_setReceiverVolumeLevel": {
|
||||
newLevel: number
|
||||
, volumeId: string
|
||||
, _id: string
|
||||
}
|
||||
, "bridge:session/impl_stop": {
|
||||
stopId: string;
|
||||
_id: string;
|
||||
}
|
||||
, "bridge:session/impl_addMessageListener": {
|
||||
namespace: string;
|
||||
_id: string;
|
||||
}
|
||||
|
||||
// Media messages
|
||||
, "shim:media/update": {
|
||||
currentTime: number
|
||||
, _lastCurrentTime: number
|
||||
, customData: any
|
||||
, playbackRate: number
|
||||
, playerState: string
|
||||
, repeatMode: string
|
||||
, _volumeLevel: number
|
||||
, _volumeMuted: boolean
|
||||
, media: unknown // MediaInfo
|
||||
, mediaSessionId: number
|
||||
}
|
||||
, "shim:media/sendMediaMessageResponse": {
|
||||
messageId: string
|
||||
, error: boolean
|
||||
}
|
||||
|
||||
// Bridge media messages
|
||||
, "bridge:media/initialize": {
|
||||
sessionId: string
|
||||
, mediaSessionId: number
|
||||
, _internalSessionId: string
|
||||
, _id: string
|
||||
}
|
||||
, "bridge:media/sendMediaMessage": {
|
||||
message: any
|
||||
, messageId: string
|
||||
, _id: string
|
||||
}
|
||||
|
||||
// Bridge messages
|
||||
, "main:receiverSelector/selected": ReceiverSelectionCast
|
||||
, "main:receiverSelector/error": string
|
||||
, "main:receiverSelector/close": {}
|
||||
, "main:receiverSelector/stop": ReceiverSelectionStop
|
||||
|
||||
, "bridge:getInfo": string
|
||||
, "bridge:initialize": { shouldWatchStatus: boolean }
|
||||
|
||||
, "bridge:receiverSelector/open": any
|
||||
, "bridge:receiverSelector/close": {}
|
||||
|
||||
, "bridge:stopReceiverApp": { receiver: Receiver }
|
||||
|
||||
, "bridge:mediaServer/start": {
|
||||
filePath: string
|
||||
, port: number
|
||||
}
|
||||
, "bridge:mediaServer/stop": {}
|
||||
, "mediaCast:mediaServer/started": {
|
||||
mediaPath: string
|
||||
, subtitlePaths: string[]
|
||||
, localAddress: string
|
||||
}
|
||||
, "mediaCast:mediaServer/stopped": {}
|
||||
, "mediaCast:mediaServer/error": {}
|
||||
|
||||
, "main:serviceUp": Receiver
|
||||
, "main:serviceDown": { id: string }
|
||||
|
||||
, "main:receiverStatus": {
|
||||
id: string
|
||||
, status: ReceiverStatus
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface MessageBase<K extends keyof MessageDefinitions> {
|
||||
subject: K;
|
||||
data: MessageDefinitions[K];
|
||||
}
|
||||
|
||||
type Messages = {
|
||||
[K in keyof MessageDefinitions]: MessageBase<K>;
|
||||
}
|
||||
|
||||
/**
|
||||
* For better call semantics, make message data key optional if
|
||||
* specified as blank or with all-optional keys.
|
||||
*/
|
||||
type NarrowedMessage<L extends MessageBase<keyof MessageDefinitions>> =
|
||||
L extends any
|
||||
? {} extends L["data"]
|
||||
? Omit<L, "data"> & Partial<L>
|
||||
: L
|
||||
: never;
|
||||
|
||||
|
||||
export type Message = NarrowedMessage<Messages[keyof Messages]>;
|
||||
@@ -84,211 +84,3 @@ export interface Receiver {
|
||||
port: number;
|
||||
status?: ReceiverStatus;
|
||||
}
|
||||
|
||||
|
||||
export type Messages = [
|
||||
{
|
||||
subject: "shim:serviceUp"
|
||||
, data: { id: Receiver["id"] }
|
||||
}
|
||||
, {
|
||||
subject: "shim:serviceDown"
|
||||
, data: { id: Receiver["id"] }
|
||||
}
|
||||
, {
|
||||
subject: "shim:launchApp"
|
||||
, data: { receiver: Receiver }
|
||||
}
|
||||
|
||||
// Session messages
|
||||
, {
|
||||
subject: "shim:session/stopped"
|
||||
}
|
||||
, {
|
||||
subject: "shim:session/connected"
|
||||
, data: {
|
||||
sessionId: string;
|
||||
namespaces: Array<{ name: string }>;
|
||||
displayName: string;
|
||||
statusText: string;
|
||||
}
|
||||
}
|
||||
, {
|
||||
subject: "shim:session/updateStatus"
|
||||
, data: any
|
||||
}
|
||||
, {
|
||||
subject: "shim:session/impl_addMessageListener"
|
||||
, data: { namespace: string, data: string }
|
||||
}
|
||||
, {
|
||||
subject: "shim:session/impl_sendMessage"
|
||||
, data: { messageId: string, error: boolean }
|
||||
}
|
||||
, {
|
||||
subject: "shim:session/impl_setReceiverMuted"
|
||||
, data: { volumeId: string, error: boolean }
|
||||
}
|
||||
, {
|
||||
subject: "shim:session/impl_setReceiverVolumeLevel"
|
||||
, data: { volumeId: string, error: boolean }
|
||||
}
|
||||
, {
|
||||
subject: "shim:session/impl_stop"
|
||||
, data: { stopId: string, error: boolean }
|
||||
}
|
||||
|
||||
// Bridge session messages
|
||||
, {
|
||||
subject: "bridge:session/initialize"
|
||||
, data: {
|
||||
address: string
|
||||
, port: number
|
||||
, appId: string
|
||||
, sessionId: string
|
||||
}
|
||||
, _id: string;
|
||||
}
|
||||
, {
|
||||
subject: "bridge:session/close"
|
||||
, _id: string;
|
||||
}
|
||||
, {
|
||||
subject: "bridge:session/impl_leave"
|
||||
, data: { id: string }
|
||||
, _id: string
|
||||
}
|
||||
, {
|
||||
subject: "bridge:session/impl_sendMessage"
|
||||
, data: { namespace: string, message: any, messageId: string }
|
||||
, _id: string
|
||||
}
|
||||
, {
|
||||
subject: "bridge:session/impl_setReceiverMuted"
|
||||
, data: { muted: boolean, volumeId: string }
|
||||
, _id: string
|
||||
}
|
||||
, {
|
||||
subject: "bridge:session/impl_setReceiverVolumeLevel"
|
||||
, data: { newLevel: number, volumeId: string }
|
||||
, _id: string
|
||||
}
|
||||
, {
|
||||
subject: "bridge:session/impl_stop"
|
||||
, data: { stopId: string }
|
||||
, _id: string
|
||||
}
|
||||
, {
|
||||
subject: "bridge:session/impl_addMessageListener"
|
||||
, data: { namespace: string }
|
||||
, _id: string
|
||||
}
|
||||
|
||||
// Media messages
|
||||
, {
|
||||
subject: "shim:media/update"
|
||||
, data: {
|
||||
currentTime: number
|
||||
, _lastCurrentTime: number
|
||||
, customData: any
|
||||
, playbackRate: number
|
||||
, playerState: string
|
||||
, repeatMode: string
|
||||
, _volumeLevel: number
|
||||
, _volumeMuted: boolean
|
||||
, media: any
|
||||
, mediaSessionId: number
|
||||
}
|
||||
}
|
||||
, {
|
||||
subject: "shim:media/sendMediaMessageResponse"
|
||||
, data: { messageId: string, error: boolean }
|
||||
}
|
||||
|
||||
// Bridge media messages
|
||||
, {
|
||||
subject: "bridge:media/initialize"
|
||||
, data: {
|
||||
sessionId: string
|
||||
, mediaSessionId: number
|
||||
, _internalSessionId: string
|
||||
}
|
||||
, _id: string;
|
||||
}
|
||||
, {
|
||||
subject: "bridge:media/sendMediaMessage"
|
||||
, data: { message: any, messageId: string }
|
||||
, _id: string;
|
||||
}
|
||||
|
||||
// Bridge messages
|
||||
, {
|
||||
subject: "main:receiverSelector/selected"
|
||||
, data: ReceiverSelectionCast
|
||||
}
|
||||
, {
|
||||
subject: "main:receiverSelector/error"
|
||||
, data: string
|
||||
}
|
||||
, {
|
||||
subject: "main:receiverSelector/close"
|
||||
}
|
||||
, {
|
||||
subject: "main:receiverSelector/stop"
|
||||
, data: ReceiverSelectionStop
|
||||
}
|
||||
, {
|
||||
subject: "bridge:getInfo"
|
||||
}
|
||||
, {
|
||||
subject: "bridge:initialize"
|
||||
, data: { shouldWatchStatus: boolean }
|
||||
}
|
||||
, {
|
||||
subject: "bridge:receiverSelector/open"
|
||||
, data: any }
|
||||
, {
|
||||
subject: "bridge:receiverSelector/close"
|
||||
}
|
||||
, {
|
||||
subject: "bridge:stopReceiverApp"
|
||||
, data: { receiver: Receiver }
|
||||
}
|
||||
, {
|
||||
subject: "bridge:mediaServer/start"
|
||||
, data: { filePath: string, port: number }
|
||||
}
|
||||
, {
|
||||
subject: "bridge:mediaServer/stop"
|
||||
}
|
||||
|
||||
, {
|
||||
subject: "mediaCast:mediaServer/started"
|
||||
, data: {
|
||||
mediaPath: string
|
||||
, subtitlePaths: string[]
|
||||
, localAddress: string
|
||||
}
|
||||
}
|
||||
, {
|
||||
subject: "mediaCast:mediaServer/stopped"
|
||||
}
|
||||
, {
|
||||
subject: "mediaCast:mediaServer/error"
|
||||
}
|
||||
|
||||
, {
|
||||
subject: "main:serviceUp"
|
||||
, data: Receiver
|
||||
}
|
||||
, {
|
||||
subject: "main:serviceDown"
|
||||
, data: { id: string }
|
||||
}
|
||||
, {
|
||||
subject: "main:receiverStatus"
|
||||
, data: { id: string, status: ReceiverStatus }
|
||||
}
|
||||
];
|
||||
|
||||
export type Message = Messages[number];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
import { Transform } from "stream";
|
||||
import { Message } from "./bridge/types";
|
||||
import { Message } from "./bridge/messaging";
|
||||
|
||||
|
||||
type ResponseHandlerFunction = (message: Message) => Promise<any>;
|
||||
|
||||
@@ -15,17 +15,23 @@ import { MediaInfo } from "./shim/cast/media";
|
||||
|
||||
/**
|
||||
* Messages are JSON objects with a `subject` string key and a
|
||||
* generic `data` key.
|
||||
* generic `data` key:
|
||||
* { subject: "...", data: ... }
|
||||
*
|
||||
* Message subjects may include an optional destination and response
|
||||
* name formatted like this:
|
||||
* Message subjects may include an optional destination and
|
||||
* response name formatted like this:
|
||||
* ^(destination:)?messageName(\/responseName)?$
|
||||
*
|
||||
* Message formats are specified with subject as a key and data as the
|
||||
* value in the message table.
|
||||
* Message formats are specified with subject as a key and data
|
||||
* as the value in the message tables.
|
||||
*/
|
||||
|
||||
type MessagesBase = {
|
||||
|
||||
/**
|
||||
* Messages exclusively used internally between extension
|
||||
* components.
|
||||
*/
|
||||
type ExtMessageDefinitions = {
|
||||
"popup:init": { appId?: string }
|
||||
, "popup:update": {
|
||||
receivers: Receiver[]
|
||||
@@ -46,10 +52,18 @@ type MessagesBase = {
|
||||
|
||||
, "main:sessionCreated": {}
|
||||
|
||||
, "shim:serviceUp": { id: Receiver["id"] }
|
||||
, "shim:initialized": BridgeInfo
|
||||
}
|
||||
|
||||
/**
|
||||
* Messages that cross the native messaging channel. MUST keep
|
||||
* in-sync with the bridge's version at:
|
||||
* app/bridge/messaging.ts > MessagesBase
|
||||
*/
|
||||
type AppMessageDefinitions = {
|
||||
"shim:serviceUp": { id: Receiver["id"] }
|
||||
, "shim:serviceDown": { id: Receiver["id"] }
|
||||
|
||||
, "shim:initialized": BridgeInfo
|
||||
, "shim:launchApp": { receiver: Receiver }
|
||||
|
||||
// Session messages
|
||||
@@ -90,6 +104,7 @@ type MessagesBase = {
|
||||
, sessionId: string
|
||||
, _id: string
|
||||
}
|
||||
, "bridge:session/close": {}
|
||||
, "bridge:session/impl_leave": {
|
||||
id: string
|
||||
, _id: string
|
||||
@@ -168,6 +183,7 @@ type MessagesBase = {
|
||||
filePath: string
|
||||
, port: number
|
||||
}
|
||||
, "bridge:mediaServer/stop": {}
|
||||
, "mediaCast:mediaServer/started": {
|
||||
mediaPath: string
|
||||
, subtitlePaths: string[]
|
||||
@@ -185,20 +201,25 @@ type MessagesBase = {
|
||||
}
|
||||
}
|
||||
|
||||
interface MessageBase<K extends keyof MessagesBase> {
|
||||
type MessageDefinitions =
|
||||
ExtMessageDefinitions
|
||||
& AppMessageDefinitions;
|
||||
|
||||
|
||||
interface MessageBase<K extends keyof MessageDefinitions> {
|
||||
subject: K;
|
||||
data: MessagesBase[K];
|
||||
data: MessageDefinitions[K];
|
||||
}
|
||||
|
||||
type Messages = {
|
||||
[K in keyof MessagesBase]: MessageBase<K>;
|
||||
[K in keyof MessageDefinitions]: MessageBase<K>;
|
||||
}
|
||||
|
||||
/**
|
||||
* For better call semantics, make message data key optional if
|
||||
* specified as blank or with all-optional keys.
|
||||
*/
|
||||
type NarrowedMessage<L extends MessageBase<keyof MessagesBase>> =
|
||||
type NarrowedMessage<L extends MessageBase<keyof MessageDefinitions>> =
|
||||
L extends any
|
||||
? {} extends L["data"]
|
||||
? Omit<L, "data"> & Partial<L>
|
||||
|
||||
Reference in New Issue
Block a user