@lvce-editor/server 0.116.12 → 0.116.14
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/ThirdPartyNotices.txt +2 -2
- package/package.json +3 -3
- package/src/sendSocket.js +16 -0
- package/src/server.js +4 -5
- package/test/fixtures/socket-transfer-child.js +25 -0
- package/test/sendSocket.test.js +23 -0
package/ThirdPartyNotices.txt
CHANGED
|
@@ -2,7 +2,7 @@ This project incorporates components from the projects listed below, that may ha
|
|
|
2
2
|
differing from this project:
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
1) License Notice for static/
|
|
5
|
+
1) License Notice for static/e271222/icons (from https://github.com/microsoft/vscode-codicons)
|
|
6
6
|
---------------------------------------
|
|
7
7
|
|
|
8
8
|
Attribution 4.0 International
|
|
@@ -402,7 +402,7 @@ public licenses.
|
|
|
402
402
|
Creative Commons may be contacted at creativecommons.org.
|
|
403
403
|
|
|
404
404
|
|
|
405
|
-
2) License Notice for static/
|
|
405
|
+
2) License Notice for static/e271222/fonts/FiraCode-VariableFont.ttf (from https://github.com/tonsky/FiraCode)
|
|
406
406
|
---------------------------------------
|
|
407
407
|
|
|
408
408
|
Copyright (c) 2014, The Fira Code Project Authors (https://github.com/tonsky/FiraCode)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lvce-editor/server",
|
|
3
|
-
"version": "0.116.
|
|
3
|
+
"version": "0.116.14",
|
|
4
4
|
"description": "Run LVCE Editor as a server.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": "bin/server.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@lvce-editor/jsonc-parser": "^1.5.2",
|
|
24
|
-
"@lvce-editor/shared-process": "0.116.
|
|
25
|
-
"@lvce-editor/static-server": "0.116.
|
|
24
|
+
"@lvce-editor/shared-process": "0.116.14",
|
|
25
|
+
"@lvce-editor/static-server": "0.116.14"
|
|
26
26
|
}
|
|
27
27
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const sendSocket = (childProcess, message, socket) => {
|
|
2
|
+
socket.pause()
|
|
3
|
+
const handle = socket._handle
|
|
4
|
+
if (handle) {
|
|
5
|
+
// pause() stops stream delivery, but can leave the native read active.
|
|
6
|
+
// send() discards reads on the parent's handle until the child acknowledges
|
|
7
|
+
// the transfer, so stop that read before the peer can send its first frame.
|
|
8
|
+
const status = handle.readStop()
|
|
9
|
+
if (status !== 0) {
|
|
10
|
+
socket.destroy()
|
|
11
|
+
throw new Error(`Unable to stop socket reads before transfer (${status})`)
|
|
12
|
+
}
|
|
13
|
+
handle.reading = false
|
|
14
|
+
}
|
|
15
|
+
childProcess.send(message, socket, { keepOpen: false })
|
|
16
|
+
}
|
package/src/server.js
CHANGED
|
@@ -7,6 +7,7 @@ import { fileURLToPath } from 'node:url'
|
|
|
7
7
|
import { Worker } from 'node:worker_threads'
|
|
8
8
|
import * as ArgvConfig from './argvConfig.js'
|
|
9
9
|
import { getRemoteSshOptions, isAuthenticatedRemoteRequest } from './remoteSshOptions.js'
|
|
10
|
+
import { sendSocket } from './sendSocket.js'
|
|
10
11
|
|
|
11
12
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
12
13
|
const ROOT = resolve(__dirname, '../')
|
|
@@ -77,7 +78,7 @@ const isStatic = (url) => {
|
|
|
77
78
|
if (url === '/index.html' || url.startsWith('/index.html?')) {
|
|
78
79
|
return !hasLinkedExtensions
|
|
79
80
|
}
|
|
80
|
-
if (url.startsWith('/
|
|
81
|
+
if (url.startsWith('/e271222')) {
|
|
81
82
|
return true
|
|
82
83
|
}
|
|
83
84
|
if (url.startsWith('/favicon.ico')) {
|
|
@@ -284,16 +285,14 @@ const sendHandleSharedProcess = async (request, socket, method, ...params) => {
|
|
|
284
285
|
}
|
|
285
286
|
socket.on('error', handleSocketError)
|
|
286
287
|
const sharedProcess = await getOrCreateSharedProcess()
|
|
287
|
-
|
|
288
|
+
sendSocket(
|
|
289
|
+
sharedProcess,
|
|
288
290
|
{
|
|
289
291
|
jsonrpc: '2.0',
|
|
290
292
|
method,
|
|
291
293
|
params: [getHandleMessage(request), ...params],
|
|
292
294
|
},
|
|
293
295
|
socket,
|
|
294
|
-
{
|
|
295
|
-
keepOpen: false,
|
|
296
|
-
},
|
|
297
296
|
)
|
|
298
297
|
}
|
|
299
298
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Delay the handoff acknowledgement so the sender still owns a native handle
|
|
2
|
+
// when the peer sends its first request.
|
|
3
|
+
const send = process._send
|
|
4
|
+
process._send = function (message, ...args) {
|
|
5
|
+
if (message?.cmd === 'NODE_HANDLE_ACK') {
|
|
6
|
+
setTimeout(() => send.call(this, message, ...args), 200)
|
|
7
|
+
return true
|
|
8
|
+
}
|
|
9
|
+
return send.call(this, message, ...args)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
process.on('message', (_message, socket) => {
|
|
13
|
+
socket.pause()
|
|
14
|
+
socket._handle.readStop()
|
|
15
|
+
socket._handle.reading = false
|
|
16
|
+
socket.write('ready\n')
|
|
17
|
+
// Keep the receiver from winning the competing read while the sender's
|
|
18
|
+
// handle is waiting for its acknowledgement.
|
|
19
|
+
setTimeout(() => {
|
|
20
|
+
socket.on('data', (data) => socket.end(data))
|
|
21
|
+
socket._handle.readStart()
|
|
22
|
+
socket._handle.reading = true
|
|
23
|
+
socket.resume()
|
|
24
|
+
}, 100)
|
|
25
|
+
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import { fork } from 'node:child_process'
|
|
3
|
+
import { once } from 'node:events'
|
|
4
|
+
import { createConnection, createServer } from 'node:net'
|
|
5
|
+
import test from 'node:test'
|
|
6
|
+
import { sendSocket } from '../src/sendSocket.js'
|
|
7
|
+
|
|
8
|
+
test('preserves the first request while the child has not acknowledged the socket handoff', { timeout: 10000 }, async (context) => {
|
|
9
|
+
const child = fork(new URL('./fixtures/socket-transfer-child.js', import.meta.url))
|
|
10
|
+
context.after(() => child.kill())
|
|
11
|
+
const server = createServer((socket) => sendSocket(child, { type: 'socket' }, socket))
|
|
12
|
+
context.after(() => server.close())
|
|
13
|
+
server.listen(0, '127.0.0.1')
|
|
14
|
+
await once(server, 'listening')
|
|
15
|
+
const client = createConnection(server.address().port, '127.0.0.1')
|
|
16
|
+
context.after(() => client.destroy())
|
|
17
|
+
const [ready] = await once(client, 'data')
|
|
18
|
+
assert.equal(ready.toString(), 'ready\n')
|
|
19
|
+
const response = once(client, 'data', { signal: AbortSignal.timeout(5000) })
|
|
20
|
+
client.write('first request')
|
|
21
|
+
const [data] = await response
|
|
22
|
+
assert.equal(data.toString(), 'first request')
|
|
23
|
+
})
|