Replace sshpass with ssh2 Node.js library for reliable SSH connections. Add all 6 servers (CWP, EasyPanel, MCP Hub, Meet, WhatsApp, WhatSMS). Add 5-minute auto-collection scheduler in production mode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
95 lines
2.9 KiB
TypeScript
95 lines
2.9 KiB
TypeScript
/**
|
|
* Express API Server
|
|
* @author Descomplicar® | @link descomplicar.pt | @copyright 2026
|
|
*/
|
|
import 'dotenv/config'
|
|
import express from 'express'
|
|
import cors from 'cors'
|
|
import path from 'path'
|
|
import { fileURLToPath } from 'url'
|
|
import dashboardRouter from './routes/dashboard.js'
|
|
import monitorRouter from './routes/monitor.js'
|
|
import diagnosticRouter from './routes/diagnostic.js'
|
|
import hetznerRouter from './routes/hetzner.js'
|
|
import wpMonitorRouter from './routes/wp-monitor.js'
|
|
import serverMetricsRouter from './routes/server-metrics.js'
|
|
import { collectAllServerMetrics } from './services/server-metrics.js'
|
|
|
|
const __filename = fileURLToPath(import.meta.url)
|
|
const __dirname = path.dirname(__filename)
|
|
|
|
const app = express()
|
|
const PORT = process.env.API_PORT || 3001
|
|
const isProduction = process.env.NODE_ENV === 'production'
|
|
|
|
// Middleware
|
|
app.use(cors({
|
|
origin: process.env.FRONTEND_URL || 'http://localhost:5173',
|
|
credentials: true
|
|
}))
|
|
app.use(express.json())
|
|
|
|
// Health check
|
|
app.get('/api/health', (_req, res) => {
|
|
res.json({ status: 'ok', timestamp: new Date().toISOString() })
|
|
})
|
|
|
|
// Routes
|
|
app.use('/api/dashboard', dashboardRouter)
|
|
app.use('/api/monitor', monitorRouter)
|
|
app.use('/api/diagnostic', diagnosticRouter)
|
|
app.use('/api/hetzner', hetznerRouter)
|
|
app.use('/api/wp-monitor', wpMonitorRouter)
|
|
app.use('/api/server-metrics', serverMetricsRouter)
|
|
|
|
// Serve static files in production
|
|
if (isProduction) {
|
|
// __dirname is /app/api/dist, need to go up 2 levels to /app/dist
|
|
const distPath = path.join(__dirname, '..', '..', 'dist')
|
|
app.use(express.static(distPath))
|
|
|
|
// SPA fallback - serve index.html for all non-API routes
|
|
app.get('*', (req, res, next) => {
|
|
if (req.path.startsWith('/api')) {
|
|
return next()
|
|
}
|
|
res.sendFile(path.join(distPath, 'index.html'))
|
|
})
|
|
}
|
|
|
|
// Error handling
|
|
app.use((err: any, _req: express.Request, res: express.Response, _next: express.NextFunction) => {
|
|
console.error('Server error:', err)
|
|
res.status(500).json({ error: 'Internal server error' })
|
|
})
|
|
|
|
// Start server
|
|
app.listen(PORT, () => {
|
|
console.log('='.repeat(50))
|
|
console.log(`API Server running on http://localhost:${PORT}`)
|
|
console.log(`Dashboard: http://localhost:${PORT}/api/dashboard`)
|
|
console.log(`Monitor: http://localhost:${PORT}/api/monitor`)
|
|
console.log(`Hetzner: http://localhost:${PORT}/api/hetzner`)
|
|
console.log('='.repeat(50))
|
|
|
|
// Auto-collect server metrics every 5 minutes
|
|
if (isProduction) {
|
|
const INTERVAL = 5 * 60 * 1000
|
|
console.log('[SCHEDULER] Server metrics collection every 5min')
|
|
|
|
// Initial collection after 30s (let server stabilize)
|
|
setTimeout(() => {
|
|
collectAllServerMetrics().catch(err =>
|
|
console.error('[SCHEDULER] Initial collection failed:', err)
|
|
)
|
|
}, 30000)
|
|
|
|
// Recurring collection
|
|
setInterval(() => {
|
|
collectAllServerMetrics().catch(err =>
|
|
console.error('[SCHEDULER] Collection failed:', err)
|
|
)
|
|
}, INTERVAL)
|
|
}
|
|
})
|