git ssb

16+

Dominic / patchbay



Tree: 169d5e007b1d1a1621fc112ff9c695e6bb25ef6f

Files: 169d5e007b1d1a1621fc112ff9c695e6bb25ef6f / app / page / network / replication-in.js

5067 bytesRaw
1const { h, Value, Dict, onceTrue, computed, watch, watchAll, throttle } = require('mutant')
2const Chart = require('chart.js')
3const pull = require('pull-stream')
4
5const MINUTE = 60 * 1000
6const DAY = 24 * 60 * MINUTE
7
8const GRAPH_Y_MIN_STEP = 50
9const GRAPH_Y_MIN = 100
10
11module.exports = function ReplicationIn ({ connection }) {
12 const minsPerStep = 10
13 const scale = 1 * DAY
14 const height = 300
15 const width = 800
16
17 const state = buildState({ connection, minsPerStep, scale })
18 const canvas = h('canvas', { height, width, style: { height: `${height}px`, width: `${width}px` } })
19
20 const body = h('ReplicationIn', [
21 h('p', `Messages received per ${minsPerStep}-minute block over the last ${scale / DAY} days`),
22 canvas
23 ])
24 // TODO hook to abort streams
25
26 initialiseChart({ state, canvas })
27
28 return {
29 title: 'Incoming Traffic',
30 body
31 }
32}
33
34function buildState ({ connection, minsPerStep, scale }) {
35 // build data, range
36 const data = Dict({
37 [toTimeBlock(Date.now(), minsPerStep) + minsPerStep * MINUTE]: 0,
38 [toTimeBlock(Date.now(), minsPerStep) + minsPerStep * MINUTE - scale]: 0
39 })
40 onceTrue(connection, server => {
41 getData({ data, server, minsPerStep, scale })
42 })
43
44 const latest = Value(toTimeBlock(Date.now(), minsPerStep))
45 // start of the most recent bar
46 setInterval(() => {
47 latest.set(toTimeBlock(Date.now(), minsPerStep))
48 }, minsPerStep / 4 * MINUTE)
49
50 const range = computed([latest], (latest) => {
51 return {
52 upper: latest + minsPerStep * MINUTE,
53 lower: latest + minsPerStep * MINUTE - scale
54 }
55 })
56
57 return {
58 data, // TODO rename this !!
59 range
60 }
61}
62
63function getData ({ data, server, minsPerStep, scale }) {
64 const upperEnd = toTimeBlock(Date.now(), minsPerStep) + minsPerStep * MINUTE
65 const lowerBound = upperEnd - scale
66
67 const query = [
68 {
69 $filter: {
70 timestamp: { $gte: lowerBound }
71 }
72 }, {
73 $filter: {
74 value: {
75 author: { $ne: server.id }
76 }
77 }
78 }, {
79 $map: {
80 ts: ['timestamp']
81 }
82 }
83 ]
84
85 pull(
86 server.query.read({ query, live: true }),
87 pull.filter(m => !m.sync),
88 pull.map(m => toTimeBlock(m.ts, minsPerStep)),
89 pull.drain(ts => {
90 if (data.has(ts)) data.put(ts, data.get(ts) + 1)
91 else data.put(ts, 1)
92 })
93 )
94}
95
96function toTimeBlock (ts, minsPerStep) {
97 return Math.floor(ts / (minsPerStep * MINUTE)) * (minsPerStep * MINUTE)
98}
99
100function initialiseChart ({ canvas, state: { data, range } }) {
101 var chart = new Chart(canvas.getContext('2d'), chartConfig(range))
102
103 watch(range, ({ lower, upper }) => {
104 // set horizontal scale
105 chart.options.scales.xAxes[0].time.min = lower
106 chart.options.scales.xAxes[0].time.max = upper
107 chart.update()
108 })
109
110 watchAll([throttle(data, 300), range], (data, { lower, upper }) => {
111 const _data = Object.keys(data)
112 .sort((a, b) => a < b ? -1 : +1)
113 .map(ts => {
114 return {
115 t: Number(ts), // NOTE - might need to offset by a half-step ?
116 y: data[ts]
117 }
118 })
119
120 // update chard data
121 chart.data.datasets[0].data = _data
122
123 // scales the height of the graph (to the visible data)!
124 const slice = _data
125 .filter(d => d.t >= lower && d.t < upper)
126 .map(d => d.y)
127 .sort((a, b) => a > b ? -1 : +1)
128
129 var max = slice[0]
130 var stepSize = GRAPH_Y_MIN_STEP
131 if (!max || max < GRAPH_Y_MIN) max = GRAPH_Y_MIN // min-height
132 else {
133 while ((max / stepSize) > 7) stepSize = stepSize * 2
134 max = Math.ceil(max / stepSize) * stepSize // round height to multiples of stepSize
135 // max = max + (stepSize - max % stepSize)
136 }
137
138 chart.options.scales.yAxes[0].ticks.max = max
139 chart.options.scales.yAxes[0].ticks.stepSize = stepSize // not sure this works
140
141 chart.update()
142 })
143}
144
145function chartConfig ({ lower, upper }) {
146 const barColor = 'hsla(215, 57%, 60%, 1)'
147
148 return {
149 type: 'bar',
150 data: {
151 datasets: [{
152 backgroundColor: barColor,
153 borderColor: barColor,
154 data: []
155 }]
156 },
157 options: {
158 legend: {
159 display: false
160 },
161 scales: {
162 xAxes: [{
163 type: 'time',
164 distribution: 'linear',
165 time: {
166 // unit: 'day',
167 // min: lower,
168 // max: upper,
169 // tooltipFormat: 'MMMM D',
170 // stepSize: 7
171 unit: 'minute',
172 min: lower,
173 max: upper,
174 tooltipFormat: 'HH:mm',
175 stepSize: 4 * 60
176 // stepSize: 240
177 },
178 bounds: 'ticks',
179 ticks: {
180 // maxTicksLimit: 4 // already disabled
181 },
182 gridLines: {
183 display: false
184 },
185 maxBarThickness: 4
186 }],
187
188 yAxes: [{
189 ticks: {
190 min: 0,
191 maxTicksLimit: 7,
192 stepSize: GRAPH_Y_MIN_STEP,
193 suggestedMax: GRAPH_Y_MIN
194 }
195 }]
196 },
197 animation: {
198 // duration: 300
199 }
200 }
201 }
202}
203

Built with git-ssb-web