fix: render registry workspaces for harness
This commit is contained in:
@@ -77,6 +77,12 @@ export function sessionRoutes(
|
||||
return typeof runner.withPrincipal === "function" ? runner.withPrincipal(principal) : runner;
|
||||
};
|
||||
|
||||
const optionsWithRuntimeConfig = (runner: any, workspaceConfigPath: string | undefined, options: any) => (
|
||||
workspaceConfigPath && typeof runner.acquireWorkspaceRuntime === "function"
|
||||
? { ...options, runtimeConfig: runner.acquireWorkspaceRuntime(workspaceConfigPath) }
|
||||
: options
|
||||
);
|
||||
|
||||
const maintenanceReply = (reply: any) => reply.code(503).send({
|
||||
code: "maintenance",
|
||||
error: "Session admission is temporarily paused for maintenance. Try again shortly.",
|
||||
@@ -413,9 +419,11 @@ export function sessionRoutes(
|
||||
principal,
|
||||
question: b.question,
|
||||
};
|
||||
let runtimeOptions = options;
|
||||
let rt: ReturnType<PiProcessManager["createFor"]> | undefined;
|
||||
try {
|
||||
rt = d.mgr.createFor(id, options);
|
||||
runtimeOptions = optionsWithRuntimeConfig(runner, workspaceConfigPath, options);
|
||||
rt = d.mgr.createFor(id, runtimeOptions);
|
||||
bindRuntime(id, rt, runner, workspaceConfigPath);
|
||||
} catch (error) {
|
||||
if (rt) d.mgr.teardownIfCurrent(id, rt);
|
||||
@@ -430,9 +438,9 @@ export function sessionRoutes(
|
||||
}
|
||||
info(id, "Session created");
|
||||
bootstrap(
|
||||
id, rt, runner, workspaceConfigPath, d.mgr.configure(rt, options),
|
||||
id, rt, runner, workspaceConfigPath, d.mgr.configure(rt, runtimeOptions),
|
||||
runner.searchPack(b.question, id, workspaceConfigPath),
|
||||
() => d.mgr.start(id, rt, options),
|
||||
() => d.mgr.start(id, rt, runtimeOptions),
|
||||
);
|
||||
return { id };
|
||||
} finally {
|
||||
@@ -560,6 +568,7 @@ export function sessionRoutes(
|
||||
principal,
|
||||
mode: "resume" as const,
|
||||
};
|
||||
let runtimeOptions = options;
|
||||
|
||||
// Reopening is validation, not the transport commit point. Keep the old hub intact if
|
||||
// persistence cannot be reopened.
|
||||
@@ -589,7 +598,8 @@ export function sessionRoutes(
|
||||
if (boundRuntimes.get(id) === current) boundRuntimes.delete(id);
|
||||
d.mgr.teardownIfCurrent(id, current);
|
||||
}
|
||||
rt = d.mgr.createFor(id, options);
|
||||
runtimeOptions = optionsWithRuntimeConfig(runner, workspaceConfigPath, options);
|
||||
rt = d.mgr.createFor(id, runtimeOptions);
|
||||
bindRuntime(id, rt, runner, workspaceConfigPath);
|
||||
} catch {
|
||||
// A created-but-unbound runtime is not usable. The old hub remains attached because
|
||||
@@ -605,7 +615,11 @@ export function sessionRoutes(
|
||||
// immediately before the first event produced by the new Resume.
|
||||
d.hub.clear(id);
|
||||
info(id, "Resuming session");
|
||||
bootstrap(id, rt, runner, workspaceConfigPath, d.mgr.configure(rt, options), null, () => d.mgr.start(id, rt, options));
|
||||
bootstrap(
|
||||
id, rt, runner, workspaceConfigPath,
|
||||
d.mgr.configure(rt, runtimeOptions), null,
|
||||
() => d.mgr.start(id, rt, runtimeOptions),
|
||||
);
|
||||
return reply.code(200).send({ id, alreadyActive: false });
|
||||
});
|
||||
});
|
||||
|
||||
+40
-11
@@ -3,22 +3,49 @@ import type { ThtRunner } from "../tht/tht-runner.js";
|
||||
import { getPrincipal } from "../auth/auth.js";
|
||||
import type { PrincipalContext } from "../auth/principal.js";
|
||||
import type { Settings } from "../settings/settings-store.js";
|
||||
import type { WorkspaceRegistry } from "../workspaces/registry.js";
|
||||
|
||||
export function sqlRoutes(app: FastifyInstance, deps: {
|
||||
tht: ThtRunner; getSettings: (principal: PrincipalContext) => Promise<Settings>;
|
||||
workspaceRegistry: WorkspaceRegistry;
|
||||
}): void {
|
||||
const runnerFor = (principal: PrincipalContext): any => {
|
||||
const runner = deps.tht as any;
|
||||
return typeof runner.withPrincipal === "function" ? runner.withPrincipal(principal) : runner;
|
||||
};
|
||||
const authorize = async (principal: PrincipalContext, id: string, workspace?: string) => {
|
||||
try {
|
||||
const runner = runnerFor(principal);
|
||||
if (typeof runner.sessionShow !== "function") return {};
|
||||
return await runner.sessionShow(id, workspace);
|
||||
const isNotFound = (error: unknown) => /not found|non trovata|inesistente|404/i.test(
|
||||
error instanceof Error ? error.message : String(error),
|
||||
);
|
||||
const locate = async (principal: PrincipalContext, id: string, legacyWorkspace?: string) => {
|
||||
const runner = runnerFor(principal);
|
||||
if (typeof runner.sessionShow !== "function") return { manifest: {}, workspace: legacyWorkspace };
|
||||
const registry = deps.workspaceRegistry as Partial<WorkspaceRegistry>;
|
||||
const revisions = typeof registry.listRetainedSnapshots === "function"
|
||||
? await registry.listRetainedSnapshots.call(deps.workspaceRegistry)
|
||||
: await deps.workspaceRegistry.list();
|
||||
for (const revision of revisions) {
|
||||
if (revision.state !== "operational") continue;
|
||||
try {
|
||||
const manifest = await runner.sessionShow(id, revision.snapshotPath);
|
||||
if (!manifest) continue;
|
||||
const saved = manifest as { workspace_id?: string; workspace_revision?: string };
|
||||
if (saved.workspace_id && saved.workspace_revision) {
|
||||
const pinned = await deps.workspaceRegistry.readPinned(saved.workspace_id, saved.workspace_revision);
|
||||
return {
|
||||
manifest,
|
||||
workspace: pinned.workspaceConfigPath ?? (pinned as any).revision?.snapshotPath,
|
||||
};
|
||||
}
|
||||
return { manifest, workspace: revision.snapshotPath };
|
||||
} catch (error) {
|
||||
if (!isNotFound(error)) throw error;
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
if (/not found|non trovata|inesistente|404/i.test(error instanceof Error ? error.message : String(error))) return undefined;
|
||||
try {
|
||||
const manifest = await runner.sessionShow(id, legacyWorkspace);
|
||||
return manifest ? { manifest, workspace: legacyWorkspace } : undefined;
|
||||
} catch (error) {
|
||||
if (isNotFound(error)) return undefined;
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
@@ -30,8 +57,9 @@ export function sqlRoutes(app: FastifyInstance, deps: {
|
||||
try {
|
||||
principal = getPrincipal(req);
|
||||
const settings = await deps.getSettings(principal);
|
||||
workspace = settings.workspace;
|
||||
if (!await authorize(principal, id, settings.workspace)) return reply.code(404).send({ error: "session not found" });
|
||||
const located = await locate(principal, id, settings.workspace);
|
||||
if (!located) return reply.code(404).send({ error: "session not found" });
|
||||
workspace = located.workspace;
|
||||
} catch {
|
||||
return reply.code(503).send({ error: "session storage is unavailable" });
|
||||
}
|
||||
@@ -49,8 +77,9 @@ export function sqlRoutes(app: FastifyInstance, deps: {
|
||||
try {
|
||||
principal = getPrincipal(req);
|
||||
const settings = await deps.getSettings(principal);
|
||||
workspace = settings.workspace;
|
||||
if (!await authorize(principal, id, settings.workspace)) return reply.code(404).send({ error: "session not found" });
|
||||
const located = await locate(principal, id, settings.workspace);
|
||||
if (!located) return reply.code(404).send({ error: "session not found" });
|
||||
workspace = located.workspace;
|
||||
} catch {
|
||||
return reply.code(503).send({ error: "session storage is unavailable" });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user