Skip to content

Commit 7747761

Browse files
authored
refactor: simplify daemon transport resolution (#228)
* refactor: simplify runtime hint parsing and daemon transport resolution * refactor: trim daemon transport cleanup scope
1 parent e5637bf commit 7747761

1 file changed

Lines changed: 52 additions & 24 deletions

File tree

src/daemon-client.ts

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ type DaemonClientSettings = {
7979
remoteAuthToken?: string;
8080
};
8181

82+
type ResolvedDaemonTransport = 'socket' | 'http';
83+
8284
const REQUEST_TIMEOUT_MS = resolveDaemonRequestTimeoutMs();
8385
const DAEMON_STARTUP_TIMEOUT_MS = resolveDaemonStartupTimeoutMs();
8486
const DAEMON_STARTUP_ATTEMPTS = resolveDaemonStartupAttempts();
@@ -532,25 +534,44 @@ async function stopDaemonProcessForTakeover(info: DaemonInfo): Promise<void> {
532534
}
533535

534536
function readDaemonInfo(infoPath: string): DaemonInfo | null {
535-
const data = readJsonFile(infoPath) as DaemonInfo | null;
536-
if (!data || typeof data.token !== 'string' || data.token.length === 0) return null;
537-
const hasSocket = Number.isInteger(data.port) && Number(data.port) > 0;
538-
const hasHttp = Number.isInteger(data.httpPort) && Number(data.httpPort) > 0;
537+
const data = readJsonFile(infoPath);
538+
if (!data || typeof data !== 'object') return null;
539+
const parsed = data as Partial<DaemonInfo>;
540+
const token = typeof parsed.token === 'string' && parsed.token.length > 0 ? parsed.token : null;
541+
if (!token) return null;
542+
const hasSocket = Number.isInteger(parsed.port) && Number(parsed.port) > 0;
543+
const hasHttp = Number.isInteger(parsed.httpPort) && Number(parsed.httpPort) > 0;
539544
if (!hasSocket && !hasHttp) return null;
545+
const transport = parsed.transport;
546+
const version = typeof parsed.version === 'string' ? parsed.version : undefined;
547+
const codeSignature = typeof parsed.codeSignature === 'string' ? parsed.codeSignature : undefined;
548+
const processStartTime = typeof parsed.processStartTime === 'string' ? parsed.processStartTime : undefined;
549+
const hasPid = Number.isInteger(parsed.pid) && Number(parsed.pid) > 0;
540550
return {
541-
...data,
542-
port: hasSocket ? Number(data.port) : undefined,
543-
httpPort: hasHttp ? Number(data.httpPort) : undefined,
544-
pid: Number.isInteger(data.pid) && data.pid > 0 ? data.pid : 0,
551+
token,
552+
port: hasSocket ? Number(parsed.port) : undefined,
553+
httpPort: hasHttp ? Number(parsed.httpPort) : undefined,
554+
transport: transport === 'socket' || transport === 'http' || transport === 'dual' ? transport : undefined,
555+
pid: hasPid ? Number(parsed.pid) : 0,
556+
version,
557+
codeSignature,
558+
processStartTime,
545559
};
546560
}
547561

548562
function readDaemonLockInfo(lockPath: string): DaemonLockInfo | null {
549-
const data = readJsonFile(lockPath) as DaemonLockInfo | null;
550-
if (!data || !Number.isInteger(data.pid) || data.pid <= 0) {
563+
const data = readJsonFile(lockPath);
564+
if (!data || typeof data !== 'object') return null;
565+
const parsed = data as Partial<DaemonLockInfo>;
566+
const hasPid = Number.isInteger(parsed.pid) && Number(parsed.pid) > 0;
567+
if (!hasPid) {
551568
return null;
552569
}
553-
return data;
570+
return {
571+
pid: Number(parsed.pid),
572+
processStartTime: typeof parsed.processStartTime === 'string' ? parsed.processStartTime : undefined,
573+
startedAt: typeof parsed.startedAt === 'number' ? parsed.startedAt : undefined,
574+
};
554575
}
555576

556577
function removeDaemonInfo(infoPath: string): void {
@@ -720,7 +741,7 @@ async function sendRequest(
720741
return await sendSocketRequest(info, req);
721742
}
722743

723-
function chooseTransport(info: DaemonInfo, preference: DaemonTransportPreference): 'socket' | 'http' {
744+
function chooseTransport(info: DaemonInfo, preference: DaemonTransportPreference): ResolvedDaemonTransport {
724745
if (info.baseUrl) {
725746
// Defensive guard: resolveClientSettings rejects this earlier for normal CLI flow.
726747
if (preference === 'socket') {
@@ -730,22 +751,29 @@ function chooseTransport(info: DaemonInfo, preference: DaemonTransportPreference
730751
}
731752
return 'http';
732753
}
733-
if (preference === 'http') {
734-
if (!info.httpPort) throw new AppError('COMMAND_FAILED', 'Daemon HTTP endpoint is unavailable');
735-
return 'http';
736-
}
737-
if (preference === 'socket') {
738-
if (!info.port) throw new AppError('COMMAND_FAILED', 'Daemon socket endpoint is unavailable');
739-
return 'socket';
754+
if (preference === 'http' || preference === 'socket') {
755+
return requireDaemonTransport(info, preference);
740756
}
741-
const transport = info.transport;
742-
if (transport === 'http' && info.httpPort) return 'http';
743-
if ((transport === 'socket' || transport === 'dual') && info.port) return 'socket';
744-
if (info.httpPort) return 'http';
745-
if (info.port) return 'socket';
757+
const autoOrder: ResolvedDaemonTransport[] = info.transport === 'socket' || info.transport === 'dual'
758+
? ['socket', 'http']
759+
: ['http', 'socket'];
760+
const available = autoOrder.find((transport) => hasDaemonTransport(info, transport));
761+
if (available) return available;
746762
throw new AppError('COMMAND_FAILED', 'Daemon metadata has no reachable transport');
747763
}
748764

765+
function hasDaemonTransport(info: DaemonInfo, transport: ResolvedDaemonTransport): boolean {
766+
return transport === 'http' ? Boolean(info.httpPort) : Boolean(info.port);
767+
}
768+
769+
function requireDaemonTransport(info: DaemonInfo, transport: ResolvedDaemonTransport): ResolvedDaemonTransport {
770+
if (hasDaemonTransport(info, transport)) return transport;
771+
throw new AppError(
772+
'COMMAND_FAILED',
773+
transport === 'http' ? 'Daemon HTTP endpoint is unavailable' : 'Daemon socket endpoint is unavailable',
774+
);
775+
}
776+
749777
async function sendSocketRequest(info: DaemonInfo, req: DaemonRequest): Promise<DaemonResponse> {
750778
const port = info.port;
751779
if (!port) throw new AppError('COMMAND_FAILED', 'Daemon socket endpoint is unavailable');

0 commit comments

Comments
 (0)