-
-
Notifications
You must be signed in to change notification settings - Fork 64
/
Copy pathmessaging.ts
357 lines (321 loc) · 10.2 KB
/
messaging.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
import type { TypedPort } from "./lib/TypedPort";
import type {
ReceiverSelection,
ReceiverSelectorMediaMessage,
ReceiverSelectorReceiverMessage
} from "./background/receiverSelector";
import type {
CastSessionCreatedDetails,
CastSessionUpdatedDetails,
MediaStatus,
ReceiverStatus,
SenderMediaMessage,
SenderMessage
} from "./cast/sdk/types";
import type { ApiConfig, Receiver, SessionRequest } from "./cast/sdk/classes";
import type {
ReceiverDevice,
ReceiverSelectorAppInfo,
ReceiverSelectorMediaType,
ReceiverSelectorPageInfo
} from "./types";
import type { ReceiverAction } from "./cast/sdk/enums";
/**
* Messages are JSON objects with a `subject` string key and a
* generic `data` key:
* { subject: "...", data: ... }
*
* 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 tables.
*/
/**
* Messages exclusively used internally between extension
* components.
*/
type ExtensionMessageDefinitions = {
/** Initial data to send to selector popup. */
"popup:init": {
appInfo?: ReceiverSelectorAppInfo;
pageInfo?: ReceiverSelectorPageInfo;
};
/** Updates selector popup with new data. */
"popup:update": {
devices: ReceiverDevice[];
isBridgeCompatible: boolean;
connectedSessionIds?: string[];
defaultMediaType?: ReceiverSelectorMediaType;
availableMediaTypes?: ReceiverSelectorMediaType;
};
/**
* Sent from the selector popup when a receiver has been
* selected.
*/
"main:receiverSelected": ReceiverSelection;
/**
* Sent from the selector popup when a receiver has been
* stopped. Used to provide cast API receiver action updates.
*/
"main:receiverStopped": { deviceId: string };
/**
* Tells the cast manager to provide the cast API instance with
* receiver data.
*/
"main:initializeCastSdk": { apiConfig: ApiConfig };
"cast:initialized": { isAvailable: boolean };
/**
* Sent to the cast API when a session is requested or stopped via
* the extension UI.
*/
"cast:receiverAction": { receiver: Receiver; action: ReceiverAction };
/**
* Sent from the cast API to trigger receiver selection on session
* request.
*/
"main:requestSession": {
sessionRequest: SessionRequest;
/** Skip receiver selection (allowed for trusted instances only). */
receiverDevice?: ReceiverDevice;
};
/** Return message to the cast API when a selection is cancelled. */
"cast:sessionRequestCancelled": undefined;
"main:requestSessionById": { sessionId: string };
"main:leaveSession": void;
"cast:instanceCreated": { isAvailable: boolean };
"cast:receiverAvailabilityUpdated": { isAvailable: boolean };
"cast:sessionCreated": CastSessionCreatedDetails & {
receiver: Receiver;
media?: MediaStatus;
};
"cast:sessionUpdated": CastSessionUpdatedDetails;
"cast:sessionDisconnected": { sessionId: string };
/** Allows the selector popup to send cast NS_RECEIVER messages. */
"main:sendReceiverMessage": ReceiverSelectorReceiverMessage;
/** Allows the selector popup to send cast NS_MEDIA messages. */
"main:sendMediaMessage": ReceiverSelectorMediaMessage;
/**
* Tells the device manager to clear its device list and re-connect
* to the bridge.
*/
"main:refreshDeviceManager": void;
"mirroringPopup:init": { device: ReceiverDevice };
};
/**
* IMPORTANT:
* Messages that cross the native messaging channel. MUST keep
* in-sync with the bridge's version at:
* app/src/bridge/messaging.ts > MessageDefinitions
*/
type BridgeMessageDefinitions = {
/**
* First message sent by the extension to the bridge.
* Includes extension version string. Responds directly with version
* string of the bridge to compare.
*
* Still uses `:/` message separator for compat talking to older
* bridge versions.
*/
"bridge:getInfo": string;
"bridge:/getInfo": string;
/**
* Tells a bridge to begin service discovery (and whether to
* establish connections to monitor the status of the receiver
* devices).
*/
"bridge:startDiscovery": {
shouldWatchStatus: boolean;
};
/**
* Sent to extension from the bridge whenever a receiver device is
* found.
*/
"main:deviceUp": { deviceId: string; deviceInfo: ReceiverDevice };
/**
* Sent to extension from the bridge whenever a previously found
* receiver device is lost.
*/
"main:deviceDown": { deviceId: string };
/**
* Sent to the extension from the bridge whenever a
* `RECEIVER_STATUS` message (`NS_RECEIVER`) is received.
*/
"main:receiverDeviceStatusUpdated": {
deviceId: string;
status: ReceiverStatus;
};
/**
* Sent to the extension from the bridge whenever a
* `MEDIA_STATUS` message (`NS_RECEIVER`) is received.
*/
"main:receiverDeviceMediaStatusUpdated": {
deviceId: string;
status: MediaStatus;
};
/**
* Sent to the bridge when non-session related receiver messages
* need to be sent (e.g. volume control, application stop, etc...).
*/
"bridge:sendReceiverMessage": {
deviceId: string;
message: SenderMessage;
};
/**
* Sent to the bridge when the receiver selector media UI is used
* to control media playback.
*/
"bridge:sendMediaMessage": {
deviceId: string;
message: SenderMediaMessage;
};
/**
* Sent to bridge from cast API instance when a session request is
* initiated.
*/
"bridge:createCastSession": {
appId: string;
receiverDevice: ReceiverDevice;
};
/**
* Connects to, and sends a `STOP` message on the `NS_RECEIVER`
* channel for the given receiver device.
*/
"bridge:stopCastSession": {
receiverDevice: ReceiverDevice;
};
/**
* Sent to cast API instances whenever a session is created or
* updates. Updated details is a mutable subset of session details
* otherwise fixed on creation.
*/
"main:castSessionCreated": CastSessionCreatedDetails;
"main:castSessionUpdated": CastSessionUpdatedDetails;
/**
* Sent to cast API instances whenever a session is stopped.
*/
"cast:sessionStopped": {
sessionId: string;
};
/**
* Sent to bridge from cast API instance whenever an `NS_RECEIVER`
* message needs to be sent.
*/
"bridge:sendCastReceiverMessage": {
sessionId: string;
messageData: SenderMessage;
messageId: string;
};
/**
* Sent to bridge from cast API instance whenever a application
* session message needs to be sent (via
* `chrome.cast.Session#sendMessage`).
*/
"bridge:sendCastSessionMessage": {
sessionId: string;
namespace: string;
messageData: object | string;
messageId: string;
};
/**
* Sent to cast API instance from bridge when session message
* received from a receiver device.
*/
"cast:sessionMessageReceived": {
sessionId: string;
namespace: string;
messageData: string;
};
/**
* Sent to cast API instance from bridge whenever a message
* operation is completed. If an error ocurred, an error string will
* be passed as the `error` data property.
*/
"cast:impl_sendMessage": {
sessionId: string;
messageId: string;
error?: string;
};
/**
* Sent to the bridge to start an HTTP media server at a given file
* path on the given port.
*/
"bridge:startMediaServer": {
filePath: string;
port: number;
};
/**
* Sent to media sender from bridge when the media server is ready
* to serve files.
*/
"mediaCast:mediaServerStarted": {
mediaPath: string;
subtitlePaths: string[];
localAddress: string;
};
/**
* Sent to bridge to stop HTTP media server.
*/
"bridge:stopMediaServer": undefined;
/**
* Sent to media sender from bridge when the media server has
* stopped.
*/
"mediaCast:mediaServerStopped": undefined;
/**
* Sent to media sender from bridge when the media server has
* encountered an error.
*/
"mediaCast:mediaServerError": string;
};
type MessageDefinitions = ExtensionMessageDefinitions &
BridgeMessageDefinitions;
interface MessageBase<K extends keyof MessageDefinitions> {
subject: K;
data: MessageDefinitions[K];
}
type Messages = {
[K in keyof MessageDefinitions]: MessageBase<K>;
};
/**
* Make message data key optional if specified as blank or with
* all-optional keys.
*/
type NarrowedMessage<L extends MessageBase<keyof MessageDefinitions>> =
L extends unknown
? undefined extends L["data"]
? Omit<L, "data"> & Partial<L>
: L
: never;
export type Port = TypedPort<Message>;
export type Message = NarrowedMessage<Messages[keyof Messages]>;
/**
* Typed WebExtension-style messaging utility class.
*/
export default new (class Messenger {
connect(connectInfo: { name: string }) {
return browser.runtime.connect(connectInfo) as Port;
}
connectTab(tabId: number, connectInfo: { name: string; frameId: number }) {
return browser.tabs.connect(tabId, connectInfo) as Port;
}
sendMessage(
message: Message,
options?: browser.runtime._SendMessageOptions
): Promise<any>;
sendMessage(
extensionId: string,
options?: browser.runtime._SendMessageOptions
): Promise<any>;
sendMessage(
messageOrExtensionId: string | Message,
options?: browser.runtime._SendMessageOptions
) {
return browser.runtime.sendMessage(messageOrExtensionId, options);
}
onConnect = browser.runtime.onConnect as WebExtEvent<(port: Port) => void>;
onMessage = browser.runtime.onMessage as WebExtEvent<
(message: Message, sender: browser.runtime.MessageSender) => void
>;
})();