Skip to content

Commit 9f7f5bb

Browse files
improve monitor page
1 parent f98e9e4 commit 9f7f5bb

1 file changed

Lines changed: 60 additions & 93 deletions

File tree

nebula/frontend/static/js/monitor/monitor.js

Lines changed: 60 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,7 @@ class Monitor {
156156
.linkSource('source')
157157
.linkTarget('target')
158158
.linkColor(link => {
159-
const sourceNode = this.gData.nodes.find(n => n.ipport === link.source);
160-
const targetNode = this.gData.nodes.find(n => n.ipport === link.target);
161-
return (sourceNode && this.offlineNodes.has(sourceNode.ip)) ||
162-
(targetNode && this.offlineNodes.has(targetNode.ip)) ? '#ff0000' : '#999';
159+
return '#999';
163160
})
164161
.linkOpacity(0.6)
165162
.linkWidth(2)
@@ -274,7 +271,7 @@ class Monitor {
274271
};
275272

276273
if (!nodeData.status) {
277-
this.offlineNodes.add(nodeData.ip);
274+
this.offlineNodes.add(nodeId);
278275
this.log(`Node ${nodeData.ip}:${nodeData.port} marked as offline from initial data`);
279276
}
280277

@@ -364,7 +361,7 @@ class Monitor {
364361

365362
// Track offline nodes
366363
if (!nodeData.status) {
367-
this.offlineNodes.add(nodeData.ip);
364+
this.offlineNodes.add(`${nodeData.ip}:${nodeData.port}`);
368365
this.log('Node marked as offline during initialization:', nodeData.ip);
369366
}
370367

@@ -411,7 +408,7 @@ class Monitor {
411408
const sourceIP = sourceNode.ip;
412409

413410
// Skip if source node is offline
414-
if (this.offlineNodes.has(sourceIP)) {
411+
if (this.offlineNodes.has(sourceNode.ipport)) {
415412
this.log('Skipping links for offline source node:', sourceIP);
416413
continue;
417414
}
@@ -421,7 +418,7 @@ class Monitor {
421418
const targetIP = targetNode.ip;
422419

423420
// Skip if target node is offline
424-
if (this.offlineNodes.has(targetIP)) {
421+
if (this.offlineNodes.has(targetNode.ipport)) {
425422
this.log('Skipping link to offline target node:', targetIP);
426423
continue;
427424
}
@@ -480,9 +477,15 @@ class Monitor {
480477
this.gData.nodes[existingNodeIndex] = updatedNode;
481478
}
482479

483-
// If node is offline, remove its links but preserve others
484-
if (!data.status || this.offlineNodes.has(data.ip)) {
485-
this.log('Node is offline, removing its links');
480+
// If node is offline, remove its links and set color to red
481+
if (!data.status || this.offlineNodes.has(nodeId)) {
482+
this.log('Node is offline, removing its links and setting color to red');
483+
// Set color to red
484+
const idx = this.gData.nodes.findIndex(n => n.ipport === nodeId);
485+
if (idx !== -1) {
486+
this.gData.nodes[idx].color = '#ff0000';
487+
}
488+
// Remove all links involving this node
486489
this.gData.links = this.gData.links.filter(link => {
487490
const sourceIP = typeof link.source === 'object' ? link.source.ipport : link.source;
488491
const targetIP = typeof link.target === 'object' ? link.target.ipport : link.target;
@@ -491,69 +494,7 @@ class Monitor {
491494
return;
492495
}
493496

494-
// For online nodes, update their connections
495-
if (data.neighbors) {
496-
// Parse neighbors using consistent format
497-
const neighbors = data.neighbors.split(/[\s,]+/).filter(ip => ip.trim() !== '');
498-
this.log('Processing neighbors:', neighbors);
499-
500-
// Get current links for this node
501-
const currentLinks = this.gData.links.filter(link => {
502-
const sourceIP = typeof link.source === 'object' ? link.source.ipport : link.source;
503-
const targetIP = typeof link.target === 'object' ? link.target.ipport : link.target;
504-
return sourceIP === nodeId || targetIP === nodeId;
505-
});
506-
507-
// Create a set of current neighbor IDs
508-
const currentNeighbors = new Set(
509-
currentLinks.map(link => {
510-
const neighborId = link.source === nodeId ? link.target : link.source;
511-
return neighborId;
512-
})
513-
);
514-
515-
// Create a set of new neighbor IDs
516-
const newNeighbors = new Set(
517-
neighbors.map(neighbor => {
518-
const [neighborIP, neighborPort] = neighbor.split(':');
519-
return `${neighborIP}:${neighborPort || data.port}`;
520-
})
521-
);
522-
523-
// Only update if there are actual changes in neighbors
524-
if (!this.areSetsEqual(currentNeighbors, newNeighbors)) {
525-
this.log('Neighbor changes detected, updating links');
526-
527-
// Remove existing links for this node
528-
this.gData.links = this.gData.links.filter(link => {
529-
const sourceIP = typeof link.source === 'object' ? link.source.ipport : link.source;
530-
const targetIP = typeof link.target === 'object' ? link.target.ipport : link.target;
531-
return sourceIP !== nodeId && targetIP !== nodeId;
532-
});
533-
534-
// Add new links for online neighbors
535-
neighbors.forEach(neighbor => {
536-
const neighborIP = neighbor.split(':')[0];
537-
if (!this.offlineNodes.has(neighborIP)) {
538-
const normalizedNeighbor = neighbor.includes(':') ? neighbor : `${neighbor}:${data.port}`;
539-
const neighborNode = this.gData.nodes.find(n =>
540-
n.ipport === normalizedNeighbor ||
541-
n.ipport.split(':')[0] === neighborIP
542-
);
543-
544-
if (neighborNode) {
545-
this.gData.links.push({
546-
source: nodeId,
547-
target: normalizedNeighbor,
548-
value: 1.0
549-
});
550-
}
551-
}
552-
});
553-
} else {
554-
this.log('No neighbor changes detected, skipping link update');
555-
}
556-
}
497+
// Modifying links based on individual WebSocket updates leads to blinking/race conditions.
557498
}
558499

559500
randomFloatFromInterval(min, max) {
@@ -602,7 +543,7 @@ class Monitor {
602543

603544
getNodeColor(node) {
604545
// Check if the node is offline using the IP
605-
if (this.offlineNodes.has(node.ip)) {
546+
if (this.offlineNodes.has(node.ipport)) {
606547
return '#ff0000'; // Red color for offline nodes
607548
}
608549

@@ -952,6 +893,11 @@ class Monitor {
952893
return sourceIP !== nodeId && targetIP !== nodeId;
953894
});
954895

896+
const idx = this.gData.nodes.findIndex(n => n.ipport === nodeId);
897+
if (idx !== -1) {
898+
this.gData.nodes[idx].color = '#ff0000';
899+
}
900+
955901
this.log(`Removed ${previousLinkCount - this.gData.links.length} links for node ${nodeId}`);
956902

957903
// Remove lines from map
@@ -965,6 +911,7 @@ class Monitor {
965911
}
966912

967913
// Also remove links from other nodes to this offline node
914+
const offlineNodeIpPort = `${data.ip}:${data.port}`;
968915
Object.entries(this.droneMarkers).forEach(([uid, marker]) => {
969916
if (marker.neighbors) {
970917
const neighbors = Array.isArray(marker.neighbors)
@@ -974,7 +921,10 @@ class Monitor {
974921
: []);
975922

976923
// If this marker has the offline node as a neighbor, update its lines
977-
if (neighbors.some(ip => ip.startsWith(data.ip))) {
924+
if (neighbors.some(neighbor => {
925+
const normalizedNeighbor = neighbor.includes(':') ? neighbor : `${neighbor}:${marker.port}`;
926+
return normalizedNeighbor === offlineNodeIpPort;
927+
})) {
978928
this.updateNeighborLines(uid, marker.getLatLng(), neighbors, true);
979929
}
980930
}
@@ -1126,6 +1076,7 @@ class Monitor {
11261076
this.updateDronePosition(
11271077
nodeData.uid,
11281078
nodeData.ip,
1079+
nodeData.port,
11291080
nodeData.latitude,
11301081
nodeData.longitude,
11311082
neighborsIPs,
@@ -1142,10 +1093,11 @@ class Monitor {
11421093
}
11431094
}
11441095

1145-
updateDronePosition(uid, ip, lat, lng, neighborIPs, neighborsDistance) {
1096+
updateDronePosition(uid, ip, port, lat, lng, neighborIPs, neighborsDistance) {
11461097
this.log('Updating drone position:', { uid, ip, lat, lng });
11471098
const droneId = uid;
11481099
const newLatLng = new L.LatLng(lat, lng);
1100+
const ipport = `${ip}:${port}`;
11491101

11501102
// Create popup content with node information
11511103
const popupContent = `
@@ -1160,10 +1112,10 @@ class Monitor {
11601112
this.log('Creating new marker for node:', droneId);
11611113
// Create new marker
11621114
const marker = L.marker(newLatLng, {
1163-
icon: this.offlineNodes.has(ip) ? this.droneIconOffline : this.droneIcon,
1115+
icon: this.offlineNodes.has(ipport) ? this.droneIconOffline : this.droneIcon,
11641116
title: `Node ${uid}`,
11651117
alt: `Node ${uid}`,
1166-
className: this.offlineNodes.has(ip) ? 'drone-offline' : ''
1118+
className: this.offlineNodes.has(ipport) ? 'drone-offline' : ''
11671119
}).addTo(this.map);
11681120

11691121
marker.bindPopup(popupContent, {
@@ -1180,14 +1132,15 @@ class Monitor {
11801132
});
11811133

11821134
marker.ip = ip;
1135+
marker.port = port;
11831136
marker.neighbors = neighborIPs;
11841137
marker.neighbors_distance = neighborsDistance;
11851138
this.droneMarkers[droneId] = marker;
11861139
this.log('Marker created and added to map:', marker);
11871140
} else {
11881141
this.log('Updating existing marker for node:', droneId);
11891142
// Update existing marker
1190-
if (this.offlineNodes.has(ip)) {
1143+
if (this.offlineNodes.has(ipport)) {
11911144
this.droneMarkers[droneId].setIcon(this.droneIconOffline);
11921145
this.droneMarkers[droneId].getElement().classList.add('drone-offline');
11931146
} else {
@@ -1211,7 +1164,8 @@ class Monitor {
12111164
this.cleanupDroneLines(droneId);
12121165

12131166
// If no neighbors or drone is offline, don't create any lines
1214-
if (!neighborsIPs || neighborsIPs.length === 0 || !this.droneMarkers[droneId] || this.offlineNodes.has(this.droneMarkers[droneId].ip)) {
1167+
const droneMarker = this.droneMarkers[droneId];
1168+
if (!neighborsIPs || neighborsIPs.length === 0 || !droneMarker || this.offlineNodes.has(`${droneMarker.ip}:${droneMarker.port}`)) {
12151169
this.log('No neighbors or drone is offline, skipping line creation');
12161170
return;
12171171
}
@@ -1229,7 +1183,7 @@ class Monitor {
12291183

12301184
if (neighborMarker) {
12311185
// Skip if neighbor is offline
1232-
if (this.offlineNodes.has(neighborIPOnly)) {
1186+
if (this.offlineNodes.has(`${neighborMarker.ip}:${neighborMarker.port}`)) {
12331187
this.log('Skipping line creation - neighbor is offline:', neighborIPOnly);
12341188
return;
12351189
}
@@ -1383,14 +1337,16 @@ class Monitor {
13831337
startStaleNodeCheck() {
13841338
// Check for stale nodes every 5 seconds
13851339
setInterval(() => {
1340+
const numberOfNodes = this.gData.nodes.length;
1341+
const staleThreshold = 20000 + (numberOfNodes * 500);
1342+
13861343
const currentTime = Date.now();
1387-
const staleThreshold = 20000; // 20 seconds in milliseconds
13881344

13891345
// Check all nodes for staleness
13901346
this.nodeTimestamps.forEach((timestamp, nodeId) => {
13911347
const timeSinceLastUpdate = currentTime - timestamp;
13921348
if (timeSinceLastUpdate > staleThreshold) {
1393-
this.log(`Node ${nodeId} is stale (${timeSinceLastUpdate}ms since last update)`);
1349+
this.log(`Node ${nodeId} is stale (${timeSinceLastUpdate}ms > ${staleThreshold}ms). Marking as offline.`);
13941350
this.markNodeAsOffline(nodeId);
13951351
}
13961352
});
@@ -1408,7 +1364,7 @@ class Monitor {
14081364
this.log(`Marking node ${nodeId} as offline`);
14091365

14101366
// Add to offline nodes set
1411-
this.offlineNodes.add(node.ip);
1367+
this.offlineNodes.add(nodeId);
14121368

14131369
// Update node color in graph data
14141370
const nodeIndex = this.gData.nodes.findIndex(n => n.ipport === nodeId);
@@ -1534,7 +1490,7 @@ class Monitor {
15341490
};
15351491

15361492
if (!nodeData.status) {
1537-
this.offlineNodes.add(nodeData.ip);
1493+
this.offlineNodes.add(nodeId);
15381494
this.log(`Node ${nodeData.ip}:${nodeData.port} marked as offline from status check`);
15391495
}
15401496

@@ -1551,6 +1507,7 @@ class Monitor {
15511507
this.updateDronePosition(
15521508
nodeData.uid,
15531509
nodeData.ip,
1510+
nodeData.port,
15541511
parseFloat(nodeData.latitude),
15551512
parseFloat(nodeData.longitude),
15561513
nodeData.neighbors ? nodeData.neighbors.split(/[\s,]+/).filter(ip => ip.trim() !== '') : [],
@@ -1805,17 +1762,27 @@ class Monitor {
18051762
});
18061763
});
18071764

1808-
// Create links between online nodes
1765+
// Create links between online nodes only
18091766
nodesTable.forEach(sourceNode => {
18101767
if (sourceNode.status && sourceNode.neighbors) {
18111768
const neighbors = sourceNode.neighbors.split(/[\s,]+/).filter(ip => ip.trim() !== '');
18121769
neighbors.forEach(neighbor => {
1813-
const [neighborIP, neighborPort] = neighbor.split(':');
1814-
const targetNode = nodesTable.find(n => n.ip === neighborIP && n.port === neighborPort);
1815-
if (targetNode && targetNode.status) {
1770+
let neighborIpPort;
1771+
if (neighbor.includes(':')) {
1772+
neighborIpPort = neighbor;
1773+
} else {
1774+
// Try to find the port from nodesTable
1775+
const found = nodesTable.find(n => n.ip === neighbor);
1776+
neighborIpPort = found ? `${found.ip}:${found.port}` : `${neighbor}:${sourceNode.port}`;
1777+
}
1778+
const isOffline = this.offlineNodes.has(neighborIpPort);
1779+
this.log('Checking neighbor', neighborIpPort, 'offline?', isOffline);
1780+
// Find the target node and ensure it is online
1781+
const targetNode = nodesTable.find(n => `${n.ip}:${n.port}` === neighborIpPort && n.status);
1782+
if (targetNode && !isOffline) {
18161783
this.gData.links.push({
18171784
source: `${sourceNode.ip}:${sourceNode.port}`,
1818-
target: `${neighborIP}:${neighborPort}`,
1785+
target: neighborIpPort,
18191786
value: this.randomFloatFromInterval(1.0, 1.3)
18201787
});
18211788
}
@@ -1826,8 +1793,8 @@ class Monitor {
18261793

18271794
updateAllMarkers() {
18281795
Object.entries(this.droneMarkers).forEach(([uid, marker]) => {
1829-
const ip = marker.ip;
1830-
if (this.offlineNodes.has(ip)) {
1796+
const ipport = `${marker.ip}:${marker.port}`;
1797+
if (this.offlineNodes.has(ipport)) {
18311798
marker.setIcon(this.droneIconOffline);
18321799
marker.getElement().classList.add('drone-offline');
18331800
} else {

0 commit comments

Comments
 (0)