From: Steph Ponzo Date: Mon, 23 Feb 2026 18:00:01 +0000 (+0100) Subject: Ajout serveur principal avec Socket.IO + page de test X-Git-Url: https://git.digitality.be/?a=commitdiff_plain;h=fba6d492d62ba8e1cd2ab676f2370ec4ead86f25;p=pdw25-26 Ajout serveur principal avec Socket.IO + page de test --- diff --git a/server/app.js b/server/app.js new file mode 100644 index 0000000..91b3589 --- /dev/null +++ b/server/app.js @@ -0,0 +1,399 @@ +// ========================================================= +// WALL-E-TTE - SERVEUR PRINCIPAL +// ========================================================= +// Point d'entrée de l'application +// Intègre tous les modules : Alerts, (Stratégie, Prix, etc.) +// ========================================================= +// USAGE : node app.js +// ========================================================= + +import cors from 'cors'; +import dotenv from 'dotenv'; +import express from 'express'; +import { createServer } from 'http'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +// Charger les variables d'environnement +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +dotenv.config({ path: path.resolve(__dirname, '.env') }); + +// ========================================================= +// IMPORTS DES MODULES +// ========================================================= + +// Module Alerts (Stéphane) +import db from './config/db.js'; +import { createMySQLAdapter } from './modules/alerts/adapters/mysql.adapter.js'; +import { createAlertsController } from './modules/alerts/alerts.controller.js'; +import { createAlertsRepo } from './modules/alerts/alerts.repo.js'; +import { createAlertsRouter } from './modules/alerts/alerts.router.js'; +import { createAlertsService } from './modules/alerts/alerts.service.js'; +import { broadcastAlert, getConnectedUsersCount, initSocketIO } from './modules/alerts/socketManager.js'; + +// ───────────────────────────────────────────────────────── +// TODO: Ajouter les autres modules ici +// ───────────────────────────────────────────────────────── +// Module Stratégie (Sacha) +// import { initializeStrategyModule } from './modules/strategy/index.js'; + +// Module Prix (Valentin) +// import { initializePriceModule } from './modules/price/index.js'; + +// Module Auth (si existant) +// import { initializeAuthModule } from './modules/auth/index.js'; + +// ========================================================= +// CRÉER L'APPLICATION EXPRESS +// ========================================================= +const app = express(); + +// Middlewares +app.use(cors()); // Autoriser les requêtes cross-origin +app.use(express.json()); // Parser le JSON +app.use(express.urlencoded({ extended: true })); + +// ========================================================= +// CRÉER LE SERVEUR HTTP (nécessaire pour Socket.IO) +// ========================================================= +const httpServer = createServer(app); + +// ========================================================= +// INITIALISER SOCKET.IO +// ========================================================= +const io = initSocketIO(httpServer, { + cors: { + origin: "*", // En prod, restreindre aux domaines autorisés + methods: ["GET", "POST"] + } +}); + +console.log('✅ Socket.IO initialisé'); + +// ========================================================= +// INITIALISER LE MODULE ALERTS (Stéphane) +// ========================================================= +const alertsAdapter = createMySQLAdapter(db); +const alertsRepo = createAlertsRepo(alertsAdapter); +const alertsService = createAlertsService(alertsRepo); +const alertsController = createAlertsController(alertsService, alertsRepo); +const alertsRouter = createAlertsRouter(alertsController); + +console.log('✅ Module Alerts initialisé'); + +// ========================================================= +// MONTER LES ROUTES API +// ========================================================= + +// Routes Alerts +app.use('/api/alerts', alertsRouter); + +// ───────────────────────────────────────────────────────── +// TODO: Monter les autres routes ici +// ───────────────────────────────────────────────────────── +// app.use('/api/strategy', strategyRouter); +// app.use('/api/price', priceRouter); +// app.use('/api/auth', authRouter); + +// ========================================================= +// ROUTE HEALTH CHECK +// ========================================================= +app.get('/', (req, res) => { + res.json({ + name: 'Wall-e-tte API', + status: 'running', + version: '1.0.0', + socketConnections: getConnectedUsersCount(), + timestamp: new Date().toISOString(), + endpoints: { + alerts: '/api/alerts', + // strategy: '/api/strategy', + // price: '/api/price', + } + }); +}); + +// ========================================================= +// PAGE DE TEST SOCKET.IO +// ========================================================= +app.get('/test', (req, res) => { + res.send(` + + + + + Wall-e-tte - Test Socket.IO + + + + +

Wall-e-tte - Test Socket.IO

+ +
+ Déconnecté +
+ + + +
+ + + +
+ +

Alertes reçues

+
+ En attente d'alertes... +
+ +

Log

+
+ + + +`); +}); + +// ========================================================= +// ROUTE DE TEST : SIMULER UNE ALERTE +// ========================================================= +app.post('/test/broadcast-alert', (req, res) => { + const testAlert = req.body.alert || { + action: 'BUY', + pair: 'BTC/EUR', + confidence: 0.87, + reason: 'Signal de test', + alertLevel: 'WARNING', + price: 42150.23 + }; + + const count = broadcastAlert(testAlert); + + res.json({ + success: true, + message: `Alerte envoyée à ${count} utilisateur(s) connecté(s)`, + alert: testAlert + }); +}); + +// ========================================================= +// GESTION DES ERREURS 404 +// ========================================================= +app.use((req, res) => { + res.status(404).json({ + error: 'Route non trouvée', + path: req.path + }); +}); + +// ========================================================= +// GESTION DES ERREURS GLOBALES +// ========================================================= +app.use((err, req, res, next) => { + console.error(' Erreur serveur:', err); + res.status(500).json({ + error: 'Erreur serveur', + message: process.env.NODE_ENV === 'development' ? err.message : undefined + }); +}); + +// ========================================================= +// DÉMARRER LE SERVEUR +// ========================================================= +const PORT = process.env.PORT || 3000; + +httpServer.listen(PORT, () => { + console.log(` +╔═══════════════════════════════════════════════════════════╗ +║ WALL-E-TTE SERVER ║ +╠═══════════════════════════════════════════════════════════╣ +║ ║ +║ HTTP : http://localhost:${PORT} ║ +║ Socket : ws://localhost:${PORT} ║ +║ ║ +╠═══════════════════════════════════════════════════════════╣ +║ MODULES ACTIFS : ║ +║ Alerts (Stéphane) → /api/alerts ║ +║ Strategy (Sacha) → À intégrer ║ +║ Price (Valentin) → À intégrer ║ +║ ║ +╠═══════════════════════════════════════════════════════════╣ +║ SOCKET.IO EVENTS : ║ +║ → Client envoie 'auth' avec userId ║ +║ → Client reçoit 'alert' quand signal détecté ║ +║ ║ +╚═══════════════════════════════════════════════════════════╝ +`); +}); + +// ========================================================= +// EXPORT POUR LES AUTRES MODULES +// ========================================================= +// Les autres modules peuvent importer le service alerts +// pour envoyer des notifications +export { alertsRepo, alertsService, io }; + diff --git a/server/package-lock.json b/server/package-lock.json index ba0a0df..4ca2e4c 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -1,22 +1,22 @@ { - "name": "wall-e-tte-alerts", + "name": "wall-e-tte-server", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "wall-e-tte-alerts", + "name": "wall-e-tte-server", "version": "1.0.0", "license": "ISC", "dependencies": { + "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.18.2", "mysql2": "^3.6.5", - "nodemailer": "^6.9.7", + "nodemailer": "^8.0.1", "socket.io": "^4.8.3", "uuid": "^9.0.1" - }, - "devDependencies": {} + } }, "node_modules/@socket.io/component-emitter": { "version": "3.1.2", @@ -749,9 +749,9 @@ } }, "node_modules/nodemailer": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.1.tgz", - "integrity": "sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.1.tgz", + "integrity": "sha512-5kcldIXmaEjZcHR6F28IKGSgpmZHaF1IXLWFTG+Xh3S+Cce4MiakLtWY+PlBU69fLbRa8HlaGIrC/QolUpHkhg==", "license": "MIT-0", "engines": { "node": ">=6.0.0" diff --git a/server/package.json b/server/package.json index 59655e5..1c28eb2 100644 --- a/server/package.json +++ b/server/package.json @@ -1,25 +1,29 @@ { - "name": "wall-e-tte-alerts", + "name": "wall-e-tte-server", "version": "1.0.0", - "description": "Module d'alertes et notifications pour Wall-e-tte", + "description": "Serveur Wall-e-tte - Trading Crypto Advisor", "type": "module", - "main": "modules/alerts/alerts.service.js", + "main": "app.js", "scripts": { - "test": "node test-alerts.js" + "start": "node app.js", + "dev": "node --watch app.js", + "test": "node test-module-complet.js", + "test:server": "node test-server-socket.js" }, "keywords": [ "crypto", + "trading", "alerts", - "notifications", "wall-e-tte" ], - "author": "Stéphane", + "author": "Équipe Wall-e-tte", "license": "ISC", "dependencies": { + "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.18.2", "mysql2": "^3.6.5", - "nodemailer": "^6.9.7", + "nodemailer": "^8.0.1", "socket.io": "^4.8.3", "uuid": "^9.0.1" } diff --git a/server/test-server-socket.js b/server/test-server-socket.js new file mode 100644 index 0000000..dbac7f0 --- /dev/null +++ b/server/test-server-socket.js @@ -0,0 +1,169 @@ +// ========================================================= +// SERVEUR DE TEST AVEC SOCKET.IO +// ========================================================= +// Lance ce serveur pour tester les alertes temps réel +// avec Thibault (mobile) ou Océane (web) +// ========================================================= +// USAGE : node test-server-socket.js +// ========================================================= + +import express from 'express'; +import { createServer } from 'http'; +import dotenv from 'dotenv'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +// Charger les variables d'environnement +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +dotenv.config({ path: path.resolve(__dirname, '.env') }); + +// ========================================================= +// IMPORTS DU MODULE ALERTS +// ========================================================= +import db from './config/db.js'; +import { createMySQLAdapter } from './modules/alerts/adapters/mysql.adapter.js'; +import { createAlertsRepo } from './modules/alerts/alerts.repo.js'; +import { createAlertsService } from './modules/alerts/alerts.service.js'; +import { createAlertsController } from './modules/alerts/alerts.controller.js'; +import { createAlertsRouter } from './modules/alerts/alerts.router.js'; +import { initSocketIO, sendAlertToUser, broadcastAlert, getConnectedUsersCount } from './modules/alerts/socketManager.js'; + +// ========================================================= +// CRÉER L'APPLICATION EXPRESS +// ========================================================= +const app = express(); +app.use(express.json()); + +// ========================================================= +// CRÉER LE SERVEUR HTTP (nécessaire pour Socket.IO) +// ========================================================= +const httpServer = createServer(app); + +// ========================================================= +// INITIALISER SOCKET.IO +// ========================================================= +const io = initSocketIO(httpServer, { + cors: { + origin: "*", // Accepter toutes les origines pour le test + methods: ["GET", "POST"] + } +}); + +// ========================================================= +// INITIALISER LE MODULE ALERTS +// ========================================================= +const adapter = createMySQLAdapter(db); +const repo = createAlertsRepo(adapter); +const service = createAlertsService(repo); +const controller = createAlertsController(service, repo); +const router = createAlertsRouter(controller); + +// ========================================================= +// MONTER LES ROUTES +// ========================================================= +app.use('/api/alerts', router); + +// ========================================================= +// ROUTE DE TEST / HEALTH CHECK +// ========================================================= +app.get('/', (req, res) => { + res.json({ + status: 'ok', + message: 'Serveur Wall-e-tte avec Socket.IO', + socketConnections: getConnectedUsersCount(), + timestamp: new Date().toISOString() + }); +}); + +// ========================================================= +// ROUTE POUR SIMULER UNE ALERTE (test) +// ========================================================= +app.post('/test/send-alert', (req, res) => { + const { userId, broadcast } = req.body; + + const testAlert = { + action: 'BUY', + pair: 'BTC/EUR', + confidence: 0.87, + reason: 'Test manuel depuis le serveur', + alertLevel: 'WARNING', + price: 42150.23 + }; + + if (broadcast) { + // Envoyer à tous + const count = broadcastAlert(testAlert); + res.json({ + success: true, + message: `Alerte envoyée à ${count} utilisateur(s)` + }); + } else if (userId) { + // Envoyer à un utilisateur spécifique + const sent = sendAlertToUser(userId, testAlert); + res.json({ + success: sent, + message: sent ? 'Alerte envoyée' : 'Utilisateur non connecté' + }); + } else { + res.status(400).json({ + error: 'userId ou broadcast requis' + }); + } +}); + +// ========================================================= +// ROUTE POUR VOIR LES CONNEXIONS ACTIVES +// ========================================================= +app.get('/test/connections', (req, res) => { + const { getConnectedUserIds } = require('./modules/alerts/socketManager.js'); + res.json({ + count: getConnectedUsersCount(), + users: getConnectedUserIds ? getConnectedUserIds() : 'N/A' + }); +}); + +// ========================================================= +// DÉMARRER LE SERVEUR +// ========================================================= +const PORT = process.env.PORT || 3000; + +httpServer.listen(PORT, () => { + console.log(` + ╔═══════════════════════════════════════════════════════════╗ + ║ SERVEUR WALL-E-TTE AVEC SOCKET.IO ║ + ╠═══════════════════════════════════════════════════════════╣ + ║ ║ + ║ HTTP Server : http://localhost:${PORT} ║ + ║ Socket.IO : ws://localhost:${PORT} ║ + ║ ║ + ╠═══════════════════════════════════════════════════════════╣ + ║ ROUTES API : ║ + ║ ─────────────────────────────────────────────────────── ║ + ║ GET / → Health check ║ + ║ GET /test/connections → Voir qui est connecté ║ + ║ POST /test/send-alert → Simuler une alerte ║ + ║ POST /api/alerts/rules → Créer une règle ║ + ║ GET /api/alerts/rules/:id → Lister les règles ║ + ║ ║ + ╠═══════════════════════════════════════════════════════════╣ + ║ SOCKET.IO EVENTS : ║ + ║ ─────────────────────────────────────────────────────── ║ + ║ Client → Serveur : ║ + ║ • 'auth' (userId) → S'authentifier ║ + ║ • 'ping_alerts' → Tester la connexion ║ + ║ ║ + ║ Serveur → Client : ║ + ║ • 'auth_success' → Authentification OK ║ + ║ • 'alert' → Réception d'une alerte ║ + ║ • 'pong_alerts' → Réponse au ping ║ + ║ ║ + ╚═══════════════════════════════════════════════════════════╝ + + + Pour tester manuellement : + curl -X POST http://localhost:${PORT}/test/send-alert -H "Content-Type: application/json" -d '{"broadcast": true}' + + Ctrl+C pour arrêter. +`); +});