aissia/plans/webmodule-implementation.md
StillHammer 18f4f16213 feat: Add WebModule for HTTP requests via IIO
Implements WebModule that allows other modules to make HTTP requests
through IIO pub/sub messaging system.

Features:
- HTTP GET/POST support via existing HttpClient
- Request/response via IIO topics (web:request/web:response)
- Security: blocks localhost and private IPs
- Statistics tracking (total, success, failed)
- Hot-reload state preservation
- Custom headers and timeout configuration

Module architecture:
- WebModule.h/cpp: 296 lines total (within 300 line limit)
- config/web.json: Configuration file
- 10 integration tests (TI_WEB_001 to TI_WEB_010)

Tests: 120/120 passing (110 existing + 10 new)

Protocol:
- Subscribe: web:request
- Publish: web:response
- Request fields: requestId, url, method, headers, body, timeoutMs
- Response fields: requestId, success, statusCode, body, error, durationMs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 17:15:46 +08:00

461 lines
12 KiB
Markdown

# 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 <grove/IModule.h>
#include <memory>
#include <spdlog/spdlog.h>
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<grove::IDataNode> getHealthStatus() override;
void shutdown() override;
// State management (hot-reload)
std::unique_ptr<grove::IDataNode> 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<spdlog::logger> m_logger;
std::unique_ptr<grove::IDataNode> 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<grove::JsonDataNode>("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<grove::JsonDataNode>("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 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