envio
Version:
A latency and sync speed optimized, developer friendly blockchain data indexer.
246 lines (229 loc) • 6.66 kB
JavaScript
// Generated by ReScript, PLEASE EDIT WITH CARE
import * as Ink from "ink";
import * as React from "react";
import * as DateFns from "date-fns";
import InkSpinner from "ink-spinner";
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
import * as Primitive_float from "@rescript/runtime/lib/es6/Primitive_float.js";
import * as JsxRuntime from "react/jsx-runtime";
function isIndexerFullySynced(chains) {
return Stdlib_Array.reduce(chains, true, (accum, current) => {
let match = current.progress;
if (typeof match !== "object" || match.TAG === "Syncing") {
return false;
} else {
return accum;
}
});
}
function getTotalRemainingBlocks(chains) {
return Stdlib_Array.reduce(chains, 0, (accum, param) => {
let progress = param.progress;
let endBlock = param.endBlock;
let finalBlock = endBlock !== undefined ? endBlock : param.knownHeight;
if (typeof progress !== "object") {
return (finalBlock - param.latestFetchedBlockNumber | 0) + accum | 0;
}
progress.TAG === "Syncing";
return (finalBlock - progress._0.latestProcessedBlock | 0) + accum | 0;
});
}
function getLatestTimeCaughtUpToHead(chains, indexerStartTime) {
let latesttimestampCaughtUpToHeadOrEndblockFloat = Stdlib_Array.reduce(chains, 0.0, (accum, current) => {
let match = current.progress;
if (typeof match !== "object") {
return accum;
}
if (match.TAG === "Syncing") {
return accum;
}
let timestampCaughtUpToHeadOrEndblock = match._0.timestampCaughtUpToHeadOrEndblock;
if (timestampCaughtUpToHeadOrEndblock.getTime() > accum) {
return timestampCaughtUpToHeadOrEndblock.getTime();
} else {
return accum;
}
});
return DateFns.formatDistance(indexerStartTime, new Date(latesttimestampCaughtUpToHeadOrEndblockFloat), {
includeSeconds: true
});
}
function getTotalBlocksProcessed(chains) {
return Stdlib_Array.reduce(chains, 0, (accum, param) => {
let progress = param.progress;
if (typeof progress !== "object") {
return param.latestFetchedBlockNumber + accum | 0;
}
progress.TAG === "Syncing";
let match = progress._0;
return (match.latestProcessedBlock - match.firstEventBlockNumber | 0) + accum | 0;
});
}
function useShouldDisplayEta(chains) {
let match = React.useState(() => false);
let setShouldDisplayEta = match[1];
let shouldDisplayEta = match[0];
React.useEffect(() => {
if (!shouldDisplayEta) {
let allChainsStartedFetching = chains.every(chain => {
if (chain.knownHeight > 0) {
return chain.latestFetchedBlockNumber > 0;
} else {
return false;
}
});
if (allChainsStartedFetching) {
setShouldDisplayEta(param => true);
}
}
}, [chains]);
return shouldDisplayEta;
}
function useEta(chains, indexerStartTime) {
let shouldDisplayEta = useShouldDisplayEta(chains);
let match = React.useState(() => 0);
let setSecondsToSub = match[1];
let match$1 = React.useState(() => 0);
let setTimeSinceStart = match$1[1];
React.useEffect(() => {
setTimeSinceStart(param => Date.now() - indexerStartTime.getTime());
setSecondsToSub(param => 0);
let intervalId = setInterval(() => setSecondsToSub(prev => prev + 1), 1000);
return () => {
clearInterval(intervalId);
};
}, [
chains,
indexerStartTime
]);
let blocksProcessed = getTotalBlocksProcessed(chains);
if (!(shouldDisplayEta && blocksProcessed > 0)) {
return;
}
let nowDate = Date.now();
let remainingBlocks = getTotalRemainingBlocks(chains);
let etaFloat = match$1[0] / blocksProcessed * remainingBlocks;
let millisToSub = match[0] * 1000;
let etaFloat$1 = Primitive_float.max(etaFloat - millisToSub, 0.0);
let eta = new Date(etaFloat$1 + nowDate);
let interval_start = new Date(nowDate);
let interval = {
start: interval_start,
end: eta
};
let duration = DateFns.intervalToDuration(interval);
let formattedDuration = DateFns.formatDuration(duration, {
format: [
"hours",
"minutes",
"seconds"
]
});
let tmp = formattedDuration === "" ? "less than 1 second" : formattedDuration;
return tmp;
}
function SyncETA$Syncing(props) {
return JsxRuntime.jsxs(Ink.Text, {
children: [
JsxRuntime.jsx(Ink.Text, {
children: "Sync Time ETA: "
}),
JsxRuntime.jsx(Ink.Text, {
children: props.etaStr
}),
JsxRuntime.jsx(Ink.Text, {
children: " ("
}),
JsxRuntime.jsx(Ink.Text, {
children: JsxRuntime.jsx(InkSpinner, {}),
color: "#9860E5"
}),
JsxRuntime.jsx(Ink.Text, {
children: " in progress",
color: "#FFBB2F"
}),
JsxRuntime.jsx(Ink.Text, {
children: ")"
})
],
bold: true
});
}
let Syncing = {
make: SyncETA$Syncing
};
function SyncETA$Synced(props) {
return JsxRuntime.jsxs(Ink.Text, {
children: [
JsxRuntime.jsx(Ink.Text, {
children: "Time Synced: "
}),
JsxRuntime.jsx(Ink.Text, {
children: props.latestTimeCaughtUpToHeadStr
}),
JsxRuntime.jsx(Ink.Text, {
children: " ("
}),
JsxRuntime.jsx(Ink.Text, {
children: "synced",
color: "#3B8C3D"
}),
JsxRuntime.jsx(Ink.Text, {
children: ")"
})
],
bold: true
});
}
let Synced = {
make: SyncETA$Synced
};
function SyncETA$Calculating(props) {
return JsxRuntime.jsxs(Ink.Text, {
children: [
JsxRuntime.jsx(Ink.Text, {
children: JsxRuntime.jsx(InkSpinner, {}),
color: "#9860E5"
}),
JsxRuntime.jsx(Ink.Text, {
children: " Calculating ETA...",
bold: true
})
]
});
}
let Calculating = {
make: SyncETA$Calculating
};
function SyncETA(props) {
let indexerStartTime = props.indexerStartTime;
let chains = props.chains;
let optEta = useEta(chains, indexerStartTime);
if (!isIndexerFullySynced(chains)) {
if (optEta !== undefined) {
return JsxRuntime.jsx(SyncETA$Syncing, {
etaStr: optEta
});
} else {
return JsxRuntime.jsx(SyncETA$Calculating, {});
}
}
let latestTimeCaughtUpToHeadStr = getLatestTimeCaughtUpToHead(chains, indexerStartTime);
return JsxRuntime.jsx(SyncETA$Synced, {
latestTimeCaughtUpToHeadStr: latestTimeCaughtUpToHeadStr
});
}
let make = SyncETA;
export {
isIndexerFullySynced,
getTotalRemainingBlocks,
getLatestTimeCaughtUpToHead,
getTotalBlocksProcessed,
useShouldDisplayEta,
useEta,
Syncing,
Synced,
Calculating,
make,
}
/* ink Not a pure module */