ework-web 0.10.43 → 0.10.44
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/package.json +1 -1
- package/src/index.ts +26 -0
- package/src/static/daemon-mgr.js +30 -1
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1023,8 +1023,34 @@ async function handle(req: Request, url: URL, ip: string, ctx: { authed: boolean
|
|
|
1023
1023
|
|
|
1024
1024
|
const daemonIdRe = /^\/api\/daemons\/(\d+)$/;
|
|
1025
1025
|
const daemonRestartRe = /^\/api\/daemons\/(\d+)\/restart$/;
|
|
1026
|
+
const daemonPauseRe = /^\/api\/daemons\/(\d+)\/pause$/;
|
|
1027
|
+
const daemonResumeRe = /^\/api\/daemons\/(\d+)\/resume$/;
|
|
1026
1028
|
const daemonRemoveRe = /^\/api\/daemons\/(\d+)\/remove$/;
|
|
1027
1029
|
|
|
1030
|
+
if (req.method === "POST" && (daemonPauseRe.test(url.pathname) || daemonResumeRe.test(url.pathname))) {
|
|
1031
|
+
if (!ctx.user || ctx.user.is_admin !== 1) return json({ error: "admin required" }, 403);
|
|
1032
|
+
const isPause = daemonPauseRe.test(url.pathname);
|
|
1033
|
+
const match = url.pathname.match(isPause ? daemonPauseRe : daemonResumeRe);
|
|
1034
|
+
const id = match ? Number(match[1]) : NaN;
|
|
1035
|
+
if (!Number.isFinite(id)) return json({ error: "invalid id" }, 400);
|
|
1036
|
+
const rows = await getDB().all<{ endpoint: string }>(
|
|
1037
|
+
`SELECT internal_endpoint AS endpoint FROM {{d_daemons}} WHERE id = ?`, [id]
|
|
1038
|
+
);
|
|
1039
|
+
if (rows.length === 0) return json({ ok: false, error: "daemon not found" }, 404);
|
|
1040
|
+
const ep = rows[0]!.endpoint;
|
|
1041
|
+
const proto = ep.startsWith("http") ? "" : "http://";
|
|
1042
|
+
try {
|
|
1043
|
+
const upstream = await fetch(`${proto}${ep}/api/admin/${isPause ? "pause" : "resume"}`, { method: "POST" });
|
|
1044
|
+
if (!upstream.ok) {
|
|
1045
|
+
const body = await upstream.text().catch(() => "");
|
|
1046
|
+
return json({ ok: false, error: `daemon returned ${upstream.status}: ${body.slice(0, 200)}` }, 502);
|
|
1047
|
+
}
|
|
1048
|
+
} catch (e) {
|
|
1049
|
+
return json({ ok: false, error: `cannot reach daemon: ${errMsg(e)}` }, 502);
|
|
1050
|
+
}
|
|
1051
|
+
return json({ ok: true, paused: isPause });
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1028
1054
|
if (req.method === "POST" && daemonRestartRe.test(url.pathname)) {
|
|
1029
1055
|
if (!ctx.user || ctx.user.is_admin !== 1) return json({ error: "admin required" }, 403);
|
|
1030
1056
|
const match = url.pathname.match(daemonRestartRe);
|
package/src/static/daemon-mgr.js
CHANGED
|
@@ -55,7 +55,11 @@
|
|
|
55
55
|
var stRaw = String(d.status || 'unknown').toLowerCase();
|
|
56
56
|
var actions = '';
|
|
57
57
|
if (stRaw === 'active') {
|
|
58
|
-
actions = '<button type="button" class="
|
|
58
|
+
actions = '<button type="button" class="pause" data-id="' + d.id + '">暂停</button>' +
|
|
59
|
+
'<button type="button" class="stop" data-id="' + d.id + '">停止</button>';
|
|
60
|
+
} else if (stRaw === 'drained' || stRaw === 'paused') {
|
|
61
|
+
actions = '<button type="button" class="resume" data-id="' + d.id + '">恢复</button>' +
|
|
62
|
+
'<button type="button" class="remove" data-id="' + d.id + '">删除</button>';
|
|
59
63
|
} else {
|
|
60
64
|
actions = '<button type="button" class="restart" data-id="' + d.id + '">重启</button>' +
|
|
61
65
|
'<button type="button" class="remove" data-id="' + d.id + '">删除</button>';
|
|
@@ -81,6 +85,8 @@
|
|
|
81
85
|
});
|
|
82
86
|
};
|
|
83
87
|
bindBtn('button.stop', stopDaemon);
|
|
88
|
+
bindBtn('button.pause', pauseDaemon);
|
|
89
|
+
bindBtn('button.resume', resumeDaemon);
|
|
84
90
|
bindBtn('button.restart', restartDaemon);
|
|
85
91
|
bindBtn('button.remove', removeDaemon);
|
|
86
92
|
}
|
|
@@ -138,6 +144,29 @@
|
|
|
138
144
|
}
|
|
139
145
|
}
|
|
140
146
|
|
|
147
|
+
async function pauseDaemon(id) {
|
|
148
|
+
if (!confirm('确认暂停 daemon #' + id + '?\n暂停后不再接收新任务,已进行中的会话不受影响。')) return;
|
|
149
|
+
setResult('正在暂停 daemon #' + id + '…', 'loading');
|
|
150
|
+
try {
|
|
151
|
+
var res = await fetch('/api/daemons/' + id + '/pause', { method: 'POST' });
|
|
152
|
+
if (res.status === 401) { setResult('✗ 登录已过期,请刷新页面重新登录', 'err'); return; }
|
|
153
|
+
var data = await res.json();
|
|
154
|
+
if (data.ok) { setResult('✓ daemon #' + id + ' 已暂停', 'ok'); await loadDaemons(); }
|
|
155
|
+
else setResult('✗ ' + (data.error || '未知错误'), 'err');
|
|
156
|
+
} catch (e) { setResult('✗ ' + (e.message || String(e)), 'err'); }
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function resumeDaemon(id) {
|
|
160
|
+
setResult('正在恢复 daemon #' + id + '…', 'loading');
|
|
161
|
+
try {
|
|
162
|
+
var res = await fetch('/api/daemons/' + id + '/resume', { method: 'POST' });
|
|
163
|
+
if (res.status === 401) { setResult('✗ 登录已过期,请刷新页面重新登录', 'err'); return; }
|
|
164
|
+
var data = await res.json();
|
|
165
|
+
if (data.ok) { setResult('✓ daemon #' + id + ' 已恢复', 'ok'); await loadDaemons(); }
|
|
166
|
+
else setResult('✗ ' + (data.error || '未知错误'), 'err');
|
|
167
|
+
} catch (e) { setResult('✗ ' + (e.message || String(e)), 'err'); }
|
|
168
|
+
}
|
|
169
|
+
|
|
141
170
|
async function stopDaemon(id) {
|
|
142
171
|
if (!confirm('确认停止 daemon #' + id + '?\n只会标记为 drained(不再接新任务),需手动 kill 进程。')) return;
|
|
143
172
|
setResult('正在标记 daemon #' + id + ' 为 drained…', 'loading');
|