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
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import { EventEmitter } from
|
|
1
|
+
import { EventEmitter } from "node:events"
|
|
2
2
|
import { getNextId } from "./util.js"
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
startSessionStatus,
|
|
5
|
+
endSessionStatus,
|
|
6
|
+
statusEvents,
|
|
7
|
+
removeWatchedFileLinks,
|
|
8
|
+
} from "./sessionManager.js"
|
|
4
9
|
|
|
5
10
|
export class WtrSession {
|
|
6
|
-
constructor
|
|
11
|
+
constructor({ apiMethods, wsConnection, wsInterfaceEmitter }) {
|
|
7
12
|
this.apiMethods = apiMethods
|
|
8
13
|
this.wsConnection = wsConnection
|
|
9
14
|
this.wsInterfaceEmitter = wsInterfaceEmitter
|
|
@@ -22,45 +27,45 @@ export class WtrSession {
|
|
|
22
27
|
startSessionStatus(this)
|
|
23
28
|
}
|
|
24
29
|
|
|
25
|
-
sendMessageToClient
|
|
30
|
+
sendMessageToClient(message) {
|
|
26
31
|
if (this.wsConnection) {
|
|
27
32
|
this.wsConnection.send(JSON.stringify(message))
|
|
28
33
|
} else {
|
|
29
|
-
this.wsInterfaceEmitter.emit(
|
|
34
|
+
this.wsInterfaceEmitter.emit("message", message)
|
|
30
35
|
}
|
|
31
36
|
}
|
|
32
37
|
|
|
33
|
-
isServer
|
|
38
|
+
isServer() {
|
|
34
39
|
return this.wsInterfaceEmitter != null
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
_subscribeToEvents = () => {
|
|
38
|
-
this.emitter.on(
|
|
39
|
-
this.emitter.on(
|
|
43
|
+
this.emitter.on("log", this._onLog.bind(this))
|
|
44
|
+
this.emitter.on("editor-active-files-update", this._onEditorActiveFilesUpdate.bind(this))
|
|
40
45
|
|
|
41
46
|
this._onActivityUpdate = this._onActivityUpdate.bind(this)
|
|
42
|
-
statusEvents.on(
|
|
47
|
+
statusEvents.on("activity-update", this._onActivityUpdate)
|
|
43
48
|
this._onStatusUpdate = this._onStatusUpdate.bind(this)
|
|
44
|
-
statusEvents.on(
|
|
49
|
+
statusEvents.on("status-update", this._onStatusUpdate)
|
|
45
50
|
|
|
46
51
|
if (this.wsConnection) {
|
|
47
52
|
this._onWsMessage = this._onWsMessage.bind(this)
|
|
48
53
|
this._onWsClose = this._onWsClose.bind(this)
|
|
49
|
-
this.wsConnection.on(
|
|
50
|
-
this.wsConnection.on(
|
|
51
|
-
this.wsConnection.on(
|
|
54
|
+
this.wsConnection.on("message", this._onWsMessage)
|
|
55
|
+
this.wsConnection.on("close", this._onWsClose)
|
|
56
|
+
this.wsConnection.on("error", this._onWsClose)
|
|
52
57
|
}
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
_onWsClose
|
|
60
|
+
_onWsClose() {
|
|
56
61
|
if (this.wsConnection) {
|
|
57
|
-
this.wsConnection.removeListener(
|
|
58
|
-
this.wsConnection.removeListener(
|
|
59
|
-
this.wsConnection.removeListener(
|
|
62
|
+
this.wsConnection.removeListener("message", this._onWsMessage)
|
|
63
|
+
this.wsConnection.removeListener("close", this._onWsClose)
|
|
64
|
+
this.wsConnection.removeListener("error", this._onWsClose)
|
|
60
65
|
}
|
|
61
66
|
|
|
62
|
-
statusEvents.removeListener(
|
|
63
|
-
statusEvents.removeListener(
|
|
67
|
+
statusEvents.removeListener("activity-update", this._onEditorActiveFilesUpdate)
|
|
68
|
+
statusEvents.removeListener("status-update", this._onStatusUpdate)
|
|
64
69
|
|
|
65
70
|
endSessionStatus(this)
|
|
66
71
|
for (const endsWith of this.watchedFiles) {
|
|
@@ -70,52 +75,63 @@ export class WtrSession {
|
|
|
70
75
|
this.emitter.removeAllListeners()
|
|
71
76
|
}
|
|
72
77
|
|
|
73
|
-
_onLog
|
|
74
|
-
if (!this.watchLogMessages) {
|
|
78
|
+
_onLog(data) {
|
|
79
|
+
if (!this.watchLogMessages) {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
75
82
|
this.sendMessageToClient({ method: "watch-log-messages", data })
|
|
76
83
|
}
|
|
77
84
|
|
|
78
|
-
_onEditorActiveFilesUpdate
|
|
79
|
-
if (!this.watchActiveFiles) {
|
|
85
|
+
_onEditorActiveFilesUpdate(files) {
|
|
86
|
+
if (!this.watchActiveFiles) {
|
|
87
|
+
return
|
|
88
|
+
}
|
|
80
89
|
this.sendMessageToClient({ method: "watch-editor-active-files", files })
|
|
81
90
|
}
|
|
82
91
|
|
|
83
|
-
_onActivityUpdate
|
|
84
|
-
if (!this.watchWtrActivity) {
|
|
92
|
+
_onActivityUpdate(data) {
|
|
93
|
+
if (!this.watchWtrActivity) {
|
|
94
|
+
return
|
|
95
|
+
}
|
|
85
96
|
this.sendMessageToClient({ method: "watch-wtr-activity", data })
|
|
86
97
|
}
|
|
87
98
|
|
|
88
|
-
_onStatusUpdate
|
|
89
|
-
if (!this.watchWtrStatus) {
|
|
99
|
+
_onStatusUpdate(data) {
|
|
100
|
+
if (!this.watchWtrStatus) {
|
|
101
|
+
return
|
|
102
|
+
}
|
|
90
103
|
this.sendMessageToClient({ method: "watch-wtr-status", data })
|
|
91
104
|
}
|
|
92
105
|
|
|
93
|
-
_onWsMessage
|
|
106
|
+
_onWsMessage(dataBuf) {
|
|
94
107
|
const str = dataBuf.toString()
|
|
95
108
|
let message
|
|
96
109
|
|
|
97
110
|
try {
|
|
98
111
|
message = JSON.parse(str)
|
|
99
|
-
} catch
|
|
100
|
-
this.emitter.emit(
|
|
112
|
+
} catch {
|
|
113
|
+
this.emitter.emit("log", { level: "error", text: `Could not parse JSON message: ${str}` })
|
|
101
114
|
return
|
|
102
115
|
}
|
|
103
116
|
|
|
104
117
|
this._handleApiMessage(message)
|
|
105
118
|
}
|
|
106
119
|
|
|
107
|
-
_handleApiMessage
|
|
120
|
+
_handleApiMessage(message) {
|
|
108
121
|
const method = message && message.method
|
|
109
122
|
const methodHandler = this.apiMethods.get(method)
|
|
110
123
|
if (!methodHandler) {
|
|
111
|
-
this.emitter.emit(
|
|
124
|
+
this.emitter.emit("log", { level: "error", text: `unknown ws api method: ${method}` })
|
|
112
125
|
return
|
|
113
126
|
}
|
|
114
127
|
|
|
115
128
|
try {
|
|
116
129
|
methodHandler(this, message)
|
|
117
130
|
} catch (e) {
|
|
118
|
-
this.emitter.emit(
|
|
131
|
+
this.emitter.emit("log", {
|
|
132
|
+
level: "error",
|
|
133
|
+
text: `Error while handling method: ${method} : ${e.stacktrace}`,
|
|
134
|
+
})
|
|
119
135
|
console.error("Error while handling ws api method", method, e)
|
|
120
136
|
}
|
|
121
137
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { createServer } from
|
|
2
|
-
import path from
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
|
|
1
|
+
import { createServer } from "node:http"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
import { createReadStream } from "node:fs"
|
|
4
|
+
import fs from "node:fs/promises"
|
|
5
|
+
import * as url from "node:url"
|
|
6
|
+
import { isValidOrigin } from "./util.js"
|
|
7
|
+
const parentDir = url.fileURLToPath(new URL("..", import.meta.url))
|
|
7
8
|
|
|
8
9
|
const uiDirName = "ui"
|
|
9
10
|
const uiDirPath = path.join(parentDir, uiDirName)
|
|
@@ -24,7 +25,9 @@ const getFilePath = (url) => {
|
|
|
24
25
|
|
|
25
26
|
const getFileType = (fileUrl) => {
|
|
26
27
|
const lastDotIndex = fileUrl.lastIndexOf(".")
|
|
27
|
-
if (lastDotIndex < 0 || lastDotIndex >= fileUrl.length) {
|
|
28
|
+
if (lastDotIndex < 0 || lastDotIndex >= fileUrl.length) {
|
|
29
|
+
return ""
|
|
30
|
+
}
|
|
28
31
|
return fileUrl.substring(lastDotIndex + 1)
|
|
29
32
|
}
|
|
30
33
|
|
|
@@ -41,16 +44,23 @@ const requestHandler = (allowedHosts) => (req, res) => {
|
|
|
41
44
|
res.writeHead(404)
|
|
42
45
|
res.end("NOT FOUND!")
|
|
43
46
|
return
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
fs.access(filePath, fs.constants.R_OK)
|
|
50
|
+
.then(() => {
|
|
51
|
+
res.setHeader("Content-Type", contentType)
|
|
52
|
+
res.writeHead(200)
|
|
53
|
+
const fileStream = createReadStream(filePath)
|
|
54
|
+
fileStream.pipe(res)
|
|
55
|
+
})
|
|
56
|
+
.catch((e) => {
|
|
57
|
+
res.writeHead(404)
|
|
58
|
+
res.end("NOT FOUND!")
|
|
59
|
+
})
|
|
49
60
|
}
|
|
50
61
|
|
|
51
|
-
export const createHttpServer = ({port, allowedHosts, allowNetworkAccess}) => {
|
|
62
|
+
export const createHttpServer = ({ port, allowedHosts, allowNetworkAccess }) => {
|
|
52
63
|
return new Promise((resolve, reject) => {
|
|
53
|
-
|
|
54
64
|
const server = createServer(requestHandler(allowedHosts))
|
|
55
65
|
|
|
56
66
|
server.on("error", (e) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { EventEmitter } from
|
|
2
|
-
import { debounce } from
|
|
1
|
+
import { EventEmitter } from "node:events"
|
|
2
|
+
import { debounce } from "./util.js"
|
|
3
3
|
|
|
4
4
|
export const statusEvents = new EventEmitter()
|
|
5
5
|
|
|
@@ -7,14 +7,13 @@ export const wtrSessions = new Set()
|
|
|
7
7
|
|
|
8
8
|
const createUpdateObject = () => {
|
|
9
9
|
const sessions = [...wtrSessions].map((wtrSession) => {
|
|
10
|
-
|
|
11
10
|
const openFileLinks = {}
|
|
12
11
|
for (const [editorFile, fileLinks] of wtrSession.activeOpenFiles) {
|
|
13
12
|
if (!openFileLinks[editorFile]) {
|
|
14
13
|
openFileLinks[editorFile] = []
|
|
15
14
|
}
|
|
16
|
-
for (const {clientSession, endsWith} of fileLinks.values()) {
|
|
17
|
-
openFileLinks[editorFile].push({clientId: clientSession.id, endsWith})
|
|
15
|
+
for (const { clientSession, endsWith } of fileLinks.values()) {
|
|
16
|
+
openFileLinks[editorFile].push({ clientId: clientSession.id, endsWith })
|
|
18
17
|
}
|
|
19
18
|
}
|
|
20
19
|
|
|
@@ -26,16 +25,16 @@ const createUpdateObject = () => {
|
|
|
26
25
|
isServer: wtrSession.isServer(),
|
|
27
26
|
watchCount: wtrSession.watchedFiles.size,
|
|
28
27
|
openCount: wtrSession.openFiles.size,
|
|
29
|
-
openFileLinks
|
|
28
|
+
openFileLinks,
|
|
30
29
|
}
|
|
31
30
|
})
|
|
32
31
|
|
|
33
|
-
return {sessions}
|
|
32
|
+
return { sessions }
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
const sendUpdate = () => {
|
|
37
36
|
const updateObject = createUpdateObject()
|
|
38
|
-
statusEvents.emit(
|
|
37
|
+
statusEvents.emit("status-update", updateObject)
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
export const triggerStatusUpdate = debounce(100, sendUpdate)
|
|
@@ -61,12 +60,14 @@ const createWatchLink = (wtrSession, editorFile, clientSession, endsWith) => {
|
|
|
61
60
|
const linkKey = createLinkKey(clientSession, endsWith)
|
|
62
61
|
fileLinks.set(linkKey, { clientSession, endsWith })
|
|
63
62
|
triggerStatusUpdate()
|
|
64
|
-
wtrSession.emitter.emit(
|
|
63
|
+
wtrSession.emitter.emit("editor-active-files-update", [...wtrSession.activeOpenFiles.keys()])
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
export const addOpenedFileLinks = (wtrSession, editorFile) => {
|
|
68
67
|
for (const clientSession of wtrSessions) {
|
|
69
|
-
if (clientSession === wtrSession) {
|
|
68
|
+
if (clientSession === wtrSession) {
|
|
69
|
+
continue
|
|
70
|
+
}
|
|
70
71
|
for (const endsWith of clientSession.watchedFiles) {
|
|
71
72
|
if (editorFile.endsWith(endsWith)) {
|
|
72
73
|
createWatchLink(wtrSession, editorFile, clientSession, endsWith)
|
|
@@ -77,13 +78,15 @@ export const addOpenedFileLinks = (wtrSession, editorFile) => {
|
|
|
77
78
|
|
|
78
79
|
export const removeOpenedFileLinks = (wtrSession, editorFile) => {
|
|
79
80
|
wtrSession.activeOpenFiles.delete(editorFile)
|
|
80
|
-
wtrSession.emitter.emit(
|
|
81
|
+
wtrSession.emitter.emit("editor-active-files-update", [...wtrSession.activeOpenFiles.keys()])
|
|
81
82
|
triggerStatusUpdate()
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
export const addWatchedFileLinks = (clientSession, endsWith) => {
|
|
85
86
|
for (const wtrSession of wtrSessions) {
|
|
86
|
-
if (wtrSession === clientSession) {
|
|
87
|
+
if (wtrSession === clientSession) {
|
|
88
|
+
continue
|
|
89
|
+
}
|
|
87
90
|
for (const editorFile of wtrSession.openFiles) {
|
|
88
91
|
if (editorFile.endsWith(endsWith)) {
|
|
89
92
|
createWatchLink(wtrSession, editorFile, clientSession, endsWith)
|
|
@@ -99,7 +102,7 @@ export const removeWatchedFileLinks = (clientSession, endsWith) => {
|
|
|
99
102
|
fileLinks.delete(linkKey)
|
|
100
103
|
if (fileLinks.size === 0) {
|
|
101
104
|
wtrSession.activeOpenFiles.delete(editorFile)
|
|
102
|
-
wtrSession.emitter.emit(
|
|
105
|
+
wtrSession.emitter.emit("editor-active-files-update", [...wtrSession.activeOpenFiles.keys()])
|
|
103
106
|
triggerStatusUpdate()
|
|
104
107
|
}
|
|
105
108
|
}
|
|
@@ -14,7 +14,7 @@ export const getNextId = () => currentId++
|
|
|
14
14
|
const defaultAllowedHost = "localhost"
|
|
15
15
|
|
|
16
16
|
export const isValidOrigin = (allowedHosts, req) => {
|
|
17
|
-
const {host, origin} = req.headers
|
|
17
|
+
const { host, origin } = req.headers
|
|
18
18
|
let hostname
|
|
19
19
|
|
|
20
20
|
if (origin == null || origin.length === 0) {
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
triggerStatusUpdate,
|
|
3
|
+
statusEvents,
|
|
4
|
+
addWatchedFileLinks,
|
|
5
|
+
removeWatchedFileLinks,
|
|
6
|
+
removeOpenedFileLinks,
|
|
7
|
+
addOpenedFileLinks,
|
|
8
|
+
} from "./sessionManager.js"
|
|
2
9
|
|
|
3
10
|
export const apiMethods = new Map([
|
|
4
11
|
["watch-log-messages", watchLogMessages],
|
|
@@ -16,45 +23,51 @@ export const apiMethods = new Map([
|
|
|
16
23
|
["unwatch-wtr-activity", unwatchWtrActivity],
|
|
17
24
|
])
|
|
18
25
|
|
|
19
|
-
function watchLogMessages
|
|
26
|
+
function watchLogMessages(wtrSession) {
|
|
20
27
|
wtrSession.watchLogMessages = true
|
|
21
|
-
wtrSession.emitter.emit(
|
|
28
|
+
wtrSession.emitter.emit("log", { level: "info", text: "Watching WTR log messages" })
|
|
22
29
|
}
|
|
23
30
|
|
|
24
|
-
function unwatchLogMessages
|
|
25
|
-
wtrSession.emitter.emit(
|
|
31
|
+
function unwatchLogMessages(wtrSession) {
|
|
32
|
+
wtrSession.emitter.emit("log", { level: "info", text: "Unwatching WTR log messages" })
|
|
26
33
|
wtrSession.watchLogMessages = false
|
|
27
34
|
}
|
|
28
35
|
|
|
29
|
-
function init
|
|
36
|
+
function init(wtrSession, data) {
|
|
30
37
|
wtrSession.name = data.name
|
|
31
38
|
wtrSession.editorPid = data.editorPid
|
|
32
39
|
wtrSession.lsPid = data.lsPid
|
|
33
40
|
triggerStatusUpdate()
|
|
34
|
-
wtrSession.emitter.emit(
|
|
41
|
+
wtrSession.emitter.emit("log", { level: "info", text: "Init success" })
|
|
35
42
|
}
|
|
36
43
|
|
|
37
|
-
function watchFile
|
|
44
|
+
function watchFile(wtrSession, data) {
|
|
38
45
|
if (data.endsWith == null || data.endsWith.length === 0) {
|
|
39
|
-
wtrSession.emitter.emit(
|
|
46
|
+
wtrSession.emitter.emit("log", { level: "error", text: "Must provide an endsWith property" })
|
|
40
47
|
return
|
|
41
48
|
}
|
|
42
49
|
wtrSession.watchedFiles.add(data.endsWith)
|
|
43
50
|
addWatchedFileLinks(wtrSession, data.endsWith)
|
|
44
|
-
wtrSession.emitter.emit(
|
|
51
|
+
wtrSession.emitter.emit("log", {
|
|
52
|
+
level: "info",
|
|
53
|
+
text: `Watching files that end with ${data.endsWith}`,
|
|
54
|
+
})
|
|
45
55
|
}
|
|
46
56
|
|
|
47
|
-
function unwatchFile
|
|
57
|
+
function unwatchFile(wtrSession, data) {
|
|
48
58
|
if (data.endsWith == null || data.endsWith.length === 0) {
|
|
49
|
-
wtrSession.emitter.emit(
|
|
59
|
+
wtrSession.emitter.emit("log", { level: "error", text: "Must provide an endsWith property" })
|
|
50
60
|
return
|
|
51
61
|
}
|
|
52
62
|
wtrSession.watchedFiles.delete(data.endsWith)
|
|
53
63
|
removeWatchedFileLinks(wtrSession, data.endsWith)
|
|
54
|
-
wtrSession.emitter.emit(
|
|
64
|
+
wtrSession.emitter.emit("log", {
|
|
65
|
+
level: "info",
|
|
66
|
+
text: `No longer watching files that end with ${data.endsWith}`,
|
|
67
|
+
})
|
|
55
68
|
}
|
|
56
69
|
|
|
57
|
-
function updateEditorOpenFiles
|
|
70
|
+
function updateEditorOpenFiles(wtrSession, data) {
|
|
58
71
|
const updatedFileSet = new Set(data.files)
|
|
59
72
|
for (const fileName of wtrSession.openFiles) {
|
|
60
73
|
if (!updatedFileSet.has(fileName)) {
|
|
@@ -71,46 +84,50 @@ function updateEditorOpenFiles (wtrSession, data) {
|
|
|
71
84
|
triggerStatusUpdate()
|
|
72
85
|
}
|
|
73
86
|
|
|
74
|
-
function watchEditorActiveFiles
|
|
87
|
+
function watchEditorActiveFiles(wtrSession) {
|
|
75
88
|
wtrSession.watchActiveFiles = true
|
|
76
|
-
wtrSession.emitter.emit(
|
|
89
|
+
wtrSession.emitter.emit("log", { level: "info", text: "Watching editor active files" })
|
|
77
90
|
}
|
|
78
91
|
|
|
79
|
-
function unwatchEditorActiveFiles
|
|
80
|
-
wtrSession.emitter.emit(
|
|
92
|
+
function unwatchEditorActiveFiles(wtrSession) {
|
|
93
|
+
wtrSession.emitter.emit("log", { level: "info", text: "Unwatching editor active files" })
|
|
81
94
|
wtrSession.watchActiveFiles = false
|
|
82
95
|
}
|
|
83
96
|
|
|
84
|
-
function relayText
|
|
85
|
-
if (!data || !data.file) {
|
|
86
|
-
|
|
97
|
+
function relayText(wtrSession, data) {
|
|
98
|
+
if (!data || !data.file) {
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
const { file, contents } = data
|
|
87
102
|
const watchers = wtrSession.activeOpenFiles.get(file)
|
|
88
|
-
if (!watchers) {
|
|
103
|
+
if (!watchers) {
|
|
104
|
+
return
|
|
105
|
+
}
|
|
89
106
|
const watcherSessionIds = []
|
|
90
|
-
for (const {clientSession: watcherWtrSession, endsWith} of watchers.values()) {
|
|
107
|
+
for (const { clientSession: watcherWtrSession, endsWith } of watchers.values()) {
|
|
91
108
|
watcherSessionIds.push(watcherWtrSession.id)
|
|
92
|
-
watcherWtrSession.sendMessageToClient({method: "watch-file", endsWith, contents})
|
|
109
|
+
watcherWtrSession.sendMessageToClient({ method: "watch-file", endsWith, contents })
|
|
93
110
|
}
|
|
94
|
-
const activityData = {action: "relay", relayer: wtrSession.id, watchers: watcherSessionIds}
|
|
95
|
-
statusEvents.emit(
|
|
111
|
+
const activityData = { action: "relay", relayer: wtrSession.id, watchers: watcherSessionIds }
|
|
112
|
+
statusEvents.emit("activity-update", activityData)
|
|
96
113
|
}
|
|
97
114
|
|
|
98
|
-
function watchWtrStatus
|
|
115
|
+
function watchWtrStatus(wtrSession) {
|
|
99
116
|
wtrSession.watchWtrStatus = true
|
|
100
|
-
wtrSession.emitter.emit(
|
|
117
|
+
wtrSession.emitter.emit("log", { level: "info", text: "Watching WTR status updates" })
|
|
101
118
|
}
|
|
102
119
|
|
|
103
|
-
function unwatchWtrStatus
|
|
104
|
-
wtrSession.emitter.emit(
|
|
120
|
+
function unwatchWtrStatus(wtrSession) {
|
|
121
|
+
wtrSession.emitter.emit("log", { level: "info", text: "Unwatching WTR status updates" })
|
|
105
122
|
wtrSession.watchWtrStatus = false
|
|
106
123
|
}
|
|
107
124
|
|
|
108
|
-
function watchWtrActivity
|
|
125
|
+
function watchWtrActivity(wtrSession) {
|
|
109
126
|
wtrSession.watchWtrActivity = true
|
|
110
|
-
wtrSession.emitter.emit(
|
|
127
|
+
wtrSession.emitter.emit("log", { level: "info", text: "Watching WTR activity events" })
|
|
111
128
|
}
|
|
112
129
|
|
|
113
|
-
function unwatchWtrActivity
|
|
114
|
-
wtrSession.emitter.emit(
|
|
130
|
+
function unwatchWtrActivity(wtrSession) {
|
|
131
|
+
wtrSession.emitter.emit("log", { level: "info", text: "Unwatching WTR activity events" })
|
|
115
132
|
wtrSession.watchWtrActivity = false
|
|
116
133
|
}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { WebSocketServer } from
|
|
1
|
+
import { WebSocketServer } from "ws"
|
|
2
2
|
import { createHttpServer } from "./httpServer.js"
|
|
3
3
|
import { apiMethods } from "./websocketApi.js"
|
|
4
|
-
import { WtrSession } from
|
|
5
|
-
import { isValidOrigin } from
|
|
4
|
+
import { WtrSession } from "./WtrSession.js"
|
|
5
|
+
import { isValidOrigin } from "./util.js"
|
|
6
6
|
|
|
7
|
-
export const createWebsocketServer = async ({port, allowedHosts, allowNetworkAccess}) => {
|
|
8
|
-
const httpServer = await createHttpServer({port, allowedHosts, allowNetworkAccess}) // promise will reject if can't start HTTP server on specified port
|
|
7
|
+
export const createWebsocketServer = async ({ port, allowedHosts, allowNetworkAccess }) => {
|
|
8
|
+
const httpServer = await createHttpServer({ port, allowedHosts, allowNetworkAccess }) // promise will reject if can't start HTTP server on specified port
|
|
9
9
|
|
|
10
10
|
const websocketServer = new WebSocketServer({ server: httpServer })
|
|
11
|
-
|
|
12
|
-
websocketServer.on('error', () => { })
|
|
13
11
|
|
|
14
|
-
websocketServer.on(
|
|
12
|
+
websocketServer.on("error", () => {})
|
|
13
|
+
|
|
14
|
+
websocketServer.on("connection", (wsConnection, request) => {
|
|
15
15
|
if (!isValidOrigin(allowedHosts, request)) {
|
|
16
16
|
wsConnection.close()
|
|
17
17
|
return
|
|
18
18
|
}
|
|
19
|
-
new WtrSession({apiMethods, wsConnection})
|
|
19
|
+
new WtrSession({ apiMethods, wsConnection })
|
|
20
20
|
})
|
|
21
21
|
|
|
22
22
|
return websocketServer
|
package/start.js
CHANGED
package/.eslintrc
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"root": true,
|
|
3
|
-
"extends": [
|
|
4
|
-
"eslint:recommended"
|
|
5
|
-
],
|
|
6
|
-
"rules": {
|
|
7
|
-
"semi": ["error", "never"],
|
|
8
|
-
"indent": ["error", 2],
|
|
9
|
-
"no-multiple-empty-lines": ["error", { "max": 1 }],
|
|
10
|
-
"no-unused-vars": 1,
|
|
11
|
-
"no-return-assign": 0,
|
|
12
|
-
"multiline-ternary": 0,
|
|
13
|
-
"object-curly-spacing": 0,
|
|
14
|
-
"object-property-newline": 0,
|
|
15
|
-
"object-curly-newline": 0,
|
|
16
|
-
"quotes": 0,
|
|
17
|
-
"quote-props": 0,
|
|
18
|
-
"import/no-absolute-path": 0
|
|
19
|
-
},
|
|
20
|
-
"env": {
|
|
21
|
-
"node": true,
|
|
22
|
-
"browser": true,
|
|
23
|
-
"es2024": true
|
|
24
|
-
},
|
|
25
|
-
"parserOptions": {
|
|
26
|
-
"sourceType": "module",
|
|
27
|
-
"ecmaVersion": "latest"
|
|
28
|
-
}
|
|
29
|
-
}
|