ultrawidify/src/ext/lib/comms/CommsServer.ts

194 lines
6.0 KiB
TypeScript
Raw Normal View History

import Debug from '../../conf/Debug';
import BrowserDetect from '../../conf/BrowserDetect';
2021-03-06 01:27:28 +01:00
import Logger from '../Logger';
import Settings from '../Settings';
import { browser } from 'webextension-polyfill-ts';
import ExtensionMode from '../../../common/enums/ExtensionMode.enum';
import EventBus from '../EventBus';
2021-03-06 01:27:28 +01:00
class CommsServer {
2021-03-06 01:27:28 +01:00
server: any;
logger: Logger;
settings: Settings;
eventBus: EventBus;
2021-03-06 01:27:28 +01:00
2021-03-06 02:22:56 +01:00
ports: {
2022-08-21 15:24:24 +02:00
[tab: string] : {
[frame: string] : {
[port: string]: any
2022-08-21 15:04:21 +02:00
}
2021-03-06 02:22:56 +01:00
}
2022-08-21 15:04:21 +02:00
} = {};
2021-03-06 01:27:28 +01:00
popupPort: any;
2021-03-29 21:14:03 +02:00
//#region getters
get activeTab() {
return browser.tabs.query({currentWindow: true, active: true});
}
//#endregion
2021-03-06 01:27:28 +01:00
//#region lifecycle
constructor(server) {
this.server = server;
this.logger = server.logger;
2018-08-07 23:31:28 +02:00
this.settings = server.settings;
this.eventBus = server.eventBus;
2021-03-06 01:27:28 +01:00
browser.runtime.onConnect.addListener(p => this.onConnect(p));
browser.runtime.onMessage.addListener((m, sender) => this.processReceivedMessage_nonpersistent(m, sender));
}
private onConnect(port){
// special case
if (port.name === 'popup-port') {
this.popupPort = port;
this.popupPort.onMessage.addListener( (m,p) => this.processReceivedMessage(m,p));
return;
2020-02-08 00:41:10 +01:00
}
var tabId = port.sender.tab.id;
var frameId = port.sender.frameId;
if (! this.ports[tabId]){
this.ports[tabId] = {};
}
if (! this.ports[tabId][frameId]) {
this.ports[tabId][frameId] = {};
}
this.ports[tabId][frameId][port.name] = port;
this.ports[tabId][frameId][port.name].onMessage.addListener( (m,p) => this.processReceivedMessage(m, p));
this.ports[tabId][frameId][port.name].onDisconnect.addListener( (p) => {
try {
delete this.ports[p.sender.tab.id][p.sender.frameId][port.name];
} catch (e) {
// no biggie if the thing above doesn't exist.
}
if (Object.keys(this.ports[tabId][frameId].length === 0)) {
delete this.ports[tabId][frameId];
if(Object.keys(this.ports[p.sender.tab.id]).length === 0) {
delete this.ports[tabId];
}
}
});
}
//#endregion
sendMessage(message, context?) {
if (context?.comms.forwardTo === 'all') {
return this.sendToAll(message);
}
if (context?.comms.forwardTo === 'active') {
return this.sendToActive(message);
}
if (context?.comms.forwardTo === 'contentScript') {
return this.sendToFrame(message, context.tab, context.frame, context.port);
}
if (context?.comms.forwardTo === 'popup') {
return this.sendToPopup(message);
}
}
/**
* Sends a message to popup script
*/
sendToPopup(message) {
this.popupPort.postMessage(message);
}
/**
* sends a message to ALL **CONTENT SCRIPTS**
* Does NOT send a message to popup.
**/
private sendToAll(message){
2022-08-21 15:04:21 +02:00
for(const tid in this.ports){
const tab = this.ports[tid];
for(const frame in tab){
for (const port in tab[frame]) {
tab[frame][port].postMessage(message);
}
}
}
}
2021-03-06 01:27:28 +01:00
/**
* Sends a message to addon content scripts in a single browser tab.
2021-03-06 01:27:28 +01:00
* @param message message
* @param tab the tab we want to send the message to
* @param frame the frame within that tab that we want to send the message to
* @param port if defined, message will only be sent to that specific script, otherwise it gets sent to all scripts of a given frame
*/
private async sendToFrameContentScripts(message, tab, frame, port?) {
if (port !== undefined) {
this.ports[tab][frame][port].postMessage(message);
return;
}
2021-03-06 01:27:28 +01:00
for (const framePort in this.ports[tab][frame]) {
this.ports[tab][frame][framePort].postMessage(message);
}
}
private async sendToFrame(message, tab, frame, port?) {
2020-01-30 23:17:43 +01:00
this.logger.log('info', 'comms', `%c[CommsServer::sendToFrame] attempting to send message to tab ${tab}, frame ${frame}`, "background: #dda; color: #11D", message);
2018-11-21 20:41:15 +01:00
if (isNaN(tab)) {
2020-02-08 00:41:10 +01:00
if (frame === '__playing') {
2018-11-21 20:41:15 +01:00
message['playing'] = true;
this.sendToAll(message);
return;
2020-02-08 00:41:10 +01:00
} else if (frame === '__all') {
2018-11-21 20:41:15 +01:00
this.sendToAll(message);
return;
}
2020-05-16 22:02:06 +02:00
[tab, frame] = frame.split('-');
2018-11-21 20:41:15 +01:00
}
2020-01-30 23:17:43 +01:00
this.logger.log('info', 'comms', `%c[CommsServer::sendToFrame] attempting to send message to tab ${tab}, frame ${frame}`, "background: #dda; color: #11D", message);
2018-11-21 20:41:15 +01:00
try {
this.sendToFrameContentScripts(message, tab, frame, port);
2018-11-21 20:41:15 +01:00
} catch (e) {
2020-01-30 23:17:43 +01:00
this.logger.log('error', 'comms', `%c[CommsServer::sendToFrame] Sending message failed. Reason:`, "background: #dda; color: #11D", e);
2018-11-21 20:41:15 +01:00
}
}
private async sendToActive(message) {
2020-01-30 23:17:43 +01:00
this.logger.log('info', 'comms', "%c[CommsServer::sendToActive] trying to send a message to active tab. Message:", "background: #dda; color: #11D", message);
2021-03-06 01:27:28 +01:00
const tabs = await this.activeTab;
2020-01-30 23:17:43 +01:00
this.logger.log('info', 'comms', "[CommsServer::_sendToActive] currently active tab(s)?", tabs);
for (const frame in this.ports[tabs[0].id]) {
this.logger.log('info', 'comms', "key?", frame, this.ports[tabs[0].id]);
}
for (const frame in this.ports[tabs[0].id]) {
this.sendToFrameContentScripts(message, tabs[0].id, frame);
}
}
private async processReceivedMessage(message, port){
2020-02-04 00:56:31 +01:00
this.logger.log('info', 'comms', "[CommsServer.js::processReceivedMessage] Received message from popup/content script!", message, "port", port);
// this triggers events
this.eventBus.send(
message.command,
message.config,
{
...message.context,
comms: {port},
fromComms: true
}
);
}
private processReceivedMessage_nonpersistent(message, sender){
2020-01-30 23:17:43 +01:00
this.logger.log('info', 'comms', "%c[CommsServer.js::processMessage_nonpersistent] Received message from background script!", "background-color: #11D; color: #aad", message, sender);
2022-07-31 01:12:54 +02:00
this.eventBus.send(message.command, message.config, {comms: {sender}, fromComms: true});
}
}
export default CommsServer;