fix(core): Improve heartbeat handling and transport routing; forward heartbeat timeout events; include clientId routing and probe improvements
This commit is contained in:
@@ -169,6 +169,8 @@ export class UnixSocketTransport extends IpcTransport {
|
||||
private socket: plugins.net.Socket | null = null;
|
||||
private server: plugins.net.Server | null = null;
|
||||
private clients: Set<plugins.net.Socket> = new Set();
|
||||
private socketToClientId = new WeakMap<plugins.net.Socket, string>();
|
||||
private clientIdToSocket = new Map<string, plugins.net.Socket>();
|
||||
|
||||
/**
|
||||
* Connect as client or start as server
|
||||
@@ -239,6 +241,12 @@ export class UnixSocketTransport extends IpcTransport {
|
||||
|
||||
socket.on('close', () => {
|
||||
this.clients.delete(socket);
|
||||
// Clean up clientId mappings
|
||||
const clientId = this.socketToClientId.get(socket);
|
||||
if (clientId && this.clientIdToSocket.get(clientId) === socket) {
|
||||
this.clientIdToSocket.delete(clientId);
|
||||
}
|
||||
this.socketToClientId.delete(socket);
|
||||
this.emit('clientDisconnected', socket);
|
||||
});
|
||||
|
||||
@@ -307,7 +315,18 @@ export class UnixSocketTransport extends IpcTransport {
|
||||
// Parse and emit the message with socket reference
|
||||
try {
|
||||
const message = JSON.parse(messageData.toString('utf8')) as IIpcMessageEnvelope;
|
||||
|
||||
// Update clientId mapping
|
||||
const clientId = message.headers?.clientId ??
|
||||
(message.type === '__register__' ? (message.payload as any)?.clientId : undefined);
|
||||
if (clientId) {
|
||||
this.socketToClientId.set(socket, clientId);
|
||||
this.clientIdToSocket.set(clientId, socket);
|
||||
}
|
||||
|
||||
// Emit both events so IpcChannel can process it
|
||||
this.emit('clientMessage', message, socket);
|
||||
this.emit('message', message);
|
||||
} catch (error: any) {
|
||||
this.emit('error', new Error(`Failed to parse message: ${error.message}`));
|
||||
}
|
||||
@@ -415,27 +434,54 @@ export class UnixSocketTransport extends IpcTransport {
|
||||
}
|
||||
});
|
||||
} else if (this.server && this.clients.size > 0) {
|
||||
// Server mode - broadcast to all clients
|
||||
const promises: Promise<boolean>[] = [];
|
||||
// Server mode - route by clientId if present, otherwise broadcast
|
||||
const targetClientId = message.headers?.clientId;
|
||||
|
||||
for (const client of this.clients) {
|
||||
promises.push(new Promise((resolve) => {
|
||||
const success = client.write(frame, (error) => {
|
||||
if (error) {
|
||||
resolve(false);
|
||||
} else {
|
||||
resolve(true);
|
||||
if (targetClientId && this.clientIdToSocket.has(targetClientId)) {
|
||||
// Send to specific client
|
||||
const targetSocket = this.clientIdToSocket.get(targetClientId)!;
|
||||
if (targetSocket && !targetSocket.destroyed) {
|
||||
return new Promise((resolve) => {
|
||||
const success = targetSocket.write(frame, (error) => {
|
||||
if (error) {
|
||||
resolve(false);
|
||||
} else {
|
||||
resolve(true);
|
||||
}
|
||||
});
|
||||
|
||||
if (!success) {
|
||||
targetSocket.once('drain', () => resolve(true));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Socket is destroyed, remove from mappings
|
||||
this.clientIdToSocket.delete(targetClientId);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Broadcast to all clients (fallback for messages without specific target)
|
||||
const promises: Promise<boolean>[] = [];
|
||||
|
||||
for (const client of this.clients) {
|
||||
promises.push(new Promise((resolve) => {
|
||||
const success = client.write(frame, (error) => {
|
||||
if (error) {
|
||||
resolve(false);
|
||||
} else {
|
||||
resolve(true);
|
||||
}
|
||||
});
|
||||
|
||||
if (!success) {
|
||||
client.once('drain', () => resolve(true));
|
||||
}
|
||||
}));
|
||||
if (!success) {
|
||||
client.once('drain', () => resolve(true));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
const results = await Promise.all(promises);
|
||||
return results.every(r => r);
|
||||
}
|
||||
|
||||
const results = await Promise.all(promises);
|
||||
return results.every(r => r);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
Reference in New Issue
Block a user