feat(worker): per-user box status and lifecycle helpers
Centralize per-user box home-path derivation, status inspection, and
lifecycle (start/stop/restart) in a new box.ts so the HTTP routes and the
terminal WS bridge share one source of truth. Add inspectUserBoxStatus to
docker.ts (single `inspect --format` call, all-null/false on non-zero exit)
and resetBox to user-container.ts (clears the idle timer and drops the
registry entry so a stopped box isn't treated as held).
Manual verification (docker required, after Task 4 wires the routes): with
the worker running and a box up,
`curl -H "Authorization: Bearer $TOKEN" localhost:3921/box/status?user=<you>`
shows running:true + image + startedAt; `POST /box/lifecycle {"action":"stop"}`
flips status to running:false; `start` brings it back.
This commit is contained in:
@@ -214,6 +214,42 @@ export const ensureUserContainer = async (args: {
|
||||
return name;
|
||||
};
|
||||
|
||||
// Inspect the per-user box in one shot. Non-zero exit (no such container) yields
|
||||
// an all-null/false status. `--memory 0` means unlimited, which the Go template
|
||||
// prints as `0`; we normalize that (and any unparseable value) to null.
|
||||
export const inspectUserBoxStatus = async (
|
||||
username: string,
|
||||
): Promise<{
|
||||
running: boolean;
|
||||
image: string | null;
|
||||
startedAt: string | null;
|
||||
memoryLimitBytes: number | null;
|
||||
}> => {
|
||||
const result = await execa(
|
||||
containerRuntime(),
|
||||
[
|
||||
'inspect',
|
||||
'--format',
|
||||
'{{.State.Running}}|{{.Config.Image}}|{{.State.StartedAt}}|{{.HostConfig.Memory}}',
|
||||
userContainerName(username),
|
||||
],
|
||||
{ reject: false, stdin: 'ignore' },
|
||||
);
|
||||
if (result.exitCode !== 0) {
|
||||
return { running: false, image: null, startedAt: null, memoryLimitBytes: null };
|
||||
}
|
||||
const [runningField, imageField, startedAtField, memoryField] = result.stdout
|
||||
.trim()
|
||||
.split('|');
|
||||
const running = runningField === 'true';
|
||||
return {
|
||||
running,
|
||||
image: imageField || null,
|
||||
startedAt: running ? startedAtField || null : null,
|
||||
memoryLimitBytes: Number(memoryField) || null,
|
||||
};
|
||||
};
|
||||
|
||||
const shellQuote = (value: string) => `'${value.replaceAll("'", "'\\''")}'`;
|
||||
|
||||
// The marker is embedded literally into a `# comment` line and into a `pgrep`
|
||||
|
||||
Reference in New Issue
Block a user