UNPKG

dagcoin-core

Version:
295 lines (244 loc) 11.7 kB
'use strict'; var instance = null; function DeviceManager() { var _this = this; this.device = require('byteballcore/device'); this.conf = require('byteballcore/conf'); this.dbManager = require('./databaseManager').getInstance(); this.timedPromises = require('./promiseManager'); this.messageCounter = 0; this.eventBus = require('byteballcore/event_bus'); this.exceptionManager = require('./exceptionManager'); var self = this; // For backward compatibility with older versions self.eventBus.on('dagcoin.is-connected', function (fromAddress, message) { var reply = { protocol: 'dagcoin', title: 'connected' }; self.exceptionManager.logOnFailure(_this.device.sendMessageToDevice, fromAddress, 'text', JSON.stringify(reply), { ifOk: function ifOk() { console.log('REPLIED TO ' + fromAddress + ', WHO WANTED TO KNOW WHETHER I WERE CONNECTED'); }, ifError: function ifError(error) { self.exceptionManager.logError(error); } }); }); self.eventBus.on('dagcoin.request.is-connected', function (fromAddress, message) { self.sendResponse(fromAddress, 'is-connected', {}, message.id); }); self.eventBus.on('text', function (fromAddress, text) { console.log('TEXT MESSAGE FROM ' + fromAddress + ': ' + text); var message = null; try { message = JSON.parse(text); } catch (err) { console.log('NEW MESSAGE FROM ' + fromAddress + ': ' + text + ' NOT A JSON MESSAGE: ' + err); } if (message !== null) { if (message.protocol === 'dagcoin') { console.log('DAGCOIN MESSAGE RECEIVED FROM ' + fromAddress); self.eventBus.emit('dagcoin.' + message.title, fromAddress, message); return Promise.resolve(true); } console.log('JSON MESSAGE RECEIVED FROM ' + fromAddress + ' WITH UNEXPECTED PROTOCOL: ' + message.protocol); } }); } /** * Ensures the device is connected and responsive. */ DeviceManager.prototype.makeSureDeviceIsConnected = function (pairingCode) { var self = this; return self.checkOrPairDevice(pairingCode).then(function (correspondent) { console.log('RECEIVED A CORRESPONDENT: ' + JSON.stringify(correspondent)); return self.sendRequestAndListen(correspondent.device_address, 'is-connected', {}).then(function () { return Promise.resolve(correspondent.device_address); }, function (legacy) { self.exceptionManager.logError(legacy); // THIS REQUEST DOES NOT WORK ON LEGACY NOT SUPPORTING THE request-response MECHANISM /*** === LEGACY STUFF === ***/ var listener = null; var promise = new Promise(function (resolve) { listener = function listener(message, fromAddress) { if (fromAddress === correspondent.device_address) { console.log('DEVICE WITH ADDRESS ' + fromAddress + ' IS RESPONSIVE'); resolve(correspondent.device_address); } else { console.log('DISCARDED connected message MESSAGE ' + fromAddress + ' != ' + correspondent.device_address); } }; self.eventBus.on('dagcoin.connected', listener); }).then(function (deviceAddress) { self.eventBus.removeListener('dagcoin.connected', listener); return Promise.resolve(deviceAddress); }, function (error) { self.eventBus.removeListener('dagcoin.connected', listener); return Promise.reject(self.exceptionManager.generateError(error)); }); return new Promise(function (resolve, reject) { self.exceptionManager.rejectOnException(self.device.sendMessageToDevice, correspondent.device_address, 'text', JSON.stringify({ protocol: 'dagcoin', title: 'is-connected' }), { ifOk: function ifOk() { console.log('MESSAGE SENT: is-connected'); resolve(); }, ifError: function ifError(error) { reject(error); } }).catch(function (e) { reject(e); }); }).then(function () { return self.timedPromises.timedPromise(promise, self.conf.DAGCOIN_MESSAGE_TIMEOUT, 'DEVICE ' + correspondent.device_address + ' DID NOT REPLY TO THE LEGACY CONNECTION TEST'); }); }); }); }; DeviceManager.prototype.lookupDeviceByPublicKey = function (pubkey) { return this.dbManager.query('SELECT device_address FROM correspondent_devices WHERE pubkey = ? AND is_confirmed = 1', [pubkey]).then(function (rows) { if (rows.length === 0) { console.log('DEVICE WITH PUBKEY ' + pubkey + ' NOT YET PAIRED'); return Promise.resolve(null); } else { var deviceAddress = rows[0].device_address; console.log('DEVICE WITH PUBKEY ' + pubkey + ' ALREADY PAIRED: ' + deviceAddress); return Promise.resolve(deviceAddress); } }); }; DeviceManager.prototype.pairDevice = function (pubkey, hub, pairingSecret) { var self = this; return new Promise(function (resolve, reject) { self.exceptionManager.rejectOnException(self.device.addUnconfirmedCorrespondent, pubkey, hub, 'New', function (deviceAddress) { console.log('PAIRING WITH ' + deviceAddress + ' ... ADD UNCONFIRMED CORRESPONDENT'); resolve(deviceAddress); }).catch(function (e) { reject(e); }); }).then(function (deviceAddress) { console.log('PAIRING WITH ' + deviceAddress + ' ... ADD UNCONFIRMED CORRESPONDENT WAITING FOR PAIRING'); return new Promise(function (resolve, reject) { self.exceptionManager.rejectOnException(self.device.startWaitingForPairing, function (reversePairingInfo) { resolve({ deviceAddress: deviceAddress, reversePairingInfo: reversePairingInfo }); }).catch(function (e) { reject(e); }); }); }).then(function (params) { return new Promise(function (resolve, reject) { self.exceptionManager.rejectOnException(self.device.sendPairingMessage, hub, pubkey, pairingSecret, params.reversePairingInfo.pairing_secret, { ifOk: function ifOk() { resolve(params.deviceAddress); }, ifError: function ifError(error) { reject(self.exceptionManager.generateError(error)); } }).catch(function (e) { reject(e); }); }); }).then(function (deviceAddress) { console.log('LOOKING UP CORRESPONDENT WITH DEVICE ADDRESS ' + deviceAddress); return self.getCorrespondent(deviceAddress); }); }; DeviceManager.prototype.getCorrespondent = function (deviceAddress) { var self = this; console.log('GETTING CORRESPONDENT FROM DB WITH DEVICE ADDRESS ' + deviceAddress); return new Promise(function (resolve, reject) { self.exceptionManager.rejectOnException(self.device.readCorrespondent, deviceAddress, resolve).catch(function (e) { reject(e); }); }); }; DeviceManager.prototype.getCorrespondentList = function () { return this.dbManager.query('SELECT device_address, hub, name, my_record_pref, peer_record_pref, latest_message_date\n FROM correspondent_devices CD\n LEFT JOIN (SELECT correspondent_address, MAX(creation_date) AS latest_message_date \n FROM chat_messages GROUP BY correspondent_address) CM\n ON CM.correspondent_address = CD.device_address\n ORDER BY latest_message_date DESC, name ASC', []).then(function (rows) { return Promise.resolve(rows); }); }; DeviceManager.prototype.checkOrPairDevice = function (pairCode) { var _this2 = this; var matches = pairCode.match(/^([\w\/+]+)@([\w.:\/-]+)#([\w\/+-]+)$/); var pubkey = matches[1]; var hub = matches[2]; var pairingSecret = matches[3]; return this.lookupDeviceByPublicKey(pubkey).then(function (deviceAddress) { if (deviceAddress === null) { return _this2.pairDevice(pubkey, hub, pairingSecret); } return _this2.getCorrespondent(deviceAddress); }); }; DeviceManager.prototype.nextMessageId = function () { var id = this.messageCounter; this.messageCounter += 1; return id; }; DeviceManager.prototype.sendMessage = function (deviceAddress, messageType, subject, messageBody, messageId) { if (!deviceAddress) { return Promise.reject(Error('CALLING deviceManager.sendMessage: PARAMETER deviceAddress UNSPECIFIED')); } if (!messageType) { return Promise.reject(Error('CALLING deviceManager.sendMessage: PARAMETER messageType UNSPECIFIED')); } if (!subject) { return Promise.reject(Error('CALLING deviceManager.sendMessage: PARAMETER subject UNSPECIFIED')); } var self = this; if (messageId == null) { messageId = this.nextMessageId(); } var message = { protocol: 'dagcoin', title: messageType + '.' + subject, id: messageId, messageType: messageType, messageBody: messageBody }; return new Promise(function (resolve, reject) { self.exceptionManager.rejectOnException(self.device.sendMessageToDevice, deviceAddress, 'text', JSON.stringify(message), { onSaved: function onSaved() { console.log('A MESSAGE WAS SAVED INTO THE DATABASE: ' + JSON.stringify(message)); }, ifOk: function ifOk() { resolve(message.id); }, ifError: function ifError(error) { reject(error); } }).catch(function (e) { reject(e); }); }); }; DeviceManager.prototype.sendRequest = function (deviceAddress, subject, messageBody, messageId) { return this.sendMessage(deviceAddress, 'request', subject, messageBody, messageId); }; DeviceManager.prototype.sendResponse = function (deviceAddress, subject, messageBody, messageId) { return this.sendMessage(deviceAddress, 'response', subject, messageBody, messageId); }; DeviceManager.prototype.sendRequestAndListen = function (deviceAddress, subject, messageBody) { var self = this; var messageId = self.nextMessageId(); console.log('SENDING MESSAGE WITH ID: ' + messageId); var listeningPromise = self.timedPromises.listeningTimedPromise('dagcoin.response.' + subject, messageId, deviceAddress, self.conf.DAGCOIN_MESSAGE_TIMEOUT, 'DID NOT RECEIVE A REPLY TO MESSAGE ' + messageId + ' FROM ' + deviceAddress + ' FOR ' + JSON.stringify(messageBody)); console.log('SENDING REQUEST ' + subject + ' TO ' + deviceAddress); return this.sendMessage(deviceAddress, 'request', subject, messageBody, messageId).then(function () { console.log('LISTENING ' + subject + ' FROM ' + deviceAddress); return listeningPromise; }); }; module.exports = DeviceManager; module.exports.getInstance = function () { if (!instance) { instance = new DeviceManager(); } return instance; };