206 lines
6.8 KiB
JavaScript
206 lines
6.8 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
const express = require('express');
|
|
const { exec } = require('child_process');
|
|
const util = require('util');
|
|
const execAsync = util.promisify(exec);
|
|
|
|
const app = express();
|
|
const PORT = 3006;
|
|
|
|
// Middleware CORS
|
|
app.use((req, res, next) => {
|
|
res.header('Access-Control-Allow-Origin', '*');
|
|
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
next();
|
|
});
|
|
|
|
// Services à surveiller
|
|
const services = [
|
|
{ name: 'Bitcoin Signet', container: 'bitcoin', port: 8332, protocol: 'RPC' },
|
|
{ name: 'BlindBit Oracle', container: 'blindbit', port: 8000, protocol: 'HTTP' },
|
|
{ name: 'SDK Relay', container: 'sdk_relay', port: 8090, protocol: 'WebSocket' },
|
|
{ name: 'SDK Storage', container: 'sdk_storage', port: 8080, protocol: 'HTTP' },
|
|
{ name: 'LeCoffre Backend', container: 'lecoffre-back', port: 8080, protocol: 'HTTP' },
|
|
{ name: 'LeCoffre Frontend', container: 'lecoffre-front', port: 3000, protocol: 'HTTP' },
|
|
{ name: 'IHM Client', container: 'ihm_client', port: 3001, protocol: 'HTTP' },
|
|
{ name: 'Tor Proxy', container: 'tor-proxy', port: 9050, protocol: 'SOCKS' },
|
|
{ name: 'Grafana', container: 'grafana', port: 3000, protocol: 'HTTP' },
|
|
{ name: 'Loki', container: 'loki', port: 3100, protocol: 'HTTP' },
|
|
{ name: 'Promtail', container: 'promtail', port: 9080, protocol: 'HTTP' },
|
|
{ name: 'Miner Signet', container: 'signet_miner', port: null, protocol: 'Bitcoin' }
|
|
];
|
|
|
|
const externalServices = [
|
|
{ name: 'Mempool Signet', url: 'https://mempool2.4nkweb.com', protocol: 'HTTPS' },
|
|
{ name: 'Relay Bootstrap', url: 'wss://dev3.4nkweb.com/ws/', protocol: 'WebSocket' },
|
|
{ name: 'Signer Bootstrap', url: 'https://dev3.4nkweb.com', protocol: 'HTTPS' },
|
|
{ name: 'Git Repository', url: 'git.4nkweb.com', protocol: 'SSH' }
|
|
];
|
|
|
|
async function getDockerContainers() {
|
|
try {
|
|
const { stdout } = await execAsync('docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"');
|
|
return stdout;
|
|
} catch (error) {
|
|
console.error('Erreur lors de la récupération des conteneurs:', error);
|
|
return '';
|
|
}
|
|
}
|
|
|
|
async function getContainerInfo(containerName) {
|
|
try {
|
|
const { stdout } = await execAsync(`docker inspect ${containerName} --format '{{.State.Status}}|{{.State.StartedAt}}|{{.Config.Image}}|{{.NetworkSettings.IPAddress}}|{{range $port, $binding := .NetworkSettings.Ports}}{{$port}}={{range $binding}}{{.HostIP}}:{{.HostPort}} {{end}}{{end}}'`);
|
|
return stdout.trim();
|
|
} catch (error) {
|
|
return 'stopped||N/A|N/A|';
|
|
}
|
|
}
|
|
|
|
async function getServiceHealth(containerName, port) {
|
|
if (!port) return 'unknown';
|
|
|
|
try {
|
|
const { stdout } = await execAsync(`docker exec ${containerName} wget -q --spider -O- http://localhost:${port}/health 2>/dev/null || echo "unhealthy"`);
|
|
return stdout.trim() === 'unhealthy' ? 'unhealthy' : 'healthy';
|
|
} catch (error) {
|
|
return 'unknown';
|
|
}
|
|
}
|
|
|
|
async function checkExternalService(url) {
|
|
const start = Date.now();
|
|
try {
|
|
// Skip WebSocket URLs for now
|
|
if (url.startsWith('wss://') || url.startsWith('ws://')) {
|
|
return {
|
|
status: 'running',
|
|
response_time: 'N/A (WebSocket)'
|
|
};
|
|
}
|
|
|
|
const http = require('http');
|
|
const https = require('https');
|
|
const urlObj = new URL(url);
|
|
const client = urlObj.protocol === 'https:' ? https : http;
|
|
|
|
return new Promise((resolve) => {
|
|
const req = client.get(url, { timeout: 5000 }, (res) => {
|
|
resolve({
|
|
status: 'running',
|
|
response_time: `${Date.now() - start}ms`
|
|
});
|
|
});
|
|
|
|
req.on('error', () => {
|
|
resolve({
|
|
status: 'error',
|
|
response_time: 'N/A'
|
|
});
|
|
});
|
|
|
|
req.on('timeout', () => {
|
|
resolve({
|
|
status: 'timeout',
|
|
response_time: '>5s'
|
|
});
|
|
});
|
|
});
|
|
} catch (error) {
|
|
return {
|
|
status: 'error',
|
|
response_time: 'N/A'
|
|
};
|
|
}
|
|
}
|
|
|
|
function calculateUptime(startedAt) {
|
|
if (!startedAt || startedAt === 'N/A') return 'N/A';
|
|
|
|
try {
|
|
const start = new Date(startedAt);
|
|
const now = new Date();
|
|
const diff = now - start;
|
|
|
|
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
|
|
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
|
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
|
|
|
|
if (days > 0) return `${days}j ${hours}h ${minutes}m`;
|
|
if (hours > 0) return `${hours}h ${minutes}m`;
|
|
return `${minutes}m`;
|
|
} catch (error) {
|
|
return 'N/A';
|
|
}
|
|
}
|
|
|
|
async function getServicesStatus() {
|
|
const servicesStatus = [];
|
|
|
|
for (const service of services) {
|
|
const containerInfo = await getContainerInfo(service.container);
|
|
const [status, startedAt, image, ip, ports] = containerInfo.split('|');
|
|
|
|
const portsArray = ports ? ports.split(' ').filter(p => p.trim()) : [];
|
|
const health = await getServiceHealth(service.container, service.port);
|
|
const uptime = calculateUptime(startedAt);
|
|
|
|
servicesStatus.push({
|
|
name: service.name,
|
|
status: status === 'running' ? 'running' : 'stopped',
|
|
image: image || 'N/A',
|
|
ip: ip || 'N/A',
|
|
ports: portsArray,
|
|
uptime: uptime,
|
|
health: health,
|
|
protocol: service.protocol,
|
|
port: service.port
|
|
});
|
|
}
|
|
|
|
return servicesStatus;
|
|
}
|
|
|
|
async function getExternalServicesStatus() {
|
|
const externalStatus = [];
|
|
|
|
for (const service of externalServices) {
|
|
const status = await checkExternalService(service.url);
|
|
externalStatus.push({
|
|
name: service.name,
|
|
url: service.url,
|
|
protocol: service.protocol,
|
|
...status
|
|
});
|
|
}
|
|
|
|
return externalStatus;
|
|
}
|
|
|
|
app.get('/api', async (req, res) => {
|
|
try {
|
|
const services = await getServicesStatus();
|
|
const external = await getExternalServicesStatus();
|
|
|
|
res.json({
|
|
timestamp: new Date().toISOString(),
|
|
services: services,
|
|
external: external
|
|
});
|
|
} catch (error) {
|
|
console.error('Erreur API:', error);
|
|
res.status(500).json({ error: 'Erreur interne du serveur' });
|
|
}
|
|
});
|
|
|
|
app.get('/health', (req, res) => {
|
|
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
|
});
|
|
|
|
app.listen(PORT, '0.0.0.0', () => {
|
|
console.log(`🚀 API Status démarrée sur http://0.0.0.0:${PORT}`);
|
|
});
|
|
|
|
module.exports = app;
|