wangzhibo
2023-10-31 9da39812105bfc387db3b3b7c4896983e03d247d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import { makeTimer } from '@solid-primitives/timer'
import type { ApexOptions } from 'apexcharts'
import byteSize from 'byte-size'
import { merge } from 'lodash'
import { SolidApexCharts } from 'solid-apexcharts'
import {
  JSX,
  ParentComponent,
  batch,
  children,
  createEffect,
  createMemo,
  createSignal,
} from 'solid-js'
import { CHART_MAX_XAXIS, DEFAULT_CHART_OPTIONS } from '~/constants'
import { useI18n } from '~/i18n'
import { latestConnectionMsg, useWsRequest } from '~/signals'
 
const TrafficWidget: ParentComponent<{ label: JSX.Element }> = (props) => (
  <div class="stat flex-1 place-items-center">
    <div class="stat-title text-primary-content">{props.label}</div>
    <div class="stat-value text-2xl text-primary-content lg:text-3xl">
      {children(() => props.children)()}
    </div>
  </div>
)
 
export default () => {
  const [t] = useI18n()
 
  const [traffics, setTraffics] = createSignal<{ down: number; up: number }[]>(
    [],
  )
  const [memories, setMemories] = createSignal<number[]>([])
 
  // https://github.com/apexcharts/apexcharts.js/blob/main/samples/source/line/realtime.xml
  // TODO: needs a better way
  makeTimer(
    () => {
      batch(() => {
        setTraffics((traffics) => traffics.slice(-CHART_MAX_XAXIS))
        setMemories((memo) => memo.slice(-CHART_MAX_XAXIS))
      })
    },
    // we shrink the chart data array size down every minute to prevent memory leaks
    60 * 1000,
    setInterval,
  )
 
  const traffic = useWsRequest<{ down: number; up: number }>('traffic')
 
  createEffect(() => {
    const t = traffic()
 
    if (t) setTraffics((traffics) => [...traffics, t])
  })
 
  const trafficChartOptions = createMemo<ApexOptions>(() =>
    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 memory = useWsRequest<{ inuse: number }>('memory')
 
  createEffect(() => {
    const m = memory()?.inuse
 
    if (m) setMemories((memories) => [...memories, m])
  })
 
  const memoryChartOptions = createMemo<ApexOptions>(() =>
    merge({ title: { text: t('memory') } }, DEFAULT_CHART_OPTIONS),
  )
 
  const memoryChartSeries = createMemo(() => [
    { name: t('memory'), data: memories() },
  ])
 
  return (
    <div class="flex flex-col gap-2">
      <div class="stats stats-vertical w-full grid-cols-2 bg-primary shadow lg:stats-horizontal lg:flex">
        <TrafficWidget label={t('upload')}>
          {byteSize(traffic()?.up || 0).toString()}/s
        </TrafficWidget>
 
        <TrafficWidget label={t('download')}>
          {byteSize(traffic()?.down || 0).toString()}/s
        </TrafficWidget>
 
        <TrafficWidget label={t('uploadTotal')}>
          {byteSize(latestConnectionMsg()?.uploadTotal || 0).toString()}
        </TrafficWidget>
 
        <TrafficWidget label={t('downloadTotal')}>
          {byteSize(latestConnectionMsg()?.downloadTotal || 0).toString()}
        </TrafficWidget>
 
        <TrafficWidget label={t('activeConnections')}>
          {latestConnectionMsg()?.connections?.length || 0}
        </TrafficWidget>
 
        <TrafficWidget label={t('memoryUsage')}>
          {byteSize(memory()?.inuse || 0).toString()}
        </TrafficWidget>
      </div>
 
      <div class="rounded-box flex flex-col gap-2 bg-base-300 py-4 lg:flex-row">
        <div class="flex-1">
          <SolidApexCharts
            type="area"
            options={trafficChartOptions()}
            series={trafficChartSeries()}
          />
        </div>
        <div class="flex-1">
          <SolidApexCharts
            type="line"
            options={memoryChartOptions()}
            series={memoryChartSeries()}
          />
        </div>
      </div>
    </div>
  )
}