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' ;
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 : {
[ frame : string ] : {
[ port : string ] : any
}
} [ ] = [ ] ;
2021-03-06 01:27:28 +01:00
popupPort : any ;
2021-03-29 21:14:03 +02:00
/ * *
* commands — functions that handle incoming messages
2022-07-31 00:15:28 +02:00
* functions can have the following arguments , which are ,
2021-03-29 21:14:03 +02:00
* in this order :
* message — the message we received
* port | sender — on persistent channels , second argument is port on which the server
* listens . If the message was sent in non - persistent way , this is the
* sender script / frame / whatever of the message
* sendResponse — callback function on messages received via non - persistent channel
* /
commands : { [ x : string ] : ( ( a : any , b : any ) = > void | Promise < void > ) [ ] } = {
'get-current-site' : [
async ( message , port ) = > {
port . postMessage ( {
cmd : 'set-current-site' ,
site : await this . server . getVideoTab ( ) ,
tabHostname : await this . getCurrentTabHostname ( )
} ) ;
} ,
] ,
2022-07-31 00:15:28 +02:00
2021-03-29 21:14:03 +02:00
'logging-stop-and-save' : [ // TODO: possibly never used/superseded — check
( message , sender ) = > {
this . logger . log ( 'info' , 'comms' , "Received command to stop logging and export the received input" ) ;
this . logger . addToGlobalHistory ( ` ${ message . host } :: ${ sender ? . tab ? . id ? ? '× ' } - ${ sender . frameId ? ? '× ' } ` , JSON . parse ( message . history ) ) ;
this . logger . finish ( ) ;
}
] ,
'logging-save' : [
( message , sender ) = > {
this . logger . log ( 'info' , 'comms' , ` Received command to save log for site ${ message . host } (tabId ${ sender . tab . id } , frameId ${ sender . frameId } ` ) ;
this . logger . addToGlobalHistory ( ` ${ message ? . host } :: ${ sender ? . tab ? . id ? ? '× ' } - ${ sender ? . frameId ? ? '× ' } ` , JSON . parse ( message . history ) ) ;
}
]
}
//#region getters
get activeTab() {
return browser . tabs . query ( { currentWindow : true , active : true } ) ;
}
//#endregion
2021-03-06 01:27:28 +01:00
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
}
2020-03-08 16:49:20 +01:00
subscribe ( command , callback ) {
if ( ! this . commands [ command ] ) {
this . commands [ command ] = [ callback ] ;
} else {
this . commands [ command ] . push ( callback ) ;
}
}
2018-09-20 01:11:18 +02:00
async getCurrentTabHostname() {
2021-03-06 01:27:28 +01:00
const activeTab = await this . activeTab ;
2020-02-08 00:41:10 +01:00
if ( ! activeTab || activeTab . length < 1 ) {
this . logger . log ( 'warn' , 'comms' , 'There is no active tab for some reason. activeTab:' , activeTab ) ;
}
2018-09-20 01:11:18 +02:00
const url = activeTab [ 0 ] . url ;
var hostname ;
if ( url . indexOf ( "://" ) > - 1 ) { //find & remove protocol (http, ftp, etc.) and get hostname
hostname = url . split ( '/' ) [ 2 ] ;
}
else {
hostname = url . split ( '/' ) [ 0 ] ;
}
2022-07-31 00:15:28 +02:00
2018-09-20 01:11:18 +02:00
hostname = hostname . split ( ':' ) [ 0 ] ; //find & remove port number
hostname = hostname . split ( '?' ) [ 0 ] ; //find & remove "?"
2018-06-27 23:55:37 +02:00
2018-09-20 01:11:18 +02:00
return hostname ;
2018-06-27 23:55:37 +02:00
}
2022-07-31 00:15:28 +02:00
sendMessage ( message , context ) {
if ( context ? . forwardTo === 'all' ) {
return this . sendToAll ( message ) ;
}
if ( context ? . forwardTo === 'active' ) {
return this . sendToActive ( message ) ;
}
if ( context ? . forwardTo === 'contentScript' ) {
return this . sendToFrame ( message , context . tab , context . frame , context . port ) ;
}
}
private sendToAll ( message ) {
2020-03-09 19:39:24 +01:00
for ( const tab of this . ports ) {
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
/ * *
* Sends a message to addon content scripts .
* @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
}
}
2020-03-13 00:13:00 +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
}
}
2018-05-26 23:08:49 +02:00
onConnect ( port ) {
2022-07-31 00:15:28 +02:00
// special case
2018-05-27 01:29:02 +02:00
if ( port . name === 'popup-port' ) {
this . popupPort = port ;
2020-03-09 21:29:39 +01:00
this . popupPort . onMessage . addListener ( ( m , p ) = > this . processReceivedMessage ( m , p ) ) ;
2018-05-27 01:29:02 +02:00
return ;
}
2018-05-26 23:08:49 +02:00
var tabId = port . sender . tab . id ;
2018-05-26 23:56:50 +02:00
var frameId = port . sender . frameId ;
2020-03-09 19:39:24 +01:00
if ( ! this . ports [ tabId ] ) {
2022-07-31 00:15:28 +02:00
this . ports [ tabId ] = { } ;
2018-05-26 23:56:50 +02:00
}
2020-03-09 19:39:24 +01:00
if ( ! this . ports [ tabId ] [ frameId ] ) {
this . ports [ tabId ] [ frameId ] = { } ;
}
this . ports [ tabId ] [ frameId ] [ port . name ] = port ;
2020-03-09 21:29:39 +01:00
this . ports [ tabId ] [ frameId ] [ port . name ] . onMessage . addListener ( ( m , p ) = > this . processReceivedMessage ( m , p ) ) ;
2020-03-09 19:39:24 +01:00
2020-03-09 21:29:39 +01:00
this . ports [ tabId ] [ frameId ] [ port . name ] . onDisconnect . addListener ( ( p ) = > {
try {
2022-07-31 00:15:28 +02:00
delete this . ports [ p . sender . tab . id ] [ p . sender . frameId ] [ port . name ] ;
2020-03-09 21:29:39 +01:00
} catch ( e ) {
2022-07-31 00:15:28 +02:00
// no biggie if the thing above doesn't exist.
2020-03-09 21:29:39 +01:00
}
2020-03-09 19:39:24 +01:00
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-05-26 23:56:50 +02:00
}
} ) ;
2018-05-26 23:08:49 +02:00
}
2020-02-04 00:56:31 +01:00
async processReceivedMessage ( message , port ) {
this . logger . log ( 'info' , 'comms' , "[CommsServer.js::processReceivedMessage] Received message from popup/content script!" , message , "port" , port ) ;
2022-07-31 00:15:28 +02:00
this . eventBus . send ( message , { port , fromComms : true } ) ;
2018-05-26 23:08:49 +02:00
}
2021-03-06 01:27:28 +01:00
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
this . eventBus . send ( message , { sender , fromComms : true } ) ;
2018-05-26 23:08:49 +02:00
}
2020-05-16 21:35:24 +02:00
// chrome shitiness mitigation
sendUnmarkPlayer ( message ) {
this . logger . log ( 'info' , 'comms' , '[CommsServer.js::sendUnmarkPlayer] Chrome is a shit browser that doesn\'t do port.postMessage() in unload events, so we have to resort to inelegant hacks. If you see this, then the workaround method works.' ) ;
this . processReceivedMessage ( message , this . popupPort ) ;
}
2018-05-26 23:08:49 +02:00
}
2018-12-30 23:41:44 +01:00
export default CommsServer ;