mirror of
https://github.com/pezkuwichain/pezkuwi-telemetry.git
synced 2026-06-14 02:31:02 +00:00
Working on map view
This commit is contained in:
@@ -44,6 +44,7 @@ export default class Chain {
|
||||
|
||||
node.events.on('block', () => this.updateBlock(node));
|
||||
node.events.on('stats', () => this.feeds.broadcast(Feed.stats(node)));
|
||||
node.events.on('location', (location) => this.feeds.broadcast(Feed.locatedNode(node, location)));
|
||||
}
|
||||
|
||||
public addFeed(feed: Feed) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import * as EventEmitter from 'events';
|
||||
import Node from './Node';
|
||||
import Chain from './Chain';
|
||||
import { VERSION, timestamp, Maybe, FeedMessage, Types, idGenerator } from '@dotstats/common';
|
||||
import { Location } from './location';
|
||||
|
||||
const nextId = idGenerator<Types.FeedId>();
|
||||
const { Actions } = FeedMessage;
|
||||
@@ -42,7 +43,7 @@ export default class Feed {
|
||||
public static addedNode(node: Node): FeedMessage.Message {
|
||||
return {
|
||||
action: Actions.AddedNode,
|
||||
payload: [node.id, node.nodeDetails(), node.nodeStats(), node.blockDetails()]
|
||||
payload: [node.id, node.nodeDetails(), node.nodeStats(), node.blockDetails(), node.nodeLocation()]
|
||||
};
|
||||
}
|
||||
|
||||
@@ -53,6 +54,13 @@ export default class Feed {
|
||||
};
|
||||
}
|
||||
|
||||
public static locatedNode(node: Node, location: Location): FeedMessage.Message {
|
||||
return {
|
||||
action: Actions.LocatedNode,
|
||||
payload: [node.id, location.lat, location.lon]
|
||||
};
|
||||
}
|
||||
|
||||
public static imported(node: Node): FeedMessage.Message {
|
||||
return {
|
||||
action: Actions.ImportedBlock,
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
import * as WebSocket from 'ws';
|
||||
import * as EventEmitter from 'events';
|
||||
import * as iplocation from 'iplocation';
|
||||
import { timestamp, Maybe, Types, idGenerator } from '@dotstats/common';
|
||||
import { parseMessage, getBestBlock, Message, BestBlock, SystemInterval } from './message';
|
||||
import { locate, Location } from './location';
|
||||
|
||||
const BLOCK_TIME_HISTORY = 10;
|
||||
const TIMEOUT = (1000 * 60 * 1) as Types.Milliseconds; // 1 minute
|
||||
|
||||
const nextId = idGenerator<Types.NodeId>();
|
||||
|
||||
export interface NodeEvents {
|
||||
on(event: 'location', fn: (location: Location) => void): void;
|
||||
emit(event: 'location', location: Location): void;
|
||||
}
|
||||
|
||||
export default class Node {
|
||||
public readonly id: Types.NodeId;
|
||||
public readonly name: Types.NodeName;
|
||||
@@ -16,8 +21,9 @@ export default class Node {
|
||||
public readonly implementation: Types.NodeImplementation;
|
||||
public readonly version: Types.NodeVersion;
|
||||
|
||||
public readonly events = new EventEmitter();
|
||||
public readonly events = new EventEmitter() as EventEmitter & NodeEvents;
|
||||
|
||||
public location: Maybe<Location> = null;
|
||||
public lastMessage: Types.Timestamp;
|
||||
public config: string;
|
||||
public best = '' as Types.BlockHash;
|
||||
@@ -30,11 +36,13 @@ export default class Node {
|
||||
private peers = 0 as Types.PeerCount;
|
||||
private txcount = 0 as Types.TransactionCount;
|
||||
|
||||
private readonly ip: string;
|
||||
private readonly socket: WebSocket;
|
||||
private blockTimes: Array<number> = new Array(BLOCK_TIME_HISTORY);
|
||||
private lastBlockAt: Maybe<Date> = null;
|
||||
|
||||
constructor(
|
||||
ip: string,
|
||||
socket: WebSocket,
|
||||
name: Types.NodeName,
|
||||
chain: Types.ChainLabel,
|
||||
@@ -42,6 +50,7 @@ export default class Node {
|
||||
implentation: Types.NodeImplementation,
|
||||
version: Types.NodeVersion,
|
||||
) {
|
||||
this.ip = ip;
|
||||
this.id = nextId();
|
||||
this.name = name;
|
||||
this.chain = chain;
|
||||
@@ -83,6 +92,18 @@ export default class Node {
|
||||
|
||||
this.disconnect();
|
||||
});
|
||||
|
||||
locate(ip).then((location) => {
|
||||
if (!location) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('node', ip, 'located at', location);
|
||||
|
||||
this.location = location;
|
||||
|
||||
this.events.emit('location', location);
|
||||
});
|
||||
}
|
||||
|
||||
public static fromSocket(socket: WebSocket, ip: string): Promise<Node> {
|
||||
@@ -102,7 +123,7 @@ export default class Node {
|
||||
|
||||
const { name, chain, config, implementation, version } = message;
|
||||
|
||||
resolve(new Node(socket, name, chain, config, implementation, version));
|
||||
resolve(new Node(ip, socket, name, chain, config, implementation, version));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,6 +157,12 @@ export default class Node {
|
||||
return [this.height, this.best, this.blockTime, this.blockTimestamp, this.propagationTime];
|
||||
}
|
||||
|
||||
public nodeLocation(): Maybe<Types.NodeLocation> {
|
||||
const { location } = this;
|
||||
|
||||
return location ? [location.lat, location.lon] : null;
|
||||
}
|
||||
|
||||
public get average(): number {
|
||||
let accounted = 0;
|
||||
let sum = 0;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import * as iplocation from 'iplocation';
|
||||
import { Maybe, Types } from '@dotstats/common';
|
||||
|
||||
export interface Location {
|
||||
lat: Types.Latitude;
|
||||
lon: Types.Longitude;
|
||||
}
|
||||
|
||||
const cache = new Map<string, Location>();
|
||||
|
||||
export async function locate(ip: string): Promise<Maybe<Location>> {
|
||||
if (ip === '127.0.0.1') {
|
||||
return Promise.resolve({
|
||||
lat: 52.5166667 as Types.Latitude,
|
||||
lon: 13.4 as Types.Longitude
|
||||
});
|
||||
}
|
||||
|
||||
const cached = cache.get(ip);
|
||||
|
||||
if (cached) {
|
||||
return Promise.resolve(cached);
|
||||
}
|
||||
|
||||
return new Promise<Maybe<Location>>((resolve, _) => {
|
||||
iplocation(ip, (err, result) => {
|
||||
if (err) {
|
||||
console.error(`Couldn't locate ${ip}`);
|
||||
|
||||
return resolve(null);
|
||||
}
|
||||
|
||||
const { lat, lon } = result;
|
||||
const location = { lat, lon } as Location;
|
||||
|
||||
cache.set(ip, location);
|
||||
|
||||
resolve(location);
|
||||
});
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user