113 lines
2.7 KiB
TypeScript
113 lines
2.7 KiB
TypeScript
import { betterCompact } from "../../util";
|
|
|
|
interface Pending {
|
|
kind: "pending";
|
|
start: number;
|
|
}
|
|
|
|
interface Timeout {
|
|
kind: "timeout";
|
|
start: number;
|
|
end: number;
|
|
}
|
|
|
|
interface Complete {
|
|
kind: "complete";
|
|
start: number;
|
|
end: number;
|
|
}
|
|
|
|
export type Ping = Complete | Pending | Timeout;
|
|
export type PingDictionary = Record<string, Ping | undefined>;
|
|
|
|
export const now = () => (new Date()).getTime();
|
|
|
|
export const startPing =
|
|
(s: PingDictionary, id: string, start = now()): PingDictionary => {
|
|
return { ...s, [id]: { kind: "pending", start } };
|
|
};
|
|
|
|
export const failPing =
|
|
(s: PingDictionary, id: string, end = now()): PingDictionary => {
|
|
const failure = s[id];
|
|
if (failure && failure.kind != "complete") {
|
|
const nextFailure: Timeout = {
|
|
kind: "timeout",
|
|
start: failure.start,
|
|
end
|
|
};
|
|
return { ...s, [id]: nextFailure };
|
|
}
|
|
|
|
return s;
|
|
};
|
|
|
|
export const completePing =
|
|
(s: PingDictionary, id: string, end = now()): PingDictionary => {
|
|
const failure = s[id];
|
|
if (failure && failure.kind == "pending") {
|
|
return {
|
|
...s,
|
|
[id]: {
|
|
kind: "complete",
|
|
start: failure.start,
|
|
end
|
|
}
|
|
};
|
|
}
|
|
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;
|
|
}
|
|
|
|
const mapper = (p: Ping) => (p.kind === "complete") ?
|
|
p.end - p.start : undefined;
|
|
|
|
export const calculateLatency =
|
|
(s: PingDictionary): LatencyReport => {
|
|
let latency: number[] =
|
|
betterCompact(getAll(s).map(mapper));
|
|
// Prevents "Infinity" from showing up in UI
|
|
// when the app is loading or the bot is 100%
|
|
// offline:
|
|
if (latency.length == 0) { latency = [0]; }
|
|
const average = Math.round(latency.reduce((a, b) => a + b, 0) / latency.length);
|
|
|
|
const report = {
|
|
best: Math.min(...latency),
|
|
worst: Math.max(...latency),
|
|
average,
|
|
total: latency.length
|
|
};
|
|
|
|
/** SIDE EFFECT WARNING: We do analytics on every nth ping to gauge
|
|
* overall system health. This is the least invasive place to put it. */
|
|
const doReport = !!report.total && !(report.total % 100);
|
|
doReport && window.logStore.log("FBOS Ping QoS Message", report, "info");
|
|
return report;
|
|
};
|