feat(core): Add heartbeat grace/timeout options, client retry/wait-for-ready, server readiness and socket cleanup, transport socket options, helper utilities, and tests
This commit is contained in:
85
ts/index.ts
85
ts/index.ts
@@ -7,7 +7,7 @@ import { IpcServer } from './classes.ipcserver.js';
|
||||
import { IpcClient } from './classes.ipcclient.js';
|
||||
import { IpcChannel } from './classes.ipcchannel.js';
|
||||
import type { IIpcServerOptions } from './classes.ipcserver.js';
|
||||
import type { IIpcClientOptions } from './classes.ipcclient.js';
|
||||
import type { IIpcClientOptions, IConnectRetryConfig } from './classes.ipcclient.js';
|
||||
import type { IIpcChannelOptions } from './classes.ipcchannel.js';
|
||||
|
||||
/**
|
||||
@@ -17,6 +17,89 @@ export class SmartIpc {
|
||||
/**
|
||||
* Create an IPC server
|
||||
*/
|
||||
/**
|
||||
* Wait for a server to become ready at the given socket path
|
||||
*/
|
||||
public static async waitForServer(options: {
|
||||
socketPath: string;
|
||||
timeoutMs?: number;
|
||||
}): Promise<void> {
|
||||
const timeout = options.timeoutMs || 10000;
|
||||
const startTime = Date.now();
|
||||
|
||||
while (Date.now() - startTime < timeout) {
|
||||
try {
|
||||
// Try to connect as a temporary client
|
||||
const testClient = new IpcClient({
|
||||
id: `test-probe-${Date.now()}`,
|
||||
socketPath: options.socketPath,
|
||||
autoReconnect: false,
|
||||
heartbeat: false
|
||||
});
|
||||
|
||||
await testClient.connect();
|
||||
await testClient.disconnect();
|
||||
return; // Server is ready
|
||||
} catch (error) {
|
||||
// Server not ready yet, wait and retry
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Server not ready at ${options.socketPath} after ${timeout}ms`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to spawn a server process and connect a client
|
||||
*/
|
||||
public static async spawnAndConnect(options: {
|
||||
serverScript: string;
|
||||
socketPath: string;
|
||||
clientId?: string;
|
||||
spawnOptions?: any;
|
||||
connectRetry?: IConnectRetryConfig;
|
||||
timeoutMs?: number;
|
||||
}): Promise<{
|
||||
client: IpcClient;
|
||||
serverProcess: any;
|
||||
}> {
|
||||
const { spawn } = await import('child_process');
|
||||
|
||||
// Spawn the server process
|
||||
const serverProcess = spawn('node', [options.serverScript], {
|
||||
detached: true,
|
||||
stdio: 'pipe',
|
||||
...options.spawnOptions
|
||||
});
|
||||
|
||||
// Handle server process errors
|
||||
serverProcess.on('error', (error: Error) => {
|
||||
console.error('Server process error:', error);
|
||||
});
|
||||
|
||||
// Wait for server to be ready
|
||||
await SmartIpc.waitForServer({
|
||||
socketPath: options.socketPath,
|
||||
timeoutMs: options.timeoutMs || 10000
|
||||
});
|
||||
|
||||
// Create and connect client
|
||||
const client = new IpcClient({
|
||||
id: options.clientId || 'test-client',
|
||||
socketPath: options.socketPath,
|
||||
connectRetry: options.connectRetry || {
|
||||
enabled: true,
|
||||
maxAttempts: 10,
|
||||
initialDelay: 100,
|
||||
maxDelay: 1000
|
||||
}
|
||||
});
|
||||
|
||||
await client.connect({ waitForReady: true });
|
||||
|
||||
return { client, serverProcess };
|
||||
}
|
||||
|
||||
public static createServer(options: IIpcServerOptions): IpcServer {
|
||||
return new IpcServer(options);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user