2023-03-30 00:43:30 +02:00
|
|
|
import { IframeData } from './video-data/IframeManager';
|
2022-09-20 01:34:59 +02:00
|
|
|
import CommsClient, { CommsOrigin } from './comms/CommsClient';
|
2022-07-31 00:15:28 +02:00
|
|
|
import CommsServer from './comms/CommsServer';
|
2026-01-07 01:42:37 +01:00
|
|
|
import { EventBusCommand, EventBusContext } from '@src/common/interfaces/EventBusMessage.interface';
|
2021-10-26 22:19:41 +02:00
|
|
|
|
2022-07-31 00:15:28 +02:00
|
|
|
|
2026-01-07 01:42:37 +01:00
|
|
|
|
|
|
|
|
// export interface EventBusContext {
|
|
|
|
|
// stopPropagation?: boolean,
|
|
|
|
|
|
|
|
|
|
// // Context stuff added by Comms
|
|
|
|
|
// origin?: CommsOrigin,
|
|
|
|
|
// comms?: {
|
|
|
|
|
// sender?: chrome.runtime.MessageSender,
|
|
|
|
|
// port?: chrome.runtime.Port,
|
|
|
|
|
// frame?: any,
|
|
|
|
|
// sourceFrame?: IframeData
|
|
|
|
|
// forwardTo?: 'all' | 'active' | 'contentScript' | 'server' | 'sameOrigin' | 'popup' | 'all-frames',
|
|
|
|
|
// };
|
|
|
|
|
// borderCrossings?: {
|
|
|
|
|
// commsServer?: boolean,
|
|
|
|
|
// iframe?: boolean,
|
|
|
|
|
// }
|
|
|
|
|
// }
|
2021-10-26 22:19:41 +02:00
|
|
|
|
|
|
|
|
export default class EventBus {
|
|
|
|
|
|
2026-01-07 01:42:37 +01:00
|
|
|
private name: string;
|
|
|
|
|
|
2021-10-26 22:19:41 +02:00
|
|
|
private commands: { [x: string]: EventBusCommand[]} = {};
|
2022-08-21 22:46:06 +02:00
|
|
|
private comms?: CommsClient | CommsServer;
|
2022-07-31 00:15:28 +02:00
|
|
|
|
2022-11-21 01:01:28 +01:00
|
|
|
private disableTunnel: boolean = false;
|
|
|
|
|
private popupContext: any = {};
|
2025-05-19 01:16:33 +02:00
|
|
|
|
|
|
|
|
private iframeForwardingList: {iframe: any, fn: (action, payload, context?) => void}[] = [];
|
|
|
|
|
|
2023-03-02 00:37:23 +01:00
|
|
|
// private uiUri = window.location.href;
|
|
|
|
|
|
2026-01-07 01:42:37 +01:00
|
|
|
constructor(options?: {isUWServer?: boolean, name?: string}) {
|
2023-07-10 22:00:53 +02:00
|
|
|
if (!options?.isUWServer) {
|
|
|
|
|
this.setupIframeTunnelling();
|
|
|
|
|
}
|
2026-01-07 01:42:37 +01:00
|
|
|
this.name = options?.name;
|
2023-03-02 00:37:23 +01:00
|
|
|
}
|
2022-11-21 01:01:28 +01:00
|
|
|
|
|
|
|
|
setupPopupTunnelWorkaround(context: EventBusContext): void {
|
|
|
|
|
this.disableTunnel = true;
|
|
|
|
|
this.popupContext = context;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-31 00:15:28 +02:00
|
|
|
//#region lifecycle
|
|
|
|
|
destroy() {
|
|
|
|
|
this.commands = null;
|
2023-03-02 00:37:23 +01:00
|
|
|
this.destroyIframeTunnelling();
|
2022-07-31 00:15:28 +02:00
|
|
|
}
|
|
|
|
|
//#endregion
|
|
|
|
|
|
2022-08-21 22:46:06 +02:00
|
|
|
setComms(comms: CommsClient | CommsServer) {
|
2022-07-31 00:15:28 +02:00
|
|
|
this.comms = comms;
|
|
|
|
|
}
|
2021-10-26 22:19:41 +02:00
|
|
|
|
2024-12-30 23:02:55 +01:00
|
|
|
subscribe(commandString: string, command: EventBusCommand) {
|
|
|
|
|
if (!this.commands[commandString]) {
|
|
|
|
|
this.commands[commandString] = [command];
|
|
|
|
|
} else {
|
|
|
|
|
this.commands[commandString].push(command);
|
2022-05-06 00:22:35 +02:00
|
|
|
}
|
|
|
|
|
}
|
2021-10-26 22:19:41 +02:00
|
|
|
|
2024-12-30 23:02:55 +01:00
|
|
|
subscribeMulti(commands: {[commandString: string]: EventBusCommand}, source?: any) {
|
|
|
|
|
for (const key in commands) {
|
|
|
|
|
this.subscribe(
|
|
|
|
|
key,
|
|
|
|
|
{
|
|
|
|
|
...commands[key],
|
|
|
|
|
source: source ?? commands[key].source
|
|
|
|
|
}
|
|
|
|
|
);
|
2022-05-06 00:28:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-30 23:02:55 +01:00
|
|
|
/**
|
|
|
|
|
* Removes all commands from a given source
|
|
|
|
|
* @param source
|
|
|
|
|
*/
|
|
|
|
|
unsubscribeAll(source: any) {
|
|
|
|
|
for (const commandString in this.commands) {
|
|
|
|
|
this.commands[commandString] = this.commands[commandString].filter(x => x.source !== source);
|
2021-10-26 22:19:41 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-19 01:16:33 +02:00
|
|
|
forwardToIframe(iframe: any, fn: (action: string, payload: any, context?: EventBusContext) => void) {
|
|
|
|
|
this.cancelIframeForwarding(iframe);
|
|
|
|
|
this.iframeForwardingList.push({iframe, fn});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cancelIframeForwarding(iframe: any) {
|
|
|
|
|
const existingForwarding = this.iframeForwardingList.findIndex((x: any) => x.iframe === iframe);
|
|
|
|
|
if (existingForwarding !== -1) {
|
|
|
|
|
this.iframeForwardingList.splice(existingForwarding, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-02 00:37:23 +01:00
|
|
|
send(command: string, commandData: any, context?: EventBusContext) {
|
2026-01-07 01:42:37 +01:00
|
|
|
console.info('sending eventBus command:', this.name, 'command:', {command, commandData, context});
|
2022-07-31 01:12:54 +02:00
|
|
|
// execute commands we have subscriptions for
|
2024-12-30 23:02:55 +01:00
|
|
|
|
2022-07-31 01:12:54 +02:00
|
|
|
if (this.commands?.[command]) {
|
|
|
|
|
for (const eventBusCommand of this.commands[command]) {
|
2023-03-02 00:37:23 +01:00
|
|
|
eventBusCommand.function(commandData, context);
|
2022-07-31 01:12:54 +02:00
|
|
|
}
|
2021-11-01 01:18:07 +01:00
|
|
|
}
|
|
|
|
|
|
2022-09-20 01:34:59 +02:00
|
|
|
// preventing messages from flowing back to their original senders is
|
|
|
|
|
// CommsServer's job. EventBus does not have enough data for this decision.
|
2025-05-07 00:42:25 +02:00
|
|
|
// We do, however, have enough data to prevent backflow of messages that
|
|
|
|
|
// crossed CommsServer once already.
|
2025-10-08 19:39:55 +02:00
|
|
|
if (
|
|
|
|
|
this.comms
|
|
|
|
|
&& context?.origin !== CommsOrigin.Server
|
|
|
|
|
&& !context?.borderCrossings?.commsServer
|
|
|
|
|
) {
|
|
|
|
|
try {
|
|
|
|
|
this.comms.sendMessage({command, config: commandData, context}, context);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
if (command !== 'reload-required') {
|
|
|
|
|
// We shouldn't let reload-required command to trigger new reload-required commands.
|
|
|
|
|
this.send('reload-required', {});
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-05-19 01:16:33 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// call forwarding functions if they exist
|
|
|
|
|
if (!context?.borderCrossings?.iframe) {
|
|
|
|
|
for (const forwarding of this.iframeForwardingList) {
|
|
|
|
|
forwarding.fn(
|
|
|
|
|
command,
|
|
|
|
|
commandData,
|
|
|
|
|
{
|
|
|
|
|
...context,
|
|
|
|
|
borderCrossings: {
|
|
|
|
|
...context?.borderCrossings,
|
|
|
|
|
iframe: true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
2026-01-07 01:42:37 +01:00
|
|
|
this.sendToTunnel(command, commandData);
|
2022-07-31 01:12:54 +02:00
|
|
|
}
|
2021-10-26 22:19:41 +02:00
|
|
|
|
2022-07-31 01:12:54 +02:00
|
|
|
if (context?.stopPropagation) {
|
|
|
|
|
return;
|
2021-10-26 22:19:41 +02:00
|
|
|
}
|
|
|
|
|
}
|
2023-03-02 00:37:23 +01:00
|
|
|
//#endregion
|
2021-10-26 22:19:41 +02:00
|
|
|
|
2022-03-29 01:53:16 +02:00
|
|
|
/**
|
|
|
|
|
* Send, but intended for sending commands from iframe to content scripts
|
|
|
|
|
* @param command
|
|
|
|
|
* @param config
|
|
|
|
|
*/
|
|
|
|
|
sendToTunnel(command: string, config: any) {
|
2022-11-21 01:01:28 +01:00
|
|
|
if (!this.disableTunnel) {
|
|
|
|
|
window.parent.postMessage(
|
|
|
|
|
{
|
|
|
|
|
action: 'uw-bus-tunnel',
|
|
|
|
|
payload: {action: command, config}
|
|
|
|
|
},
|
|
|
|
|
'*'
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
// because iframe UI components get reused in the popup, we
|
|
|
|
|
// also need to set up a detour because the tunnel is closed
|
|
|
|
|
// in the popup
|
|
|
|
|
if (this.comms) {
|
2025-10-08 19:39:55 +02:00
|
|
|
try {
|
|
|
|
|
this.comms.sendMessage({command, config, context: this.popupContext}, this.popupContext);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
if (command !== 'reload-required') {
|
|
|
|
|
this.send('reload-required', {});
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-21 01:01:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-03-29 01:53:16 +02:00
|
|
|
}
|
|
|
|
|
|
2023-03-02 00:37:23 +01:00
|
|
|
//#region iframe tunnelling
|
|
|
|
|
private setupIframeTunnelling() {
|
2024-06-02 16:06:26 +02:00
|
|
|
// forward messages coming from iframe tunnels
|
2023-03-02 00:37:23 +01:00
|
|
|
window.addEventListener('message', this.handleIframeMessage);
|
|
|
|
|
}
|
|
|
|
|
private destroyIframeTunnelling() {
|
|
|
|
|
window.removeEventListener('message', this.handleIframeMessage);
|
|
|
|
|
}
|
|
|
|
|
private handleIframeMessage(event: any) {
|
2026-01-07 01:42:37 +01:00
|
|
|
if (event.data?.action !== 'uw-bus-tunnel') {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
console.info(this.name, 'received message from iframe. command:', event.data.payload);
|
|
|
|
|
this.send(event.data.payload.command, event.data.payload.config);
|
2023-03-02 00:37:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//#endregion
|
|
|
|
|
|
2021-10-26 22:19:41 +02:00
|
|
|
}
|