const mqtt = require('mqtt');
const express = require('express');
const WebSocket = require('ws');
const fs = require('fs');
const path = require('path');
const app = express();
const port = 3001;
const brokerUrl = 'mqtt://localhost'; // Replace with your broker's URL
const client = mqtt.connect(brokerUrl);
const mainTopic = 'apu_tb';
const nodeData = Array.from({ length: 5 }, () => Array(5).fill(null));
const nodeLastActive = {}; // Track the last active timestamp for each node
// Define the path to the script
const scriptPath = path.join(__dirname, 'node_addresses.sh');
// Read the bash script
const scriptContent = fs.readFileSync(scriptPath, 'utf8');
app.post('public/index.html')
// Serve static files from the template's public folder
app.use(express.static(path.join(__dirname, 'public')));
// app.use(express.static(__dirname));
// Route to serve the main dashboard HTML file
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'public/index.html'));
});
// Example API endpoint for dashboard data
app.get('/api/data', (req, res) => {
res.json({
users: 150,
sales: 2500,
revenue: 50000,
active_sessions: 45
});
});
const server = require('http').createServer(app);
const ws = new WebSocket.Server({ server });
// Start the server
server.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
// Function to parse associative arrays from the bash script
function parseAssociativeArray(script, arrayName) {
const regex = new RegExp(`declare -A ${arrayName}\\s*=\\s*\\(([^)]+)\\)`, 's');
const match = script.match(regex);
if (!match) return {};
const entries = match[1].trim().split('\n').map(line => line.trim()).filter(line => line.startsWith('["'));
const obj = {};
entries.forEach(entry => {
const parts = entry.match(/\["(.+?)"\]="(.+?)"/);
if (parts) {
obj[parts[1]] = parts[2];
}
});
return obj;
}
const mesh0MAC = parseAssociativeArray(scriptContent, 'phy0MAC');
const mesh1MAC = parseAssociativeArray(scriptContent, 'phy1MAC');
// console.log(mesh0MAC);
// console.log(mesh1MAC);
function broadcastNodeData() {
const nodeStatus = generateNodeStatus();
const message = JSON.stringify({ nodeData, nodeStatus });
// Send to WebSocket clients
ws.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
}
// Function to generate status colors based on activity
function generateNodeStatus() {
const now = Date.now();
return nodeData.map((row, y) =>
row.map((cell, x) =>
nodeLastActive[`${y},${x}`] && (now - nodeLastActive[`${y},${x}`] < 60000) ? "lightgreen" : "lightcoral"
)
);
}
client.on('connect', () => {
console.log('Connected to MQTT broker');
client.subscribe(`${mainTopic}/#`, (err) => {
if (!err) {
console.log(`Subscribed to all subtopics of: ${mainTopic}`);
} else {
console.error('Subscription error:', err);
}
});
});
client.on('message', (topic, message) => {
try {
const payload = JSON.parse(message.toString());
if (Array.isArray(payload) && payload.length === 2) {
const data = payload[0];
const metadata = payload[1];
const { uptime, cpu_temp, mem_util, cpu_util, XPosition, YPosition, mesh0_neighbors, mesh1_neighbors } = data;
const { id } = metadata;
if (XPosition >= 0 && XPosition < 5 && YPosition >= 0 && YPosition < 5) {
// nodeData[YPosition][XPosition] = `ID: ${id}
Temp: ${cpu_temp}°C
CUtil: ${cpu_util}
MUtil: ${mem_util}
UpTime: ${uptime}`;
nodeData[YPosition][XPosition] = {
id, cpu_temp, mem_util, cpu_util, uptime, mesh0_neighbors, mesh1_neighbors
};
// console.log("MAC Links:", JSON.stringify(mesh0_neighbors, null, 2));
// Update the last active timestamp for the node
nodeLastActive[`${YPosition},${XPosition}`] = Date.now();
// console.log(`Node data updated for ID ${id} at position (${XPosition}, ${YPosition})`);
// Broadcast updated data and statuses
// broadcastNodeData();
// console.log("Checkboxes known:", checkedNodeInfo); // Use this array in your app
}
} else {
console.error('Unexpected payload format:', payload);
}
} catch (err) {
console.error('Failed to process message:', err);
}
});
// Periodically broadcast the node status
setInterval(() => {
broadcastNodeData();
}, 1000);