Sort chains by node count

This commit is contained in:
maciejhirsz
2018-07-12 16:04:04 +02:00
parent 47b80ad30e
commit ea8d7ad77d
10 changed files with 63 additions and 25 deletions
+4 -2
View File
@@ -16,13 +16,15 @@ export default class Aggregator {
let chain = this.getChain(node.chain); let chain = this.getChain(node.chain);
chain.addNode(node); chain.addNode(node);
this.feeds.broadcast(Feed.addedChain(chain));
} }
public addFeed(feed: Feed) { public addFeed(feed: Feed) {
this.feeds.add(feed); this.feeds.add(feed);
for (const chain of this.chains.values()) { for (const chain of this.chains.values()) {
feed.sendMessage(Feed.addedChain(chain.label)); feed.sendMessage(Feed.addedChain(chain));
} }
feed.events.on('subscribe', (label: Types.ChainLabel) => { feed.events.on('subscribe', (label: Types.ChainLabel) => {
@@ -68,7 +70,7 @@ export default class Aggregator {
this.chains.set(label, chain); this.chains.set(label, chain);
console.log(`New chain: ${label}`); console.log(`New chain: ${label}`);
this.feeds.broadcast(Feed.addedChain(label)); this.feeds.broadcast(Feed.addedChain(chain));
return chain; return chain;
} }
+2 -2
View File
@@ -18,8 +18,8 @@ export default class Chain {
this.label = label; this.label = label;
} }
public get nodeCount(): number { public get nodeCount(): Types.NodeCount {
return this.nodes.size; return this.nodes.size as Types.NodeCount;
} }
public addNode(node: Node) { public addNode(node: Node) {
+3 -2
View File
@@ -1,6 +1,7 @@
import * as WebSocket from 'ws'; import * as WebSocket from 'ws';
import * as EventEmitter from 'events'; import * as EventEmitter from 'events';
import Node from './Node'; import Node from './Node';
import Chain from './Chain';
import { timestamp, Maybe, FeedMessage, Types, idGenerator } from '@dotstats/common'; import { timestamp, Maybe, FeedMessage, Types, idGenerator } from '@dotstats/common';
const nextId = idGenerator<Types.FeedId>(); const nextId = idGenerator<Types.FeedId>();
@@ -66,10 +67,10 @@ export default class Feed {
}; };
} }
public static addedChain(label: Types.ChainLabel): FeedMessage.Message { public static addedChain(chain: Chain): FeedMessage.Message {
return { return {
action: Actions.AddedChain, action: Actions.AddedChain,
payload: label payload: [chain.label, chain.nodeCount]
}; };
} }
+11 -2
View File
@@ -1,5 +1,14 @@
import { Opaque } from './helpers'; import { Opaque } from './helpers';
import { NodeId, NodeDetails, NodeStats, BlockNumber, BlockDetails, Timestamp, ChainLabel } from './types'; import {
NodeId,
NodeCount,
NodeDetails,
NodeStats,
BlockNumber,
BlockDetails,
Timestamp,
ChainLabel
} from './types';
export const Actions = { export const Actions = {
BestBlock: 0 as 0, BestBlock: 0 as 0,
@@ -54,7 +63,7 @@ export namespace Variants {
export interface AddedChainMessage extends MessageBase { export interface AddedChainMessage extends MessageBase {
action: typeof Actions.AddedChain; action: typeof Actions.AddedChain;
payload: ChainLabel; payload: [ChainLabel, NodeCount];
} }
export interface RemovedChainMessage extends MessageBase { export interface RemovedChainMessage extends MessageBase {
+1
View File
@@ -12,6 +12,7 @@ export type BlockHash = Opaque<string, 'BlockHash'>;
export type Milliseconds = Opaque<number, 'Milliseconds'>; export type Milliseconds = Opaque<number, 'Milliseconds'>;
export type Timestamp = Opaque<Milliseconds, 'Timestamp'>; export type Timestamp = Opaque<Milliseconds, 'Timestamp'>;
export type PropagationTime = Opaque<Milliseconds, 'PropagationTime'>; export type PropagationTime = Opaque<Milliseconds, 'PropagationTime'>;
export type NodeCount = Opaque<number, 'NodeCount'>;
export type PeerCount = Opaque<number, 'PeerCount'>; export type PeerCount = Opaque<number, 'PeerCount'>;
export type TransactionCount = Opaque<number, 'TransactionCount'>; export type TransactionCount = Opaque<number, 'TransactionCount'>;
+2 -2
View File
@@ -1,7 +1,7 @@
import * as React from 'react'; import * as React from 'react';
import { Types } from '@dotstats/common'; import { Types } from '@dotstats/common';
import { Chains, Chain, Ago } from './components'; import { Chains, Chain, Ago } from './components';
import { Connection } from './message'; import { Connection } from './Connection';
import { State } from './state'; import { State } from './state';
import './App.css'; import './App.css';
@@ -12,7 +12,7 @@ export default class App extends React.Component<{}, State> {
blockTimestamp: 0 as Types.Timestamp, blockTimestamp: 0 as Types.Timestamp,
timeDiff: 0 as Types.Milliseconds, timeDiff: 0 as Types.Milliseconds,
subscribed: null, subscribed: null,
chains: new Set(), chains: new Map(),
nodes: new Map() nodes: new Map()
}; };
@@ -146,8 +146,8 @@ export class Connection {
} }
case Actions.AddedChain: { case Actions.AddedChain: {
chains.add(message.payload); const [label, nodeCount] = message.payload;
chains.set(label, nodeCount);
this.autoSubscribe(); this.autoSubscribe();
break; break;
@@ -195,10 +195,22 @@ export class Connection {
private autoSubscribe() { private autoSubscribe() {
const { subscribed, chains } = this.state; const { subscribed, chains } = this.state;
if (subscribed == null && chains.size) { if (subscribed) {
const first = chains.values().next().value; return;
}
this.subscribe(first); let topLabel: Maybe<Types.ChainLabel> = null;
let topCount: Types.NodeCount = 0 as Types.NodeCount;
for (const [label, count] of chains.entries()) {
if (count > topCount) {
topLabel = label;
topCount = topCount;
}
}
if (topLabel) {
this.subscribe(topLabel);
} }
} }
+1 -1
View File
@@ -6,7 +6,7 @@
.Chain-content { .Chain-content {
position: absolute; position: absolute;
left: 80px; left: 0; /*80px;*/
right: 0; right: 0;
min-height: 50vh; min-height: 50vh;
background: #222; background: #222;
+21 -8
View File
@@ -1,14 +1,19 @@
import * as React from 'react'; import * as React from 'react';
import { Connection } from '../message'; import { Connection } from '../Connection';
import { Icon } from './Icon'; import { Icon } from './Icon';
import { Types, Maybe } from '@dotstats/common'; import { Types, Maybe } from '@dotstats/common';
import chainIcon from '../icons/link.svg'; import chainIcon from '../icons/link.svg';
import './Chains.css'; import './Chains.css';
interface ChainData {
label: Types.ChainLabel;
nodeCount: Types.NodeCount;
}
export namespace Chains { export namespace Chains {
export interface Props { export interface Props {
chains: Set<Types.ChainLabel>, chains: Map<Types.ChainLabel, Types.NodeCount>,
subscribed: Maybe<Types.ChainLabel>, subscribed: Maybe<Types.ChainLabel>,
connection: Promise<Connection> connection: Promise<Connection>
} }
@@ -26,20 +31,28 @@ export class Chains extends React.Component<Chains.Props, {}> {
); );
} }
private renderChain(chain: Types.ChainLabel): React.ReactNode { private renderChain(chain: ChainData): React.ReactNode {
const className = chain === this.props.subscribed const { label, nodeCount } = chain;
const className = label === this.props.subscribed
? 'Chains-chain Chains-chain-selected' ? 'Chains-chain Chains-chain-selected'
: 'Chains-chain'; : 'Chains-chain';
return ( return (
<a key={chain} className={className} onClick={this.subscribe.bind(this, chain)}> <a key={label} className={className} onClick={this.subscribe.bind(this, label)}>
{chain} {label} ({nodeCount})
</a> </a>
) )
} }
private get chains(): Types.ChainLabel[] { private get chains(): ChainData[] {
return Array.from(this.props.chains); return Array
.from(this.props.chains.entries())
.sort((a, b) => {
return b[1] - a[1];
})
.map(([label, nodeCount]) => ({ label, nodeCount }));
} }
private async subscribe(chain: Types.ChainLabel) { private async subscribe(chain: Types.ChainLabel) {
+1 -1
View File
@@ -6,7 +6,7 @@ export interface State {
blockTimestamp: Types.Timestamp, blockTimestamp: Types.Timestamp,
timeDiff: Types.Milliseconds, timeDiff: Types.Milliseconds,
subscribed: Maybe<Types.ChainLabel>, subscribed: Maybe<Types.ChainLabel>,
chains: Set<Types.ChainLabel>, chains: Map<Types.ChainLabel, Types.NodeCount>,
nodes: Map<Types.NodeId, Node.Props>, nodes: Map<Types.NodeId, Node.Props>,
} }