# API Reference - sdk_relay ## Vue d'Ensemble `sdk_relay` expose deux interfaces principales : - **WebSocket API** (port 8090) : Communication temps réel bidirectionnelle - **HTTP REST API** (port 8091) : Interface REST pour les opérations CRUD ## Base URLs ```bash # WebSocket ws://localhost:8090 wss://localhost:8090 # Sécurisé # HTTP REST http://localhost:8091 https://localhost:8091 # Sécurisé ``` --- ## WebSocket API - Flux de Messages ### 1. Connexion et Handshake **Flux de connexion :** ``` Client → WebSocket Connection → sdk_relay Client → Handshake Message → sdk_relay sdk_relay → Handshake Response → Client ``` **Message de Handshake (Client → sdk_relay) :** ```json { "type": "handshake", "client_id": "my-client-123", "version": "1.0.0", "capabilities": ["sync", "notifications", "health"], "timestamp": 1703001600 } ``` **Réponse de Handshake (sdk_relay → Client) :** ```json { "type": "handshake_response", "status": "accepted", "relay_id": "relay-1", "version": "1.0.0", "capabilities": ["sync", "notifications", "health", "metrics"], "timestamp": 1703001600 } ``` ### 2. Messages de Synchronisation #### StateSync **Flux :** ``` relay-1 → StateSync → relay-2 relay-2 → StateSync Response → relay-1 ``` **Message StateSync (relay-1 → relay-2) :** ```json { "type": "sync", "sync_type": "StateSync", "relay_id": "relay-1", "payload": { "state": { "uptime": 3600, "version": "1.0.0", "network": "signet", "status": "healthy", "last_block": 12345, "connections": 5, "known_relays": 3, "mesh_connections": 6 } }, "timestamp": 1703001600, "message_id": "msg-123" } ``` **Réponse StateSync (relay-2 → relay-1) :** ```json { "type": "sync_response", "sync_type": "StateSync", "relay_id": "relay-2", "payload": { "state": { "uptime": 1800, "version": "1.0.0", "network": "signet", "status": "healthy", "last_block": 12345, "connections": 3, "known_relays": 3, "mesh_connections": 6 } }, "timestamp": 1703001600, "message_id": "msg-124" } ``` #### HealthSync **Flux :** ``` relay-1 → HealthSync → relay-2 relay-2 → HealthSync Response → relay-1 ``` **Message HealthSync (relay-1 → relay-2) :** ```json { "type": "sync", "sync_type": "HealthSync", "relay_id": "relay-1", "payload": { "health": { "status": "healthy", "memory_usage": "128MB", "cpu_usage": "5%", "disk_usage": "2GB", "network_latency": 45, "error_count": 0, "last_error": null } }, "timestamp": 1703001600, "message_id": "msg-125" } ``` **Réponse HealthSync (relay-2 → relay-1) :** ```json { "type": "sync_response", "sync_type": "HealthSync", "relay_id": "relay-2", "payload": { "health": { "status": "healthy", "memory_usage": "96MB", "cpu_usage": "3%", "disk_usage": "1.5GB", "network_latency": 32, "error_count": 0, "last_error": null } }, "timestamp": 1703001600, "message_id": "msg-126" } ``` #### MetricsSync **Flux :** ``` relay-1 → MetricsSync → relay-2 relay-2 → MetricsSync Response → relay-1 ``` **Message MetricsSync (relay-1 → relay-2) :** ```json { "type": "sync", "sync_type": "MetricsSync", "relay_id": "relay-1", "payload": { "metrics": { "known_relays": 3, "mesh_connections": 6, "sync_requests": 150, "sync_responses": 150, "cache_hits": 120, "cache_misses": 30, "avg_latency": 45.2, "error_count": 0, "success_rate": 98.67, "messages_per_second": 2.5 } }, "timestamp": 1703001600, "message_id": "msg-127" } ``` **Réponse MetricsSync (relay-2 → relay-1) :** ```json { "type": "sync_response", "sync_type": "MetricsSync", "relay_id": "relay-2", "payload": { "metrics": { "known_relays": 3, "mesh_connections": 6, "sync_requests": 120, "sync_responses": 120, "cache_hits": 95, "cache_misses": 25, "avg_latency": 38.5, "error_count": 0, "success_rate": 100.0, "messages_per_second": 2.0 } }, "timestamp": 1703001600, "message_id": "msg-128" } ``` ### 3. Messages de Notification #### Payment Detected **Flux :** ``` sdk_relay → Payment Notification → Client ``` **Message Payment Detected (sdk_relay → Client) :** ```json { "type": "notification", "notification_type": "payment_detected", "data": { "txid": "abc123def456789abcdef456789abcdef456789abc", "block_height": 12345, "block_hash": "def789abc123456def789abc123456def789abc123", "amount": "0.001", "address": "sp1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh", "confirmations": 1, "timestamp": 1703001600, "fee": "0.00001", "size": 250 }, "timestamp": 1703001600 } ``` #### Block Mined **Flux :** ``` sdk_relay → Block Notification → Client ``` **Message Block Mined (sdk_relay → Client) :** ```json { "type": "notification", "notification_type": "block_mined", "data": { "block_height": 12346, "block_hash": "ghi012jkl345678ghi012jkl345678ghi012jkl345", "transactions": 150, "size": 1024000, "timestamp": 1703001600, "difficulty": 1.0, "merkle_root": "abc123def456789abcdef456789abcdef456789abc" }, "timestamp": 1703001600 } ``` #### Relay Connected **Flux :** ``` sdk_relay → Relay Notification → Client ``` **Message Relay Connected (sdk_relay → Client) :** ```json { "type": "notification", "notification_type": "relay_connected", "data": { "relay_id": "relay-4", "address": "relay-4.example.com:8090", "version": "1.0.0", "capabilities": ["sync", "notifications"], "timestamp": 1703001600, "connection_id": "conn-456" }, "timestamp": 1703001600 } ``` ### 4. Messages de Contrôle #### Ping/Pong **Flux :** ``` Client → Ping → sdk_relay sdk_relay → Pong → Client ``` **Message Ping (Client → sdk_relay) :** ```json { "type": "ping", "client_id": "my-client-123", "timestamp": 1703001600 } ``` **Message Pong (sdk_relay → Client) :** ```json { "type": "pong", "relay_id": "relay-1", "timestamp": 1703001600 } ``` #### Subscribe/Unsubscribe **Flux :** ``` Client → Subscribe → sdk_relay sdk_relay → Subscribe Response → Client ``` **Message Subscribe (Client → sdk_relay) :** ```json { "type": "subscribe", "subscriptions": ["notifications", "health", "metrics"], "client_id": "my-client-123", "timestamp": 1703001600 } ``` **Réponse Subscribe (sdk_relay → Client) :** ```json { "type": "subscribe_response", "status": "subscribed", "subscriptions": ["notifications", "health", "metrics"], "relay_id": "relay-1", "timestamp": 1703001600 } ``` **Message Unsubscribe (Client → sdk_relay) :** ```json { "type": "unsubscribe", "subscriptions": ["metrics"], "client_id": "my-client-123", "timestamp": 1703001600 } ``` **Réponse Unsubscribe (sdk_relay → Client) :** ```json { "type": "unsubscribe_response", "status": "unsubscribed", "subscriptions": ["notifications", "health"], "relay_id": "relay-1", "timestamp": 1703001600 } ``` --- ## HTTP REST API - Flux de Requêtes ### 1. Health Check **Flux :** ``` Client → GET /health → sdk_relay sdk_relay → Health Response → Client ``` **Requête :** ```http GET /health HTTP/1.1 Host: localhost:8091 User-Agent: curl/7.68.0 Accept: application/json ``` **Réponse :** ```json { "status": "healthy", "uptime": 3600, "version": "1.0.0", "timestamp": 1703001600, "services": { "bitcoin_core": "connected", "blindbit": "connected", "websocket": "listening", "sync_manager": "active" }, "checks": { "bitcoin_rpc": true, "blindbit_api": true, "websocket_server": true, "sync_manager": true } } ``` ### 2. Métriques **Flux :** ``` Client → GET /metrics → sdk_relay sdk_relay → Metrics Response → Client ``` **Requête :** ```http GET /metrics HTTP/1.1 Host: localhost:8091 User-Agent: curl/7.68.0 Accept: application/json ``` **Réponse :** ```json { "sync_metrics": { "known_relays": 3, "mesh_connections": 6, "sync_requests": 150, "sync_responses": 150, "cache_hits": 120, "cache_misses": 30, "avg_latency": 45.2, "error_count": 0, "success_rate": 98.67 }, "system_metrics": { "memory_usage": "128MB", "cpu_usage": "5%", "active_connections": 10, "total_requests": 1000, "uptime": 3600 }, "bitcoin_metrics": { "block_height": 12345, "connections": 8, "mempool_size": 150, "verification_progress": 0.9999 }, "timestamp": 1703001600 } ``` ### 3. Configuration **Flux :** ``` Client → GET /config → sdk_relay sdk_relay → Config Response → Client ``` **Requête :** ```http GET /config HTTP/1.1 Host: localhost:8091 User-Agent: curl/7.68.0 Accept: application/json ``` **Réponse :** ```json { "relay_id": "relay-1", "network": "signet", "ws_url": "0.0.0.0:8090", "http_url": "0.0.0.0:8091", "bitcoin_core": { "url": "http://bitcoin:18443", "wallet": "relay_wallet", "zmq_url": "tcp://bitcoin:29000" }, "blindbit": { "url": "http://blindbit:8000" }, "sync": { "interval": 30, "health_interval": 60, "metrics_interval": 120 }, "dev_mode": true, "standalone": false, "timestamp": 1703001600 } ``` ### 4. Liste des Relais **Flux :** ``` Client → GET /relays → sdk_relay sdk_relay → Relays Response → Client ``` **Requête :** ```http GET /relays?status=healthy&limit=10 HTTP/1.1 Host: localhost:8091 User-Agent: curl/7.68.0 Accept: application/json ``` **Réponse :** ```json { "relays": [ { "relay_id": "relay-1", "address": "sdk_relay_1:8090", "version": "1.0.0", "uptime": 3600, "health": "healthy", "last_seen": 1703001600, "capabilities": ["sync", "notifications", "health"], "connections": 5, "metrics": { "sync_requests": 50, "sync_responses": 50, "avg_latency": 45.2 } }, { "relay_id": "relay-2", "address": "sdk_relay_2:8090", "version": "1.0.0", "uptime": 1800, "health": "healthy", "last_seen": 1703001600, "capabilities": ["sync", "notifications"], "connections": 3, "metrics": { "sync_requests": 30, "sync_responses": 30, "avg_latency": 38.5 } } ], "total": 2, "healthy": 2, "warning": 0, "critical": 0, "timestamp": 1703001600 } ``` ### 5. Détails d'un Relais **Flux :** ``` Client → GET /relays/{relay_id} → sdk_relay sdk_relay → Relay Details Response → Client ``` **Requête :** ```http GET /relays/relay-1 HTTP/1.1 Host: localhost:8091 User-Agent: curl/7.68.0 Accept: application/json ``` **Réponse :** ```json { "relay_id": "relay-1", "address": "sdk_relay_1:8090", "version": "1.0.0", "uptime": 3600, "health": "healthy", "last_seen": 1703001600, "capabilities": ["sync", "notifications", "health"], "connections": 5, "metrics": { "sync_requests": 50, "sync_responses": 50, "avg_latency": 45.2, "error_count": 0, "success_rate": 100.0 }, "configuration": { "network": "signet", "dev_mode": true, "sync_interval": 30 }, "status": { "bitcoin_connected": true, "blindbit_connected": true, "websocket_listening": true, "sync_active": true }, "timestamp": 1703001600 } ``` ### 6. Statut de Synchronisation **Flux :** ``` Client → GET /sync/status → sdk_relay sdk_relay → Sync Status Response → Client ``` **Requête :** ```http GET /sync/status HTTP/1.1 Host: localhost:8091 User-Agent: curl/7.68.0 Accept: application/json ``` **Réponse :** ```json { "status": "syncing", "last_sync": 1703001600, "next_sync": 1703001630, "sync_types": [ "StateSync", "HealthSync", "MetricsSync" ], "errors": [], "statistics": { "total_syncs": 150, "successful_syncs": 148, "failed_syncs": 2, "success_rate": 98.67, "avg_duration": 45.2 }, "active_syncs": [ { "sync_type": "StateSync", "target_relay": "relay-2", "started": 1703001600, "status": "in_progress" } ], "timestamp": 1703001600 } ``` ### 7. Forcer la Synchronisation **Flux :** ``` Client → POST /sync/force → sdk_relay sdk_relay → Force Sync Response → Client ``` **Requête :** ```http POST /sync/force HTTP/1.1 Host: localhost:8091 User-Agent: curl/7.68.0 Content-Type: application/json Accept: application/json { "sync_types": ["StateSync", "HealthSync"], "target_relays": ["relay-2", "relay-3"] } ``` **Réponse :** ```json { "status": "sync_triggered", "sync_types": ["StateSync", "HealthSync"], "target_relays": ["relay-2", "relay-3"], "timestamp": 1703001600, "estimated_duration": "30s", "sync_id": "sync-789" } ``` ### 8. Historique des Synchronisations **Flux :** ``` Client → GET /sync/history → sdk_relay sdk_relay → Sync History Response → Client ``` **Requête :** ```http GET /sync/history?limit=10&since=1703000000&sync_type=StateSync HTTP/1.1 Host: localhost:8091 User-Agent: curl/7.68.0 Accept: application/json ``` **Réponse :** ```json { "history": [ { "timestamp": 1703001600, "sync_type": "StateSync", "target_relay": "relay-2", "status": "success", "duration": 45, "message_id": "msg-123", "payload_size": 1024, "latency": 45.2 }, { "timestamp": 1703001570, "sync_type": "HealthSync", "target_relay": "relay-3", "status": "success", "duration": 32, "message_id": "msg-122", "payload_size": 512, "latency": 32.1 } ], "total": 2, "successful": 2, "failed": 0, "filters": { "limit": 10, "since": 1703000000, "sync_type": "StateSync" }, "timestamp": 1703001600 } ``` ### 9. Informations Bitcoin **Flux :** ``` Client → GET /bitcoin/info → sdk_relay sdk_relay → Bitcoin Info Response → Client ``` **Requête :** ```http GET /bitcoin/info HTTP/1.1 Host: localhost:8091 User-Agent: curl/7.68.0 Accept: application/json ``` **Réponse :** ```json { "blockchain_info": { "chain": "signet", "blocks": 12345, "headers": 12345, "bestblockhash": "abc123def456789abcdef456789abcdef456789abc", "difficulty": 1.0, "verificationprogress": 0.9999, "initialblockdownload": false, "size_on_disk": 1073741824, "pruned": false }, "network_info": { "connections": 8, "connections_in": 4, "connections_out": 4, "networkactive": true, "networks": [ { "name": "ipv4", "limited": false, "reachable": true, "proxy": "tor:9050" } ] }, "mempool_info": { "size": 150, "bytes": 1024000, "usage": 2048000, "maxmempool": 300000000, "mempoolminfee": 0.00001000 }, "timestamp": 1703001600 } ``` ### 10. Bloc Spécifique **Flux :** ``` Client → GET /bitcoin/blocks/{block_hash} → sdk_relay sdk_relay → Block Details Response → Client ``` **Requête :** ```http GET /bitcoin/blocks/abc123def456789abcdef456789abcdef456789abc HTTP/1.1 Host: localhost:8091 User-Agent: curl/7.68.0 Accept: application/json ``` **Réponse :** ```json { "hash": "abc123def456789abcdef456789abcdef456789abc", "height": 12345, "version": 536870912, "merkleroot": "def456789abcdef456789abcdef456789abcdef456", "time": 1703001600, "mediantime": 1703001500, "nonce": 123456, "bits": "207fffff", "difficulty": 1.0, "size": 1024, "strippedsize": 512, "weight": 4096, "tx": [ "txid1abc123def456789abcdef456789abcdef456789abc", "txid2def456789abcdef456789abcdef456789abcdef456" ], "confirmations": 1, "previousblockhash": "ghi789jkl012345ghi789jkl012345ghi789jkl012", "nextblockhash": "mno012pqr345678mno012pqr345678mno012pqr345", "timestamp": 1703001600 } ``` ### 11. Logs **Flux :** ``` Client → GET /logs → sdk_relay sdk_relay → Logs Response → Client ``` **Requête :** ```http GET /logs?level=info&limit=50&search=sync HTTP/1.1 Host: localhost:8091 User-Agent: curl/7.68.0 Accept: application/json ``` **Réponse :** ```json { "logs": [ { "timestamp": "2024-12-19T10:00:00Z", "level": "info", "message": "Relay started successfully", "relay_id": "relay-1", "module": "main", "line": 45 }, { "timestamp": "2024-12-19T10:00:30Z", "level": "info", "message": "Sync completed", "relay_id": "relay-1", "sync_type": "StateSync", "module": "sync", "line": 123 } ], "total": 2, "levels": { "debug": 0, "info": 2, "warn": 0, "error": 0 }, "filters": { "level": "info", "limit": 50, "search": "sync" }, "timestamp": 1703001600 } ``` ### 12. Mettre à Jour la Configuration **Flux :** ``` Client → PUT /config → sdk_relay sdk_relay → Config Update Response → Client ``` **Requête :** ```http PUT /config HTTP/1.1 Host: localhost:8091 User-Agent: curl/7.68.0 Content-Type: application/json Accept: application/json { "sync": { "interval": 60, "health_interval": 120 }, "dev_mode": false } ``` **Réponse :** ```json { "status": "updated", "changes": [ "sync.interval: 30 -> 60", "sync.health_interval: 60 -> 120", "dev_mode: true -> false" ], "timestamp": 1703001600, "restart_required": false } ``` ### 13. Redémarrer le Service **Flux :** ``` Client → POST /restart → sdk_relay sdk_relay → Restart Response → Client ``` **Requête :** ```http POST /restart HTTP/1.1 Host: localhost:8091 User-Agent: curl/7.68.0 Accept: application/json ``` **Réponse :** ```json { "status": "restarting", "timestamp": 1703001600, "estimated_duration": "30s", "restart_id": "restart-456" } ``` --- ## Codes d'Erreur ### WebSocket - `1000` : Fermeture normale - `1001` : Client part - `1002` : Erreur de protocole - `1003` : Type de données non supporté - `1006` : Connexion fermée anormalement - `1011` : Erreur serveur ### HTTP - `200` : Succès - `400` : Requête invalide - `401` : Non autorisé - `404` : Endpoint non trouvé - `422` : Données invalides - `429` : Trop de requêtes - `500` : Erreur serveur interne - `503` : Service indisponible --- ## Exemples d'Utilisation ### Client JavaScript ```javascript class SdkRelayClient { constructor(wsUrl, httpUrl) { this.wsUrl = wsUrl; this.httpUrl = httpUrl; this.ws = null; this.clientId = `client-${Date.now()}`; } async connect() { return new Promise((resolve, reject) => { this.ws = new WebSocket(this.wsUrl); this.ws.onopen = () => { console.log('Connecté à sdk_relay'); this.sendHandshake(); resolve(); }; this.ws.onmessage = (event) => { const message = JSON.parse(event.data); this.handleMessage(message); }; this.ws.onerror = (error) => { console.error('Erreur WebSocket:', error); reject(error); }; }); } sendHandshake() { const handshake = { type: 'handshake', client_id: this.clientId, version: '1.0.0', capabilities: ['sync', 'notifications', 'health'] }; this.ws.send(JSON.stringify(handshake)); } handleMessage(message) { switch(message.type) { case 'handshake_response': console.log('Handshake accepté'); break; case 'notification': this.handleNotification(message); break; case 'sync': this.handleSync(message); break; case 'pong': console.log('Pong reçu'); break; } } handleNotification(message) { console.log('Notification:', message.notification_type, message.data); } handleSync(message) { console.log('Sync:', message.sync_type, message.payload); } // Méthodes HTTP async getHealth() { const response = await fetch(`${this.httpUrl}/health`); return response.json(); } async getMetrics() { const response = await fetch(`${this.httpUrl}/metrics`); return response.json(); } async getRelays() { const response = await fetch(`${this.httpUrl}/relays`); return response.json(); } async forceSync(syncTypes = ['StateSync']) { const response = await fetch(`${this.httpUrl}/sync/force`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ sync_types: syncTypes }) }); return response.json(); } disconnect() { if (this.ws) { this.ws.close(); } } } // Utilisation const client = new SdkRelayClient('ws://localhost:8090', 'http://localhost:8091'); async function main() { await client.connect(); // Obtenir les métriques const metrics = await client.getMetrics(); console.log('Métriques:', metrics); // Forcer une synchronisation await client.forceSync(['HealthSync']); } main().catch(console.error); ``` ### Client Python ```python import asyncio import aiohttp import json import websockets from datetime import datetime class SdkRelayClient: def __init__(self, ws_url, http_url): self.ws_url = ws_url self.http_url = http_url self.websocket = None self.client_id = f"python-client-{int(datetime.now().timestamp())}" async def connect(self): self.websocket = await websockets.connect(self.ws_url) await self.send_handshake() async def send_handshake(self): handshake = { "type": "handshake", "client_id": self.client_id, "version": "1.0.0", "capabilities": ["sync", "notifications", "health"] } await self.websocket.send(json.dumps(handshake)) async def listen(self): async for message in self.websocket: data = json.loads(message) await self.handle_message(data) async def handle_message(self, message): if message['type'] == 'handshake_response': print(f"Handshake accepté par {message['relay_id']}") elif message['type'] == 'notification': await self.handle_notification(message) elif message['type'] == 'sync': await self.handle_sync(message) async def handle_notification(self, message): print(f"Notification {message['notification_type']}: {message['data']}") async def handle_sync(self, message): print(f"Sync {message['sync_type']}: {message['payload']}") # Méthodes HTTP async def get_health(self): async with aiohttp.ClientSession() as session: async with session.get(f"{self.http_url}/health") as response: return await response.json() async def get_metrics(self): async with aiohttp.ClientSession() as session: async with session.get(f"{self.http_url}/metrics") as response: return await response.json() async def get_relays(self): async with aiohttp.ClientSession() as session: async with session.get(f"{self.http_url}/relays") as response: return await response.json() async def force_sync(self, sync_types=None): if sync_types is None: sync_types = ['StateSync'] async with aiohttp.ClientSession() as session: async with session.post( f"{self.http_url}/sync/force", json={"sync_types": sync_types} ) as response: return await response.json() async def close(self): if self.websocket: await self.websocket.close() async def main(): client = SdkRelayClient('ws://localhost:8090', 'http://localhost:8091') try: await client.connect() # Obtenir les métriques metrics = await client.get_metrics() print("Métriques:", metrics) # Écouter les messages await client.listen() except Exception as e: print(f"Erreur: {e}") finally: await client.close() if __name__ == "__main__": asyncio.run(main()) ``` ### Client cURL ```bash # Vérifier la santé curl -X GET http://localhost:8091/health # Obtenir les métriques curl -X GET http://localhost:8091/metrics # Obtenir la liste des relais curl -X GET http://localhost:8091/relays # Obtenir les détails d'un relais curl -X GET http://localhost:8091/relays/relay-1 # Forcer une synchronisation curl -X POST http://localhost:8091/sync/force \ -H "Content-Type: application/json" \ -d '{"sync_types": ["StateSync", "HealthSync"]}' # Obtenir l'historique des synchronisations curl -X GET "http://localhost:8091/sync/history?limit=10" # Obtenir les logs curl -X GET "http://localhost:8091/logs?level=info&limit=50" # Obtenir les informations Bitcoin curl -X GET http://localhost:8091/bitcoin/info # Obtenir un bloc spécifique curl -X GET http://localhost:8091/bitcoin/blocks/abc123... # Mettre à jour la configuration curl -X PUT http://localhost:8091/config \ -H "Content-Type: application/json" \ -d '{"sync": {"interval": 60}}' # Redémarrer le service curl -X POST http://localhost:8091/restart ``` --- **Cette documentation décrit tous les flux de données JSON entre les clients et sdk_relay.** 🚀