websocket-text-relay 1.1.2 → 1.1.4
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.
- package/.prettierignore +3 -0
- package/.prettierrc +4 -0
- package/changelog.md +11 -0
- package/docs/code-structure.md +1 -1
- package/eslint.config.js +28 -0
- package/package.json +15 -10
- package/{index.js → src/index.js} +25 -23
- package/src/language-server/JsonRpcInterface.js +59 -29
- package/src/language-server/JsonRpcInterface.test.js +102 -72
- package/src/language-server/LspReader.js +30 -20
- package/src/language-server/LspReader.test.js +147 -65
- package/src/language-server/LspWriter.js +5 -5
- package/src/language-server/LspWriter.test.js +31 -24
- package/src/ui/css/fonts.css +0 -1
- package/src/ui/css/main.css +7 -7
- package/src/ui/index.html +4 -4
- package/src/ui/js/components/ActivityTimeseriesGraph.js +83 -32
- package/src/ui/js/components/HeaderSummary.js +11 -5
- package/src/ui/js/components/ServerStatus.js +19 -7
- package/src/ui/js/components/SessionLabels.js +197 -49
- package/src/ui/js/components/SessionWedges.js +44 -24
- package/src/ui/js/components/StatusRing.js +20 -8
- package/src/ui/js/components/grids.js +14 -7
- package/src/ui/js/index.js +23 -19
- package/src/ui/js/main.js +53 -21
- package/src/ui/js/util/DependencyManager.js +5 -5
- package/src/ui/js/util/EventEmitter.js +11 -7
- package/src/ui/js/util/WebsocketClient.js +28 -22
- package/src/ui/js/util/constants.js +2 -2
- package/src/ui/js/util/drawing.js +58 -28
- package/src/websocket-interface/WebsocketClient.js +15 -15
- package/src/websocket-interface/WebsocketInterface.js +30 -22
- package/src/websocket-interface/WtrSession.js +49 -33
- package/src/websocket-interface/httpServer.js +24 -14
- package/src/websocket-interface/sessionManager.js +16 -13
- package/src/websocket-interface/util.js +1 -1
- package/src/websocket-interface/websocketApi.js +51 -34
- package/src/websocket-interface/websocketServer.js +9 -9
- package/start.js +1 -1
- package/.eslintrc +0 -29
package/src/ui/js/main.js
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
/* eslint no-unused-vars: 0 */
|
|
2
|
-
const {
|
|
3
|
-
|
|
2
|
+
const {
|
|
3
|
+
HeaderSummary,
|
|
4
|
+
StatusRing,
|
|
5
|
+
onEvent,
|
|
6
|
+
statusDataEmitter,
|
|
7
|
+
SessionWedges,
|
|
8
|
+
ClientLabel,
|
|
9
|
+
ActivityTimeseriesGraph,
|
|
10
|
+
EditorLabel,
|
|
11
|
+
ServerStatus,
|
|
12
|
+
constants,
|
|
13
|
+
} = window.__WTR__
|
|
4
14
|
const { outerRingRadius, innerRingRadius, outerArcSize } = constants
|
|
5
15
|
|
|
6
16
|
const gridGroup = document.getElementById("grid_group")
|
|
@@ -8,26 +18,44 @@ gridGroup.innerHTML = ""
|
|
|
8
18
|
// drawPolarGrid(gridGroup)
|
|
9
19
|
// drawGrid(gridGroup)
|
|
10
20
|
|
|
11
|
-
const headerSummaryNode = document.getElementById(
|
|
12
|
-
new HeaderSummary({parentNode: headerSummaryNode})
|
|
21
|
+
const headerSummaryNode = document.getElementById("header_summary_group")
|
|
22
|
+
new HeaderSummary({ parentNode: headerSummaryNode })
|
|
13
23
|
|
|
14
|
-
const statusRingNode = document.getElementById(
|
|
15
|
-
const statusRing = new StatusRing({
|
|
24
|
+
const statusRingNode = document.getElementById("status_ring_group")
|
|
25
|
+
const statusRing = new StatusRing({
|
|
26
|
+
innerRingRadius,
|
|
27
|
+
outerRingRadius,
|
|
28
|
+
outerArcSize,
|
|
29
|
+
parentNode: statusRingNode,
|
|
30
|
+
})
|
|
16
31
|
|
|
17
|
-
const clientWedgesNode = document.getElementById(
|
|
18
|
-
const clientWedges = new SessionWedges({
|
|
32
|
+
const clientWedgesNode = document.getElementById("client_wedges_group")
|
|
33
|
+
const clientWedges = new SessionWedges({
|
|
34
|
+
outerRingRadius,
|
|
35
|
+
outerArcSize,
|
|
36
|
+
direction: -1,
|
|
37
|
+
Label: ClientLabel,
|
|
38
|
+
parentNode: clientWedgesNode,
|
|
39
|
+
})
|
|
19
40
|
|
|
20
|
-
const editorWedgesNode = document.getElementById(
|
|
21
|
-
const editorWedges = new SessionWedges({
|
|
41
|
+
const editorWedgesNode = document.getElementById("editor_wedges_group")
|
|
42
|
+
const editorWedges = new SessionWedges({
|
|
43
|
+
outerRingRadius,
|
|
44
|
+
outerArcSize,
|
|
45
|
+
Label: EditorLabel,
|
|
46
|
+
parentNode: editorWedgesNode,
|
|
47
|
+
})
|
|
22
48
|
|
|
23
|
-
const activityGraphNode = document.getElementById(
|
|
24
|
-
const activityGraph = new ActivityTimeseriesGraph({
|
|
49
|
+
const activityGraphNode = document.getElementById("activity_timeseries_graph")
|
|
50
|
+
const activityGraph = new ActivityTimeseriesGraph({
|
|
51
|
+
innerRingRadius,
|
|
52
|
+
parentNode: activityGraphNode,
|
|
53
|
+
})
|
|
25
54
|
|
|
26
|
-
const serverStatusNode = document.getElementById(
|
|
27
|
-
const serverStatus = new ServerStatus({parentNode: serverStatusNode})
|
|
55
|
+
const serverStatusNode = document.getElementById("server_status_group")
|
|
56
|
+
const serverStatus = new ServerStatus({ parentNode: serverStatusNode })
|
|
28
57
|
|
|
29
58
|
const statusDataTranform = (rawData) => {
|
|
30
|
-
|
|
31
59
|
const editors = []
|
|
32
60
|
const clients = []
|
|
33
61
|
const allSessions = new Map()
|
|
@@ -48,9 +76,11 @@ const statusDataTranform = (rawData) => {
|
|
|
48
76
|
const openFileLinks = Object.values(session.openFileLinks)
|
|
49
77
|
session.activeOpenCount = openFileLinks.length
|
|
50
78
|
openFileLinks.forEach((links) => {
|
|
51
|
-
links.forEach(({clientId}) => {
|
|
79
|
+
links.forEach(({ clientId }) => {
|
|
52
80
|
const clientSession = allSessions.get(clientId)
|
|
53
|
-
if (!clientSession) {
|
|
81
|
+
if (!clientSession) {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
54
84
|
clientSession.activeWatchCount++
|
|
55
85
|
})
|
|
56
86
|
})
|
|
@@ -61,7 +91,9 @@ const statusDataTranform = (rawData) => {
|
|
|
61
91
|
|
|
62
92
|
const getServerPid = (editors) => {
|
|
63
93
|
for (const editor of editors) {
|
|
64
|
-
if (editor.isServer) {
|
|
94
|
+
if (editor.isServer) {
|
|
95
|
+
return editor.lsPid
|
|
96
|
+
}
|
|
65
97
|
}
|
|
66
98
|
return null
|
|
67
99
|
}
|
|
@@ -76,7 +108,7 @@ const handleStatusData = (rawData) => {
|
|
|
76
108
|
serverStatus.update(getServerPid(data.editors))
|
|
77
109
|
}
|
|
78
110
|
|
|
79
|
-
onEvent(statusDataEmitter,
|
|
111
|
+
onEvent(statusDataEmitter, "data", handleStatusData)
|
|
80
112
|
|
|
81
113
|
if (window.__WTR__.lastStatusData) {
|
|
82
114
|
handleStatusData(window.__WTR__.lastStatusData)
|
|
@@ -88,9 +120,9 @@ const handleActivity = (data) => {
|
|
|
88
120
|
activityGraph.triggerActivity()
|
|
89
121
|
}
|
|
90
122
|
|
|
91
|
-
onEvent(statusDataEmitter,
|
|
123
|
+
onEvent(statusDataEmitter, "activity", handleActivity)
|
|
92
124
|
|
|
93
|
-
onEvent(statusDataEmitter,
|
|
125
|
+
onEvent(statusDataEmitter, "socket-close", () => {
|
|
94
126
|
console.log("socket closed!")
|
|
95
127
|
serverStatus.update(null)
|
|
96
128
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EventEmitter } from
|
|
1
|
+
import { EventEmitter } from "./EventEmitter.js"
|
|
2
2
|
|
|
3
3
|
const dependencies = {}
|
|
4
4
|
window.__WTR__ = dependencies
|
|
@@ -10,10 +10,10 @@ const statusDataEmitter = new EventEmitter()
|
|
|
10
10
|
const cleanupFuncs = []
|
|
11
11
|
|
|
12
12
|
const onEvent = (emitter, event, func) => {
|
|
13
|
-
if (typeof emitter.on ===
|
|
13
|
+
if (typeof emitter.on === "function") {
|
|
14
14
|
emitter.on(event, func)
|
|
15
15
|
cleanupFuncs.push(() => emitter.removeListener(event, func))
|
|
16
|
-
} else if (typeof emitter.addEventListener ===
|
|
16
|
+
} else if (typeof emitter.addEventListener === "function") {
|
|
17
17
|
emitter.addEventListener(event, func)
|
|
18
18
|
cleanupFuncs.push(() => emitter.removeEventListener(event, func))
|
|
19
19
|
} else {
|
|
@@ -22,10 +22,10 @@ const onEvent = (emitter, event, func) => {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
const cleanupEventHandlers = () => {
|
|
25
|
-
cleanupFuncs.forEach(f => f())
|
|
25
|
+
cleanupFuncs.forEach((f) => f())
|
|
26
26
|
cleanupFuncs.length = 0
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
exportDeps({exportDeps, statusDataEmitter, onEvent, cleanupEventHandlers})
|
|
29
|
+
exportDeps({ exportDeps, statusDataEmitter, onEvent, cleanupEventHandlers })
|
|
30
30
|
|
|
31
31
|
export default dependencies
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export class EventEmitter {
|
|
2
|
-
constructor
|
|
2
|
+
constructor() {
|
|
3
3
|
this.events = new Map()
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
on
|
|
6
|
+
on(event, listener) {
|
|
7
7
|
let eventSubscribers = this.events.get(event)
|
|
8
8
|
if (!eventSubscribers) {
|
|
9
9
|
eventSubscribers = new Set()
|
|
@@ -13,9 +13,11 @@ export class EventEmitter {
|
|
|
13
13
|
return () => this.removeListener(event, listener)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
removeListener
|
|
16
|
+
removeListener(event, listener) {
|
|
17
17
|
const eventSubscribers = this.events.get(event)
|
|
18
|
-
if (!eventSubscribers) {
|
|
18
|
+
if (!eventSubscribers) {
|
|
19
|
+
return
|
|
20
|
+
}
|
|
19
21
|
if (!listener) {
|
|
20
22
|
this.events.delete(event)
|
|
21
23
|
return
|
|
@@ -23,15 +25,17 @@ export class EventEmitter {
|
|
|
23
25
|
eventSubscribers.delete(listener)
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
emit
|
|
28
|
+
emit(event, ...args) {
|
|
27
29
|
const eventSubscribers = this.events.get(event)
|
|
28
|
-
if (!eventSubscribers) {
|
|
30
|
+
if (!eventSubscribers) {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
29
33
|
for (const listener of eventSubscribers) {
|
|
30
34
|
listener.apply(this, args)
|
|
31
35
|
}
|
|
32
36
|
}
|
|
33
37
|
|
|
34
|
-
once
|
|
38
|
+
once(event, listener) {
|
|
35
39
|
const remove = this.on(event, (...args) => {
|
|
36
40
|
remove()
|
|
37
41
|
listener.apply(this, args)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { EventEmitter } from
|
|
1
|
+
import { EventEmitter } from "./EventEmitter.js"
|
|
2
2
|
|
|
3
3
|
const RECONNECT_DELAY_SECONDS = 1
|
|
4
4
|
|
|
5
5
|
export class WebsocketClient {
|
|
6
|
-
constructor
|
|
6
|
+
constructor({ port, host = "localhost", protocol = "ws" }) {
|
|
7
7
|
this.port = port
|
|
8
8
|
this.host = host
|
|
9
9
|
this.protocol = protocol
|
|
@@ -20,39 +20,43 @@ export class WebsocketClient {
|
|
|
20
20
|
this.startClient()
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
getUrl
|
|
23
|
+
getUrl() {
|
|
24
24
|
return `${this.protocol}://${this.host}:${this.port}`
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
startClient
|
|
27
|
+
startClient() {
|
|
28
28
|
this.socket = new WebSocket(this.getUrl())
|
|
29
|
-
this.socket.addEventListener(
|
|
30
|
-
this.socket.addEventListener(
|
|
31
|
-
this.socket.addEventListener(
|
|
32
|
-
this.socket.addEventListener(
|
|
29
|
+
this.socket.addEventListener("open", this._onSocketOpen)
|
|
30
|
+
this.socket.addEventListener("message", this._onSocketMessage)
|
|
31
|
+
this.socket.addEventListener("error", this._onSocketError)
|
|
32
|
+
this.socket.addEventListener("close", this._onSocketClose)
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
onSocketOpen
|
|
35
|
+
onSocketOpen() {
|
|
36
36
|
console.log("websocket client connected")
|
|
37
37
|
this.socketOpen = true
|
|
38
38
|
this.emitter.emit("socket-open")
|
|
39
|
-
this.sessionMessages.forEach(msgStr => this.socket.send(msgStr))
|
|
39
|
+
this.sessionMessages.forEach((msgStr) => this.socket.send(msgStr))
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
onSocketClose
|
|
43
|
-
console.log(
|
|
44
|
-
|
|
42
|
+
onSocketClose() {
|
|
43
|
+
console.log(
|
|
44
|
+
`websocket text relay connection closed. Retrying connection in ${RECONNECT_DELAY_SECONDS} second${RECONNECT_DELAY_SECONDS === 1 ? "" : "s"}...`,
|
|
45
|
+
)
|
|
46
|
+
if (this.socket == null) {
|
|
47
|
+
return
|
|
48
|
+
}
|
|
45
49
|
this.emitter.emit("socket-close")
|
|
46
50
|
this.socketOpen = false
|
|
47
|
-
this.socket.removeEventListener(
|
|
48
|
-
this.socket.removeEventListener(
|
|
49
|
-
this.socket.removeEventListener(
|
|
50
|
-
this.socket.removeEventListener(
|
|
51
|
+
this.socket.removeEventListener("open", this._onSocketOpen)
|
|
52
|
+
this.socket.removeEventListener("message", this._onSocketMessage)
|
|
53
|
+
this.socket.removeEventListener("error", this._onSocketError)
|
|
54
|
+
this.socket.removeEventListener("close", this._onSocketClose)
|
|
51
55
|
this.socket = null
|
|
52
56
|
setTimeout(() => this.startClient(), RECONNECT_DELAY_SECONDS * 1000)
|
|
53
57
|
}
|
|
54
58
|
|
|
55
|
-
onSocketMessage
|
|
59
|
+
onSocketMessage(event) {
|
|
56
60
|
let message
|
|
57
61
|
try {
|
|
58
62
|
message = JSON.parse(event.data)
|
|
@@ -60,17 +64,19 @@ export class WebsocketClient {
|
|
|
60
64
|
console.error("Error parsing websocket message JSON", e)
|
|
61
65
|
return
|
|
62
66
|
}
|
|
63
|
-
this.emitter.emit(
|
|
67
|
+
this.emitter.emit("message", message)
|
|
64
68
|
}
|
|
65
69
|
|
|
66
|
-
onSocketError
|
|
70
|
+
onSocketError(error) {
|
|
67
71
|
console.error("websocket text relay connection error: ", error)
|
|
68
72
|
}
|
|
69
73
|
|
|
70
|
-
sendMessage
|
|
74
|
+
sendMessage(message) {
|
|
71
75
|
const messageStr = JSON.stringify(message)
|
|
72
76
|
this.sessionMessages.push(messageStr)
|
|
73
|
-
if (!this.socketOpen) {
|
|
77
|
+
if (!this.socketOpen) {
|
|
78
|
+
return
|
|
79
|
+
}
|
|
74
80
|
this.socket.send(messageStr)
|
|
75
81
|
}
|
|
76
82
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
const { exportDeps } = window.__WTR__
|
|
2
2
|
|
|
3
3
|
const TWO_PI = 2 * Math.PI
|
|
4
|
-
const MAX_ANGLE_DELTA = .99999
|
|
4
|
+
const MAX_ANGLE_DELTA = 0.99999
|
|
5
5
|
|
|
6
|
-
const drawSvgElement = ({tag, attributes = {}, className, parent}) => {
|
|
6
|
+
const drawSvgElement = ({ tag, attributes = {}, className, parent }) => {
|
|
7
7
|
const element = document.createElementNS("http://www.w3.org/2000/svg", tag)
|
|
8
8
|
|
|
9
9
|
if (className && className.length > 0) {
|
|
@@ -27,25 +27,30 @@ const drawSvgElement = ({tag, attributes = {}, className, parent}) => {
|
|
|
27
27
|
return element
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
const drawText = ({x, y, text, dominantBaseline, textAnchor, className, parentNode: parent}) => {
|
|
31
|
-
const textElement = drawSvgElement({
|
|
30
|
+
const drawText = ({ x, y, text, dominantBaseline, textAnchor, className, parentNode: parent }) => {
|
|
31
|
+
const textElement = drawSvgElement({
|
|
32
|
+
tag: "text",
|
|
33
|
+
attributes: { x, y, "dominant-baseline": dominantBaseline, "text-anchor": textAnchor },
|
|
34
|
+
className,
|
|
35
|
+
parent,
|
|
36
|
+
})
|
|
32
37
|
textElement.textContent = text
|
|
33
38
|
return textElement
|
|
34
39
|
}
|
|
35
40
|
|
|
36
|
-
const drawLine = ({x1, y1, x2, y2, className, parentNode: parent}) => {
|
|
37
|
-
return drawSvgElement({tag: "line", attributes: {x1, y1, x2, y2}, className, parent})
|
|
41
|
+
const drawLine = ({ x1, y1, x2, y2, className, parentNode: parent }) => {
|
|
42
|
+
return drawSvgElement({ tag: "line", attributes: { x1, y1, x2, y2 }, className, parent })
|
|
38
43
|
}
|
|
39
44
|
|
|
40
|
-
const drawCircle = ({cx, cy, r, className, parentNode: parent}) => {
|
|
41
|
-
return drawSvgElement({tag: "circle", attributes: {cx, cy, r}, className, parent})
|
|
45
|
+
const drawCircle = ({ cx, cy, r, className, parentNode: parent }) => {
|
|
46
|
+
return drawSvgElement({ tag: "circle", attributes: { cx, cy, r }, className, parent })
|
|
42
47
|
}
|
|
43
48
|
|
|
44
|
-
const coordsToPathData = (coords) => "M " + coords.map(coord => coord.join(
|
|
49
|
+
const coordsToPathData = (coords) => "M " + coords.map((coord) => coord.join(",")).join(" L ")
|
|
45
50
|
|
|
46
|
-
const drawLinearPath = ({coords, className, parentNode: parent}) => {
|
|
51
|
+
const drawLinearPath = ({ coords, className, parentNode: parent }) => {
|
|
47
52
|
const d = coordsToPathData(coords)
|
|
48
|
-
return drawSvgElement({tag: "path", attributes: {d}, className, parent})
|
|
53
|
+
return drawSvgElement({ tag: "path", attributes: { d }, className, parent })
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
const polarToCartesian = (angle, radius) => {
|
|
@@ -55,24 +60,28 @@ const polarToCartesian = (angle, radius) => {
|
|
|
55
60
|
return [x, y]
|
|
56
61
|
}
|
|
57
62
|
|
|
58
|
-
const drawPolarLine = ({startAngle, startRadius, endAngle, endRadius, className, parentNode: parent}) => {
|
|
63
|
+
const drawPolarLine = ({ startAngle, startRadius, endAngle, endRadius, className, parentNode: parent }) => {
|
|
59
64
|
const [x1, y1] = polarToCartesian(startAngle, startRadius)
|
|
60
65
|
const [x2, y2] = polarToCartesian(endAngle, endRadius)
|
|
61
66
|
|
|
62
|
-
return drawSvgElement({tag: "line", attributes: {x1, y1, x2, y2}, className, parent})
|
|
67
|
+
return drawSvgElement({ tag: "line", attributes: { x1, y1, x2, y2 }, className, parent })
|
|
63
68
|
}
|
|
64
69
|
|
|
65
|
-
const drawPolarCircle = ({angle, radius, r, className, parentNode: parent}) => {
|
|
70
|
+
const drawPolarCircle = ({ angle, radius, r, className, parentNode: parent }) => {
|
|
66
71
|
const [cx, cy] = polarToCartesian(angle, radius)
|
|
67
|
-
return drawSvgElement({tag: "circle", attributes: {cx, cy, r}, className, parent})
|
|
72
|
+
return drawSvgElement({ tag: "circle", attributes: { cx, cy, r }, className, parent })
|
|
68
73
|
}
|
|
69
74
|
|
|
70
|
-
const drawWedge = ({startAngle, angleDelta, innerRadius, radiusDelta, className, parentNode: parent}) => {
|
|
71
|
-
if (angleDelta < 0) {
|
|
72
|
-
|
|
75
|
+
const drawWedge = ({ startAngle, angleDelta, innerRadius, radiusDelta, className, parentNode: parent }) => {
|
|
76
|
+
if (angleDelta < 0) {
|
|
77
|
+
angleDelta = 0
|
|
78
|
+
}
|
|
79
|
+
if (angleDelta > MAX_ANGLE_DELTA) {
|
|
80
|
+
angleDelta = MAX_ANGLE_DELTA
|
|
81
|
+
}
|
|
73
82
|
const endAngle = startAngle + angleDelta
|
|
74
83
|
const outerRadius = innerRadius + radiusDelta
|
|
75
|
-
const largeArcFlag =
|
|
84
|
+
const largeArcFlag = angleDelta % 1 > 0.5 ? "1" : "0"
|
|
76
85
|
|
|
77
86
|
const [startX1, startY1] = polarToCartesian(startAngle, innerRadius)
|
|
78
87
|
const [startX2, startY2] = polarToCartesian(startAngle, outerRadius)
|
|
@@ -87,29 +96,50 @@ A ${outerRadius} ${outerRadius} 0 ${largeArcFlag} 1 ${startX2} ${startY2},
|
|
|
87
96
|
Z
|
|
88
97
|
`
|
|
89
98
|
|
|
90
|
-
return drawSvgElement({tag: "path", attributes: {d}, className, parent})
|
|
99
|
+
return drawSvgElement({ tag: "path", attributes: { d }, className, parent })
|
|
91
100
|
}
|
|
92
101
|
|
|
93
102
|
const triangleHeight = 0.06
|
|
94
103
|
const verticalPadding = 0.01
|
|
95
104
|
const horizontalPadding = 0.04
|
|
96
105
|
|
|
97
|
-
const drawToolTip = ({x, y, text, direction = "below", parentNode: parent}) => {
|
|
106
|
+
const drawToolTip = ({ x, y, text, direction = "below", parentNode: parent }) => {
|
|
98
107
|
const directionMultiplier = direction === "above" ? -1 : 1
|
|
99
|
-
const tooltipDisplayGroup = drawSvgElement({
|
|
100
|
-
|
|
108
|
+
const tooltipDisplayGroup = drawSvgElement({
|
|
109
|
+
tag: "g",
|
|
110
|
+
className: "tooltip_display_group",
|
|
111
|
+
parent,
|
|
112
|
+
})
|
|
113
|
+
const bgPlaceholder = drawSvgElement({ tag: "g", parent: tooltipDisplayGroup })
|
|
101
114
|
const textY = y + (triangleHeight + verticalPadding) * directionMultiplier
|
|
102
|
-
const textElement = drawText({
|
|
115
|
+
const textElement = drawText({
|
|
116
|
+
x,
|
|
117
|
+
y: textY,
|
|
118
|
+
text,
|
|
119
|
+
className: "tooltip_text",
|
|
120
|
+
parentNode: tooltipDisplayGroup,
|
|
121
|
+
})
|
|
103
122
|
const textBbox = textElement.getBBox()
|
|
104
123
|
const attributes = {
|
|
105
124
|
x: textBbox.x - horizontalPadding,
|
|
106
125
|
y: textBbox.y - verticalPadding,
|
|
107
126
|
width: textBbox.width + horizontalPadding * 2,
|
|
108
127
|
height: textBbox.height + verticalPadding * 2,
|
|
109
|
-
rx: 0.015
|
|
128
|
+
rx: 0.015,
|
|
110
129
|
}
|
|
111
|
-
drawSvgElement({tag: "rect", attributes, className: "tooltip_outline", parent: bgPlaceholder})
|
|
130
|
+
drawSvgElement({ tag: "rect", attributes, className: "tooltip_outline", parent: bgPlaceholder })
|
|
112
131
|
}
|
|
113
132
|
|
|
114
|
-
exportDeps({
|
|
115
|
-
|
|
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
|
+
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import WebSocket from
|
|
1
|
+
import WebSocket from "ws"
|
|
2
2
|
|
|
3
3
|
export class WebsocketClient {
|
|
4
|
-
constructor
|
|
4
|
+
constructor({ port, wsInterfaceEmitter, host = "localhost", protocol = "ws" }) {
|
|
5
5
|
this.port = port
|
|
6
6
|
this.host = host
|
|
7
7
|
this.protocol = protocol
|
|
@@ -16,29 +16,29 @@ export class WebsocketClient {
|
|
|
16
16
|
this.startClient()
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
getUrl
|
|
19
|
+
getUrl() {
|
|
20
20
|
return `${this.protocol}://${this.host}:${this.port}`
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
startClient
|
|
23
|
+
startClient() {
|
|
24
24
|
this.socket = new WebSocket(this.getUrl())
|
|
25
|
-
this.socket.addEventListener(
|
|
26
|
-
this.socket.addEventListener(
|
|
27
|
-
this.socket.addEventListener(
|
|
25
|
+
this.socket.addEventListener("open", this._onSocketOpen)
|
|
26
|
+
this.socket.addEventListener("message", this._onSocketMessage)
|
|
27
|
+
this.socket.addEventListener("close", this._onSocketClose)
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
onSocketOpen
|
|
30
|
+
onSocketOpen() {
|
|
31
31
|
this.socketOpen = true
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
onSocketClose
|
|
34
|
+
onSocketClose() {
|
|
35
35
|
this.socketOpen = false
|
|
36
|
-
this.socket.removeEventListener(
|
|
37
|
-
this.socket.removeEventListener(
|
|
38
|
-
this.socket.removeEventListener(
|
|
36
|
+
this.socket.removeEventListener("open", this._onSocketOpen)
|
|
37
|
+
this.socket.removeEventListener("message", this._onSocketMessage)
|
|
38
|
+
this.socket.removeEventListener("close", this._onSocketClose)
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
onSocketMessage
|
|
41
|
+
onSocketMessage(event) {
|
|
42
42
|
let message
|
|
43
43
|
try {
|
|
44
44
|
message = JSON.parse(event.data)
|
|
@@ -46,10 +46,10 @@ export class WebsocketClient {
|
|
|
46
46
|
console.error("Error parsing websocket message JSON", e)
|
|
47
47
|
return
|
|
48
48
|
}
|
|
49
|
-
this.wsInterfaceEmitter.emit(
|
|
49
|
+
this.wsInterfaceEmitter.emit("message", message)
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
sendMessage
|
|
52
|
+
sendMessage(message) {
|
|
53
53
|
const messageStr = JSON.stringify(message)
|
|
54
54
|
this.socket.send(messageStr)
|
|
55
55
|
}
|
|
@@ -2,12 +2,12 @@ import { WebsocketClient } from "./WebsocketClient.js"
|
|
|
2
2
|
import { WtrSession } from "./WtrSession.js"
|
|
3
3
|
import { apiMethods } from "./websocketApi.js"
|
|
4
4
|
import { createWebsocketServer } from "./websocketServer.js"
|
|
5
|
-
import {EventEmitter} from
|
|
5
|
+
import { EventEmitter } from "node:events"
|
|
6
6
|
|
|
7
7
|
const watchActiveFilesMessage = { method: "watch-editor-active-files" }
|
|
8
8
|
|
|
9
9
|
export class WebsocketInterface {
|
|
10
|
-
constructor
|
|
10
|
+
constructor({ port }) {
|
|
11
11
|
this.port = port
|
|
12
12
|
this.emitter = new EventEmitter() // emits "message" events from the server
|
|
13
13
|
this.initMessage = null
|
|
@@ -20,60 +20,68 @@ export class WebsocketInterface {
|
|
|
20
20
|
this._sendQueuedMessages = this._sendQueuedMessages.bind(this)
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
sendInitMessage
|
|
23
|
+
sendInitMessage(initMessage) {
|
|
24
24
|
this.initMessage = initMessage
|
|
25
25
|
this._sendMessageToServer(initMessage)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
sendOpenFileList
|
|
29
|
-
this.openFileListMessage = {method: "update-open-files", files}
|
|
28
|
+
sendOpenFileList(files) {
|
|
29
|
+
this.openFileListMessage = { method: "update-open-files", files }
|
|
30
30
|
this._sendMessageToServer(this.openFileListMessage)
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
sendText
|
|
34
|
-
const sendTextMessage = {method: "relay-text", file, contents}
|
|
33
|
+
sendText({ file, contents }) {
|
|
34
|
+
const sendTextMessage = { method: "relay-text", file, contents }
|
|
35
35
|
this._sendMessageToServer(sendTextMessage)
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
setAllowedHosts
|
|
38
|
+
setAllowedHosts(allowedHostsList) {
|
|
39
39
|
this.allowedHosts = new Set(allowedHostsList)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
setAllowNetworkAccess
|
|
42
|
+
setAllowNetworkAccess(allowNetworkAccessParam) {
|
|
43
43
|
if (allowNetworkAccessParam != null) {
|
|
44
44
|
this.allowNetworkAccess = allowNetworkAccessParam
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
async startInterface
|
|
48
|
+
async startInterface() {
|
|
49
49
|
try {
|
|
50
|
-
await createWebsocketServer({
|
|
51
|
-
|
|
50
|
+
await createWebsocketServer({
|
|
51
|
+
port: this.port,
|
|
52
|
+
allowedHosts: this.allowedHosts,
|
|
53
|
+
allowNetworkAccess: this.allowNetworkAccess,
|
|
54
|
+
})
|
|
55
|
+
this.serverSession = new WtrSession({ apiMethods, wsInterfaceEmitter: this.emitter })
|
|
52
56
|
this._sendQueuedMessages()
|
|
53
|
-
} catch
|
|
54
|
-
this.wsClient = new WebsocketClient({port: this.port, wsInterfaceEmitter: this.emitter})
|
|
55
|
-
this.wsClient.socket.on(
|
|
56
|
-
this.wsClient.socket.on(
|
|
57
|
+
} catch {
|
|
58
|
+
this.wsClient = new WebsocketClient({ port: this.port, wsInterfaceEmitter: this.emitter })
|
|
59
|
+
this.wsClient.socket.on("close", this._onSocketClose)
|
|
60
|
+
this.wsClient.socket.on("open", this._sendQueuedMessages)
|
|
57
61
|
}
|
|
58
62
|
}
|
|
59
63
|
|
|
60
|
-
_onSocketClose
|
|
64
|
+
_onSocketClose() {
|
|
61
65
|
this.wsClient.socket.removeEventListener("close", this._onSocketClose)
|
|
62
66
|
this.wsClient.socket.removeEventListener("open", this._sendQueuedMessages)
|
|
63
67
|
this.wsClient = null
|
|
64
68
|
this.startInterface()
|
|
65
69
|
}
|
|
66
70
|
|
|
67
|
-
_sendQueuedMessages
|
|
71
|
+
_sendQueuedMessages() {
|
|
68
72
|
this._sendMessageToServer(watchActiveFilesMessage)
|
|
69
|
-
if (this.initMessage) {
|
|
70
|
-
|
|
73
|
+
if (this.initMessage) {
|
|
74
|
+
this._sendMessageToServer(this.initMessage)
|
|
75
|
+
}
|
|
76
|
+
if (this.openFileListMessage) {
|
|
77
|
+
this._sendMessageToServer(this.openFileListMessage)
|
|
78
|
+
}
|
|
71
79
|
}
|
|
72
80
|
|
|
73
|
-
_sendMessageToServer
|
|
81
|
+
_sendMessageToServer(message) {
|
|
74
82
|
if (this.serverSession) {
|
|
75
83
|
this.serverSession._handleApiMessage(message)
|
|
76
|
-
} else if (this.wsClient && this.wsClient.socketOpen){
|
|
84
|
+
} else if (this.wsClient && this.wsClient.socketOpen) {
|
|
77
85
|
this.wsClient.sendMessage(message)
|
|
78
86
|
}
|
|
79
87
|
}
|