2018-12-30 23:41:44 +01:00
import Debug from '../../conf/Debug' ;
2019-01-02 20:36:00 +01:00
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' ;
2022-07-31 00:15:28 +02:00
import EventBus from '../EventBus' ;
2022-09-20 01:34:59 +02:00
import { CommsOrigin } from './CommsClient' ;
2021-03-06 01:27:28 +01:00
2018-05-26 23:08:49 +02:00
class CommsServer {
2021-03-06 01:27:28 +01:00
server : any ;
logger : Logger ;
settings : Settings ;
2022-07-31 00:15:28 +02:00
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
2022-08-21 22:46:06 +02:00
//#region lifecycle
2018-05-26 23:08:49 +02:00
constructor ( server ) {
this . server = server ;
2019-09-03 22:17:10 +02:00
this . logger = server . logger ;
2018-08-07 23:31:28 +02:00
this . settings = server . settings ;
2022-07-31 00:15:28 +02:00
this . eventBus = server . eventBus ;
2018-05-26 23:08:49 +02:00
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 ) ) ;
2018-05-26 23:08:49 +02:00
}
2022-08-21 22:46:06 +02:00
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
}
2022-08-21 22:46:06 +02:00
var tabId = port . sender . tab . id ;
var frameId = port . sender . frameId ;
if ( ! this . ports [ tabId ] ) {
this . ports [ tabId ] = { } ;
2018-09-20 01:11:18 +02:00
}
2022-08-21 22:46:06 +02:00
if ( ! this . ports [ tabId ] [ frameId ] ) {
this . ports [ tabId ] [ frameId ] = { } ;
2018-09-20 01:11:18 +02:00
}
2022-08-21 22:46:06 +02:00
this . ports [ tabId ] [ frameId ] [ port . name ] = port ;
this . ports [ tabId ] [ frameId ] [ port . name ] . onMessage . addListener ( ( m , p ) = > this . processReceivedMessage ( m , p ) ) ;
2022-07-31 00:15:28 +02:00
2022-08-21 22:46:06 +02:00
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 ] ;
}
}
} ) ;
2018-06-27 23:55:37 +02:00
}
2022-08-21 22:46:06 +02:00
//#endregion
sendMessage ( message , context ? ) {
2022-09-20 01:34:59 +02:00
// stop messages from returning where they came from, and prevent
// cross-pollination between content scripts running in different
// tabs.
if ( context ? . origin !== CommsOrigin . ContentScript ) {
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 ) ;
}
2022-07-31 00:15:28 +02:00
}
2022-09-20 01:34:59 +02:00
if ( context ? . origin !== CommsOrigin . Popup ) {
if ( context ? . comms . forwardTo === 'popup' ) {
return this . sendToPopup ( message ) ;
}
2022-08-21 22:46:06 +02:00
}
}
/ * *
* Sends a message to popup script
* /
sendToPopup ( message ) {
this . popupPort . postMessage ( message ) ;
2022-07-31 00:15:28 +02:00
}
2022-08-21 22:46:06 +02:00
/ * *
* 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 ] ;
2020-03-09 19:39:24 +01:00
for ( const frame in tab ) {
for ( const port in tab [ frame ] ) {
tab [ frame ] [ port ] . postMessage ( message ) ;
}
2018-05-26 23:56:50 +02:00
}
}
}
2021-03-06 01:27:28 +01:00
/ * *
2022-08-21 22:46:06 +02: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
* /
2022-07-31 00:15:28 +02:00
private async sendToFrameContentScripts ( message , tab , frame , port ? ) {
2020-03-13 00:13:00 +01:00
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 ) ;
2020-03-09 19:39:24 +01:00
}
}
2022-07-31 00:15:28 +02:00
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 {
2020-03-13 00:13:00 +01:00
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
}
}
2022-07-31 00:15:28 +02: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 ) ;
2018-05-26 23:56:50 +02:00
2021-03-06 01:27:28 +01:00
const tabs = await this . activeTab ;
2018-05-27 01:29:02 +02:00
2020-01-30 23:17:43 +01:00
this . logger . log ( 'info' , 'comms' , "[CommsServer::_sendToActive] currently active tab(s)?" , tabs ) ;
2020-03-09 19:39:24 +01:00
for ( const frame in this . ports [ tabs [ 0 ] . id ] ) {
this . logger . log ( 'info' , 'comms' , "key?" , frame , this . ports [ tabs [ 0 ] . id ] ) ;
2018-05-27 01:29:02 +02:00
}
2020-03-09 19:39:24 +01:00
for ( const frame in this . ports [ tabs [ 0 ] . id ] ) {
2020-03-13 00:13:00 +01:00
this . sendToFrameContentScripts ( message , tabs [ 0 ] . id , frame ) ;
2018-05-26 23:56:50 +02:00
}
}
2022-08-21 22:46:06 +02:00
private async processReceivedMessage ( message , port ) {
// this triggers events
this . eventBus . send (
message . command ,
message . config ,
{
. . . message . context ,
2022-09-20 01:34:59 +02:00
comms : {
. . . message . context ? . comms ,
port
} ,
// origin is required to stop cross-pollination between content scripts, while still
// preserving the ability to send messages directly between popup and content scripts
origin : port.name === 'popup-port' ? CommsOrigin.Popup : CommsOrigin.ContentScript
2022-08-21 22:46:06 +02:00
}
) ;
2018-05-26 23:08:49 +02:00
}
2022-08-21 22:46:06 +02:00
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 00:15:28 +02:00
2022-09-20 01:34:59 +02:00
this . eventBus . send (
message . command ,
message . config , {
. . . message . context ,
comms : {
. . . message . context ? . comms ,
sender
} ,
origin : CommsOrigin.Server
}
) ;
2018-05-26 23:08:49 +02:00
}
}
2018-12-30 23:41:44 +01:00
export default CommsServer ;