UNPKG

envio

Version:

A latency and sync speed optimized, developer friendly blockchain data indexer.

246 lines (229 loc) • 6.66 kB
// 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 */