dsh-crate-web 0.1.0 → 0.1.1
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/LICENSE +21 -0
- package/core/dsh_pack/importer.py +1347 -1347
- package/core/dsh_pack/verify.py +1336 -1336
- package/package.json +3 -2
- package/restart-helper.mjs +121 -121
- package/runtime/python/LICENSE.txt +676 -676
- package/runtime/python/__install__.json +81 -81
- package/runtime/python/python314._pth +6 -6
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-crate-web",
|
|
3
3
|
"description": "DSH Web Settings surface for DSH Crate export, import, inspect, and history",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/types/index.d.ts",
|
|
@@ -69,5 +69,6 @@
|
|
|
69
69
|
"repository": {
|
|
70
70
|
"type": "git",
|
|
71
71
|
"url": "https://github.com/joezhou172/dsh-crate-web.git"
|
|
72
|
-
}
|
|
72
|
+
},
|
|
73
|
+
"author": "joezhou172 <rdhwhyhrg@163.com>"
|
|
73
74
|
}
|
package/restart-helper.mjs
CHANGED
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process'
|
|
2
|
-
import { mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { openSync } from 'node:fs'
|
|
4
|
-
import { dirname } from 'node:path'
|
|
5
|
-
|
|
6
|
-
const encoded = process.argv[2]
|
|
7
|
-
if (!encoded) process.exit(2)
|
|
8
|
-
|
|
9
|
-
const spec = JSON.parse(Buffer.from(encoded, 'base64url').toString('utf8'))
|
|
10
|
-
const sleep = milliseconds => new Promise(resolve => setTimeout(resolve, milliseconds))
|
|
11
|
-
|
|
12
|
-
async function writeReport(value) {
|
|
13
|
-
await mkdir(dirname(spec.reportPath), { recursive: true })
|
|
14
|
-
await writeFile(spec.reportPath, `${JSON.stringify(value, null, 2)}\n`, { encoding: 'utf8' })
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function alive(pid) {
|
|
18
|
-
if (!Number.isInteger(pid) || pid <= 0) return false
|
|
19
|
-
try {
|
|
20
|
-
process.kill(pid, 0)
|
|
21
|
-
return true
|
|
22
|
-
} catch {
|
|
23
|
-
return false
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async function waitForExit(pid, timeoutMs) {
|
|
28
|
-
const deadline = Date.now() + timeoutMs
|
|
29
|
-
while (alive(pid) && Date.now() < deadline) await sleep(250)
|
|
30
|
-
return !alive(pid)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async function httpReady(url, timeoutMs) {
|
|
34
|
-
const deadline = Date.now() + timeoutMs
|
|
35
|
-
while (Date.now() < deadline) {
|
|
36
|
-
try {
|
|
37
|
-
const response = await fetch(url, { signal: AbortSignal.timeout(2000) })
|
|
38
|
-
if (response.status >= 200 && response.status < 300) return true
|
|
39
|
-
} catch {
|
|
40
|
-
// The new DSH listener may need a few seconds to bind.
|
|
41
|
-
}
|
|
42
|
-
await sleep(500)
|
|
43
|
-
}
|
|
44
|
-
return false
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async function logTail(path) {
|
|
48
|
-
try {
|
|
49
|
-
const value = await readFile(path, 'utf8')
|
|
50
|
-
return value.slice(-12000)
|
|
51
|
-
} catch {
|
|
52
|
-
return ''
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
await writeReport({
|
|
57
|
-
status: 'pending',
|
|
58
|
-
operationId: spec.operationId,
|
|
59
|
-
stage: 'stopping',
|
|
60
|
-
oldProfile: spec.oldProfile,
|
|
61
|
-
targetProfile: spec.targetProfile,
|
|
62
|
-
message: 'Waiting for the previous DSH process to exit.',
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
if (!(await waitForExit(spec.oldPid, 30000))) {
|
|
66
|
-
await writeReport({
|
|
67
|
-
status: 'failed', code: 'PROFILE_SWITCH_STOP_TIMEOUT', stage: 'stop',
|
|
68
|
-
operationId: spec.operationId, oldProfile: spec.oldProfile, targetProfile: spec.targetProfile,
|
|
69
|
-
item: String(spec.oldPid), expected: 'the previous DSH process exits', observed: 'the previous process is still running',
|
|
70
|
-
evidence: { pid: spec.oldPid }, impact: 'The target Profile was not started.', canContinue: false,
|
|
71
|
-
suggestedNextStep: 'Stop the current DSH process and retry switching the Profile.',
|
|
72
|
-
message: 'Timed out while stopping the previous DSH process.',
|
|
73
|
-
})
|
|
74
|
-
process.exit(1)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
await writeReport({
|
|
78
|
-
status: 'pending',
|
|
79
|
-
operationId: spec.operationId,
|
|
80
|
-
stage: 'boot',
|
|
81
|
-
oldProfile: spec.oldProfile,
|
|
82
|
-
targetProfile: spec.targetProfile,
|
|
83
|
-
message: 'Starting the target Profile.',
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
const stdoutPath = `${spec.reportPath}.stdout.log`
|
|
87
|
-
const stderrPath = `${spec.reportPath}.stderr.log`
|
|
88
|
-
const stdout = openSync(stdoutPath, 'a')
|
|
89
|
-
const stderr = openSync(stderrPath, 'a')
|
|
90
|
-
const child = spawn(spec.nodePath, [spec.scriptPath, ...spec.args], {
|
|
91
|
-
cwd: spec.cwd,
|
|
92
|
-
env: spec.env,
|
|
93
|
-
detached: true,
|
|
94
|
-
windowsHide: true,
|
|
95
|
-
stdio: ['ignore', stdout, stderr],
|
|
96
|
-
})
|
|
97
|
-
child.unref()
|
|
98
|
-
|
|
99
|
-
const ready = await httpReady(spec.url, 60000)
|
|
100
|
-
if (ready) {
|
|
101
|
-
await writeReport({
|
|
102
|
-
status: 'ready', code: 'PROFILE_SWITCH_READY', stage: 'ready',
|
|
103
|
-
operationId: spec.operationId, oldProfile: spec.oldProfile, targetProfile: spec.targetProfile,
|
|
104
|
-
pid: child.pid, url: spec.url, expected: 'the target DSH Profile is ready', observed: 'HTTP ready response received',
|
|
105
|
-
evidence: { pid: child.pid, url: spec.url }, impact: 'The DSH runtime is now using the target Profile.', canContinue: true,
|
|
106
|
-
suggestedNextStep: 'Continue using the DSH runtime.', message: 'Profile switched and DSH restarted successfully.',
|
|
107
|
-
})
|
|
108
|
-
process.exit(0)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
await writeReport({
|
|
112
|
-
status: 'failed', code: 'PROFILE_SWITCH_BOOT_FAILED', stage: 'boot',
|
|
113
|
-
operationId: spec.operationId, oldProfile: spec.oldProfile, targetProfile: spec.targetProfile,
|
|
114
|
-
pid: child.pid, item: spec.targetProfile, expected: 'the target DSH Profile becomes HTTP ready', observed: 'HTTP ready was not detected',
|
|
115
|
-
evidence: { pid: child.pid, url: spec.url, stdout: await logTail(stdoutPath), stderr: await logTail(stderrPath) },
|
|
116
|
-
impact: 'The target Profile could not be started or did not become ready.', canContinue: false,
|
|
117
|
-
suggestedNextStep: 'Review stderr and verify the target Profile composition, then retry.',
|
|
118
|
-
message: 'The target Profile failed to become ready.',
|
|
119
|
-
})
|
|
120
|
-
try { process.kill(child.pid) } catch { /* already stopped */ }
|
|
121
|
-
process.exit(1)
|
|
1
|
+
import { spawn } from 'node:child_process'
|
|
2
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
3
|
+
import { openSync } from 'node:fs'
|
|
4
|
+
import { dirname } from 'node:path'
|
|
5
|
+
|
|
6
|
+
const encoded = process.argv[2]
|
|
7
|
+
if (!encoded) process.exit(2)
|
|
8
|
+
|
|
9
|
+
const spec = JSON.parse(Buffer.from(encoded, 'base64url').toString('utf8'))
|
|
10
|
+
const sleep = milliseconds => new Promise(resolve => setTimeout(resolve, milliseconds))
|
|
11
|
+
|
|
12
|
+
async function writeReport(value) {
|
|
13
|
+
await mkdir(dirname(spec.reportPath), { recursive: true })
|
|
14
|
+
await writeFile(spec.reportPath, `${JSON.stringify(value, null, 2)}\n`, { encoding: 'utf8' })
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function alive(pid) {
|
|
18
|
+
if (!Number.isInteger(pid) || pid <= 0) return false
|
|
19
|
+
try {
|
|
20
|
+
process.kill(pid, 0)
|
|
21
|
+
return true
|
|
22
|
+
} catch {
|
|
23
|
+
return false
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function waitForExit(pid, timeoutMs) {
|
|
28
|
+
const deadline = Date.now() + timeoutMs
|
|
29
|
+
while (alive(pid) && Date.now() < deadline) await sleep(250)
|
|
30
|
+
return !alive(pid)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function httpReady(url, timeoutMs) {
|
|
34
|
+
const deadline = Date.now() + timeoutMs
|
|
35
|
+
while (Date.now() < deadline) {
|
|
36
|
+
try {
|
|
37
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(2000) })
|
|
38
|
+
if (response.status >= 200 && response.status < 300) return true
|
|
39
|
+
} catch {
|
|
40
|
+
// The new DSH listener may need a few seconds to bind.
|
|
41
|
+
}
|
|
42
|
+
await sleep(500)
|
|
43
|
+
}
|
|
44
|
+
return false
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function logTail(path) {
|
|
48
|
+
try {
|
|
49
|
+
const value = await readFile(path, 'utf8')
|
|
50
|
+
return value.slice(-12000)
|
|
51
|
+
} catch {
|
|
52
|
+
return ''
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
await writeReport({
|
|
57
|
+
status: 'pending',
|
|
58
|
+
operationId: spec.operationId,
|
|
59
|
+
stage: 'stopping',
|
|
60
|
+
oldProfile: spec.oldProfile,
|
|
61
|
+
targetProfile: spec.targetProfile,
|
|
62
|
+
message: 'Waiting for the previous DSH process to exit.',
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
if (!(await waitForExit(spec.oldPid, 30000))) {
|
|
66
|
+
await writeReport({
|
|
67
|
+
status: 'failed', code: 'PROFILE_SWITCH_STOP_TIMEOUT', stage: 'stop',
|
|
68
|
+
operationId: spec.operationId, oldProfile: spec.oldProfile, targetProfile: spec.targetProfile,
|
|
69
|
+
item: String(spec.oldPid), expected: 'the previous DSH process exits', observed: 'the previous process is still running',
|
|
70
|
+
evidence: { pid: spec.oldPid }, impact: 'The target Profile was not started.', canContinue: false,
|
|
71
|
+
suggestedNextStep: 'Stop the current DSH process and retry switching the Profile.',
|
|
72
|
+
message: 'Timed out while stopping the previous DSH process.',
|
|
73
|
+
})
|
|
74
|
+
process.exit(1)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
await writeReport({
|
|
78
|
+
status: 'pending',
|
|
79
|
+
operationId: spec.operationId,
|
|
80
|
+
stage: 'boot',
|
|
81
|
+
oldProfile: spec.oldProfile,
|
|
82
|
+
targetProfile: spec.targetProfile,
|
|
83
|
+
message: 'Starting the target Profile.',
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
const stdoutPath = `${spec.reportPath}.stdout.log`
|
|
87
|
+
const stderrPath = `${spec.reportPath}.stderr.log`
|
|
88
|
+
const stdout = openSync(stdoutPath, 'a')
|
|
89
|
+
const stderr = openSync(stderrPath, 'a')
|
|
90
|
+
const child = spawn(spec.nodePath, [spec.scriptPath, ...spec.args], {
|
|
91
|
+
cwd: spec.cwd,
|
|
92
|
+
env: spec.env,
|
|
93
|
+
detached: true,
|
|
94
|
+
windowsHide: true,
|
|
95
|
+
stdio: ['ignore', stdout, stderr],
|
|
96
|
+
})
|
|
97
|
+
child.unref()
|
|
98
|
+
|
|
99
|
+
const ready = await httpReady(spec.url, 60000)
|
|
100
|
+
if (ready) {
|
|
101
|
+
await writeReport({
|
|
102
|
+
status: 'ready', code: 'PROFILE_SWITCH_READY', stage: 'ready',
|
|
103
|
+
operationId: spec.operationId, oldProfile: spec.oldProfile, targetProfile: spec.targetProfile,
|
|
104
|
+
pid: child.pid, url: spec.url, expected: 'the target DSH Profile is ready', observed: 'HTTP ready response received',
|
|
105
|
+
evidence: { pid: child.pid, url: spec.url }, impact: 'The DSH runtime is now using the target Profile.', canContinue: true,
|
|
106
|
+
suggestedNextStep: 'Continue using the DSH runtime.', message: 'Profile switched and DSH restarted successfully.',
|
|
107
|
+
})
|
|
108
|
+
process.exit(0)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
await writeReport({
|
|
112
|
+
status: 'failed', code: 'PROFILE_SWITCH_BOOT_FAILED', stage: 'boot',
|
|
113
|
+
operationId: spec.operationId, oldProfile: spec.oldProfile, targetProfile: spec.targetProfile,
|
|
114
|
+
pid: child.pid, item: spec.targetProfile, expected: 'the target DSH Profile becomes HTTP ready', observed: 'HTTP ready was not detected',
|
|
115
|
+
evidence: { pid: child.pid, url: spec.url, stdout: await logTail(stdoutPath), stderr: await logTail(stderrPath) },
|
|
116
|
+
impact: 'The target Profile could not be started or did not become ready.', canContinue: false,
|
|
117
|
+
suggestedNextStep: 'Review stderr and verify the target Profile composition, then retry.',
|
|
118
|
+
message: 'The target Profile failed to become ready.',
|
|
119
|
+
})
|
|
120
|
+
try { process.kill(child.pid) } catch { /* already stopped */ }
|
|
121
|
+
process.exit(1)
|