websocket-text-relay 1.1.4 → 1.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/changelog.md +4 -0
  2. package/docs/code-structure.md +15 -11
  3. package/eslint.config.js +5 -1
  4. package/package.json +9 -9
  5. package/src/ui/css/main.css +22 -78
  6. package/src/ui/favicon.png +0 -0
  7. package/src/ui/index.html +19 -14
  8. package/src/ui/js/components/activityLabels.js +41 -0
  9. package/src/ui/js/components/activityTimeSeries.js +58 -0
  10. package/src/ui/js/components/drawSessionLabel.js +117 -0
  11. package/src/ui/js/components/footerStatus.js +37 -0
  12. package/src/ui/js/components/headers.js +100 -0
  13. package/src/ui/js/components/sessionWedges.js +96 -0
  14. package/src/ui/js/components/statusRing.js +51 -0
  15. package/src/ui/js/data/wtrActivity.js +85 -0
  16. package/src/ui/js/data/wtrActivity.types.js +3 -0
  17. package/src/ui/js/data/wtrStatus.js +134 -0
  18. package/src/ui/js/data/wtrStatus.types.js +61 -0
  19. package/src/ui/js/{util → setup}/EventEmitter.js +5 -1
  20. package/src/ui/js/{util → setup}/WebsocketClient.js +1 -4
  21. package/src/ui/js/setup/dependencyManager.js +9 -0
  22. package/src/ui/js/setup/evalOnChange.js +18 -0
  23. package/src/ui/js/setup/eventSubscriber.js +21 -0
  24. package/src/ui/js/setup.js +141 -0
  25. package/src/ui/js/util/constants.js +5 -1
  26. package/src/ui/js/util/drawing.js +26 -76
  27. package/src/websocket-interface/httpServer.js +1 -1
  28. package/src/ui/js/components/ActivityTimeseriesGraph.js +0 -194
  29. package/src/ui/js/components/HeaderSummary.js +0 -22
  30. package/src/ui/js/components/ServerStatus.js +0 -43
  31. package/src/ui/js/components/SessionLabels.js +0 -319
  32. package/src/ui/js/components/SessionWedges.js +0 -127
  33. package/src/ui/js/components/StatusRing.js +0 -54
  34. package/src/ui/js/components/grids.js +0 -36
  35. package/src/ui/js/index.js +0 -121
  36. package/src/ui/js/main.js +0 -128
  37. package/src/ui/js/util/DependencyManager.js +0 -31
@@ -1,4 +1,6 @@
1
- const { exportDeps } = window.__WTR__
1
+ const { exportDeps, evalOnChange } = window.__WTR__
2
+
3
+ evalOnChange(["js/components/statusRing.js", "js/components/sessionWedges.js"])
2
4
 
3
5
  const TWO_PI = 2 * Math.PI
4
6
  const MAX_ANGLE_DELTA = 0.99999
@@ -27,32 +29,23 @@ const drawSvgElement = ({ tag, attributes = {}, className, parent }) => {
27
29
  return element
28
30
  }
29
31
 
30
- const drawText = ({ x, y, text, dominantBaseline, textAnchor, className, parentNode: parent }) => {
32
+ const drawText = ({ x, y, text, attributes = {}, dominantBaseline, textAnchor, className, parent }) => {
31
33
  const textElement = drawSvgElement({
32
34
  tag: "text",
33
- attributes: { x, y, "dominant-baseline": dominantBaseline, "text-anchor": textAnchor },
35
+ attributes: { ...attributes, x, y },
34
36
  className,
35
37
  parent,
36
38
  })
37
39
  textElement.textContent = text
40
+ if (textAnchor) {
41
+ textElement.style["text-anchor"] = textAnchor
42
+ }
43
+ if (dominantBaseline) {
44
+ textElement.style["dominant-baseline"] = dominantBaseline
45
+ }
38
46
  return textElement
39
47
  }
40
48
 
41
- const drawLine = ({ x1, y1, x2, y2, className, parentNode: parent }) => {
42
- return drawSvgElement({ tag: "line", attributes: { x1, y1, x2, y2 }, className, parent })
43
- }
44
-
45
- const drawCircle = ({ cx, cy, r, className, parentNode: parent }) => {
46
- return drawSvgElement({ tag: "circle", attributes: { cx, cy, r }, className, parent })
47
- }
48
-
49
- const coordsToPathData = (coords) => "M " + coords.map((coord) => coord.join(",")).join(" L ")
50
-
51
- const drawLinearPath = ({ coords, className, parentNode: parent }) => {
52
- const d = coordsToPathData(coords)
53
- return drawSvgElement({ tag: "path", attributes: { d }, className, parent })
54
- }
55
-
56
49
  const polarToCartesian = (angle, radius) => {
57
50
  const angleRadians = (angle % 1) * TWO_PI
58
51
  const x = Math.cos(angleRadians) * radius
@@ -60,19 +53,7 @@ const polarToCartesian = (angle, radius) => {
60
53
  return [x, y]
61
54
  }
62
55
 
63
- const drawPolarLine = ({ startAngle, startRadius, endAngle, endRadius, className, parentNode: parent }) => {
64
- const [x1, y1] = polarToCartesian(startAngle, startRadius)
65
- const [x2, y2] = polarToCartesian(endAngle, endRadius)
66
-
67
- return drawSvgElement({ tag: "line", attributes: { x1, y1, x2, y2 }, className, parent })
68
- }
69
-
70
- const drawPolarCircle = ({ angle, radius, r, className, parentNode: parent }) => {
71
- const [cx, cy] = polarToCartesian(angle, radius)
72
- return drawSvgElement({ tag: "circle", attributes: { cx, cy, r }, className, parent })
73
- }
74
-
75
- const drawWedge = ({ startAngle, angleDelta, innerRadius, radiusDelta, className, parentNode: parent }) => {
56
+ const drawWedge = ({ startAngle, angleDelta, innerRadius, radiusDelta, className, parent }) => {
76
57
  if (angleDelta < 0) {
77
58
  angleDelta = 0
78
59
  }
@@ -89,57 +70,26 @@ const drawWedge = ({ startAngle, angleDelta, innerRadius, radiusDelta, className
89
70
  const [endX2, endY2] = polarToCartesian(endAngle, outerRadius)
90
71
 
91
72
  const d = `
92
- M ${startX1} ${startY1},
93
- A ${innerRadius} ${innerRadius} 0 ${largeArcFlag} 0 ${endX1} ${endY1},
94
- L ${endX2} ${endY2},
95
- A ${outerRadius} ${outerRadius} 0 ${largeArcFlag} 1 ${startX2} ${startY2},
73
+ M ${startX1},${startY1}
74
+ A ${innerRadius} ${innerRadius} 0 ${largeArcFlag} 0 ${endX1},${endY1}
75
+ L ${endX2},${endY2}
76
+ A ${outerRadius} ${outerRadius} 0 ${largeArcFlag} 1 ${startX2},${startY2}
96
77
  Z
97
78
  `
98
79
 
99
80
  return drawSvgElement({ tag: "path", attributes: { d }, className, parent })
100
81
  }
101
82
 
102
- const triangleHeight = 0.06
103
- const verticalPadding = 0.01
104
- const horizontalPadding = 0.04
83
+ const drawPolarLine = ({ startAngle, startRadius, endAngle, endRadius, className, parent }) => {
84
+ const [x1, y1] = polarToCartesian(startAngle, startRadius)
85
+ const [x2, y2] = polarToCartesian(endAngle, endRadius)
105
86
 
106
- const drawToolTip = ({ x, y, text, direction = "below", parentNode: parent }) => {
107
- const directionMultiplier = direction === "above" ? -1 : 1
108
- const tooltipDisplayGroup = drawSvgElement({
109
- tag: "g",
110
- className: "tooltip_display_group",
111
- parent,
112
- })
113
- const bgPlaceholder = drawSvgElement({ tag: "g", parent: tooltipDisplayGroup })
114
- const textY = y + (triangleHeight + verticalPadding) * directionMultiplier
115
- const textElement = drawText({
116
- x,
117
- y: textY,
118
- text,
119
- className: "tooltip_text",
120
- parentNode: tooltipDisplayGroup,
121
- })
122
- const textBbox = textElement.getBBox()
123
- const attributes = {
124
- x: textBbox.x - horizontalPadding,
125
- y: textBbox.y - verticalPadding,
126
- width: textBbox.width + horizontalPadding * 2,
127
- height: textBbox.height + verticalPadding * 2,
128
- rx: 0.015,
129
- }
130
- drawSvgElement({ tag: "rect", attributes, className: "tooltip_outline", parent: bgPlaceholder })
87
+ return drawSvgElement({ tag: "line", attributes: { x1, y1, x2, y2 }, className, parent })
88
+ }
89
+
90
+ const drawPolarCircle = ({ angle, radius, r, className, parent }) => {
91
+ const [cx, cy] = polarToCartesian(angle, radius)
92
+ return drawSvgElement({ tag: "circle", attributes: { cx, cy, r }, className, parent })
131
93
  }
132
94
 
133
- exportDeps({
134
- drawSvgElement,
135
- drawLine,
136
- drawCircle,
137
- drawLinearPath,
138
- drawPolarLine,
139
- drawPolarCircle,
140
- drawWedge,
141
- drawText,
142
- polarToCartesian,
143
- coordsToPathData,
144
- drawToolTip,
145
- })
95
+ exportDeps({ drawSvgElement, drawText, polarToCartesian, drawWedge, drawPolarLine, drawPolarCircle })
@@ -53,7 +53,7 @@ const requestHandler = (allowedHosts) => (req, res) => {
53
53
  const fileStream = createReadStream(filePath)
54
54
  fileStream.pipe(res)
55
55
  })
56
- .catch((e) => {
56
+ .catch(() => {
57
57
  res.writeHead(404)
58
58
  res.end("NOT FOUND!")
59
59
  })
@@ -1,194 +0,0 @@
1
- const { exportDeps, drawSvgElement, drawCircle, drawLinearPath, coordsToPathData, drawText, drawToolTip } =
2
- window.__WTR__
3
-
4
- const drawValueWithTooltip = ({ x, y, label, direction, parentNode }) => {
5
- const tooltipWrapperGroup = drawSvgElement({
6
- tag: "g",
7
- className: "tooltip_wrapper_group",
8
- parent: parentNode,
9
- })
10
- drawToolTip({ x: x, y: y - 0.0032, text: label, direction, parentNode: tooltipWrapperGroup })
11
- return drawText({
12
- x: x,
13
- y: y,
14
- dominantBaseline: "middle",
15
- text: "0",
16
- className: "timeseries_value",
17
- parentNode: tooltipWrapperGroup,
18
- })
19
- }
20
-
21
- const dataWindowSize = 16
22
- const dataWindowInterval = 1000
23
- const graphHeight = 0.25
24
-
25
- const innerCircleClipPathId = "inner_circle_clip"
26
-
27
- const createLinearScale = (domainMin, domainMax, rangeMin, rangeMax) => {
28
- const domainSize = domainMax - domainMin
29
- if (domainSize === 0) {
30
- return () => rangeMin
31
- }
32
- const rangeSize = rangeMax - rangeMin
33
- const ratio = rangeSize / domainSize
34
-
35
- return (domainValue) => (domainValue - domainMin) * ratio + rangeMin
36
- }
37
-
38
- const createRandomDataWindow = () => {
39
- const series = []
40
- const endTime = new Date().setMilliseconds(0).valueOf()
41
- const startTime = endTime - dataWindowInterval * dataWindowSize
42
- let maxValue = 0
43
-
44
- for (let time = startTime; time < endTime; time += dataWindowInterval) {
45
- // const value = Math.floor(Math.random() * 101)
46
- const value = 0
47
- if (value > maxValue) {
48
- maxValue = value
49
- }
50
- series.push({ time, value })
51
- }
52
-
53
- return series
54
- }
55
-
56
- const getSeriesWindowInfo = (series) => {
57
- const startTime = series.at(1).time
58
- const endTime = series.at(-1).time
59
- let maxValue = 0
60
- series.forEach(({ value }) => {
61
- if (value > maxValue) {
62
- maxValue = value
63
- }
64
- })
65
-
66
- return { startTime, endTime, maxValue }
67
- }
68
-
69
- class ActivityTimeseriesGraph {
70
- constructor({ innerRingRadius, parentNode }) {
71
- this.innerRingRadius = innerRingRadius
72
- this.parentNode = parentNode
73
- this.parentNode.innerHTML = ""
74
- this.dataWindow = window.activityDataWindow || createRandomDataWindow()
75
- window.activityDataWindow = this.dataWindow
76
- if (!window.currentActivityCount) {
77
- window.currentActivityCount = 0
78
- }
79
- this.draw()
80
- }
81
-
82
- draw() {
83
- const minX = -this.innerRingRadius
84
- const maxX = this.innerRingRadius
85
- const width = maxX - minX
86
- const height = graphHeight
87
- const minY = -height / 2
88
- const maxY = minY + height
89
-
90
- const clipPath = drawSvgElement({
91
- tag: "clipPath",
92
- attributes: { id: innerCircleClipPathId },
93
- parent: this.parentNode,
94
- })
95
- drawCircle({ cx: 0, cy: 0, r: this.innerRingRadius - 0.005, parentNode: clipPath })
96
- drawSvgElement({
97
- tag: "rect",
98
- attributes: {
99
- "clip-path": `url(#${innerCircleClipPathId})`,
100
- x: minX,
101
- y: minY,
102
- height,
103
- width,
104
- },
105
- className: "timeseries_bg",
106
- parent: this.parentNode,
107
- })
108
-
109
- const series = this.dataWindow
110
- const { startTime, endTime, maxValue } = getSeriesWindowInfo(series)
111
-
112
- const maxValueElement = drawValueWithTooltip({
113
- x: minX + width / 2,
114
- y: minY - 0.08,
115
- label: "Max updates in a 1 second window",
116
- direction: "above",
117
- parentNode: this.parentNode,
118
- })
119
- const currentValueElement = drawValueWithTooltip({
120
- x: minX + width / 2,
121
- y: maxY + 0.095,
122
- label: "Updates in last full second",
123
- parentNode: this.parentNode,
124
- })
125
-
126
- let valueScale = createLinearScale(0, maxValue, maxY, minY) // in svg, y increases as it goes down, so we need to flip max and min in the range
127
- let timeScale = createLinearScale(startTime, endTime, minX, maxX)
128
-
129
- const pathCoords = series.map(({ time, value }) => {
130
- return [timeScale(time), valueScale(value)]
131
- })
132
-
133
- const graphPath = drawLinearPath({
134
- coords: pathCoords,
135
- className: "timeseries_path",
136
- parentNode: this.parentNode,
137
- })
138
-
139
- if (window.activityTimeout) {
140
- clearTimeout(window.activityTimeout)
141
- }
142
- const onTickUpdate = () => {
143
- scheduleNextTick()
144
-
145
- const series = this.dataWindow
146
- const prevEndTime = series.at(-1).time
147
- const newTime = prevEndTime + dataWindowInterval
148
- series.shift()
149
- series.push({ time: newTime, value: window.currentActivityCount })
150
- currentValueElement.textContent = window.currentActivityCount
151
- window.currentActivityCount = 0
152
-
153
- const pathCoords = series.map(({ time, value }) => {
154
- return [timeScale(time), valueScale(value)]
155
- })
156
-
157
- const pathData = coordsToPathData(pathCoords)
158
- graphPath.style.transition = ""
159
- graphPath.setAttribute("d", pathData)
160
-
161
- requestAnimationFrame(() => {
162
- requestAnimationFrame(() => {
163
- const { startTime, endTime, maxValue } = getSeriesWindowInfo(series)
164
- maxValueElement.textContent = maxValue
165
-
166
- valueScale = createLinearScale(0, maxValue, maxY, minY) // in svg, y increases as it goes down, so we need to flip max and min in the range
167
- timeScale = createLinearScale(startTime, endTime, minX, maxX)
168
-
169
- const pathCoords = series.map(({ time, value }) => {
170
- return [timeScale(time), valueScale(value)]
171
- })
172
-
173
- const pathData = coordsToPathData(pathCoords)
174
- graphPath.style.transition = "all 1s linear"
175
- graphPath.setAttribute("d", pathData)
176
- })
177
- })
178
- }
179
-
180
- const scheduleNextTick = () => {
181
- const nowMillis = new Date().getMilliseconds()
182
- const millisUntilNextSecond = 1000 - nowMillis
183
- window.activityTimeout = setTimeout(onTickUpdate, millisUntilNextSecond)
184
- }
185
-
186
- scheduleNextTick()
187
- }
188
-
189
- triggerActivity() {
190
- window.currentActivityCount++
191
- }
192
- }
193
-
194
- exportDeps({ ActivityTimeseriesGraph })
@@ -1,22 +0,0 @@
1
- const { exportDeps, drawText } = window.__WTR__
2
-
3
- class HeaderSummary {
4
- constructor({ parentNode }) {
5
- this.parentNode = parentNode
6
- this.draw()
7
- }
8
-
9
- draw() {
10
- this.parentNode.innerHTML = ""
11
- drawText({ x: -0.86, y: -0.73, text: "editors", parentNode: this.parentNode })
12
- drawText({
13
- x: 0.86,
14
- y: -0.73,
15
- text: "clients",
16
- className: "right_header",
17
- parentNode: this.parentNode,
18
- })
19
- }
20
- }
21
-
22
- exportDeps({ HeaderSummary })
@@ -1,43 +0,0 @@
1
- const { exportDeps, drawText } = window.__WTR__
2
-
3
- const valueTextClass = "server_status_value"
4
- const offlineTextClass = "server_status_offline"
5
-
6
- class ServerStatus {
7
- constructor({ parentNode }) {
8
- this.parentNode = parentNode
9
- this.draw()
10
- }
11
-
12
- draw() {
13
- this.parentNode.innerHTML = ""
14
- drawText({
15
- x: 0,
16
- y: 0.85,
17
- text: "WS Server PID",
18
- className: "server_status_label",
19
- parentNode: this.parentNode,
20
- })
21
- this.valueElement = drawText({ x: 0, y: 0.748, text: "138324", parentNode: this.parentNode })
22
- this.offlineElement = drawText({
23
- x: 0,
24
- y: 0.748,
25
- text: "OFFLINE",
26
- className: offlineTextClass,
27
- parentNode: this.parentNode,
28
- })
29
- }
30
-
31
- update(pid) {
32
- if (pid == null) {
33
- this.valueElement.classList.remove(valueTextClass)
34
- this.offlineElement.classList.add(offlineTextClass)
35
- } else {
36
- this.valueElement.textContent = pid
37
- this.valueElement.classList.add(valueTextClass)
38
- this.offlineElement.classList.remove(offlineTextClass)
39
- }
40
- }
41
- }
42
-
43
- exportDeps({ ServerStatus })