refactor: reduce cognitive complexity in 3 functions (#184)
Co-authored-by: 星月 <xingyue@shazhou.work> Co-committed-by: 星月 <xingyue@shazhou.work>
This commit was merged in pull request #184.
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
import { rmSync } from "node:fs";
|
||||
import { type Server, type Socket, createServer } from "node:net";
|
||||
|
||||
import type { DaemonIpcResponse } from "@uncaged/nerve-core";
|
||||
import type { DaemonIpcRequest, DaemonIpcResponse } from "@uncaged/nerve-core";
|
||||
import { parseDaemonIpcRequest } from "@uncaged/nerve-core";
|
||||
|
||||
import type { DaemonHandlerBundle } from "./daemon-handlers.js";
|
||||
@@ -29,54 +29,65 @@ export function createDaemonIpcServer(
|
||||
// file did not exist — that is fine
|
||||
}
|
||||
|
||||
function writeIpcLine(socket: Socket, resp: DaemonIpcResponse): void {
|
||||
socket.write(`${JSON.stringify(resp)}\n`);
|
||||
}
|
||||
|
||||
function dispatchDaemonIpcRequest(socket: Socket, req: DaemonIpcRequest): void {
|
||||
switch (req.type) {
|
||||
case "trigger-workflow": {
|
||||
const r = handlers.triggerWorkflow(req.workflow, {
|
||||
prompt: req.prompt,
|
||||
maxRounds: req.maxRounds,
|
||||
dryRun: req.dryRun,
|
||||
});
|
||||
writeIpcLine(socket, r.ok ? { ok: true } : { ok: false, error: r.error });
|
||||
return;
|
||||
}
|
||||
case "trigger-sense": {
|
||||
const r = handlers.triggerSense(req.sense);
|
||||
writeIpcLine(socket, r.ok ? { ok: true } : { ok: false, error: r.error });
|
||||
return;
|
||||
}
|
||||
case "list-senses": {
|
||||
writeIpcLine(socket, { ok: true, senses: handlers.listSenses() });
|
||||
return;
|
||||
}
|
||||
case "kill-workflow": {
|
||||
const r = handlers.killWorkflowByRunId(req.runId);
|
||||
writeIpcLine(socket, r.ok ? { ok: true } : { ok: false, error: r.error });
|
||||
return;
|
||||
}
|
||||
case "list-workflows": {
|
||||
writeIpcLine(socket, { ok: true, workflows: handlers.listWorkflows() });
|
||||
return;
|
||||
}
|
||||
case "health": {
|
||||
writeIpcLine(socket, { ok: true, health: handlers.health() });
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
const _exhaustive: never = req;
|
||||
void _exhaustive;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleLine(socket: Socket, line: string): void {
|
||||
const trimmed = line.trim();
|
||||
if (trimmed.length === 0) return;
|
||||
|
||||
const req = parseDaemonIpcRequest(trimmed);
|
||||
if (req === null) {
|
||||
const resp: DaemonIpcResponse = { ok: false, error: "Invalid request" };
|
||||
socket.write(`${JSON.stringify(resp)}\n`);
|
||||
writeIpcLine(socket, { ok: false, error: "Invalid request" });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (req.type === "trigger-workflow") {
|
||||
const r = handlers.triggerWorkflow(req.workflow, {
|
||||
prompt: req.prompt,
|
||||
maxRounds: req.maxRounds,
|
||||
dryRun: req.dryRun,
|
||||
});
|
||||
const resp: DaemonIpcResponse = r.ok ? { ok: true } : { ok: false, error: r.error };
|
||||
socket.write(`${JSON.stringify(resp)}\n`);
|
||||
} else if (req.type === "trigger-sense") {
|
||||
const r = handlers.triggerSense(req.sense);
|
||||
const resp: DaemonIpcResponse = r.ok ? { ok: true } : { ok: false, error: r.error };
|
||||
socket.write(`${JSON.stringify(resp)}\n`);
|
||||
} else if (req.type === "list-senses") {
|
||||
const senses = handlers.listSenses();
|
||||
const resp: DaemonIpcResponse = { ok: true, senses };
|
||||
socket.write(`${JSON.stringify(resp)}\n`);
|
||||
} else if (req.type === "kill-workflow") {
|
||||
const r = handlers.killWorkflowByRunId(req.runId);
|
||||
const resp: DaemonIpcResponse = r.ok ? { ok: true } : { ok: false, error: r.error };
|
||||
socket.write(`${JSON.stringify(resp)}\n`);
|
||||
} else if (req.type === "list-workflows") {
|
||||
const workflows = handlers.listWorkflows();
|
||||
const resp: DaemonIpcResponse = { ok: true, workflows };
|
||||
socket.write(`${JSON.stringify(resp)}\n`);
|
||||
} else if (req.type === "health") {
|
||||
const health = handlers.health();
|
||||
const resp: DaemonIpcResponse = { ok: true, health };
|
||||
socket.write(`${JSON.stringify(resp)}\n`);
|
||||
} else {
|
||||
const _exhaustive: never = req;
|
||||
void _exhaustive;
|
||||
}
|
||||
dispatchDaemonIpcRequest(socket, req);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const resp: DaemonIpcResponse = { ok: false, error: msg };
|
||||
socket.write(`${JSON.stringify(resp)}\n`);
|
||||
writeIpcLine(socket, { ok: false, error: msg });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+56
-43
@@ -168,6 +168,47 @@ function validateResumeThreadMsg(obj: Record<string, unknown>): string | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
function parseParentCompute(obj: Record<string, unknown>): Result<ParentToWorkerMessage> {
|
||||
if (typeof obj.sense !== "string") {
|
||||
return err(new Error("IPC 'compute' message missing string 'sense' field"));
|
||||
}
|
||||
return ok({ type: "compute", sense: obj.sense });
|
||||
}
|
||||
|
||||
function parseParentStartThread(obj: Record<string, unknown>): Result<ParentToWorkerMessage> {
|
||||
const errMsg = validateStartThreadMsg(obj);
|
||||
if (errMsg !== null) return err(new Error(errMsg));
|
||||
// Field types are validated above; `Record<string, unknown>` values stay `unknown` to TypeScript.
|
||||
return ok({
|
||||
type: "start-thread",
|
||||
runId: obj.runId,
|
||||
workflow: obj.workflow,
|
||||
prompt: obj.prompt,
|
||||
maxRounds: obj.maxRounds,
|
||||
dryRun: obj.dryRun,
|
||||
} as StartThreadMessage);
|
||||
}
|
||||
|
||||
function parseParentResumeThread(obj: Record<string, unknown>): Result<ParentToWorkerMessage> {
|
||||
const errMsg = validateResumeThreadMsg(obj);
|
||||
if (errMsg !== null) return err(new Error(errMsg));
|
||||
// Elements are validated as plain objects by the kernel; trust the wire shape here.
|
||||
return ok({
|
||||
type: "resume-thread",
|
||||
runId: obj.runId,
|
||||
messages: obj.messages as ResumeThreadMessage["messages"],
|
||||
maxRounds: obj.maxRounds,
|
||||
dryRun: obj.dryRun,
|
||||
} as ResumeThreadMessage);
|
||||
}
|
||||
|
||||
function parseParentKillThread(obj: Record<string, unknown>): Result<ParentToWorkerMessage> {
|
||||
if (typeof obj.runId !== "string") {
|
||||
return err(new Error("'kill-thread' message missing string 'runId'"));
|
||||
}
|
||||
return ok({ type: "kill-thread", runId: obj.runId } as KillThreadMessage);
|
||||
}
|
||||
|
||||
/** Validate and parse an unknown IPC message received from the parent process. */
|
||||
export function parseParentMessage(raw: unknown): Result<ParentToWorkerMessage> {
|
||||
if (!isPlainRecord(raw)) {
|
||||
@@ -180,50 +221,22 @@ export function parseParentMessage(raw: unknown): Result<ParentToWorkerMessage>
|
||||
if (!PARENT_MSG_TYPES.has(obj.type)) {
|
||||
return err(new Error(`Unknown IPC message type: "${obj.type}"`));
|
||||
}
|
||||
if (obj.type === "compute") {
|
||||
if (typeof obj.sense !== "string") {
|
||||
return err(new Error("IPC 'compute' message missing string 'sense' field"));
|
||||
}
|
||||
return ok({ type: "compute", sense: obj.sense });
|
||||
switch (obj.type) {
|
||||
case "compute":
|
||||
return parseParentCompute(obj);
|
||||
case "shutdown":
|
||||
return ok({ type: "shutdown" });
|
||||
case "health-request":
|
||||
return ok({ type: "health-request" });
|
||||
case "start-thread":
|
||||
return parseParentStartThread(obj);
|
||||
case "resume-thread":
|
||||
return parseParentResumeThread(obj);
|
||||
case "kill-thread":
|
||||
return parseParentKillThread(obj);
|
||||
default:
|
||||
return err(new Error(`Unhandled IPC message type: "${obj.type}"`));
|
||||
}
|
||||
if (obj.type === "shutdown") {
|
||||
return ok({ type: "shutdown" });
|
||||
}
|
||||
if (obj.type === "health-request") {
|
||||
return ok({ type: "health-request" });
|
||||
}
|
||||
if (obj.type === "start-thread") {
|
||||
const errMsg = validateStartThreadMsg(obj);
|
||||
if (errMsg !== null) return err(new Error(errMsg));
|
||||
// Field types are validated above; `Record<string, unknown>` values stay `unknown` to TypeScript.
|
||||
return ok({
|
||||
type: "start-thread",
|
||||
runId: obj.runId,
|
||||
workflow: obj.workflow,
|
||||
prompt: obj.prompt,
|
||||
maxRounds: obj.maxRounds,
|
||||
dryRun: obj.dryRun,
|
||||
} as StartThreadMessage);
|
||||
}
|
||||
if (obj.type === "resume-thread") {
|
||||
const errMsg = validateResumeThreadMsg(obj);
|
||||
if (errMsg !== null) return err(new Error(errMsg));
|
||||
// Elements are validated as plain objects by the kernel; trust the wire shape here.
|
||||
return ok({
|
||||
type: "resume-thread",
|
||||
runId: obj.runId,
|
||||
messages: obj.messages as ResumeThreadMessage["messages"],
|
||||
maxRounds: obj.maxRounds,
|
||||
dryRun: obj.dryRun,
|
||||
} as ResumeThreadMessage);
|
||||
}
|
||||
if (obj.type === "kill-thread") {
|
||||
if (typeof obj.runId !== "string") {
|
||||
return err(new Error("'kill-thread' message missing string 'runId'"));
|
||||
}
|
||||
return ok({ type: "kill-thread", runId: obj.runId } as KillThreadMessage);
|
||||
}
|
||||
return err(new Error(`Unhandled IPC message type: "${obj.type}"`));
|
||||
}
|
||||
|
||||
function parseSignalMsg(obj: Record<string, unknown>): Result<WorkerToParentMessage> {
|
||||
|
||||
Reference in New Issue
Block a user