diff --git a/.bowerrc b/.bowerrc deleted file mode 100644 index 5773025..0000000 --- a/.bowerrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "directory": "app/bower_components" -} diff --git a/.firebase/hosting.d2Vic2l0ZQ.cache b/.firebase/hosting.d2Vic2l0ZQ.cache deleted file mode 100644 index bff5691..0000000 --- a/.firebase/hosting.d2Vic2l0ZQ.cache +++ /dev/null @@ -1,50 +0,0 @@ -styles/core.css,1595840369786,46b50c321b39e89a491b6727a01628c34245605a30beb3e7414c5e01cff90e6e -index.html,1595840369867,ba089e47ba60710123d3517bf8af48f1002704b40af6ee456c339a786564e0ae -html/iframe/chat.html,1595840369933,a671af0cddbeaef30f863717873e11ff6f295aed5ffbaa043494ebe0ec4a33ca -images/icons/android-icon-192x192.png,1595840369917,ae586a4518a08bfae8f6ed29b180967bb1023b7dcc890d4a0eabf3a8f459c46c -fonts/Open_Sans/LICENSE.txt,1595840369905,17f0f0a955b32272a4f41fd44841f95b2a7333f1641116547d4231e7b7af8361 -images/icons/android-icon-36x36.png,1595840369919,a14f796d3294bceef60489787316f6e97e9dbccd169f45d0d46b7415929b08ce -images/icons/android-icon-48x48.png,1595840369921,415ac75bc2875ba8069b75b80a0fd03cf9e90b3b2a53a3f36355f63fcbc2b32a -images/icons/android-icon-72x72.png,1595840369924,d87db46d6c8b5ce3210179935c731aa1a4e5bc9b4108ca8b52568e05340fb1d7 -images/icons/apple-icon-114x114.png,1595840369926,13b631bfe93beb1a578868b62e7001999a9732b31a340d480f57f4f1f5fd94f7 -images/icons/android-icon-96x96.png,1595840369925,065c26131ab232ba1253d61443df311930b9e4e8aab335858b7f8b66c6ea5533 -images/icons/apple-icon-120x120.png,1595840369926,66c4bfc967303dbac393aa40a04bdf8c952687339d42eeba6ac873e517f2ecfe -images/icons/apple-icon-144x144.png,1595840369927,16d9acef18c051e16244a5a512d1c6469c4a5535ce387d07474586856e636b45 -images/icons/android-icon-144x144.png,1595840369914,16d9acef18c051e16244a5a512d1c6469c4a5535ce387d07474586856e636b45 -images/icons/apple-icon-152x152.png,1595840369927,903f37828f64d5a757084e3da808acb0d6143d5ae2f3bca602e3c301c3ec5f97 -images/icons/apple-icon-57x57.png,1595840369928,cb824f469da8903eb7fba95090612cd0bb534eb006fa95bfcabc3b3b430fb371 -images/icons/apple-icon-60x60.png,1595840369928,8f6b95268d1983217ad44978347bd892f7d37a17e9f48bf7d3192ab8a1160d3a -images/icons/apple-icon-72x72.png,1595840369928,d87db46d6c8b5ce3210179935c731aa1a4e5bc9b4108ca8b52568e05340fb1d7 -images/icons/browserconfig.xml,1595840369930,cd6445d8fe791d1cae6328c3eee28a97d3e7e1bf501c62d8f2108f5087e7d730 -images/icons/apple-icon-180x180.png,1595840369927,9c1f053db53ee1c7c99cd795b261928a0f9b620ac74c74784968c5eec651bbe6 -images/icons/favicon-16x16.png,1595840369930,e2df1c109d2f44227cb4bff99c28a9958bbda1148db94c3a9792ec25f4f6e1d1 -images/icons/favicon-32x32.png,1595840369930,036accd70b5ce09dc6039d986e44736038261482d5d2742383494a9d389a3768 -images/icons/apple-icon.png,1595840369929,df258a3d133440aedb709977dd6fe387a0aed22617411a5560ac5b10dce6bad1 -images/icons/apple-icon-76x76.png,1595840369928,afa18b3b753e1d78323403a205ce94239e84f1da677bcf1e03248a04092cc83b -images/icons/favicon-96x96.png,1595840369930,065c26131ab232ba1253d61443df311930b9e4e8aab335858b7f8b66c6ea5533 -images/icons/apple-icon-precomposed.png,1595840369929,df258a3d133440aedb709977dd6fe387a0aed22617411a5560ac5b10dce6bad1 -images/icons/manifest.json,1595840369931,46e7f5e409f1e10cb0007bcdd51eb6031ff1bd4a61d07513a4d2b80f6cc5381f -images/icons/ms-icon-144x144.png,1595840369931,16d9acef18c051e16244a5a512d1c6469c4a5535ce387d07474586856e636b45 -images/icons/ms-icon-150x150.png,1595840369932,b0d8b457a7a60a064472bdfa5c7c83110ccc1defe296184468bc75756e5d4540 -images/icons/ms-icon-310x310.png,1595840369932,ad87c2f970d82d2f57add11fa0750eb135459b158bf0f8b8ce4839e92cbb31b9 -scripts/backgroundPortManager.js,1595840369901,341513c3258d73a2c170f280d015206404e8e4ab1269dc794d6957b36d9a4b79 -images/icons/favicon.ico,1595840369931,637008d0ad07668fa8f0251760e4c71dc0b9649d8d8098fa35abce8c562cf011 -scripts/backgroundPortManager.js.map,1595840369837,be6470ef1384147836c2f2c0334f7735e2e95516c1534fff1ac1eb18162ef167 -scripts/chat.js,1595840369786,9955a95b2ef9ff07630c1124bdfe9355950d5672d50fa83c9bedce42db7a81b1 -scripts/chat.js.map,1595840369783,3b52c180214bf3a858c85ca6b727605046dba44e67e77de44b3bcb9f51eb301d -scripts/inject.js,1595840369789,ce9d5502c41c85e883e02dc1fd4123d494c4750c9862b322c8b1f525d15e87e7 -images/icons/ms-icon-70x70.png,1595840369932,703d7e1c795ddf09ee426e60fc3edde9e69a663aa7ea1a464addbe1972f0b635 -scripts/logger.js,1595840369750,8531df21fded5c2b7c0c28b2548e5d4cd2437c57f10d52802d821095a48741ea -scripts/logger.js.map,1595840369749,082250fe83e2fe9aee688ad427ff3d7a50c6ec2a81f039a0dc2eca9140164451 -scripts/portManager.js,1595840369903,eb655c910f173e6ebb2ec3b402804573963eac626b183331d8cacebe34ad94c5 -styles/chat.css,1595840369787,243f520009fdb00e153908a2b3a57eea6853981e250775cefef18f476906cc48 -styles/inject.css,1595840369787,b4434f3afb87583142913b017f9092ff0723fec77e50c16d1fd880c4e26bf7bb -scripts/portManager.js.map,1595840369838,af571486e2042c3f2c14ed4b87846a10bb4840467814ceb390bc5a13982e604d -scripts/inject.js.map,1595840369789,80faf7b5ee6729bfc7fc7624a2b77853da00761ed14b556cd4cbdea8c469cb53 -libs/jquery-3.5.1.min.js,1595840369788,a6c14aef7ed02ef768bcdbb789322eea70b6a860e467cdbcc1238429e3274c5f -images/aero_arrow.cur,1595840369888,4b93b0fd38f2201b3516f4ebbaf8132ae23207c246fac2755ad3f794b5bcd37b -fonts/Open_Sans/OpenSans-ExtraBold.ttf,1595840369908,0b790194f0e2d1f5665624f990a7ea11cc76b90670691bf54a4e654e4f9be595 -fonts/Open_Sans/OpenSans-Regular.ttf,1595840369911,966d538f2bd817920517cb7db6439d226be602c95ec4919483737fd74c198089 -libs/jquery-3.5.1.min.js.map,1595840369788,5d5f9d57069201811da9ec14bd1398f3b9fec24fb13e179e39b2562dc36f1a9d -scripts/bundle.js,1595840369781,5bf85cc6b943a420b9a13f4d7cde5dc53ddd6146cc3c07802d340b146f054805 -scripts/bundle.js.map,1595840369772,dedc40529e52ab54731d6331a5d7da99a3ee9fe4dc1e2307c39ffe1cbc222372 diff --git a/.gitignore b/.gitignore index d47ba66..c874f0e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ temp .tmp .firebase dist +notes .sass-cache app/bower_components website diff --git a/.yo-rc.json b/.yo-rc.json deleted file mode 100644 index c6bb600..0000000 --- a/.yo-rc.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "generator-mocha": { - "ui": "bdd", - "rjs": false - } -} \ No newline at end of file diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..aeb3c37 --- /dev/null +++ b/README.txt @@ -0,0 +1,14 @@ +Requires npm and gulp to build + +Versions used to build v1.0.0 of Internet Friends: + +npm v8.4.1 +gulp CLI v2.3.0 +gulp Local v4.0.2 + +To build: + +1) cd to the root directory +2) run 'npm install' +3) run 'gulp' +4) run 'gulp package' \ No newline at end of file diff --git a/app/extension/html/background.html b/app/extension/html/background.html deleted file mode 100644 index c5f9f5d..0000000 --- a/app/extension/html/background.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - Internet Friends - - - - - - \ No newline at end of file diff --git a/app/extension/html/iframe/chat.html b/app/extension/html/iframe/chat.html index d7f37fb..92a6612 100644 --- a/app/extension/html/iframe/chat.html +++ b/app/extension/html/iframe/chat.html @@ -7,7 +7,7 @@ - + Internet Friends diff --git a/app/extension/scripts/backgroundPortManager.js b/app/extension/scripts/backgroundPortManager.js deleted file mode 100644 index 9fd73a9..0000000 --- a/app/extension/scripts/backgroundPortManager.js +++ /dev/null @@ -1,170 +0,0 @@ -'use strict'; - -var backgroundPortManager = function (messageCallback, roomDisconnectCallback){ - // variables ---------------------------------------------------------------- - var _this = {}, - _openTabs = {}, - _rooms = {}, - _messageCallback = null, - _roomDisconnectCallback = null; - - // initialize --------------------------------------------------------------- - _this.init = function (messageCallback, roomDisconnectCallback){ - _messageCallback = messageCallback; - _roomDisconnectCallback = roomDisconnectCallback; - - // send messages from "background.js" - chrome.runtime.onConnect.addListener(processTabPortConnected); - - Logger.log('Internet Friends Background Port Manager Initialized'); - }; - - // private functions -------------------------------------------------------- - function getUrl(port) { - let url; - - if (port.sender.tab.url) { // Chrome - url = new URL(port.sender.tab.url); - } - else // FireFox - { - var tabId = port.sender.tab.id; - var source = port.name; - if (source == 'InternetFriends-main') { - url = new URL(port.sender.tab.url); - } else if (_openTabs[tabId]['InternetFriends-main']) { - url = new URL(_openTabs[tabId]['InternetFriends-main'].sender.url); - } - } - - return url; - } - - function getRoomCodeFromPort(port, url) { - // Room code is based on url and title - // e.g. 'www.google.com/search : test - Google Search' - // The goal is to group users based on the page they're currently on - // Ignoring url.search because many websites url.search values are unique to each user - var url = getUrl(port); - return url.host + url.pathname + " : " + port.sender.tab.title; - } - - // events ------------------------------------------------------------------- - function processTabPortConnected (port){ - // Only process if site not disabled - var websiteUrl = getUrl(port); - - // If websiteUrl is present in disabledSites, InternetFriends is disabled for this site, return - if (IFSettings.disabledSites[websiteUrl.host]) - return; - - var tabId = port.sender.tab.id; - var source = port.name; - var roomCode = getRoomCodeFromPort(port); - - Logger.log('Tab Connected RoomCode: ' + roomCode + ' ID: ' + tabId); - - // Add port to tab - if(!_openTabs[tabId]) - _openTabs[tabId] = {}; - - _openTabs[tabId][source] = port; - - // Create room - if (!_rooms[roomCode]) - _rooms[roomCode] = {}; - - // Add tab to room - _rooms[roomCode][tabId] = true; - - // After both sources have connected - if(_openTabs[tabId]['InternetFriends-chat'] && - _openTabs[tabId]['InternetFriends-main']) - { - // Setup Listeners - _openTabs[tabId]['InternetFriends-chat'].onMessage.addListener(function (event) { processMessage(event, tabId, 'InternetFriends-chat', roomCode) }); - _openTabs[tabId]['InternetFriends-main'].onMessage.addListener(function (event) { processMessage(event, tabId, 'InternetFriends-main', roomCode) }); - _openTabs[tabId]['InternetFriends-chat'].onDisconnect.addListener(function () { processTabPortDisconnect(tabId, 'InternetFriends-chat', roomCode) }); - _openTabs[tabId]['InternetFriends-main'].onDisconnect.addListener(function () { processTabPortDisconnect(tabId, 'InternetFriends-main', roomCode) }); - - // Post loaded messages - _openTabs[tabId]['InternetFriends-chat'].postMessage({event: 'loaded'}); - _openTabs[tabId]['InternetFriends-main'].postMessage({event: 'loaded'}); - } - }; - - function processMessage (message, tabId, source, roomCode) { - _messageCallback(message, roomCode); - - // Forward to iframe - if(source != 'InternetFriends-chat') { - message.data.userId = "localuser"; - _this.tellByTabId(tabId, message); - } - } - - function processTabPortDisconnect (tabId, source, roomCode){ - // process the disconnect - if (_openTabs[tabId]) { - delete _openTabs[tabId][source]; - } - - if(source == 'InternetFriends-main') { - delete _openTabs[tabId]; - delete _rooms[roomCode][tabId]; - - let tabIds = Object.keys(_rooms[roomCode]); - - // If there are no other tabs associated with this room code, disconnect - if (tabIds.length === 0) - _roomDisconnectCallback(roomCode); - } - }; - - // public functions --------------------------------------------------------- - _this.tellByRoomCode = function (roomCode, data){ - if (!_rooms[roomCode]) - return false; - - let success = false; - - // Loop through all tabs that are associated with the given room code - for (var tabId in _rooms[roomCode]) { - success ||= _this.tellByTabId(tabId, data); - } - - // If any tabs were found, this should return true - return success; - }; - - _this.tellByTabId = function (tabId, data){ - if(_openTabs[tabId] && _openTabs[tabId]["InternetFriends-chat"]) { - _openTabs[tabId]["InternetFriends-chat"].postMessage(data); - return true; - } - - return false; - }; - - _this.updateBadgeTextByRoomCode = function (roomCode, peers) { - if (!_rooms[roomCode]) - return false; - - // Loop through all tabs that are associated with the given room code - for (var tabId in _rooms[roomCode]) { - chrome.browserAction.setBadgeText( - { - text: peers > 0 ? peers.toString() : '', - tabId: parseInt(tabId) - } - ); - } - - return true; - }; - - // messages ----------------------------------------------------------------- - _this.init(messageCallback, roomDisconnectCallback); - - return _this; -}; diff --git a/app/extension/scripts/portManager.js b/app/extension/scripts/portManager.js index 2e2ccc9..e0605d2 100644 --- a/app/extension/scripts/portManager.js +++ b/app/extension/scripts/portManager.js @@ -12,26 +12,9 @@ var portManager = function (source, messageCallback, disconnectCallback){ _messageListener = messageCallback; _disconnectListener = disconnectCallback; - // receive messages from "background.js" - _port = chrome.runtime.connect({name: "InternetFriends-" + source}); - _port.onMessage.addListener(port_onMessage); - _port.onDisconnect.addListener(port_onDisconnect); - Logger.log(`PortManager Initialized in "${source}"`); }; - // private functions -------------------------------------------------------- - - // events ------------------------------------------------------------------- - function port_onMessage (message){ - // call the listener callback - if (_messageListener) _messageListener(message); - }; - - function port_onDisconnect (){ - if (_disconnectListener) _disconnectListener(); - }; - // public functions --------------------------------------------------------- _this.tell = function (event, data){ var data = data || {}; @@ -43,6 +26,25 @@ var portManager = function (source, messageCallback, disconnectCallback){ }); } }; + + _this.connect = function () { + Logger.log("Connecting to Background Script..."); + + _port = chrome.runtime.connect({name: "InternetFriends-" + source}); + + if (_messageListener) _port.onMessage.addListener(_messageListener); + if (_disconnectListener) _port.onDisconnect.addListener(_disconnectListener); + } + + _this.disconnect = function () { + if (!_port) + return; + + Logger.log("Disconnecting from Background Script..."); + + _port.disconnect(); + _port = null; + } // messages ----------------------------------------------------------------- _this.init(source, messageCallback, disconnectCallback); diff --git a/app/manifest.json b/app/manifest.json index 4bebfd0..f05ac43 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,20 +1,20 @@ { "name": "__MSG_appName__", - "version": "1.0.0", - "manifest_version": 2, + "version": "1.1.1", + "manifest_version": 3, "description": "__MSG_appDescription__", "icons": { "16": "images/icon-16.png", "128": "images/icon-128.png" }, "default_locale": "en", - "incognito": "split", "background": { - "page": "html/background.html" + "service_worker": "scripts/background.js" }, "permissions": [ "storage", - "activeTab" + "activeTab", + "tabs" ], "content_scripts": [{ "matches": [ @@ -42,19 +42,23 @@ "run_at": "document_start" }], "web_accessible_resources": [ - "scripts/logger.js", - "scripts/settings.js", - "scripts/backgroundPortManager.js", - "scripts/bundle.js", - "scripts/popup.js", - "html/iframe/chat.html", - "scripts/chat.js", - "styles/core.css", - "styles/chat.css", - "styles/slider.css", - "styles/popup.css" + { + "resources": [ + "scripts/logger.js", + "scripts/settings.js", + "scripts/background.js", + "scripts/popup.js", + "html/iframe/chat.html", + "scripts/bundle.js", + "styles/core.css", + "styles/chat.css", + "styles/slider.css", + "styles/popup.css" + ], + "matches": ["*://*/*"] + } ], - "browser_action": { + "action": { "default_popup": "html/popup.html", "default_icon": { "19": "images/icon-19.png", diff --git a/app/scripts.babel/background.js b/app/scripts.babel/background.js index d3c6389..595a012 100644 --- a/app/scripts.babel/background.js +++ b/app/scripts.babel/background.js @@ -1,166 +1,67 @@ -'use strict'; - -var swarm = require('webrtc-swarm') -var signalhub = require('signalhub') - -var Background = (function() { - // variables ---------------------------------------------------------------- - var _this = {}, - _local = false, - _portManager = null, - _swarms = {}; - - // initialize --------------------------------------------------------------- - _this.init = function() { - // receive post messages from 'inject.js' and any iframes - _portManager = new backgroundPortManager(processMessageFromBrowser, processRoomDisconnect); - - if (chrome && chrome.browserAction) { - chrome.browserAction.setBadgeBackgroundColor({ color: IFSettings.userColor }); - - // add listener for storage changes - IFEvents.addEventListener('settings.change.userColor', function () { - chrome.browserAction.setBadgeBackgroundColor({color: IFSettings.userColor }); - }); - } - - Logger.log('Internet Friends Background Script Initialized'); - }; - - // private functions -------------------------------------------------------- - function connectToSwarm(roomCode, callback) { - if (_swarms[roomCode]) - return; - - Logger.log('connecting to swarm ', roomCode); - - // init user info message - var userInfoMessage = { - event: 'userInfo', - data: { - userId: 'localuser', - userColor: IFSettings.userColor, - } - } - - // send user info message to front end - _portManager.tellByRoomCode(roomCode, userInfoMessage); - - var hub = signalhub(roomCode, _local ? ['localhost:8080'] : ['https://if-signalhub.herokuapp.com/']) - _swarms[roomCode] = swarm(hub) - - _swarms[roomCode].on('peer', function(peer, id) { - Logger.log('connected to a new peer:', id) - Logger.log('total peers:', _swarms[roomCode].peers.length) - - // setup data listener - peer.on('data', (payload) => { - const message = JSON.parse(payload.toString()) - message.data.source = 'peer' - message.data.userId = id - Logger.log(message); - - // Forward the message to the chat window - const foundRoom = _portManager.tellByRoomCode(roomCode, message); - if (!foundRoom) { - disconnectFromSwarm(roomCode) +// ---------------------------------------- Badge Text Listener ---------------------------------------- +chrome.runtime.onMessage.addListener( + function(request, sender, sendResponse) { + if (request.event === 'updateBadgeText') + { + let peers = request.data.peers; + + chrome.action.setBadgeText( + { + text: peers > 0 ? peers.toString() : '', + tabId: sender.tab.id } - }) - - // update the badge based on the number of peers - _portManager.updateBadgeTextByRoomCode(roomCode, _swarms[roomCode].peers.length); - - // send user info message to peers on connection - userInfoMessage.data.userColor = IFSettings.userColor; - peer.send(JSON.stringify(userInfoMessage)); - }) - - _swarms[roomCode].on('disconnect', function(peer, id) { - Logger.log('disconnected from a peer:', id) - _portManager.tellByRoomCode(roomCode, { - event: 'disconnected', - data: { - source: 'peer', - userId: id - } - }); - - // update the badge based on the number of peers - _portManager.updateBadgeTextByRoomCode(roomCode, _swarms[roomCode] ? _swarms[roomCode].peers.length : 0); - }) - - // Resend user info if the user color is changed - IFEvents.addEventListener('settings.change.userColor', function () { - userInfoMessage.data.userColor = IFSettings.userColor; - - // send to the swarm - sendMessageToSwarm(userInfoMessage, roomCode); - - // also send locally - _portManager.tellByRoomCode(roomCode, userInfoMessage); - }); - - if (callback) - callback(); - }; - - function disconnectFromSwarm(roomCode) { - if (_swarms[roomCode]) { - Logger.log('disconnecting from swarm ', roomCode); - - _swarms[roomCode].close() - delete _swarms[roomCode] - - Logger.log('disconnected'); + ); } - }; - - function sendMessageToSwarm(message, roomCode) { - // if message if intended for a new swarm - if (!_swarms[roomCode]) { - // connect to the new swarm - connectToSwarm(roomCode, function () { - // once connected, send the message to the swarm - if (_swarms[roomCode]) { - _swarms[roomCode].peers.forEach((peer) => { - peer.send(JSON.stringify(message)); - }); - } - }); + else if (request.event === 'updateBadgeColor') + { + chrome.action.setBadgeBackgroundColor({ color: request.data.userColor }); } - // already connected, send the message to the swarm - else if (_swarms[roomCode]) { - _swarms[roomCode].peers.forEach((peer) => { - peer.send(JSON.stringify(message)); - }); - } - }; - // events ------------------------------------------------------------------- - function processMessageFromBrowser(message, roomCode) { - if (message.event == 'pageHidden') { - disconnectFromSwarm(roomCode); - } else if (message.event == 'pageVisible') { - connectToSwarm(roomCode); - } else if (message.event != 'scroll') { - var wsMessage = JSON.parse(JSON.stringify(message)); - sendMessageToSwarm(wsMessage, roomCode); - } + // dummy response due to bug: https://stackoverflow.com/questions/71520198/manifestv3-new-promise-error-the-message-port-closed-before-a-response-was-rece/71520415#71520415 + sendResponse(); + } +); + +// ---------------------------------------- Logger ---------------------------------------- +var debug = false; +var Logger = { + log: debug ? console.log.bind(console) : function(){} +}; + +// ---------------------------------------- Settings ---------------------------------------- +// wrap in a self-invoking function to use define private variables & functions +(function () { + // define default combo + var _defaultCombo = { + ctrlKey: true, + shiftKey: true, + altKey: false, + key: "Enter" }; - function processRoomDisconnect(roomCode) { - disconnectFromSwarm(roomCode); - }; + // define function for getting a random color + function getRandomColor () { + return 'hsla(' + Math.round(Math.random() * 360) + ', 78%, 54%, 1)'; + } + + // if chrome is available + if (chrome && chrome.storage) { + // retrieve settings from storage + chrome.storage.sync.get(null, function(result) { + var storedSettings = result; + + // set settings based on storedSettings, get default values if necessary + var settings = { + combo: storedSettings?.combo || _defaultCombo, + disabledSites: storedSettings?.disabledSites || {}, + enableChat: storedSettings?.enableChat === true || storedSettings?.enableChat === undefined, + userColor: storedSettings?.userColor || getRandomColor() + } - return _this; -}()); + // store new settings + chrome.storage.sync.set(settings); -// If IFSettings have not been initialized, wait for init event to be dispatched -if (!IFSettings) { - IFEvents.addEventListener('settings.init', function () { - Background.init(); - }); -} else { - // else, init now - Background.init(); -} \ No newline at end of file + Logger.log('Settings initialized:', settings); + }); + } +}()); \ No newline at end of file diff --git a/app/scripts.babel/chat.js b/app/scripts.babel/chat.js index bfcbd2f..3653321 100644 --- a/app/scripts.babel/chat.js +++ b/app/scripts.babel/chat.js @@ -1,3 +1,110 @@ +var swarm = require('webrtc-swarm') +var signalhub = require('signalhub') +const { createHash } = require('crypto'); + +var IFSwarm = function(messageCallback) { + // variables ---------------------------------------------------------------- + var _this = {}, + _local = false, + _swarm = null, + _messageCallback = messageCallback, + _userInfoMessage = { + event: 'userInfo', + data: {} + }; + + + // initialize --------------------------------------------------------------- + function init() { + }; + + // public functions -------------------------------------------------------- + _this.connect = function(roomCode) { + if (_swarm) + return; + + let encodedRoomCode = createHash('sha256').update(roomCode).digest('hex'); + + Logger.log('connecting to swarm ', roomCode); + Logger.log('encoded room code: ', encodedRoomCode); + + var hub = signalhub(encodedRoomCode, _local ? ['localhost:8080'] : ['https://if-signalhub.herokuapp.com/']) + _swarm = swarm(hub, { wrtc: require('wrtc') }) + + _swarm.on('peer', function(peer, id) { + Logger.log('connected to a new peer:', id) + Logger.log('total peers:', _swarm.peers.length) + + // setup data listener + peer.on('data', (payload) => { + const message = JSON.parse(payload.toString()) + message.data.source = 'peer' + message.data.userId = id + Logger.log(message); + + // fire callback with the given message + _messageCallback(message); + }) + + // update the badge based on the number of peers + chrome.runtime.sendMessage({ event: 'updateBadgeText', data: { peers: _swarm ? _swarm.peers.length : 0 }}); + + // send user info message to peers on connection + _userInfoMessage.data.userColor = IFSettings.userColor; + peer.send(JSON.stringify(_userInfoMessage)); + }) + + _swarm.on('disconnect', function(peer, id) { + Logger.log('disconnected from a peer:', id) + + // fire callback with the given message + _messageCallback({ + event: 'disconnected', + data: { + source: 'peer', + userId: id + } + }); + + // update the badge based on the number of peers + chrome.runtime.sendMessage({ event: 'updateBadgeText', data: { peers: _swarm ? _swarm.peers.length : 0 }}); + }) + + // Resend user info if the user color is changed + IFEvents.addEventListener('settings.change.userColor', function () { + _userInfoMessage.data.userColor = IFSettings.userColor; + + // send to the swarm + _this.sendMessage(_userInfoMessage); + }); + }; + + _this.disconnect = function () { + if (!_swarm) + return; + + Logger.log('disconnecting from swarm'); + + _swarm.close() + _swarm = null; + + Logger.log('disconnected'); + }; + + _this.sendMessage = function (message) { + if (!_swarm) + return; + + _swarm.peers.forEach((peer) => { + peer.send(JSON.stringify(message)); + }); + }; + + init(); + + return _this; +}; + var User = function(id, submitCallback) { // variables ---------------------------------------------------------------- var _this = {}, @@ -26,8 +133,14 @@ var User = function(id, submitCallback) { if (_id == "localuser") { _inputElement = $('').appendTo(_userElement); setupInputElement(); + _this.setColor(IFSettings.userColor); + + // Add listener for color changes + IFEvents.addEventListener('settings.change.userColor', function () { + _this.setColor(IFSettings.userColor); + }); } else { - var cursorURL = typeof chrome !== "undefined" && chrome.extension ? chrome.extension.getURL('../../images/aero_arrow.png') : './images/aero_arrow.png'; + var cursorURL = typeof chrome !== "undefined" && chrome.runtime ? chrome.runtime.getURL('../../images/aero_arrow.png') : './images/aero_arrow.png'; _mouseElement = $('
').appendTo(_userElement); _mouseBGElm = $('
').appendTo(_mouseElement); _mouseBGElm.css({ 'background-image': 'url(' + cursorURL + ')' }); @@ -62,8 +175,10 @@ var User = function(id, submitCallback) { }; function repositionElements() { - _userElement.css('top', _mousePosition.y + 'px'); - _userElement.css('left', _mousePosition.x + 'px'); + _userElement.css({ + 'top': _mousePosition.y + 'px', + 'left': _mousePosition.x + 'px' + }); if (!_flipped && _mousePosition.x > document.documentElement.clientWidth / 2) { _flipped = true; @@ -135,22 +250,53 @@ var User = function(id, submitCallback) { var Chat = (function() { // variables ---------------------------------------------------------------- var _this = {}, - _portManager = null, + _roomCode = null, + _connectionTimeout = null, _users = {}, - _scrollPosition = {}, - _mouseVisible = true; + _scrollPosition = { x: 0, y: 0 }, + _mouseVisible = true, + _swarm = null; // initialize --------------------------------------------------------------- _this.init = function() { Logger.log('Chat View Initialized') - _portManager = new portManager("chat", onMessage); - _scrollPosition = { x: 0, y: 0 }; + Logger.log('Chat Init Visibility State: ', document.visibilityState); + + _swarm = new IFSwarm(onMessage); + + window.addEventListener("message", (event) => { + if (event.data.data) + event.data.data.userId = 'localuser'; + + onMessage(event.data); + }); + + document.addEventListener("visibilitychange", onVisibilityStateChanged, false); + + window.parent.postMessage('iframeInitialized', '*'); }; // events ------------------------------------------------------------------- function onMessage(message) { Logger.log('got chat message', message) + + // forward certain messages that didn't come from the swarm (from a peer) + if (_swarm && (!message.data.source || message.data.source != 'peer')) { + switch (message.event) { + case 'userInfo': + case 'mousemove': + case 'userchat': + case 'disconnected': + _swarm.sendMessage(message); + break; + } + } + + // process messages switch (message.event) { + case 'roomCodeChanged': + message_onRoomCodeChanged(message.data); + break; case 'userInfo': message_onUserInfo(message.data); break; @@ -182,8 +328,18 @@ var Chat = (function() { // private functions --------------------------------------------------------- function submitInput(message) { - var data = { message: message }; - _portManager.tell('userchat', data); + // process locally + message_onUserchat({ userId: 'localuser', message: message }) + + // send to swarm + if (_swarm) { + _swarm.sendMessage({ + event: 'userchat', + data: { + message: message + } + }); + } }; function getUser(userId) { @@ -192,8 +348,40 @@ var Chat = (function() { return _users[userId]; }; + + function onVisibilityStateChanged() { + Logger.log('Visiblility Changed: ', document.visibilityState); + tryConnect(); + } + + function tryConnect() { + // wait one second before connecting in case multiple changes are made in rapid succession + clearTimeout(_connectionTimeout); + _connectionTimeout = setTimeout(function () { + if (document.visibilityState === 'visible') { + _swarm.connect(_roomCode); + } else { + _swarm.disconnect(); + } + }, 1000); + } // messages ----------------------------------------------------------------- + function message_onRoomCodeChanged(data) { + // if the room code is the same, return + if (data.roomCode === _roomCode) + return; + + // disconnect from the current room + _swarm.disconnect(); + + // set the new room code + _roomCode = data.roomCode; + + // reconnect to the swarm + tryConnect(); + } + function message_onUserInfo(data) { var user = getUser(data.userId); user.setColor(data.userColor); diff --git a/app/scripts.babel/inject.js b/app/scripts.babel/inject.js index cb0196c..89205c6 100644 --- a/app/scripts.babel/inject.js +++ b/app/scripts.babel/inject.js @@ -2,14 +2,14 @@ var Inject = (function() { // constants ---------------------------------------------------------------- var ID = { CONTAINER: 'internetFriends-container', - IFRAME_PREFIX: 'internetFriends-iframe-' + IFRAME: 'internetFriends-iframe' }; // variables ---------------------------------------------------------------- var _this = {}, - _views = {}, _container = null, - _portManager = null, + _iframe = null, + _roomCode = null, _comboDown = false; // initialize --------------------------------------------------------------- @@ -23,25 +23,50 @@ var Inject = (function() { return; } - // create the main container - _container = $('
', { id: ID.CONTAINER }); - _container.appendTo(document.body); + // add message listener + window.addEventListener("message", (event) => { + switch (event.data) { + case 'iframeInitialized': + onIframeInitialized(); + break; + } + }); + // create the main container + _container = document.createElement('div'); + _container.id = ID.CONTAINER; + document.body.append(_container); + // add the "chat" iframe - getView('chat', _container); - - // setup port manager to communicate with background.js - _portManager = new portManager("main", onMessage, onDisconnect); - _portManager.tell("tabInit"); + _iframe = document.createElement('iframe'); + _iframe.id = ID.IFRAME; + _iframe.src = typeof chrome !== "undefined" && chrome.runtime ? chrome.runtime.getURL('html/iframe/chat.html?view=chat&_' + new Date().getTime()) : './html/iframe/chat.html'; + _container.append(_iframe); + }; + // private functions -------------------------------------------------------- + function onIframeInitialized() { + Logger.log('iFrame initialized, sendMessage and swarm events are now available'); + + // update the room code + _roomCode = getRoomCode(); + onRoomCodeChanged(); + + // add listener to detect room code changes that occur without page refresh + new MutationObserver(() => { + let roomCode = getRoomCode(); + if (_roomCode !== roomCode) { + _roomCode = roomCode; + onRoomCodeChanged(); + } + }).observe(document, {subtree: true, childList: true}); + // add event listeners document.addEventListener("scroll", dom_onScroll, false); document.addEventListener("mouseover", dom_onMousemove, false); document.addEventListener("mousemove", dom_onMousemove, false); document.addEventListener("mouseenter", dom_onMouseenter, false); document.addEventListener("mouseleave", dom_onMouseleave, false); - document.addEventListener("webkitvisibilitychange", dom_onVisibilityChange, false); - document.addEventListener("msvisibilitychange", dom_onVisibilityChange, false); // if chat is not enabled, return if (!IFSettings.enableChat) { @@ -52,90 +77,41 @@ var Inject = (function() { // only detect key presses if chat is enabled document.addEventListener("keydown", dom_onKeydown, false); document.addEventListener("keyup", dom_onKeyup, false); - }; - - // private functions -------------------------------------------------------- - function getView(id) { - // return the view if it's already created - if (_views[id]) return _views[id]; - - // iframe initial details - var src = typeof chrome !== "undefined" && chrome.extension ? chrome.extension.getURL('html/iframe/' + id + '.html?view=' + id + '&_' + new Date().getTime()) : './html/iframe/chat.html', - iframe = $('