const express = require('express'); const { exec } = require('child_process'); const fs = require('fs'); const path = require('path'); const csv = require('csv-parser'); const http = require('http'); const socketIoServer = require('socket.io'); const chokidar = require('chokidar'); const socketIoClient = require('socket.io-client'); const app = express(); const server = http.createServer(app); const ioServer = socketIoServer(server); // Server-side socket.io instance const socketClient = socketIoClient('http://localhost:5000'); // Client-side socket.io connection to Python app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(express.static(path.join(__dirname, 'public'))); // Define file paths const processingLogPath = "/Users/macos/Documents/SINDIGILIVE/CLIENTS/ICON+/Project-HES/Update_DCU/processing_log.txt"; const updatedLogPath = "/Users/macos/Documents/SINDIGILIVE/CLIENTS/ICON+/Project-HES/Update_DCU/update_log.csv"; // Clear specified files when the app starts function clearLogs() { [processingLogPath, updatedLogPath].forEach((filePath) => { fs.writeFile(filePath, '', (err) => { if (err) { console.error(`Error clearing file ${filePath}:`, err); } else { console.log(`File cleared: ${filePath}`); } }); }); } // Call clearLogs on startup clearLogs(); // Stream log data in real-time to WebSocket clients function streamLogToClients(socket) { // Send the entire log file content when a client connects fs.readFile(processingLogPath, 'utf8', (err, data) => { if (!err && data) { socket.emit('logUpdate', data); } }); // Watch for changes to the log file fs.watch(processingLogPath, { encoding: 'utf8' }, (eventType) => { if (eventType === 'change') { fs.readFile(processingLogPath, 'utf8', (err, data) => { if (!err && data) { // Send updated log content to the client socket.emit('logUpdate', data); } }); } }); // Clean up on disconnect socket.on('disconnect', () => { console.log('Client disconnected'); }); } // Function for streaming log real-time to table function streamUpdatedLogToClients(socket) { // Read and send initial data from CSV to client on first connection sendUpdatedLogData(socket); // Watch for changes in the CSV file const watcher = chokidar.watch(updatedLogPath, { ignoreInitial: true }); watcher.on('change', () => { sendUpdatedLogData(socket); }); socket.on('disconnect', () => { watcher.close(); console.log('Stopped watching updated log file'); }); } // Function to read and send data from CSV to client function sendUpdatedLogData(socket) { const rows = []; fs.createReadStream(updatedLogPath) .pipe(csv()) .on('data', (row) => { rows.push(row); }) .on('end', () => { console.log('Updated data sent to client:', rows); socket.emit('tableUpdate', rows); // Emit data to the client }) .on('error', (err) => { console.error('Error reading CSV file:', err); }); } // Count number of DCU entries app.post('/count-ips', (req, res) => { const ipList = req.body.ipList || ''; const sanitizedList = ipList.replace(/\r\n/g, '\n'); // Normalize line endings const ips = sanitizedList.split(/[\n,]+/).map(ip => ip.trim()).filter(ip => ip !== ''); res.json({ total: ips.length }); }); // Variabel global untuk menyimpan proses yang sedang berjalan let currentProcess = null; app.post('/run-script', (req, res) => { const ipList = req.body.ipList; const venvPath = path.join(__dirname, 'bin/activate'); const pythonScriptPath = path.join(__dirname, 'update_dcu_by_nodejs.py'); const ipArgs = ipList.join(' '); const command = `source ${venvPath} && python ${pythonScriptPath} ${ipArgs}`; // Jalankan perintah Python dan simpan proses ke `currentProcess` currentProcess = exec(command, (error, stdout, stderr) => { currentProcess = null; // Reset `currentProcess` setelah selesai if (error) { console.error(`Error: ${error.message}`); return res.status(500).send(`Error: ${error.message}`); } if (stderr) { console.error(`Stderr: ${stderr}`); return res.status(500).send(`Stderr: ${stderr}`); } const processedData = []; fs.createReadStream(updatedLogPath) .pipe(csv()) .on('data', (row) => { if (row['Update Status'] === 'Success') { processedData.push(row); } }) .on('end', () => { res.json({ processedData, totalProcessed: processedData.length }); }); }); }); // Endpoint untuk menghentikan proses yang sedang berjalan app.post('/stop-script', (req, res) => { console.log("Stop script endpoint hit"); // Emit the 'stop_tunnel' event to Python socketClient.emit("stop_tunnel"); // Optionally, handle the response from Python socketClient.once("tunnel_status", (data) => { console.log("Tunnel status:", data.status); // Logs 'terminated' or 'not_active' status res.send({status: data.status}); }); }); // WebSocket connection event for clients connecting to this server ioServer.on('connection', (socket) => { console.log('Client connected to WebSocket'); // Stream log text streamLogToClients(socket); // Stream updated log CSV streamUpdatedLogToClients(socket); }); const PORT = process.env.PORT || 3000; server.listen(PORT, () => { console.log(`Server running on port ${PORT}`); }); module.exports = app;