mirror of
https://github.com/pezkuwichain/pezkuwi-telemetry.git
synced 2026-07-02 07:27:28 +00:00
Restructure the js app (#243)
* prettier * linter * add prettier, and format the code * remove common, merge it with frontend * refactor the app * better lint and code fix * travis for the frontend app * travis build script Signed-off-by: Daniel Maricic <daniel@woss.io> * lint and build * update the README.md Signed-off-by: Daniel Maricic <daniel@woss.io> * change the commands to reflect refactor Signed-off-by: Daniel Maricic <daniel@woss.io> * prettier and tslint are friends Signed-off-by: Daniel Maricic <daniel@woss.io> * code that wasn't linted properly before Signed-off-by: Daniel Maricic <daniel@woss.io> * prettier rc got deleted * workgin on making the travis pass Signed-off-by: Daniel Maricic <daniel@woss.io> * travis build please? Signed-off-by: Daniel Maricic <daniel@woss.io> * update readme.md Signed-off-by: Daniel Maricic <daniel@woss.io> * dockerfile deleted from fronted - out of scope Signed-off-by: Daniel Maricic <daniel@woss.io> * remove Signed-off-by: Daniel Maricic <daniel@woss.io> * tsconfig Signed-off-by: Daniel Maricic <daniel@woss.io> * found the reason why EOL wasn't happening Signed-off-by: Daniel Maricic <daniel@woss.io> * type for the event in the ConnectionInput as suggested * strictnullCheck to true * noImplicitAny * noUnusedParams * AfgHandling * update * fix Location.tsx * Few minor fixes * remove connection input and revert to original * esnext fixes the imports for icons and non default `* as ` * update to the tsconfig.test.json don't use commonjs please * fixed wrong comment for TIMEOUT_BASE * return totem.svg and type decraration of maybe Signed-off-by: Daniel Maricic <daniel@woss.io> Co-authored-by: Will <w.kopp@kigroup.de>
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
import { Maybe, Opaque } from './helpers';
|
||||
|
||||
export type Compare<T> = (a: T, b: T) => number;
|
||||
|
||||
/**
|
||||
* Insert an item into a sorted array using binary search.
|
||||
*
|
||||
* @type {T} item type
|
||||
* @param {T} item to be inserted
|
||||
* @param {Array<T>} array to be modified
|
||||
* @param {(a, b) => number} compare function
|
||||
*
|
||||
* @return {number} insertion index
|
||||
*/
|
||||
export function sortedInsert<T>(
|
||||
item: T,
|
||||
into: Array<T>,
|
||||
compare: Compare<T>
|
||||
): number {
|
||||
if (into.length === 0) {
|
||||
into.push(item);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
let min = 0;
|
||||
let max = into.length - 1;
|
||||
|
||||
while (min !== max) {
|
||||
const guess = ((min + max) / 2) | 0;
|
||||
|
||||
if (compare(item, into[guess]) < 0) {
|
||||
max = Math.max(min, guess - 1);
|
||||
} else {
|
||||
min = Math.min(max, guess + 1);
|
||||
}
|
||||
}
|
||||
|
||||
const insert = compare(item, into[min]) <= 0 ? min : min + 1;
|
||||
|
||||
into.splice(insert, 0, item);
|
||||
|
||||
return insert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an index of an element within a sorted array. This should be substantially
|
||||
* faster than `indexOf` for large arrays.
|
||||
*
|
||||
* @type {T} item type
|
||||
* @param {T} item to find
|
||||
* @param {Array<T>} array to look through
|
||||
* @param {(a, b) => number} compare function
|
||||
*
|
||||
* @return {number} index of the element, `-1` if not found
|
||||
*/
|
||||
export function sortedIndexOf<T>(
|
||||
item: T,
|
||||
within: Array<T>,
|
||||
compare: Compare<T>
|
||||
): number {
|
||||
if (within.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
let min = 0;
|
||||
let max = within.length - 1;
|
||||
|
||||
while (min !== max) {
|
||||
const guess = ((min + max) / 2) | 0;
|
||||
const other = within[guess];
|
||||
|
||||
if (item === other) {
|
||||
return guess;
|
||||
}
|
||||
|
||||
const result = compare(item, other);
|
||||
|
||||
if (result < 0) {
|
||||
max = Math.max(min, guess - 1);
|
||||
} else if (result > 0) {
|
||||
min = Math.min(max, guess + 1);
|
||||
} else {
|
||||
// Equal sort value, but different reference, do value search from min
|
||||
return within.indexOf(item, min);
|
||||
}
|
||||
}
|
||||
|
||||
if (item === within[min]) {
|
||||
return min;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
export namespace SortedCollection {
|
||||
export type StateRef = Opaque<number, 'SortedCollection.StateRef'>;
|
||||
}
|
||||
|
||||
export class SortedCollection<Item extends { id: number }> {
|
||||
private compare: Compare<Item>;
|
||||
private map = Array<Maybe<Item>>();
|
||||
private list = Array<Item>();
|
||||
private changeRef = 0;
|
||||
|
||||
constructor(compare: Compare<Item>) {
|
||||
this.compare = compare;
|
||||
}
|
||||
|
||||
public setComparator(compare: Compare<Item>) {
|
||||
this.compare = compare;
|
||||
this.list = this.map.filter((item) => item != null) as Item[];
|
||||
this.list.sort(compare);
|
||||
this.changeRef += 1;
|
||||
}
|
||||
|
||||
public ref(): SortedCollection.StateRef {
|
||||
return this.changeRef as SortedCollection.StateRef;
|
||||
}
|
||||
|
||||
public add(item: Item) {
|
||||
if (this.map.length <= item.id) {
|
||||
// Grow map if item.id would be out of scope
|
||||
this.map = this.map.concat(
|
||||
Array<Maybe<Item>>(Math.max(10, 1 + item.id - this.map.length))
|
||||
);
|
||||
}
|
||||
|
||||
// Remove old item if overriding
|
||||
this.remove(item.id);
|
||||
|
||||
this.map[item.id] = item;
|
||||
|
||||
sortedInsert(item, this.list, this.compare);
|
||||
|
||||
this.changeRef += 1;
|
||||
}
|
||||
|
||||
public remove(id: number) {
|
||||
const item = this.map[id];
|
||||
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = sortedIndexOf(item, this.list, this.compare);
|
||||
this.list.splice(index, 1);
|
||||
this.map[id] = null;
|
||||
|
||||
this.changeRef += 1;
|
||||
}
|
||||
|
||||
public get(id: number): Maybe<Item> {
|
||||
return this.map[id];
|
||||
}
|
||||
|
||||
public sorted(): Array<Item> {
|
||||
return this.list;
|
||||
}
|
||||
|
||||
public mut(id: number, mutator: (item: Item) => void) {
|
||||
const item = this.map[id];
|
||||
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
mutator(item);
|
||||
}
|
||||
|
||||
public mutAndSort(id: number, mutator: (item: Item) => void) {
|
||||
const item = this.map[id];
|
||||
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = sortedIndexOf(item, this.list, this.compare);
|
||||
|
||||
mutator(item);
|
||||
|
||||
this.list.splice(index, 1);
|
||||
|
||||
const newIndex = sortedInsert(item, this.list, this.compare);
|
||||
|
||||
if (newIndex !== index) {
|
||||
this.changeRef += 1;
|
||||
}
|
||||
}
|
||||
|
||||
public mutAndMaybeSort(
|
||||
id: number,
|
||||
mutator: (item: Item) => void,
|
||||
sort: boolean
|
||||
) {
|
||||
if (sort) {
|
||||
this.mutAndSort(id, mutator);
|
||||
} else {
|
||||
this.mut(id, mutator);
|
||||
}
|
||||
}
|
||||
|
||||
public mutEach(mutator: (item: Item) => void) {
|
||||
this.list.forEach(mutator);
|
||||
}
|
||||
|
||||
public mutEachAndSort(mutator: (item: Item) => void) {
|
||||
this.list.forEach(mutator);
|
||||
this.list.sort(this.compare);
|
||||
}
|
||||
|
||||
public clear() {
|
||||
this.map = [];
|
||||
this.list = [];
|
||||
|
||||
this.changeRef += 1;
|
||||
}
|
||||
|
||||
public hasChangedSince(ref: SortedCollection.StateRef): boolean {
|
||||
return this.changeRef > ref;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
import { Maybe } from './helpers';
|
||||
import { stringify, parse, Stringified } from './stringify';
|
||||
import {
|
||||
FeedVersion,
|
||||
Address,
|
||||
Latitude,
|
||||
Longitude,
|
||||
City,
|
||||
NodeId,
|
||||
NodeCount,
|
||||
NodeDetails,
|
||||
NodeStats,
|
||||
NodeIO,
|
||||
NodeHardware,
|
||||
NodeLocation,
|
||||
BlockNumber,
|
||||
BlockHash,
|
||||
BlockDetails,
|
||||
Timestamp,
|
||||
Milliseconds,
|
||||
ChainLabel,
|
||||
AuthoritySetInfo,
|
||||
} from './types';
|
||||
|
||||
export const ACTIONS = {
|
||||
FeedVersion: 0x00 as 0x00,
|
||||
BestBlock: 0x01 as 0x01,
|
||||
BestFinalized: 0x02 as 0x02,
|
||||
AddedNode: 0x03 as 0x03,
|
||||
RemovedNode: 0x04 as 0x04,
|
||||
LocatedNode: 0x05 as 0x05,
|
||||
ImportedBlock: 0x06 as 0x06,
|
||||
FinalizedBlock: 0x07 as 0x07,
|
||||
NodeStats: 0x08 as 0x08,
|
||||
NodeHardware: 0x09 as 0x09,
|
||||
TimeSync: 0x0a as 0x0a,
|
||||
AddedChain: 0x0b as 0x0b,
|
||||
RemovedChain: 0x0c as 0x0c,
|
||||
SubscribedTo: 0x0d as 0x0d,
|
||||
UnsubscribedFrom: 0x0e as 0x0e,
|
||||
Pong: 0x0f as 0x0f,
|
||||
AfgFinalized: 0x10 as 0x10,
|
||||
AfgReceivedPrevote: 0x11 as 0x11,
|
||||
AfgReceivedPrecommit: 0x12 as 0x12,
|
||||
AfgAuthoritySet: 0x13 as 0x13,
|
||||
StaleNode: 0x14 as 0x14,
|
||||
NodeIO: 0x15 as 0x15,
|
||||
};
|
||||
|
||||
export type Action = typeof ACTIONS[keyof typeof ACTIONS];
|
||||
export type Payload = Message['payload'];
|
||||
|
||||
export namespace Variants {
|
||||
export interface MessageBase {
|
||||
action: Action;
|
||||
}
|
||||
|
||||
export interface FeedVersionMessage extends MessageBase {
|
||||
action: typeof ACTIONS.FeedVersion;
|
||||
payload: FeedVersion;
|
||||
}
|
||||
|
||||
export interface BestBlockMessage extends MessageBase {
|
||||
action: typeof ACTIONS.BestBlock;
|
||||
payload: [BlockNumber, Timestamp, Maybe<Milliseconds>];
|
||||
}
|
||||
|
||||
export interface BestFinalizedBlockMessage extends MessageBase {
|
||||
action: typeof ACTIONS.BestFinalized;
|
||||
payload: [BlockNumber, BlockHash];
|
||||
}
|
||||
|
||||
export interface AddedNodeMessage extends MessageBase {
|
||||
action: typeof ACTIONS.AddedNode;
|
||||
payload: [
|
||||
NodeId,
|
||||
NodeDetails,
|
||||
NodeStats,
|
||||
NodeIO,
|
||||
NodeHardware,
|
||||
BlockDetails,
|
||||
Maybe<NodeLocation>,
|
||||
Timestamp
|
||||
];
|
||||
}
|
||||
|
||||
export interface RemovedNodeMessage extends MessageBase {
|
||||
action: typeof ACTIONS.RemovedNode;
|
||||
payload: NodeId;
|
||||
}
|
||||
|
||||
export interface LocatedNodeMessage extends MessageBase {
|
||||
action: typeof ACTIONS.LocatedNode;
|
||||
payload: [NodeId, Latitude, Longitude, City];
|
||||
}
|
||||
|
||||
export interface ImportedBlockMessage extends MessageBase {
|
||||
action: typeof ACTIONS.ImportedBlock;
|
||||
payload: [NodeId, BlockDetails];
|
||||
}
|
||||
|
||||
export interface FinalizedBlockMessage extends MessageBase {
|
||||
action: typeof ACTIONS.FinalizedBlock;
|
||||
payload: [NodeId, BlockNumber, BlockHash];
|
||||
}
|
||||
|
||||
export interface NodeStatsMessage extends MessageBase {
|
||||
action: typeof ACTIONS.NodeStats;
|
||||
payload: [NodeId, NodeStats];
|
||||
}
|
||||
|
||||
export interface NodeHardwareMessage extends MessageBase {
|
||||
action: typeof ACTIONS.NodeHardware;
|
||||
payload: [NodeId, NodeHardware];
|
||||
}
|
||||
|
||||
export interface NodeIOMessage extends MessageBase {
|
||||
action: typeof ACTIONS.NodeIO;
|
||||
payload: [NodeId, NodeIO];
|
||||
}
|
||||
|
||||
export interface TimeSyncMessage extends MessageBase {
|
||||
action: typeof ACTIONS.TimeSync;
|
||||
payload: Timestamp;
|
||||
}
|
||||
|
||||
export interface AddedChainMessage extends MessageBase {
|
||||
action: typeof ACTIONS.AddedChain;
|
||||
payload: [ChainLabel, NodeCount];
|
||||
}
|
||||
|
||||
export interface RemovedChainMessage extends MessageBase {
|
||||
action: typeof ACTIONS.RemovedChain;
|
||||
payload: ChainLabel;
|
||||
}
|
||||
|
||||
export interface SubscribedToMessage extends MessageBase {
|
||||
action: typeof ACTIONS.SubscribedTo;
|
||||
payload: ChainLabel;
|
||||
}
|
||||
|
||||
export interface UnsubscribedFromMessage extends MessageBase {
|
||||
action: typeof ACTIONS.UnsubscribedFrom;
|
||||
payload: ChainLabel;
|
||||
}
|
||||
|
||||
export interface PongMessage extends MessageBase {
|
||||
action: typeof ACTIONS.Pong;
|
||||
payload: string; // just echo whatever `ping` sent
|
||||
}
|
||||
|
||||
export interface AfgFinalizedMessage extends MessageBase {
|
||||
action: typeof ACTIONS.AfgFinalized;
|
||||
payload: [Address, BlockNumber, BlockHash];
|
||||
}
|
||||
|
||||
export interface AfgAuthoritySet extends MessageBase {
|
||||
action: typeof ACTIONS.AfgAuthoritySet;
|
||||
payload: AuthoritySetInfo;
|
||||
}
|
||||
|
||||
export interface AfgReceivedPrecommit extends MessageBase {
|
||||
action: typeof ACTIONS.AfgReceivedPrecommit;
|
||||
payload: [Address, BlockNumber, BlockHash, Address];
|
||||
}
|
||||
|
||||
export interface AfgReceivedPrevote extends MessageBase {
|
||||
action: typeof ACTIONS.AfgReceivedPrevote;
|
||||
payload: [Address, BlockNumber, BlockHash, Address];
|
||||
}
|
||||
|
||||
export interface StaleNodeMessage extends MessageBase {
|
||||
action: typeof ACTIONS.StaleNode;
|
||||
payload: NodeId;
|
||||
}
|
||||
}
|
||||
|
||||
export type Message =
|
||||
| Variants.FeedVersionMessage
|
||||
| Variants.BestBlockMessage
|
||||
| Variants.BestFinalizedBlockMessage
|
||||
| Variants.AddedNodeMessage
|
||||
| Variants.RemovedNodeMessage
|
||||
| Variants.LocatedNodeMessage
|
||||
| Variants.ImportedBlockMessage
|
||||
| Variants.FinalizedBlockMessage
|
||||
| Variants.NodeStatsMessage
|
||||
| Variants.NodeHardwareMessage
|
||||
| Variants.TimeSyncMessage
|
||||
| Variants.AddedChainMessage
|
||||
| Variants.RemovedChainMessage
|
||||
| Variants.SubscribedToMessage
|
||||
| Variants.UnsubscribedFromMessage
|
||||
| Variants.AfgFinalizedMessage
|
||||
| Variants.AfgReceivedPrevote
|
||||
| Variants.AfgReceivedPrecommit
|
||||
| Variants.AfgAuthoritySet
|
||||
| Variants.StaleNodeMessage
|
||||
| Variants.PongMessage
|
||||
| Variants.NodeIOMessage;
|
||||
|
||||
/**
|
||||
* Data type to be sent to the feed. Passing through strings means we can only serialize once,
|
||||
* no matter how many feed clients are listening in.
|
||||
*/
|
||||
export interface SquashedMessages extends Array<Action | Payload> {}
|
||||
export type Data = Stringified<SquashedMessages>;
|
||||
|
||||
/**
|
||||
* Serialize an array of `Message`s to a single JSON string.
|
||||
*
|
||||
* All messages are squashed into a single array of alternating opcodes and payloads.
|
||||
*
|
||||
* Action `string`s are converted to opcodes using the `actionToCode` mapping.
|
||||
*/
|
||||
export function serialize(messages: Array<Message>): Data {
|
||||
const squashed: SquashedMessages = new Array(messages.length * 2);
|
||||
let index = 0;
|
||||
|
||||
messages.forEach((message) => {
|
||||
const { action, payload } = message;
|
||||
|
||||
squashed[index++] = action;
|
||||
squashed[index++] = payload;
|
||||
});
|
||||
|
||||
return stringify(squashed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize data to an array of `Message`s.
|
||||
*/
|
||||
export function deserialize(data: Data): Array<Message> {
|
||||
const json = parse(data);
|
||||
|
||||
if (!Array.isArray(json) || json.length === 0 || json.length % 2 !== 0) {
|
||||
throw new Error('Invalid FeedMessage.Data');
|
||||
}
|
||||
|
||||
const messages = new Array<Message>(json.length / 2);
|
||||
|
||||
for (const index of messages.keys()) {
|
||||
const [action, payload] = json.slice(index * 2);
|
||||
|
||||
messages[index] = { action, payload } as Message;
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import { Milliseconds, Timestamp } from './types';
|
||||
|
||||
/**
|
||||
* PhantomData akin to Rust, because sometimes you need to be smarter than
|
||||
* the compiler.
|
||||
*/
|
||||
export abstract class PhantomData<P> {
|
||||
public __PHANTOM__: P;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opaque type, similar to `opaque type` in Flow, or new types in Rust/C.
|
||||
* These should be produced only by manually casting `t as Opaque<T, P>`.
|
||||
*
|
||||
* `P` can be anything as it's never actually used. Using strings is okay:
|
||||
*
|
||||
* ```
|
||||
* type MyType = Opaque<number, 'MyType'>;
|
||||
* ```
|
||||
*/
|
||||
export type Opaque<T, P> = T & PhantomData<P>;
|
||||
|
||||
/**
|
||||
* Just a readable shorthand for null-ish-able types, akin to `T?` in Flow.
|
||||
*/
|
||||
export type Maybe<T> = T | null | undefined;
|
||||
|
||||
/**
|
||||
* Asynchronous sleep
|
||||
*/
|
||||
export function sleep(time: Milliseconds): Promise<void> {
|
||||
return new Promise<void>((resolve, _reject) => {
|
||||
setTimeout(() => resolve(), time);
|
||||
});
|
||||
}
|
||||
|
||||
export const timestamp = Date.now as () => Timestamp;
|
||||
|
||||
export function noop() {}
|
||||
|
||||
/**
|
||||
* Keep track of last N numbers pushed onto internal stack.
|
||||
* Provides means to get an average of said numbers.
|
||||
*/
|
||||
export class NumStats<T extends number> {
|
||||
private readonly stack: Array<T>;
|
||||
private readonly history: number;
|
||||
private index = 0;
|
||||
|
||||
constructor(history: number) {
|
||||
if (history < 1) {
|
||||
throw new Error('Must track at least one number');
|
||||
}
|
||||
|
||||
this.history = history;
|
||||
this.stack = new Array(history);
|
||||
}
|
||||
|
||||
public push(val: T) {
|
||||
this.stack[this.index++ % this.history] = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get average value of all values on the stack.
|
||||
*
|
||||
* @return {T} average value
|
||||
*/
|
||||
public average(): T {
|
||||
if (this.index === 0) {
|
||||
return 0 as T;
|
||||
}
|
||||
|
||||
const list = this.nonEmpty();
|
||||
let sum = 0;
|
||||
|
||||
for (const n of list as Array<number>) {
|
||||
sum += n;
|
||||
}
|
||||
|
||||
return (sum / list.length) as T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get average value of all values of the stack after filtering
|
||||
* out a number of highest and lowest values
|
||||
*
|
||||
* @param {number} extremes number of high/low values to ignore
|
||||
* @return {T} average value
|
||||
*/
|
||||
public averageWithoutExtremes(extremes: number): T {
|
||||
if (this.index === 0) {
|
||||
return 0 as T;
|
||||
}
|
||||
|
||||
const list = this.nonEmpty();
|
||||
const count = list.length - extremes * 2;
|
||||
|
||||
if (count < 1) {
|
||||
// Not enough entries to remove desired number of extremes,
|
||||
// fall back to regular average
|
||||
return this.average();
|
||||
}
|
||||
|
||||
let sum = 0;
|
||||
|
||||
for (const n of list.sort((a, b) => a - b).slice(extremes, -extremes)) {
|
||||
sum += n;
|
||||
}
|
||||
|
||||
return (sum / count) as T;
|
||||
}
|
||||
|
||||
private nonEmpty(): Readonly<Array<number>> {
|
||||
return this.index < this.history
|
||||
? this.stack.slice(0, this.index)
|
||||
: this.stack;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Opaque } from './helpers';
|
||||
|
||||
/**
|
||||
* Unique type-constrained Id number.
|
||||
*/
|
||||
export type Id<T> = Opaque<number, T>;
|
||||
|
||||
/**
|
||||
* Higher order function producing new auto-incremented `Id`s.
|
||||
*/
|
||||
export function idGenerator<I extends Id<any>>(): () => I {
|
||||
let current = 0;
|
||||
|
||||
return () => current++ as I;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
export * from './helpers';
|
||||
export * from './id';
|
||||
export * from './stringify';
|
||||
export * from './SortedCollection';
|
||||
|
||||
import * as Types from './types';
|
||||
import * as FeedMessage from './feed';
|
||||
|
||||
export { Types, FeedMessage };
|
||||
|
||||
// Increment this if breaking changes were made to types in `feed.ts`
|
||||
export const VERSION: Types.FeedVersion = 29 as Types.FeedVersion;
|
||||
@@ -0,0 +1,84 @@
|
||||
export function* map<T, U>(
|
||||
iter: IterableIterator<T>,
|
||||
fn: (item: T) => U
|
||||
): IterableIterator<U> {
|
||||
for (const item of iter) {
|
||||
yield fn(item);
|
||||
}
|
||||
}
|
||||
|
||||
export function* chain<T>(
|
||||
a: IterableIterator<T>,
|
||||
b: IterableIterator<T>
|
||||
): IterableIterator<T> {
|
||||
yield* a;
|
||||
yield* b;
|
||||
}
|
||||
|
||||
export function* zip<T, U>(
|
||||
a: IterableIterator<T>,
|
||||
b: IterableIterator<U>
|
||||
): IterableIterator<[T, U]> {
|
||||
let itemA = a.next();
|
||||
let itemB = b.next();
|
||||
|
||||
while (!itemA.done && !itemB.done) {
|
||||
yield [itemA.value, itemB.value];
|
||||
|
||||
itemA = a.next();
|
||||
itemB = b.next();
|
||||
}
|
||||
}
|
||||
|
||||
export function* take<T>(
|
||||
iter: IterableIterator<T>,
|
||||
n: number
|
||||
): IterableIterator<T> {
|
||||
for (const item of iter) {
|
||||
if (n-- === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
yield item;
|
||||
}
|
||||
}
|
||||
|
||||
export function skip<T>(
|
||||
iter: IterableIterator<T>,
|
||||
n: number
|
||||
): IterableIterator<T> {
|
||||
while (n-- !== 0 && !iter.next().done) {}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
export function reduce<T, R>(
|
||||
iter: IterableIterator<T>,
|
||||
fn: (accu: R, item: T) => R,
|
||||
accumulator: R
|
||||
): R {
|
||||
for (const item of iter) {
|
||||
accumulator = fn(accumulator, item);
|
||||
}
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
export function join(
|
||||
iter: IterableIterator<{ toString: () => string }>,
|
||||
glue: string
|
||||
): string {
|
||||
const first = iter.next();
|
||||
|
||||
if (first.done) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let result = first.value.toString();
|
||||
|
||||
for (const item of iter) {
|
||||
result += glue + item;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
export abstract class Stringified<T> {
|
||||
public __PHANTOM__: T;
|
||||
}
|
||||
|
||||
export const parse = (JSON.parse as any) as <T>(val: Stringified<T>) => T;
|
||||
export const stringify = (JSON.stringify as any) as <T>(
|
||||
val: T
|
||||
) => Stringified<T>;
|
||||
@@ -0,0 +1,95 @@
|
||||
import { Opaque, Maybe } from './helpers';
|
||||
import { Id } from './id';
|
||||
|
||||
export type FeedVersion = Opaque<number, 'FeedVersion'>;
|
||||
export type ChainLabel = Opaque<string, 'ChainLabel'>;
|
||||
export type FeedId = Id<'Feed'>;
|
||||
export type NodeId = Id<'Node'>;
|
||||
export type NodeName = Opaque<string, 'NodeName'>;
|
||||
export type NodeImplementation = Opaque<string, 'NodeImplementation'>;
|
||||
export type NodeVersion = Opaque<string, 'NodeVersion'>;
|
||||
export type BlockNumber = Opaque<number, 'BlockNumber'>;
|
||||
export type BlockHash = Opaque<string, 'BlockHash'>;
|
||||
export type Address = Opaque<string, 'Address'>;
|
||||
export type Milliseconds = Opaque<number, 'Milliseconds'>;
|
||||
export type Timestamp = Opaque<Milliseconds, 'Timestamp'>;
|
||||
export type PropagationTime = Opaque<Milliseconds, 'PropagationTime'>;
|
||||
export type NodeCount = Opaque<number, 'NodeCount'>;
|
||||
export type PeerCount = Opaque<number, 'PeerCount'>;
|
||||
export type TransactionCount = Opaque<number, 'TransactionCount'>;
|
||||
export type Latitude = Opaque<number, 'Latitude'>;
|
||||
export type Longitude = Opaque<number, 'Longitude'>;
|
||||
export type City = Opaque<string, 'City'>;
|
||||
export type MemoryUse = Opaque<number, 'MemoryUse'>;
|
||||
export type CPUUse = Opaque<number, 'CPUUse'>;
|
||||
export type Bytes = Opaque<number, 'Bytes'>;
|
||||
export type BytesPerSecond = Opaque<number, 'BytesPerSecond'>;
|
||||
export type NetworkId = Opaque<string, 'NetworkId'>;
|
||||
export type NetworkState = Opaque<string | object, 'NetworkState'>;
|
||||
|
||||
export type BlockDetails = [
|
||||
BlockNumber,
|
||||
BlockHash,
|
||||
Milliseconds,
|
||||
Timestamp,
|
||||
Maybe<PropagationTime>
|
||||
];
|
||||
export type NodeDetails = [
|
||||
NodeName,
|
||||
NodeImplementation,
|
||||
NodeVersion,
|
||||
Maybe<Address>,
|
||||
Maybe<NetworkId>
|
||||
];
|
||||
export type NodeStats = [PeerCount, TransactionCount];
|
||||
export type NodeIO = [
|
||||
Array<Bytes>,
|
||||
Array<Bytes>,
|
||||
Array<BytesPerSecond>,
|
||||
Array<BytesPerSecond>
|
||||
];
|
||||
export type NodeHardware = [
|
||||
Array<MemoryUse>,
|
||||
Array<CPUUse>,
|
||||
Array<BytesPerSecond>,
|
||||
Array<BytesPerSecond>,
|
||||
Array<Timestamp>
|
||||
];
|
||||
export type NodeLocation = [Latitude, Longitude, City];
|
||||
|
||||
export interface Authority {
|
||||
Address: Address;
|
||||
NodeId: Maybe<NodeId>;
|
||||
Name: Maybe<NodeName>;
|
||||
}
|
||||
export declare type Authorities = Array<Address>;
|
||||
export declare type AuthoritySetId = Opaque<number, 'AuthoritySetId'>;
|
||||
export declare type AuthoritySetInfo = [
|
||||
AuthoritySetId,
|
||||
Authorities,
|
||||
Address,
|
||||
BlockNumber,
|
||||
BlockHash
|
||||
];
|
||||
export declare type ConsensusItem = [BlockNumber, ConsensusView];
|
||||
export declare type ConsensusInfo = Array<ConsensusItem>;
|
||||
export declare type ConsensusView = Map<Address, ConsensusState>;
|
||||
export declare type ConsensusState = Map<Address, ConsensusDetail>;
|
||||
export interface ConsensusDetail {
|
||||
Precommit: Precommit;
|
||||
ImplicitPrecommit: ImplicitPrecommit;
|
||||
Prevote: Prevote;
|
||||
ImplicitPrevote: ImplicitPrevote;
|
||||
ImplicitPointer: ImplicitPointer;
|
||||
Finalized: ImplicitFinalized;
|
||||
ImplicitFinalized: Finalized;
|
||||
FinalizedHash: BlockHash;
|
||||
FinalizedHeight: BlockNumber;
|
||||
}
|
||||
export declare type Precommit = Opaque<boolean, 'Precommit'>;
|
||||
export declare type Prevote = Opaque<boolean, 'Prevote'>;
|
||||
export declare type Finalized = Opaque<boolean, 'Finalized'>;
|
||||
export declare type ImplicitPrecommit = Opaque<boolean, 'ImplicitPrecommit'>;
|
||||
export declare type ImplicitPrevote = Opaque<boolean, 'ImplicitPrevote'>;
|
||||
export declare type ImplicitFinalized = Opaque<boolean, 'ImplicitFinalized'>;
|
||||
export declare type ImplicitPointer = Opaque<BlockNumber, 'ImplicitPointer'>;
|
||||
Reference in New Issue
Block a user