import { createEventSignal } from '@solid-primitives/event-listener'
import { useI18n } from '@solid-primitives/i18n'
import { makeTimer } from '@solid-primitives/timer'
import { createReconnectingWS } from '@solid-primitives/websocket'
import type { ApexOptions } from 'apexcharts'
import byteSize from 'byte-size'
import { merge } from 'lodash'
import { SolidApexCharts } from 'solid-apexcharts'
import {
JSX,
ParentComponent,
children,
createEffect,
createMemo,
createSignal,
} from 'solid-js'
import { CHART_MAX_XAXIS, DEFAULT_CHART_OPTIONS } from '~/constants'
import { secret, wsEndpointURL } from '~/signals'
import type { Connection } from '~/types'
const TrafficWidget: ParentComponent<{ label: JSX.Element }> = (props) => (
{props.label}
{children(() => props.children)()}
)
export default () => {
const [t] = useI18n()
const [traffics, setTraffics] = createSignal<{ down: number; up: number }[]>(
[],
)
const [memories, setMemories] = createSignal([])
// https://github.com/apexcharts/apexcharts.js/blob/main/samples/source/line/realtime.xml
// TODO: needs a better way
makeTimer(
() => {
setTraffics((traffics) => traffics.slice(-CHART_MAX_XAXIS))
setMemories((memo) => memo.slice(-CHART_MAX_XAXIS))
},
// we shrink the chart data array size down every 10 minutes to prevent memory leaks
10 * 60 * 1000,
setInterval,
)
const trafficWS = createReconnectingWS(
`${wsEndpointURL()}/traffic?token=${secret()}`,
)
const trafficWSMessageEvent = createEventSignal(trafficWS, 'message')
const traffic = () => {
const data = trafficWSMessageEvent()?.data
return data ? (JSON.parse(data) as { down: number; up: number }) : null
}
createEffect(() => {
const t = traffic()
if (t) setTraffics((traffics) => [...traffics, t])
})
const trafficChartOptions = createMemo(() =>
merge({ title: { text: t('traffic') } }, DEFAULT_CHART_OPTIONS),
)
const trafficChartSeries = createMemo(() => [
{
name: t('down'),
data: traffics().map((t) => t.down),
},
{
name: t('up'),
data: traffics().map((t) => t.up),
},
])
const memoryWS = createReconnectingWS(
`${wsEndpointURL()}/memory?token=${secret()}`,
)
const memoryWSMessageEvent = createEventSignal(memoryWS, 'message')
const memory = () => {
const data = memoryWSMessageEvent()?.data
return data ? (JSON.parse(data) as { inuse: number }).inuse : null
}
createEffect(() => {
const m = memory()
if (m) setMemories((memories) => [...memories, m])
})
const memoryChartOptions = createMemo(() =>
merge({ title: { text: t('memory') } }, DEFAULT_CHART_OPTIONS),
)
const memoryChartSeries = createMemo(() => [{ data: memories() }])
const connectionsWS = createReconnectingWS(
`${wsEndpointURL()}/connections?token=${secret()}`,
)
const connectionsWSMessageEvent = createEventSignal<{
message: WebSocketEventMap['message']
}>(connectionsWS, 'message')
const connection = () => {
const data = connectionsWSMessageEvent()?.data
return data
? (JSON.parse(data) as {
downloadTotal: number
uploadTotal: number
connections: Connection[]
})
: null
}
return (
{byteSize(traffic()?.up || 0).toString()}/s
{byteSize(traffic()?.down || 0).toString()}/s
{byteSize(connection()?.uploadTotal || 0).toString()}
{byteSize(connection()?.downloadTotal || 0).toString()}
{connection()?.connections.length || 0}
{byteSize(memory() || 0).toString()}
)
}