|
1 | | -import { readLine, writeLine } from '@metamask/kernel-node-runtime/daemon'; |
2 | | -import type { JsonRpcResponse } from '@metamask/utils'; |
3 | | -import { assertIsJsonRpcResponse } from '@metamask/utils'; |
4 | | -import { randomUUID } from 'node:crypto'; |
5 | | -import { createConnection } from 'node:net'; |
6 | | -import type { Socket } from 'node:net'; |
7 | | -import { join } from 'node:path'; |
| 1 | +import { |
| 2 | + getSocketPath, |
| 3 | + sendCommand, |
| 4 | +} from '@metamask/kernel-node-runtime/daemon'; |
8 | 5 |
|
9 | | -import { getOcapHome } from '../ocap-home.ts'; |
10 | | - |
11 | | -/** |
12 | | - * Get the default daemon socket path. |
13 | | - * |
14 | | - * @returns The socket path. |
15 | | - */ |
16 | | -export function getSocketPath(): string { |
17 | | - return join(getOcapHome(), 'daemon.sock'); |
18 | | -} |
19 | | - |
20 | | -/** |
21 | | - * Connect to a UNIX domain socket. |
22 | | - * |
23 | | - * @param socketPath - The socket path to connect to. |
24 | | - * @returns A connected socket. |
25 | | - */ |
26 | | -async function connectSocket(socketPath: string): Promise<Socket> { |
27 | | - return new Promise((resolve, reject) => { |
28 | | - const socket = createConnection(socketPath, () => { |
29 | | - socket.removeListener('error', reject); |
30 | | - resolve(socket); |
31 | | - }); |
32 | | - socket.on('error', reject); |
33 | | - }); |
34 | | -} |
35 | | - |
36 | | -/** |
37 | | - * Options for {@link sendCommand}. |
38 | | - */ |
39 | | -type SendCommandOptions = { |
40 | | - /** The UNIX socket path. */ |
41 | | - socketPath: string; |
42 | | - /** The RPC method name. */ |
43 | | - method: string; |
44 | | - /** Optional method parameters (object or positional array). */ |
45 | | - params?: Record<string, unknown> | unknown[] | undefined; |
46 | | - /** Read timeout in milliseconds (default: no timeout). */ |
47 | | - timeoutMs?: number | undefined; |
48 | | -}; |
49 | | - |
50 | | -/** |
51 | | - * Send a JSON-RPC request to the daemon over a UNIX socket and return the response. |
52 | | - * |
53 | | - * Opens a connection, writes one JSON-RPC request line, reads one JSON-RPC |
54 | | - * response line, then closes the connection. Retries once after a short delay |
55 | | - * if the connection is rejected (e.g. due to a probe connection race). |
56 | | - * |
57 | | - * @param options - Command options. |
58 | | - * @param options.socketPath - The UNIX socket path. |
59 | | - * @param options.method - The RPC method name. |
60 | | - * @param options.params - Optional method parameters. |
61 | | - * @param options.timeoutMs - Read timeout in milliseconds (default: no timeout). |
62 | | - * @returns The parsed JSON-RPC response. |
63 | | - */ |
64 | | -export async function sendCommand({ |
65 | | - socketPath, |
66 | | - method, |
67 | | - params, |
68 | | - timeoutMs, |
69 | | -}: SendCommandOptions): Promise<JsonRpcResponse> { |
70 | | - const id = randomUUID(); |
71 | | - const request = { |
72 | | - jsonrpc: '2.0', |
73 | | - id, |
74 | | - method, |
75 | | - ...(params === undefined ? {} : { params }), |
76 | | - }; |
77 | | - |
78 | | - const attempt = async (): Promise<JsonRpcResponse> => { |
79 | | - const socket = await connectSocket(socketPath); |
80 | | - try { |
81 | | - await writeLine(socket, JSON.stringify(request)); |
82 | | - const responseLine = await readLine(socket, timeoutMs); |
83 | | - const parsed: unknown = JSON.parse(responseLine); |
84 | | - assertIsJsonRpcResponse(parsed); |
85 | | - return parsed; |
86 | | - } finally { |
87 | | - socket.destroy(); |
88 | | - } |
89 | | - }; |
90 | | - |
91 | | - try { |
92 | | - return await attempt(); |
93 | | - } catch (error: unknown) { |
94 | | - // Retry once on connection errors only — the daemon's socket may |
95 | | - // still be cleaning up a previous connection. |
96 | | - const code = (error as NodeJS.ErrnoException | undefined)?.code; |
97 | | - if (code !== 'ECONNREFUSED' && code !== 'ECONNRESET') { |
98 | | - throw error; |
99 | | - } |
100 | | - await new Promise((resolve) => setTimeout(resolve, 100)); |
101 | | - return attempt(); |
102 | | - } |
103 | | -} |
| 6 | +export { getSocketPath, sendCommand }; |
104 | 7 |
|
105 | 8 | /** |
106 | 9 | * Check whether the daemon is running by sending a lightweight `getStatus` |
|
0 commit comments