# Plan d'Implémentation: WebModule **Objectif**: Ajouter un module hot-reload permettant aux autres modules de faire des requêtes HTTP de manière dynamique via IIO. **Status**: 📋 Planifié **Priorité**: Moyenne **Durée estimée**: 2-3h --- ## 1. Vue d'Ensemble ### Architecture ``` ┌─────────────────────────────────────────────────┐ │ Modules Clients │ │ (AI, Monitoring, Scheduler, etc.) │ │ │ │ → Publient: "web:request" │ │ ← Reçoivent: "web:response" │ └──────────────┬──────────────────────────────────┘ │ IIO pub/sub ▼ ┌─────────────────────────────────────────────────┐ │ WebModule (Hot-reload) │ │ │ │ • Subscribe: "web:request" │ │ • Execute HTTP via HttpClient.hpp │ │ • Publish: "web:response" │ │ • Track stats (total, success, failed) │ │ • State preservation (hot-reload) │ └──────────────┬──────────────────────────────────┘ │ Uses existing HttpClient.hpp ▼ Internet ``` ### Avantages ✅ **Hot-reload**: Rechargement sans arrêter le système ✅ **Découplage**: Modules clients ignorent les détails HTTP ✅ **Centralisé**: Un seul point pour toutes les requêtes HTTP ✅ **Statistiques**: Tracking automatique (total, succès, échecs) ✅ **État persistant**: Stats survivent au hot-reload ✅ **Réutilisation**: Utilise HttpClient.hpp existant --- ## 2. Fichiers à Créer ### 2.1 Module Core #### `src/modules/WebModule.h` (70 lignes) ```cpp #pragma once #include #include #include namespace aissia { class WebModule : public grove::IModule { public: WebModule(); ~WebModule() override = default; // IModule interface void setConfiguration(const grove::IDataNode& config, grove::IIO* io, grove::ITaskScheduler* scheduler) override; const grove::IDataNode& getConfiguration() override; void process(const grove::IDataNode& input) override; std::unique_ptr getHealthStatus() override; void shutdown() override; // State management (hot-reload) std::unique_ptr getState() override; void setState(const grove::IDataNode& state) override; private: void processMessages(); void handleWebRequest(const grove::IDataNode& request); grove::IIO* m_io = nullptr; std::shared_ptr m_logger; std::unique_ptr m_config; // Configuration int m_requestTimeoutMs = 30000; int m_maxConcurrentRequests = 10; // Statistics int m_totalRequests = 0; int m_successfulRequests = 0; int m_failedRequests = 0; }; } // namespace aissia ``` #### `src/modules/WebModule.cpp` (180 lignes) - Implémentation complète - Gestion GET/POST - Gestion des erreurs - Publication des réponses - État pour hot-reload ### 2.2 Configuration #### `config/web.json` (nouveau) ```json { "enabled": true, "requestTimeoutMs": 30000, "maxConcurrentRequests": 10, "allowedDomains": [ "api.example.com", "*.openai.com" ], "blockedDomains": [] } ``` ### 2.3 Tests #### `tests/modules/WebModuleTests.cpp` (10 tests) ``` TI_WEB_001: Simple GET Request TI_WEB_002: POST Request with Body TI_WEB_003: Invalid URL Handling TI_WEB_004: Timeout Handling TI_WEB_005: Multiple Concurrent Requests TI_WEB_006: Request ID Tracking TI_WEB_007: Statistics Tracking TI_WEB_008: State Serialization TI_WEB_009: Configuration Loading TI_WEB_010: Error Response Format ``` --- ## 3. Protocole IIO ### 3.1 Requête (`web:request`) **Topic**: `web:request` **Payload**: ```json { "requestId": "unique-id-123", "url": "https://api.example.com/data", "method": "GET", "headers": { "Authorization": "Bearer xxx", "Content-Type": "application/json" }, "body": "{\"key\": \"value\"}", "timeoutMs": 5000 } ``` **Champs**: - `requestId` (string, required): ID unique pour matcher la réponse - `url` (string, required): URL complète avec schéma - `method` (string, optional): "GET", "POST", "PUT", "DELETE" (default: "GET") - `headers` (object, optional): Headers HTTP custom - `body` (string, optional): Body pour POST/PUT - `timeoutMs` (int, optional): Timeout custom (default: 30000) ### 3.2 Réponse (`web:response`) **Topic**: `web:response` **Payload (Success)**: ```json { "requestId": "unique-id-123", "success": true, "statusCode": 200, "body": "{\"result\": \"data\"}", "headers": { "Content-Type": "application/json" }, "durationMs": 234 } ``` **Payload (Error)**: ```json { "requestId": "unique-id-123", "success": false, "error": "Connection timeout", "errorCode": "TIMEOUT", "durationMs": 30001 } ``` --- ## 4. Étapes d'Implémentation ### Phase 1: Core Module (1h) 1. **Créer les fichiers de base** - [ ] `src/modules/WebModule.h` - [ ] `src/modules/WebModule.cpp` - [ ] `config/web.json` 2. **Implémenter les méthodes IModule** - [ ] `setConfiguration()` - Subscribe "web:request" - [ ] `process()` - Appeler processMessages() - [ ] `getHealthStatus()` - Retourner stats - [ ] `shutdown()` - Log final - [ ] `getState()` / `setState()` - Sérialisation stats 3. **Implémenter handleWebRequest()** - [ ] Extraction des paramètres - [ ] Validation URL - [ ] Appel HttpClient (GET/POST) - [ ] Gestion erreurs (try/catch) - [ ] Publication "web:response" 4. **Ajouter au CMakeLists.txt** ```cmake add_library(WebModule SHARED src/modules/WebModule.cpp ) target_link_libraries(WebModule PRIVATE grove_impl) ``` 5. **Ajouter au main.cpp** ```cpp // Load WebModule moduleConfigs.push_back({ "WebModule", "./build/modules/libWebModule.so", "./config/web.json" }); ``` ### Phase 2: Tests (1h) 6. **Créer les tests** - [ ] `tests/modules/WebModuleTests.cpp` - [ ] Mock HTTP server (simple echo server) - [ ] 10 tests unitaires - [ ] Intégration avec MockIO 7. **Exécuter les tests** ```bash cmake --build build --target aissia_tests ./build/tests/aissia_tests "[web]" ``` ### Phase 3: Documentation & Exemples (30min) 8. **Documenter l'utilisation** - [ ] Ajouter exemple dans `docs/modules/WebModule.md` - [ ] Mettre à jour `CLAUDE.md` - [ ] Mettre à jour `README.md` 9. **Créer un exemple d'utilisation** - [ ] Exemple dans AIModule ou nouveau module --- ## 5. Exemple d'Utilisation ### Dans un module client (ex: AIModule) ```cpp // 1. Dans setConfiguration() - S'abonner aux réponses if (m_io) { grove::SubscriptionConfig subConfig; m_io->subscribe("web:response", subConfig); } // 2. Faire une requête HTTP void AIModule::fetchExternalData() { auto request = std::make_unique("request"); request->setString("requestId", "weather-" + std::to_string(m_requestCounter++)); request->setString("url", "https://api.weather.com/current"); request->setString("method", "GET"); // Optional headers auto headers = std::make_unique("headers"); headers->setString("Authorization", "Bearer " + m_apiKey); request->setChild("headers", std::move(headers)); m_io->publish("web:request", std::move(request)); } // 3. Dans processMessages() - Recevoir la réponse if (msg.topic == "web:response" && msg.data) { std::string requestId = msg.data->getString("requestId", ""); if (requestId.find("weather-") == 0) { bool success = msg.data->getBool("success", false); if (success) { std::string body = msg.data->getString("body", ""); int statusCode = msg.data->getInt("statusCode", 0); m_logger->info("Weather data received: {} bytes", body.size()); // Parse JSON and use data } else { std::string error = msg.data->getString("error", "Unknown"); m_logger->error("Weather request failed: {}", error); } } } ``` --- ## 6. Sécurité & Limitations ### Sécurité 1. **Validation URL** - Vérifier schéma (https:// recommandé) - Whitelist/Blacklist de domaines (config) - Pas d'exécution de code arbitraire 2. **Rate Limiting** - Max concurrent requests (config) - Timeout par défaut (30s) - Pas de retry automatique (responsabilité du client) 3. **Sanitization** - Headers validés - Pas d'injection possible ### Limitations - **Pas de streaming**: Requêtes one-shot uniquement - **Pas de websockets**: HTTP classique seulement - **Pas de retry**: Le client doit gérer - **Pas de cache**: Chaque requête est exécutée - **Thread-safe**: Mais pas de parallélisation interne --- ## 7. Extensions Futures (Optionnel) ### Phase 4: Features Avancées - [ ] **Cache HTTP**: LRU cache pour réponses GET - [ ] **Retry automatique**: Avec backoff exponentiel - [ ] **Circuit breaker**: Protection contre services down - [ ] **Métriques avancées**: Latence P50/P95/P99 - [ ] **Support HTTPS custom**: Certificats custom - [ ] **Compression**: gzip/deflate support - [ ] **Streaming**: Support chunked transfer ### Phase 5: Tools pour l'Agent LLM - [ ] Ajouter `fetch_url` tool dans InternalTools - [ ] Agent peut faire "Fetch https://example.com" - [ ] Parsing HTML automatique (option) --- ## 8. Critères de Succès ### Fonctionnel - [ ] Module compile et charge sans erreur - [ ] GET requests fonctionnent - [ ] POST requests fonctionnent - [ ] Erreurs sont gérées correctement - [ ] Stats sont trackées - [ ] Hot-reload préserve l'état ### Tests - [ ] 10/10 tests passent - [ ] Coverage > 80% - [ ] Pas de memory leaks (valgrind) ### Documentation - [ ] README.md updated - [ ] Exemples d'utilisation fournis - [ ] Protocol IIO documenté ### Performance - [ ] Latency < 100ms overhead (vs direct HTTP) - [ ] Pas de blocking de la main loop - [ ] Memory footprint < 1MB --- ## 9. Checklist de Validation Avant de merger: - [ ] Code review (self-review) - [ ] Tests unitaires passent - [ ] Tests d'intégration passent - [ ] Documentation à jour - [ ] Pas de warnings de compilation - [ ] Module hot-reload testé manuellement - [ ] Config JSON validé - [ ] Exemple fonctionnel créé - [ ] Commit message descriptif - [ ] Branch mergée vers master --- ## 10. Fichiers Affectés ### Nouveaux fichiers ``` src/modules/WebModule.h src/modules/WebModule.cpp config/web.json tests/modules/WebModuleTests.cpp plans/webmodule-implementation.md (ce fichier) ``` ### Fichiers modifiés ``` CMakeLists.txt # Ajouter WebModule target src/main.cpp # Charger WebModule README.md # Documentation CLAUDE.md # Règles de développement ``` ### Fichiers utilisés (existants) ``` src/shared/http/HttpClient.hpp # Réutilisé pour HTTP external/GroveEngine/ # IModule, IIO, etc. ``` --- ## Notes Techniques ### Dépendances - ✅ HttpClient.hpp (déjà implémenté) - ✅ GroveEngine (IModule, IIO) - ✅ nlohmann/json (parsing) - ✅ spdlog (logging) ### Compatibilité - ✅ Windows (HTTPS via WinHTTP) - ✅ Linux/WSL (HTTPS via libcurl si disponible) - ✅ Hot-reload ready ### Performance - Requêtes asynchrones dans le sens où elles ne bloquent pas la main loop - Mais chaque requête est synchrone (HttpClient bloque jusqu'à réponse) - Pour async vrai, il faudrait un thread pool (Phase 4+) --- **Auteur**: Claude Code **Date**: 2025-11-28 **Version**: 1.0