You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
123 lines
3.5 KiB
JavaScript
123 lines
3.5 KiB
JavaScript
/* global setTimeout, clearTimeout */
|
|
|
|
const EventEmitter = require('events');
|
|
const { isEmpty } = require('lodash');
|
|
|
|
const offlinePingTime = 2 * 60 * 1000; // 2 minutes
|
|
|
|
class LokiP2pAPI extends EventEmitter {
|
|
constructor(ourKey) {
|
|
super();
|
|
this.contactP2pDetails = {};
|
|
this.ourKey = ourKey;
|
|
}
|
|
|
|
reset() {
|
|
Object.keys(this.contactP2pDetails).forEach(key => {
|
|
clearTimeout(this.contactP2pDetails[key].pingTimer);
|
|
delete this.contactP2pDetails[key];
|
|
});
|
|
}
|
|
|
|
updateContactP2pDetails(pubKey, address, port, isP2PMessage = false) {
|
|
// Stagger the timers so the friends don't ping each other at the same time
|
|
const timerDuration =
|
|
pubKey < this.ourKey
|
|
? 60 * 1000 // 1 minute
|
|
: 2 * 60 * 1000; // 2 minutes
|
|
|
|
// Get the current contact details
|
|
// This will be empty if we don't have them
|
|
const baseDetails = { ...(this.contactP2pDetails[pubKey] || {}) };
|
|
|
|
// Always set the new contact details
|
|
this.contactP2pDetails[pubKey] = {
|
|
address,
|
|
port,
|
|
timerDuration,
|
|
pingTimer: null,
|
|
isOnline: false,
|
|
};
|
|
|
|
const contactExists = !isEmpty(baseDetails);
|
|
const { isOnline } = baseDetails;
|
|
const detailsChanged =
|
|
baseDetails.address !== address || baseDetails.port !== port;
|
|
|
|
// If we had the contact details
|
|
// And we got a P2P message
|
|
// And the contact was online
|
|
// And the new details that we got matched the old
|
|
// Then we don't need to bother pinging
|
|
if (contactExists && isP2PMessage && isOnline && !detailsChanged) {
|
|
// We also need to set the current contact details to show online
|
|
// because they get reset to `false` above
|
|
this.setContactOnline(pubKey);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
Ping the contact.
|
|
This happens in the following scenarios:
|
|
1. We didn't have the contact, we need to ping them to let them know our details.
|
|
2. isP2PMessage = false, so we assume the contact doesn't have our details.
|
|
3. We had the contact marked as offline,
|
|
we need to make sure that we can reach their server.
|
|
4. The other contact details have changed,
|
|
we need to make sure that we can reach their new server.
|
|
*/
|
|
this.pingContact(pubKey);
|
|
}
|
|
|
|
getContactP2pDetails(pubKey) {
|
|
if (!this.contactP2pDetails[pubKey]) {
|
|
return null;
|
|
}
|
|
return { ...this.contactP2pDetails[pubKey] };
|
|
}
|
|
|
|
setContactOffline(pubKey) {
|
|
this.emit('offline', pubKey);
|
|
if (!this.contactP2pDetails[pubKey]) {
|
|
return;
|
|
}
|
|
clearTimeout(this.contactP2pDetails[pubKey].pingTimer);
|
|
this.contactP2pDetails[pubKey].pingTimer = setTimeout(
|
|
this.pingContact.bind(this),
|
|
offlinePingTime,
|
|
pubKey
|
|
);
|
|
this.contactP2pDetails[pubKey].isOnline = false;
|
|
}
|
|
|
|
setContactOnline(pubKey) {
|
|
if (!this.contactP2pDetails[pubKey]) {
|
|
return;
|
|
}
|
|
this.emit('online', pubKey);
|
|
clearTimeout(this.contactP2pDetails[pubKey].pingTimer);
|
|
this.contactP2pDetails[pubKey].isOnline = true;
|
|
this.contactP2pDetails[pubKey].pingTimer = setTimeout(
|
|
this.pingContact.bind(this),
|
|
this.contactP2pDetails[pubKey].timerDuration,
|
|
pubKey
|
|
);
|
|
}
|
|
|
|
isOnline(pubKey) {
|
|
return !!(
|
|
this.contactP2pDetails[pubKey] && this.contactP2pDetails[pubKey].isOnline
|
|
);
|
|
}
|
|
|
|
pingContact(pubKey) {
|
|
if (!this.contactP2pDetails[pubKey]) {
|
|
// Don't ping if we don't have their details
|
|
return;
|
|
}
|
|
this.emit('pingContact', pubKey);
|
|
}
|
|
}
|
|
|
|
module.exports = LokiP2pAPI;
|