feat: update to new cluster protocol
This commit is contained in:
@@ -91,50 +91,110 @@ class UdpDiscovery extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update node last seen time
|
||||
// Handle different message types
|
||||
if (message.startsWith('cluster/heartbeat:')) {
|
||||
// Extract hostname from heartbeat: "cluster/heartbeat:hostname"
|
||||
const hostname = message.substring('cluster/heartbeat:'.length);
|
||||
this.handleHeartbeat(hostname, nodeIp, rinfo.port);
|
||||
} else if (message.startsWith('node/update:')) {
|
||||
// Extract hostname and JSON from update: "node/update:hostname:{json}"
|
||||
const parts = message.substring('node/update:'.length).split(':');
|
||||
if (parts.length >= 2) {
|
||||
const hostname = parts[0];
|
||||
const jsonStr = parts.slice(1).join(':'); // Rejoin in case JSON contains colons
|
||||
this.handleNodeUpdate(hostname, jsonStr, nodeIp, rinfo.port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleHeartbeat(hostname, nodeIp, port) {
|
||||
console.log(`Heartbeat from ${hostname} @ ${nodeIp}`);
|
||||
|
||||
// Update or add node
|
||||
const existingNode = this.nodes.get(nodeIp);
|
||||
this.nodes.set(nodeIp, {
|
||||
lastSeen: Date.now(),
|
||||
status: 'connected',
|
||||
address: nodeIp,
|
||||
port: rinfo.port
|
||||
port: port,
|
||||
hostname: hostname
|
||||
});
|
||||
|
||||
// Emit node discovered/updated event
|
||||
this.emit('nodeDiscovered', {
|
||||
ip: nodeIp,
|
||||
port: rinfo.port,
|
||||
status: 'connected'
|
||||
});
|
||||
// Only emit if this is a new node or if we need to update
|
||||
if (!existingNode || existingNode.hostname !== hostname) {
|
||||
this.emit('nodeDiscovered', {
|
||||
ip: nodeIp,
|
||||
hostname: hostname,
|
||||
port: port,
|
||||
status: 'connected'
|
||||
});
|
||||
}
|
||||
|
||||
// Clean up stale nodes periodically
|
||||
this.cleanupStaleNodes();
|
||||
}
|
||||
|
||||
startDiscoveryBroadcast() {
|
||||
// Broadcast discovery message every 5 seconds
|
||||
this.discoveryInterval = setInterval(() => {
|
||||
this.broadcastDiscovery();
|
||||
}, 5000);
|
||||
handleNodeUpdate(hostname, jsonStr, nodeIp, port) {
|
||||
console.log(`Node update from ${hostname} @ ${nodeIp}`);
|
||||
|
||||
// Send initial broadcast
|
||||
this.broadcastDiscovery();
|
||||
// Try to parse JSON to extract additional info
|
||||
let nodeInfo = {};
|
||||
try {
|
||||
nodeInfo = JSON.parse(jsonStr);
|
||||
} catch (e) {
|
||||
console.warn(`Failed to parse node update JSON: ${e.message}`);
|
||||
}
|
||||
|
||||
// Update node with hostname and any additional info
|
||||
const existingNode = this.nodes.get(nodeIp);
|
||||
this.nodes.set(nodeIp, {
|
||||
lastSeen: Date.now(),
|
||||
status: 'connected',
|
||||
address: nodeIp,
|
||||
port: port,
|
||||
hostname: hostname || nodeInfo.hostname || existingNode?.hostname,
|
||||
...nodeInfo
|
||||
});
|
||||
|
||||
// Emit update event
|
||||
this.emit('nodeDiscovered', {
|
||||
ip: nodeIp,
|
||||
hostname: hostname || nodeInfo.hostname || existingNode?.hostname,
|
||||
port: port,
|
||||
status: 'connected'
|
||||
});
|
||||
}
|
||||
|
||||
broadcastDiscovery() {
|
||||
startDiscoveryBroadcast() {
|
||||
// With the new protocol, SPORE nodes automatically broadcast heartbeats
|
||||
// LEDLab passively listens for these heartbeats, so we don't need to broadcast.
|
||||
// However, we can optionally send a heartbeat to prompt nodes to respond faster.
|
||||
// For now, we just listen for incoming heartbeats from nodes.
|
||||
|
||||
// Optional: send initial heartbeat to prompt nodes to announce themselves
|
||||
this.broadcastHeartbeat();
|
||||
|
||||
// Send periodic heartbeats to prompt node announcements (every 10 seconds)
|
||||
this.discoveryInterval = setInterval(() => {
|
||||
this.broadcastHeartbeat();
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
broadcastHeartbeat() {
|
||||
if (!this.socket) {
|
||||
return;
|
||||
}
|
||||
|
||||
const discoveryMessage = 'SPORE_DISCOVERY';
|
||||
// Send heartbeat using the new protocol format: "cluster/heartbeat:hostname"
|
||||
const hostname = 'ledlab-client';
|
||||
const discoveryMessage = `cluster/heartbeat:${hostname}`;
|
||||
const message = Buffer.from(discoveryMessage, 'utf8');
|
||||
|
||||
// Broadcast to all nodes on the network (broadcast already enabled in bind callback)
|
||||
|
||||
this.socket.send(message, 0, message.length, this.port, '255.255.255.255', (err) => {
|
||||
if (err) {
|
||||
console.error('Error broadcasting discovery message:', err);
|
||||
console.error('Error broadcasting heartbeat:', err);
|
||||
} else {
|
||||
console.log('Discovery message broadcasted');
|
||||
console.log('Discovery heartbeat broadcasted');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -154,6 +214,7 @@ class UdpDiscovery extends EventEmitter {
|
||||
getNodes() {
|
||||
const nodes = Array.from(this.nodes.entries()).map(([ip, node]) => ({
|
||||
ip,
|
||||
hostname: node.hostname || ip,
|
||||
...node
|
||||
}));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user