From b1cc4f316bca53ac37c59ba429633152b2c45e64 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 18 Apr 2020 19:43:05 -0400 Subject: [PATCH] last seen node --- services/gunDB/Mediator/index.js | 2 + services/gunDB/contact-api/jobs/index.js | 4 +- .../gunDB/contact-api/jobs/lastSeenNode.js | 40 +++++++++++++++++ services/gunDB/contact-api/key.js | 2 + services/gunDB/contact-api/utils/index.js | 43 ++++++++++++++++--- 5 files changed, 85 insertions(+), 6 deletions(-) create mode 100644 services/gunDB/contact-api/jobs/lastSeenNode.js diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index e233199a..167c9460 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -282,6 +282,7 @@ const authenticate = async (alias, pass, __user) => { // move this to a subscription; implement off() ? todo API.Jobs.onAcceptedRequests(_user, mySEA) API.Jobs.onOrders(_user, gun, mySEA) + API.Jobs.lastSeenNode(_user) return _user._.sea.pub } @@ -313,6 +314,7 @@ const authenticate = async (alias, pass, __user) => { API.Jobs.onAcceptedRequests(_user, mySEA) API.Jobs.onOrders(_user, gun, mySEA) + API.Jobs.lastSeenNode(_user) return ack.sea.pub } else { diff --git a/services/gunDB/contact-api/jobs/index.js b/services/gunDB/contact-api/jobs/index.js index 55c993e1..8818d047 100644 --- a/services/gunDB/contact-api/jobs/index.js +++ b/services/gunDB/contact-api/jobs/index.js @@ -11,8 +11,10 @@ const onAcceptedRequests = require('./onAcceptedRequests') const onOrders = require('./onOrders') +const lastSeenNode = require('./lastSeenNode') module.exports = { onAcceptedRequests, - onOrders + onOrders, + lastSeenNode } diff --git a/services/gunDB/contact-api/jobs/lastSeenNode.js b/services/gunDB/contact-api/jobs/lastSeenNode.js new file mode 100644 index 00000000..881d41b2 --- /dev/null +++ b/services/gunDB/contact-api/jobs/lastSeenNode.js @@ -0,0 +1,40 @@ +/** + * @format + */ + +const logger = require('winston') + +const ErrorCode = require('../errorCode') +const Key = require('../key') +const { LAST_SEEN_NODE_INTERVAL } = require('../utils') + +/** + * @typedef {import('../SimpleGUN').GUNNode} GUNNode + * @typedef {import('../SimpleGUN').ListenerData} ListenerData + * @typedef {import('../SimpleGUN').ISEA} ISEA + * @typedef {import('../SimpleGUN').UserGUNNode} UserGUNNode + */ + +/** + * @param {UserGUNNode} user + * @throws {Error} NOT_AUTH + * @returns {void} + */ +const lastSeenNode = user => { + if (!user.is) { + logger.warn('onOrders() -> tried to sub without authing') + throw new Error(ErrorCode.NOT_AUTH) + } + + setInterval(() => { + if (user.is) { + user.get(Key.LAST_SEEN_NODE).put(Date.now(), ack => { + if (ack.err) { + logger.error(`Error inside lastSeenNode job: ${ack.err}`) + } + }) + } + }, LAST_SEEN_NODE_INTERVAL) +} + +module.exports = lastSeenNode diff --git a/services/gunDB/contact-api/key.js b/services/gunDB/contact-api/key.js index 6f380432..a1b26023 100644 --- a/services/gunDB/contact-api/key.js +++ b/services/gunDB/contact-api/key.js @@ -38,3 +38,5 @@ exports.BIO = 'bio' exports.SEED_BACKUP = 'seedBackup' exports.LAST_SEEN_APP = 'lastSeenApp' + +exports.LAST_SEEN_NODE = 'lastSeenNode' diff --git a/services/gunDB/contact-api/utils/index.js b/services/gunDB/contact-api/utils/index.js index 63432cd7..93b3dd4c 100644 --- a/services/gunDB/contact-api/utils/index.js +++ b/services/gunDB/contact-api/utils/index.js @@ -1,7 +1,7 @@ -/* eslint-disable init-declarations */ /** * @format */ +/* eslint-disable init-declarations */ const logger = require('winston') const ErrorCode = require('../errorCode') @@ -30,11 +30,11 @@ const mySecret = () => Promise.resolve(require('../../Mediator').getMySecret()) * @returns {Promise} */ const timeout10 = promise => { - /** @type {NodeJS.Timeout} */ + /** @type {NodeJS.Timeout} */ // @ts-ignore let timeoutID return Promise.race([ - promise.then((v) => { + promise.then(v => { clearTimeout(timeoutID) return v }), @@ -57,7 +57,7 @@ const timeout5 = promise => { // @ts-ignore let timeoutID return Promise.race([ - promise.then((v) => { + promise.then(v => { clearTimeout(timeoutID) return v }), @@ -314,6 +314,37 @@ const dataHasSoul = listenerData => */ const defaultName = pub => 'anon' + pub.slice(0, 8) +const LAST_SEEN_NODE_INTERVAL = 10000 + +/** + * @param {string} pub + * @returns {Promise} + */ +const isNodeOnline = async pub => { + const SET_LAST_SEEN_APP_INTERVAL = 15000 + + /** + * @param {any} lastSeen + * @returns {boolean} + */ + const isAppOnline = lastSeen => + typeof lastSeen === 'number' && + Date.now() - lastSeen < SET_LAST_SEEN_APP_INTERVAL * 2 + + const userNode = require('../../Mediator') + .getGun() + .user(pub) + + const isOnlineApp = isAppOnline(await userNode.get(Key.LAST_SEEN_APP).then()) + const lastSeenNode = await userNode.get(Key.LAST_SEEN_NODE).then() + + return ( + isOnlineApp || + (typeof lastSeenNode === 'number' && + Date.now() - lastSeenNode < LAST_SEEN_NODE_INTERVAL * 2) + ) +} + module.exports = { asyncMap, asyncFilter, @@ -328,5 +359,7 @@ module.exports = { mySecret, promisifyGunNode: require('./promisifygun'), asyncForEach, - timeout5 + timeout5, + LAST_SEEN_NODE_INTERVAL, + isNodeOnline }