import { createSlice as t, createAction as e, createSelector as s } from "@reduxjs/toolkit"
import { prettyBytes as a } from "../lib/pretty-bytes"
import { DEFAULT_STATS_POLL_INTERVAL as o, CLICKS_TO_UNLOCK as n } from "./stats.constants"
export const STATS_STATE_KEY = "stats"
function d(t, e = 1) {
return `${(100 * t).toFixed(e)}%`
}
const c = (t) => ({
UIStore: {
Load: t.store?.load || "-",
A: `${t.store?.actions || "-"}/${t.store?.avgAction || "-"}ms`,
},
Rooms: { Active: t.activeRooms, Open: t.openRooms },
Cores: { Open: t.openCores, OpLogs: t.ops, Appends: t.appends },
Swarm: { Conns: t.connections },
Punches: {
Const: t.dht?.punches.consistent,
Rand: t.dht?.punches.random,
Open: t.dht?.punches.open,
},
Queries: { Active: t.dht?.queries?.active, Total: t.dht?.queries?.total },
Requests: {
Active: t.dht?.requests?.active,
Total: t.dht?.requests?.total,
Resp: t.dht?.requests?.responses,
Timeouts: t.dht?.requests?.timeouts,
Retries: t.dht?.requests?.retries,
},
Commands: {
"Ping tx/rx": `${t.dht?.commands?.ping?.tx ?? "-"}/${t.dht?.commands?.ping?.rx ?? "-"}`,
"PingNat tx/rx": `${t.dht?.commands?.pingNat?.tx ?? "-"}/${t.dht?.commands?.pingNat?.rx ?? "-"}`,
"FindNode tx/rx": `${t.dht?.commands?.findNode?.tx ?? "-"}/${t.dht?.commands?.findNode?.rx ?? "-"}`,
"DownHint tx/rx": `${t.dht?.commands?.downHint?.tx ?? "-"}/${t.dht?.commands?.downHint?.rx ?? "-"}`,
},
Relaying: {
Attempts: t.dht?.relaying?.attempts,
Successes: t.dht?.relaying?.successes,
Aborts: t.dht?.relaying?.aborts,
},
Uploads: { Blocks: t.uploaded, Bytes: a(t.bytesUploaded || 0) },
Downloads: { Blocks: t.downloaded, Bytes: a(t.bytesDownloaded || 0) },
}),
r = (t) => ({
CPU: { Perc: d(t.cpu?.percent || 0) },
Heap: { Used: a(t.memory?.heapUsed || 0), Total: a(t.memory?.heapTotal || 0) },
"Heap(Cr)": {
Used: a(t.chromium.memory?.heapUsed || 0),
Total: a(t.chromium.memory?.heapTotal || 0),
},
})
export const INITIAL_STATE = {
stats: {},
deviceStats: { cpu: null, memory: null, chromium: { memory: null } },
timeStats: { sendMsg: { latest: 0, average: 0, worse: 0, count: 0 }, items: [] },
enabled: !1,
unlocked: !1,
pollInterval: o,
clicksToUnlockToggle: n,
}
export const statsSlice = t({
name: "stats",
initialState: INITIAL_STATE,
reducers: {
enableStats: (t) => {
t.enabled = !0
},
disableStats: (t) => {
;((t.enabled = !1), (t.stats = {}))
},
unlockStats: (t, { payload: e = !0 }) => {
t.unlocked = e
},
unlockClick: (t) => {
t.clicksToUnlockToggle > 0 && (t.clicksToUnlockToggle -= 1)
},
setPollInterval: (t, { payload: { pollInterval: e } }) => {
t.pollInterval = e
},
setStatsData: (t, { payload: e }) => {
const { data: s, cpu: a, memory: o, chromium: n, store: d } = e
;((t.deviceStats.cpu = a),
(t.deviceStats.memory = o),
n && (t.deviceStats.chromium.memory = n.memory),
(t.stats = {
...s,
swarm: {
updates: s?.swarm?.updates,
connects: {
client: {
opened: s?.swarm?.connects.client.opened,
closed: s?.swarm?.connects.client.closed,
attempted: s?.swarm?.connects.client.attempted,
},
server: {
opened: s?.swarm?.connects.server.opened,
closed: s?.swarm?.connects.server.closed,
},
},
},
dht: {
punches: {
consistent: s?.dht?.punches?.consistent,
random: s?.dht?.punches?.random,
open: s?.dht?.punches?.open,
},
queries: { active: s?.dht?.queries?.active, total: s?.dht?.queries?.total },
requests: {
active: s?.dht?.requests?.active,
total: s?.dht?.requests?.total,
responses: s?.dht?.requests?.responses,
timeouts: s?.dht?.requests?.timeouts,
retries: s?.dht?.requests?.retries,
},
commands: {
ping: s?.dht?.commands?.ping,
pingNat: s?.dht?.commands?.pingNat,
findNode: s?.dht?.commands?.findNode,
downHint: s?.dht?.commands?.downHint,
},
relaying: {
attempts: s?.dht?.relaying?.attempts,
successes: s?.dht?.relaying?.successes,
aborts: s?.dht?.relaying?.aborts,
},
},
store: d,
}))
},
setTimeStatsData: (t, { payload: e }) => {
Array.isArray(e) && (t.timeStats.items = e)
},
setTimeStatsSendMsg: (t, { payload: e }) => {
if (!Number.isInteger(e)) return
const { average: s, count: a, worse: o } = t.timeStats.sendMsg,
n = a + 1
;((t.timeStats.sendMsg.latest = e),
(t.timeStats.sendMsg.average = Math.floor((s * a + e) / n)),
(t.timeStats.sendMsg.count = n),
(t.timeStats.sendMsg.worse = o < e ? e : o))
},
clearTimeStatsAll: (t) => {
t.timeStats = INITIAL_STATE.timeStats
},
clearTimeStatsSendMsg: (t) => {
t.timeStats.sendMsg = INITIAL_STATE.timeStats.sendMsg
},
},
})
const l = (t) => t.stats
export const getStats = s(l, ({ stats: t }) => c(t))
export const getDeviceStats = s(l, ({ deviceStats: t }) => r(t))
export const getStatsRaw = (t) => l(t).stats
export const getStatsDhtRequests = (t) => getStatsRaw(t)?.dht?.requests
export const getStatsUnlocked = (t) => l(t).unlocked
export const getStatsEnabled = (t) => l(t).enabled
export const getStatsPollInterval = (t) => l(t).pollInterval
export const getClicksToUnlockToggle = (t) => l(t).clicksToUnlockToggle
export const getStatsTimeItems = (t) => l(t).timeStats.items
export const getStatsTimeSendMsg = (t) => l(t).timeStats.sendMsg
export const {
unlockStats: unlockStats,
enableStats: enableStats,
disableStats: disableStats,
unlockClick: unlockClick,
setPollInterval: setPollInterval,
setStatsData: setStatsData,
setTimeStatsData: setTimeStatsData,
setTimeStatsSendMsg: setTimeStatsSendMsg,
clearTimeStatsAll: clearTimeStatsAll,
clearTimeStatsSendMsg: clearTimeStatsSendMsg,
} = statsSlice.actions
export const toggleStats = e("stats/toggle-stats")
export const loadTimeStatsDataCmd = e("stats/load-time-stats-data-cmd")