136 lines
3.4 KiB
JavaScript
136 lines
3.4 KiB
JavaScript
const { config } = require('./config');
|
|
const Keyv = require('keyv');
|
|
const { KeyvFile } = require('keyv-file');
|
|
const { Signale } = require('signale');
|
|
const log = new Signale().scope('GTWY');
|
|
const interactive = new Signale({ interactive: true, scope: 'GTWY' });
|
|
const stp = require('./STP');
|
|
const appdata = require('./appdata');
|
|
|
|
class Gateway {
|
|
constructor(identity, endpoints) {
|
|
this.identity = identity;
|
|
|
|
this.endpoints = new Keyv({
|
|
store: new KeyvFile({
|
|
filename: `${appdata}/valnet/relay/${this.identity.name}-endpoints.json`
|
|
})
|
|
});
|
|
|
|
this.ready = this.insertEndpoints(endpoints)
|
|
.then(this.networkTest.bind(this));
|
|
}
|
|
|
|
async insertEndpoints(endpoints) {
|
|
for (const endpoint of endpoints) {
|
|
const storeValue = await this.endpoints.get(endpoint);
|
|
if (storeValue) continue;
|
|
|
|
const [host, port] = endpoint.split(':');
|
|
const record = new EndpointRecord(host, port, null, 'unknown');
|
|
const currentEnpoints = await this.endpoints.get('cache') || [];
|
|
|
|
if (currentEnpoints.indexOf(endpoint) === -1) {
|
|
currentEnpoints.push(endpoint);
|
|
await this.endpoints.set('cache', currentEnpoints);
|
|
}
|
|
|
|
await this.endpoints.set(endpoint, record);
|
|
}
|
|
|
|
log.info('gateway endpoints:');
|
|
log.info('\t' + (await this.endpoints.get('cache')).join('\n\t'));
|
|
}
|
|
|
|
async networkTest() {
|
|
const endpoints = (await Promise.all(
|
|
(await this.endpoints.get('cache'))
|
|
.map(endpoint => this.endpoints.get(endpoint))
|
|
)).map(EndpointRecord.fromJson);
|
|
|
|
for (const endpoint of endpoints) {
|
|
await this.testEndpoint(endpoint.host, endpoint.port);
|
|
}
|
|
}
|
|
|
|
async testEndpoint(host, port) {
|
|
await new Promise(async (res, rej) => {
|
|
let pings = [];
|
|
let maxPings = 10;
|
|
let connectionAttempts = 0;
|
|
log.info(`Connecting to ${host}:${port}...`);
|
|
|
|
while (connectionAttempts < 10 && pings.length < maxPings) {
|
|
|
|
await new Promise(async (res) => {
|
|
const client = stp.connect({
|
|
identity: this.identity,
|
|
ip: host,
|
|
port: parseInt(port)
|
|
});
|
|
|
|
client.on('error', _ => _);
|
|
|
|
client.on('ready', async () => {
|
|
while (pings.length < maxPings) {
|
|
interactive.info(`[${pings.length + 1}/${maxPings}] Testing connection...`);
|
|
pings.push(await client.ping());
|
|
// pings.push(10);
|
|
await new Promise(res => setTimeout(res, 100));
|
|
}
|
|
const average = Math.round(pings.reduce((a, v) => a + v, 0) / maxPings);
|
|
interactive.success(`Test complete. Average Ping: ${average}`)
|
|
client.tcpSocket.destroy();
|
|
res();
|
|
});
|
|
|
|
client.on('close', () => {
|
|
res();
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
class EndpointRecord {
|
|
|
|
/**
|
|
* @param {Object|string} json string / object representation
|
|
* @returns {EndpointRecord}
|
|
*/
|
|
static fromJson(obj) {
|
|
if (typeof obj === 'string')
|
|
return EndpointRecord.fromJson(JSON.parse(obj));
|
|
|
|
return new EndpointRecord(
|
|
obj.host,
|
|
obj.port,
|
|
obj.lastPing ? new PingRecord(
|
|
obj.lastPing.average,
|
|
obj.lastPing.tests,
|
|
obj.lastPing.date
|
|
) : null,
|
|
obj.status
|
|
);
|
|
}
|
|
|
|
constructor(host, port, lastPing, status) {
|
|
this.host = host;
|
|
this.port = port;
|
|
this.lastPing = lastPing;
|
|
this.status = status;
|
|
}
|
|
}
|
|
|
|
class PingRecord {
|
|
constructor(average, tests, date) {
|
|
this.average = average;
|
|
this.tests = tests;
|
|
this.date = date;
|
|
}
|
|
}
|
|
|
|
module.exports = Gateway |