const express = require('express'); const { spawn } = require('child_process'); const cors = require('cors'); const path = require('path'); const fs = require('fs'); const VERSION = "1.2.0"; // Added for debugging and tracking const app = express(); const port = 3005; // --- DATABASE INITIALIZATION --- // Initialize the SQLite database on startup to ensure the 'gtm_projects' table exists. const dbScript = path.join(__dirname, 'gtm_db_manager.py'); console.log(`[Init] Initializing database via ${dbScript}...`); const initProcess = spawn('python3', [dbScript, 'init']); initProcess.stdout.on('data', (data) => console.log(`[DB Init] ${data.toString().trim()}`)); initProcess.stderr.on('data', (data) => console.error(`[DB Init Error] ${data.toString().trim()}`)); initProcess.on('close', (code) => { if (code === 0) { console.log('[DB Init] Database initialization completed successfully.'); } else { console.error(`[DB Init] Database initialization failed with code ${code}.`); } }); // ------------------------------- // Enable CORS for all routes app.use(cors()); // Serve static files from the 'dist' directory const staticPath = path.join(__dirname, 'dist'); if (fs.existsSync(staticPath)) { app.use(express.static(staticPath)); } else { console.warn(`Static path not found: ${staticPath}. The frontend might not be served correctly. Make sure to build the frontend first.`); } app.use(express.json({ limit: '50mb' })); // API endpoint to run the Python script app.post('/api/run', (req, res) => { const { mode, ...payload } = req.body; if (!mode) { return res.status(400).json({ error: 'Mode is required' }); } // E2BIG FIX: Write payload to a temporary file instead of passing via command line args const tmpDir = path.join(__dirname, 'tmp'); if (!fs.existsSync(tmpDir)) { fs.mkdirSync(tmpDir); } const payloadFilePath = path.join(tmpDir, `payload_${Date.now()}_${Math.random().toString(36).substring(7)}.json`); try { fs.writeFileSync(payloadFilePath, JSON.stringify(payload)); } catch (err) { console.error("Failed to write payload file:", err); return res.status(500).json({ error: "Failed to process request payload." }); } const pythonScriptPath = path.join(__dirname, 'gtm_architect_orchestrator.py'); const pythonProcess = spawn('python3', [ pythonScriptPath, '--mode', mode, '--payload_file', payloadFilePath // Use file path instead of base64 string ]); let stdoutData = ''; let stderrData = ''; // STREAMING LOGS: Output Python logs immediately to Docker console pythonProcess.stdout.on('data', (data) => { const str = data.toString(); console.log(`[Python stdout] ${str.trim()}`); stdoutData += str; }); pythonProcess.stderr.on('data', (data) => { const str = data.toString(); console.error(`[Python stderr] ${str.trim()}`); stderrData += str; }); pythonProcess.on('close', (code) => { // Cleanup temp file try { if (fs.existsSync(payloadFilePath)) fs.unlinkSync(payloadFilePath); } catch (e) { console.error("Failed to delete temp payload file:", e); } if (code !== 0) { console.error(`Python script exited with code ${code}`); console.error('Stderr:', stderrData); return res.status(500).json({ error: 'Python script execution failed.', stderr: stderrData, }); } try { // The Python script is expected to print JSON to stdout const result = JSON.parse(stdoutData); res.json(result); } catch (e) { console.error('Failed to parse JSON from Python script stdout:', e); console.error('Stdout:', stdoutData); res.status(500).json({ error: 'Failed to parse response from Python script.', stdout: stdoutData, }); } }); }); // Serve the main index.html for any other GET request to support client-side routing if (fs.existsSync(staticPath)) { app.get('*', (req, res) => { res.sendFile(path.join(staticPath, 'index.html')); }); } const server = app.listen(port, () => { console.log(`Server listening on port ${port} (Version: ${VERSION})`); }); server.setTimeout(600000); // 10 minutes server.keepAliveTimeout = 610000; server.headersTimeout = 620000;