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' ;
2018-05-26 23:08:49 +02:00
class CommsServer {
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 ;
2018-05-26 23:08:49 +02:00
this . ports = [ ] ;
2020-01-30 01:06:21 +01:00
this . popupPort = null ;
2018-05-26 23:08:49 +02:00
2018-12-30 23:41:44 +01:00
if ( BrowserDetect . firefox ) {
2020-03-09 19:39:24 +01:00
browser . runtime . onConnect . addListener ( p => this . onConnect ( p ) ) ;
2020-03-09 21:29:39 +01:00
browser . runtime . onMessage . addListener ( ( m , sender ) => this . processReceivedMessage _nonpersistent ( m , sender ) ) ;
2018-05-26 23:08:49 +02:00
} else {
2020-03-09 21:41:31 +01:00
chrome . runtime . onConnect . addListener ( p => this . onConnect ( p ) ) ;
2020-03-09 21:29:39 +01:00
chrome . runtime . onMessage . addListener ( ( m , sender , callback ) => this . processReceivedMessage _nonpersistent ( m , sender , callback ) ) ;
2018-05-26 23:08:49 +02:00
}
2020-01-30 01:06:21 +01:00
// commands — functions that handle incoming messages
// functions can have the following arguments, which are,
// 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
this . commands = {
'announce-zoom' : [
( message ) => {
try {
// forward message to the popup
this . popupPort . postMessage ( { cmd : 'set-current-zoom' , zoom : message . zoom } ) ;
} catch ( e ) {
// if popup is closed, this will/may fail. This is okay, so we just ignore this error
}
} ,
] ,
'get-current-zoom' : [
( message ) => this . sendToActive ( message ) ,
] ,
'get-current-site' : [
async ( message , port ) => {
port . postMessage ( {
cmd : 'set-current-site' ,
site : await this . server . getVideoTab ( ) ,
tabHostname : await this . getCurrentTabHostname ( )
} ) ;
} ,
] ,
'popup-set-selected-tab' : [
( message ) => this . server . setSelectedTab ( message . selectedMenu , message . selectedSubitem ) ,
] ,
'get-config' : [
( message , port ) => {
2020-01-30 23:17:43 +01:00
this . logger . log ( 'info' , 'comms' , "CommsServer: received get-config. Active settings?" , this . settings . active , "\n(settings:" , this . settings , ")" ) ;
2020-01-30 01:06:21 +01:00
port . postMessage (
{ cmd : "set-config" , conf : this . settings . active , site : this . server . currentSite }
) ;
} ,
] ,
'has-video' : [
( message , port ) => this . server . registerVideo ( port . sender ) ,
] ,
'noVideo' : [
( message , port ) => this . server . unregisterVideo ( port . sender ) ,
] ,
'inject-css' : [
( message , sender ) => this . server . injectCss ( message . cssString , sender ) ,
] ,
'eject-css' : [
( message , sender ) => this . server . removeCss ( message . cssString , sender ) ,
] ,
'replace-css' : [
( message , sender ) => this . server . replaceCss ( message . oldCssString , message . newCssString , sender ) ,
] ,
'get-config' : [
( message , sender , sendResponse ) => {
if ( BrowserDetect . firefox ) {
var ret = { extensionConf : JSON . stringify ( this . settings . active ) } ;
2020-01-30 23:17:43 +01:00
this . logger . log ( 'info' , 'comms' , "%c[CommsServer.js::processMessage_nonpersistent] Returning this:" , "background-color: #11D; color: #aad" , ret ) ;
2020-01-30 01:06:21 +01:00
Promise . resolve ( ret ) ;
} else {
sendResponse ( { extensionConf : JSON . stringify ( this . settings . active ) } ) ;
return true ;
}
}
] ,
'autoar-enable' : [
( ) => {
this . settings . active . sites [ '@global' ] . autoar = "blacklist" ;
this . settings . save ( ) ;
2020-01-30 23:17:43 +01:00
this . logger . log ( 'info' , 'comms' , "[uw-bg] autoar set to enabled (blacklist). evidenz:" , this . settings . active ) ;
2020-01-30 01:06:21 +01:00
}
] ,
'autoar-disable' : [
( message ) => {
this . settings . active . sites [ '@global' ] . autoar = "disabled" ;
if ( message . reason ) {
this . settings . active . arDetect . disabledReason = message . reason ;
} else {
this . settings . active . arDetect . disabledReason = 'User disabled' ;
}
this . settings . save ( ) ;
2020-01-30 23:17:43 +01:00
this . logger . log ( 'info' , 'comms' , "[uw-bg] autoar set to disabled. evidenz:" , this . settings . active ) ;
2020-01-30 01:06:21 +01:00
}
] ,
'autoar-set-interval' : [
( message ) => {
2020-01-30 23:17:43 +01:00
this . logger . log ( 'info' , 'comms' , ` [uw-bg] trying to set new interval for autoAr. New interval is, ${ message . timeout } ms ` ) ;
2020-01-30 01:06:21 +01:00
// set fairly liberal limit
var timeout = message . timeout < 4 ? 4 : message . timeout ;
this . settings . active . arDetect . timer _playing = timeout ;
this . settings . save ( ) ;
}
] ,
'logging-stop-and-save' : [ // TODO: possibly never used/superseded — check
( message , sender ) => {
2020-01-30 23:17:43 +01:00
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 ) ) ;
2020-01-30 01:06:21 +01:00
this . logger . finish ( ) ;
}
] ,
'logging-save' : [
( message , sender ) => {
2020-01-30 23:17:43 +01:00
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 ) ) ;
2020-01-30 01:06:21 +01:00
}
]
}
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 ( ) {
const activeTab = await this . _getActiveTab ( ) ;
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 ] ;
}
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
}
2018-05-26 23:56:50 +02:00
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
}
}
}
2018-07-16 22:30:52 +02:00
async _getActiveTab ( ) {
2018-12-30 23:41:44 +01:00
if ( BrowserDetect . firefox ) {
2018-07-16 22:30:52 +02:00
return await browser . tabs . query ( { currentWindow : true , active : true } ) ;
} else {
return await new Promise ( ( resolve , reject ) => {
2018-09-20 21:45:09 +02:00
chrome . tabs . query ( { lastFocusedWindow : true , active : true } , function ( res ) {
2018-07-16 22:30:52 +02:00
resolve ( res ) ;
2019-05-09 21:07:40 +02:00
return true ;
2018-07-16 22:30:52 +02:00
} ) ;
} ) ;
2018-05-27 01:29:02 +02:00
}
2018-07-16 22:30:52 +02:00
}
2018-05-27 01:29:02 +02:00
2020-03-13 00:13:00 +01:00
// if port is NOT defined, send to all content scripts of a given frame
// if port is defined, send just to that particular script of a given frame
async sendToFrameContentScripts ( message , tab , frame , port ) {
if ( port !== undefined ) {
// note: 'port' is _not_ shadowed here.
this . ports [ tab ] [ frame ] [ port ] . postMessage ( message ) ;
return ;
}
2020-03-09 19:39:24 +01:00
for ( const port in this . ports [ tab ] [ frame ] ) {
2020-03-13 00:13:00 +01:00
// note: 'port' is shadowed here!
2020-03-09 19:39:24 +01:00
this . ports [ tab ] [ frame ] [ port ] . postMessage ( message ) ;
}
}
2020-03-13 00:13:00 +01:00
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
async sendToAllFrames ( message , tab , port ) {
for ( const frame in this . ports [ tab ] ) {
this . sendToFrameContentScripts ( message , tab , frame , port ) ;
}
}
2018-07-16 22:30:52 +02:00
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
2020-03-09 19:39:24 +01:00
const tabs = await this . _getActiveTab ( ) ;
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 ) {
2018-05-27 01:29:02 +02:00
// poseben primer | special case
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 ] ) {
2018-05-26 23:56:50 +02:00
this . ports [ tabId ] = { } ;
}
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 {
delete this . ports [ p . sender . tab . id ] [ p . sender . frameId ] [ port . name ] ;
} catch ( e ) {
// no biggie if the thing above doesn't exist.
}
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-01-30 01:06:21 +01:00
2020-03-08 16:49:20 +01:00
async execCmd ( message , portOrSender , sendResponse ) {
2020-01-30 23:17:43 +01:00
this . logger . log (
'info' , 'comms' , '[CommsServer.js::execCmd] Received message' , message ,
2020-02-04 00:56:31 +01:00
". Port/sender:" , portOrSender , "sendResponse:" , sendResponse , "\nThere is " , this . commands [ message . cmd ] ? . length ? ? 0 ,
2020-01-30 23:17:43 +01:00
" command(s) for action" , message . cmd
) ;
2020-03-08 16:49:20 +01:00
if ( this . commands [ message . cmd ] ) {
for ( const c of this . commands [ message . cmd ] ) {
2020-03-09 21:29:39 +01:00
try {
await c ( message , portOrSender , sendResponse ) ;
} catch ( e ) {
this . logger . log ( 'error' , 'debug' , "[CommsServer.js::execCmd] failed to execute command." , e )
}
2020-03-08 16:49:20 +01:00
}
2020-01-30 01:06:21 +01:00
}
}
2020-03-08 16:49:20 +01:00
async handleMessage ( message , portOrSender , sendResponse ) {
await this . execCmd ( message , portOrSender , sendResponse ) ;
2020-03-13 00:13:00 +01:00
if ( message . forwardToSameFramePort ) {
this . sendToFrameContentScripts ( message , portOrSender . tab . id , portOrSender . frameId , message . port )
}
2019-01-02 20:36:00 +01:00
if ( message . forwardToContentScript ) {
2020-01-30 23:17:43 +01:00
this . logger . log ( 'info' , 'comms' , "[CommsServer.js::processReceivedMessage] Message has 'forward to content script' flag set. Forwarding message as is. Message:" , message ) ;
2019-04-13 03:09:29 +02:00
this . sendToFrame ( message , message . targetTab , message . targetFrame ) ;
}
if ( message . forwardToAll ) {
2020-01-30 23:17:43 +01:00
this . logger . log ( 'info' , 'comms' , "[CommsServer.js::processReceivedMessage] Message has 'forward to all' flag set. Forwarding message as is. Message:" , message ) ;
2019-04-13 03:09:29 +02:00
this . sendToAll ( message ) ;
}
if ( message . forwardToActive ) {
2020-01-30 23:17:43 +01:00
this . logger . log ( 'info' , 'comms' , "[CommsServer.js::processReceivedMessage] Message has 'forward to active' flag set. Forwarding message as is. Message:" , message ) ;
2018-09-21 00:26:08 +02:00
this . sendToActive ( message ) ;
}
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 ) ;
this . handleMessage ( message , port )
2018-05-26 23:08:49 +02:00
}
2019-05-09 21:07:40 +02:00
processReceivedMessage _nonpersistent ( message , sender , sendResponse ) {
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 ) ;
2019-06-14 21:53:48 +02:00
2020-02-04 00:56:31 +01:00
this . handleMessage ( message , sender , sendResponse ) ;
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 ;