(
candidates: string[],
listen: (socketPath: string) => Promise<net.Server>,
opts: { onRelocate?: (from: string, to: string, code: string) => void } = {},
)
| 701 | * direct mode (#974). Exported for testing. |
| 702 | */ |
| 703 | export async function bindFirstUsableSocket( |
| 704 | candidates: string[], |
| 705 | listen: (socketPath: string) => Promise<net.Server>, |
| 706 | opts: { onRelocate?: (from: string, to: string, code: string) => void } = {}, |
| 707 | ): Promise<{ server: net.Server; socketPath: string }> { |
| 708 | let lastErr: unknown; |
| 709 | for (let i = 0; i < candidates.length; i++) { |
| 710 | const socketPath = candidates[i]!; // i < length, so always defined |
| 711 | const isLast = i === candidates.length - 1; |
| 712 | try { |
| 713 | const server = await listen(socketPath); |
| 714 | return { server, socketPath }; |
| 715 | } catch (err) { |
| 716 | lastErr = err; |
| 717 | const code = (err as NodeJS.ErrnoException).code; |
| 718 | if (!isLast && code !== SOCKET_BIND_CONFLICT_CODE) { |
| 719 | opts.onRelocate?.(socketPath, candidates[i + 1]!, code ?? ''); // !isLast ⇒ i+1 in range |
| 720 | continue; |
| 721 | } |
| 722 | throw err; |
| 723 | } |
| 724 | } |
| 725 | // Only reachable with an empty candidate list — a programmer error. |
| 726 | throw lastErr ?? new Error('no socket candidates to bind'); |
| 727 | } |
| 728 | |
| 729 | function resolveIdleTimeoutMs(): number { |
| 730 | const raw = process.env.CODEGRAPH_DAEMON_IDLE_TIMEOUT_MS; |
no outgoing calls
no test coverage detected