2019-09-05 12:54:17 -06:00
|
|
|
import { betterCompact } from "../../util";
|
|
|
|
|
|
|
|
interface Pending {
|
|
|
|
kind: "pending";
|
|
|
|
id: string;
|
2019-09-05 15:44:12 -06:00
|
|
|
start: number;
|
|
|
|
end?: number;
|
2019-09-05 12:54:17 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
interface Timeout {
|
|
|
|
kind: "timeout";
|
|
|
|
id: string;
|
2019-09-05 15:44:12 -06:00
|
|
|
start: number;
|
|
|
|
end?: number;
|
2019-09-05 12:54:17 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
interface Complete {
|
|
|
|
kind: "complete";
|
|
|
|
id: string;
|
2019-09-05 15:44:12 -06:00
|
|
|
start: number;
|
|
|
|
end: number;
|
2019-09-05 12:54:17 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
export type Ping = Complete | Pending | Timeout;
|
|
|
|
export type PingDictionary = Record<string, Ping | undefined>;
|
|
|
|
|
2019-09-05 16:27:42 -06:00
|
|
|
export const now = () => (new Date()).getTime();
|
2019-09-05 15:44:12 -06:00
|
|
|
|
2019-09-05 12:54:17 -06:00
|
|
|
export const startPing =
|
2019-09-05 15:44:12 -06:00
|
|
|
(s: PingDictionary, id: string, start = now()): PingDictionary => {
|
|
|
|
return { ...s, [id]: { kind: "pending", id, start } };
|
2019-09-05 12:54:17 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
export const failPing =
|
|
|
|
(s: PingDictionary, id: string): PingDictionary => {
|
|
|
|
const failure = s[id];
|
|
|
|
if (failure && failure.kind != "complete") {
|
|
|
|
const nextFailure: Timeout = {
|
|
|
|
kind: "timeout",
|
|
|
|
id,
|
|
|
|
start: failure.start
|
|
|
|
};
|
|
|
|
return { ...s, [id]: nextFailure };
|
|
|
|
}
|
|
|
|
|
|
|
|
return s;
|
|
|
|
};
|
|
|
|
|
|
|
|
export const completePing =
|
2019-09-05 15:44:12 -06:00
|
|
|
(s: PingDictionary, id: string, end = now()): PingDictionary => {
|
2019-09-05 12:54:17 -06:00
|
|
|
const failure = s[id];
|
|
|
|
if (failure && failure.kind == "pending") {
|
|
|
|
return {
|
|
|
|
...s,
|
|
|
|
[id]: {
|
|
|
|
kind: "complete",
|
|
|
|
id,
|
|
|
|
start: failure.start,
|
2019-09-05 15:44:12 -06:00
|
|
|
end
|
2019-09-05 12:54:17 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
};
|
|
|
|
|
|
|
|
type PingLossReport = Record<Ping["kind"] | "total", number>;
|
|
|
|
|
|
|
|
const getAll = (s: PingDictionary) => betterCompact(Object.values(s));
|
|
|
|
|
|
|
|
export const calculatePingLoss = (s: PingDictionary): PingLossReport => {
|
|
|
|
const all = getAll(s);
|
|
|
|
const report: PingLossReport = {
|
|
|
|
complete: 0,
|
|
|
|
pending: 0,
|
|
|
|
timeout: 0,
|
|
|
|
total: 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
all.map(p => report[p.kind] += 1);
|
|
|
|
report.total = all.length;
|
|
|
|
|
|
|
|
return report;
|
|
|
|
};
|
|
|
|
|
|
|
|
interface LatencyReport {
|
|
|
|
best: number;
|
|
|
|
worst: number;
|
|
|
|
average: number;
|
|
|
|
total: number;
|
|
|
|
}
|
|
|
|
|
2019-09-05 15:44:12 -06:00
|
|
|
const mapper = (p: Ping) => (p.kind === "complete") ?
|
|
|
|
p.end - p.start : undefined;
|
2019-09-05 12:54:17 -06:00
|
|
|
|
|
|
|
export const calculateLatency =
|
|
|
|
(s: PingDictionary): LatencyReport => {
|
|
|
|
const latency: number[] =
|
|
|
|
betterCompact(getAll(s).map(mapper));
|
|
|
|
|
|
|
|
return {
|
|
|
|
best: Math.min(...latency) || 0,
|
|
|
|
worst: Math.max(...latency) || 0,
|
|
|
|
average: latency.reduce((a, b) => a + b, 0) / latency.length,
|
|
|
|
total: latency.length
|
|
|
|
};
|
|
|
|
};
|