diff --git a/js/background.js b/js/background.js index 50ff93c31..f37fc6fd7 100644 --- a/js/background.js +++ b/js/background.js @@ -219,6 +219,13 @@ return; } first = false; + window.lokiP2pAPI = new window.LokiP2pAPI( + textsecure.storage.user.getNumber() + ); + window.lokiP2pAPI.on('pingContact', pubKey => { + const forceP2p = true; + window.libloki.api.sendOnlineBroadcastMessage(pubKey, forceP2p); + }); // These make key operations available to IPC handlers created in preload.js window.Events = { diff --git a/js/modules/loki_p2p_api.js b/js/modules/loki_p2p_api.js index 6fc18f10d..349517c6b 100644 --- a/js/modules/loki_p2p_api.js +++ b/js/modules/loki_p2p_api.js @@ -1,16 +1,23 @@ -/* global setTimeout, clearTimeout, window */ +/* global setTimeout, clearTimeout */ const EventEmitter = require('events'); class LokiP2pAPI extends EventEmitter { - constructor() { + constructor(ourKey) { super(); this.contactP2pDetails = {}; + this.ourKey = ourKey; } - updateContactP2pDetails(pubKey, address, port, fromP2p = false) { + reset() { + Object.keys(this.contactP2pDetails).forEach(key => { + clearTimeout(this.contactP2pDetails[key].pingTimer); + delete this.contactP2pDetails[key]; + }); + } + + updateContactP2pDetails(pubKey, address, port, isOnline = false) { // Stagger the timers so the friends don't ping each other at the same time - this.ourKey = this.ourKey || window.textsecure.storage.user.getNumber(); const timerDuration = pubKey < this.ourKey ? 60 * 1000 // 1 minute @@ -28,7 +35,7 @@ class LokiP2pAPI extends EventEmitter { pingTimer: null, }; - if (fromP2p) { + if (isOnline) { this.setContactOnline(pubKey); return; } @@ -73,7 +80,7 @@ class LokiP2pAPI extends EventEmitter { if (!this.contactP2pDetails[pubKey]) { return; } - window.libloki.api.sendOnlineBroadcastMessage(pubKey, true); + this.emit('pingContact', pubKey); } } diff --git a/libloki/test/node/loki_p2p_api_test.js b/libloki/test/node/loki_p2p_api_test.js new file mode 100644 index 000000000..5875927ea --- /dev/null +++ b/libloki/test/node/loki_p2p_api_test.js @@ -0,0 +1,92 @@ +const { assert } = require('chai'); +const LokiP2pAPI = require('../../../js/modules/loki_p2p_api'); + +describe('LocalLokiServer', () => { + const usedKey = 'aPubKey'; + const usedAddress = 'anAddress'; + const usedPort = 'aPort'; + + beforeEach(() => { + this.lokiP2pAPI = new LokiP2pAPI(); + }); + + afterEach(() => { + this.lokiP2pAPI.reset(); + }); + + it("Should not emit a pingContact event if that contact doesn't exits", () => { + this.lokiP2pAPI.on('pingContact', () => { + assert.fail(); + }); + this.lokiP2pAPI.pingContact('not stored'); + }); + + it('Should emit an online event if the contact is online', done => { + this.lokiP2pAPI.on('online', pubKey => { + assert.strictEqual(pubKey, usedKey); + done(); + }); + this.lokiP2pAPI.updateContactP2pDetails( + usedKey, + usedAddress, + usedPort, + true + ); + }).timeout(1000); + + it("Should send a pingContact event if the contact isn't online", done => { + this.lokiP2pAPI.on('pingContact', pubKey => { + assert.strictEqual(pubKey, usedKey); + done(); + }); + this.lokiP2pAPI.updateContactP2pDetails( + usedKey, + usedAddress, + usedPort, + false + ); + }).timeout(1000); + + it('Should store a contacts p2p details', () => { + this.lokiP2pAPI.updateContactP2pDetails( + usedKey, + usedAddress, + usedPort, + true + ); + const p2pDetails = this.lokiP2pAPI.getContactP2pDetails(usedKey); + assert.strictEqual(usedAddress, p2pDetails.address); + assert.strictEqual(usedPort, p2pDetails.port); + }); + + it('Should say if a contact is online', () => { + this.lokiP2pAPI.updateContactP2pDetails( + usedKey, + usedAddress, + usedPort, + true + ); + assert.isTrue(this.lokiP2pAPI.isOnline(usedKey)); + this.lokiP2pAPI.updateContactP2pDetails( + usedKey, + usedAddress, + usedPort, + false + ); + assert.isFalse(this.lokiP2pAPI.isOnline(usedKey)); + }); + + it('Should set a contact as offline', () => { + this.lokiP2pAPI.updateContactP2pDetails( + usedKey, + usedAddress, + usedPort, + true + ); + let p2pDetails = this.lokiP2pAPI.getContactP2pDetails(usedKey); + assert.isTrue(p2pDetails.isOnline); + p2pDetails = this.lokiP2pAPI.getContactP2pDetails(usedKey); + this.lokiP2pAPI.setContactOffline(usedKey); + assert.isFalse(p2pDetails.isOnline); + }); +}); diff --git a/package.json b/package.json index a4f6d8898..b7d9092ed 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "test-electron": "yarn grunt test", "test-node": "mocha --recursive test/app test/modules ts/test libloki/test/node", "test-node-coverage": "nyc --reporter=lcov --reporter=text mocha --recursive test/app test/modules ts/test libloki/test/node", + "test-node-coverage-html": "nyc --reporter=lcov --reporter=html mocha --recursive test/app test/modules ts/test libloki/test/node", "eslint": "eslint .", "lint": "yarn format --list-different && yarn lint-windows", "lint-windows": "yarn eslint && yarn tslint", diff --git a/preload.js b/preload.js index fb3dc298a..1e2fd0468 100644 --- a/preload.js +++ b/preload.js @@ -276,9 +276,7 @@ window.LokiSnodeAPI = new LokiSnodeAPI({ swarmServerPort: config.swarmServerPort, }); -const LokiP2pAPI = require('./js/modules/loki_p2p_api'); - -window.lokiP2pAPI = new LokiP2pAPI(); +window.LokiP2pAPI = require('./js/modules/loki_p2p_api'); const LokiMessageAPI = require('./js/modules/loki_message_api'); diff --git a/test/_test.js b/test/_test.js index fd9f8fcc2..f55ff8bc2 100644 --- a/test/_test.js +++ b/test/_test.js @@ -79,3 +79,5 @@ before(async () => { window.clearDatabase = async () => { await window.Signal.Data.removeAll(); }; + +window.lokiP2pAPI = new window.LokiP2pAPI('ourKey');