sdk_relay/docs/API.md
Nicolas Cantu 9d4b70598e
Some checks failed
CI - sdk_relay / build-test (push) Failing after 34s
CI - sdk_relay / security (push) Successful in 2m3s
Documentation API: refonte complète avec documentation professionnelle des endpoints HTTP et WebSocket
2025-08-25 15:17:45 +02:00

22 KiB

API Reference - sdk_relay

Vue d'Ensemble

sdk_relay expose deux interfaces principales pour l'intégration avec les clients :

  • WebSocket API (port 8090) : Communication temps réel bidirectionnelle
  • HTTP REST API (port 8091) : Interface REST pour les opérations CRUD

Base URLs

# WebSocket
ws://localhost:8090
wss://localhost:8090  # Sécurisé

# HTTP REST
http://localhost:8091
https://localhost:8091  # Sécurisé

WebSocket API

Connexion

const ws = new WebSocket('ws://localhost:8090');

ws.onopen = () => {
    console.log('Connecté à sdk_relay');
    // Envoyer le handshake initial
    sendHandshake();
};

ws.onmessage = (event) => {
    const message = JSON.parse(event.data);
    handleMessage(message);
};

ws.onerror = (error) => {
    console.error('Erreur WebSocket:', error);
};

ws.onclose = (event) => {
    console.log('Connexion fermée:', event.code, event.reason);
};

Handshake Initial

Endpoint : ws://localhost:8090

Message de Handshake :

{
    "type": "handshake",
    "client_id": "my-client-123",
    "version": "1.0.0",
    "capabilities": ["sync", "notifications", "health"],
    "timestamp": 1703001600
}

Réponse de Handshake :

{
    "type": "handshake_response",
    "status": "accepted",
    "relay_id": "relay-1",
    "version": "1.0.0",
    "capabilities": ["sync", "notifications", "health", "metrics"],
    "timestamp": 1703001600
}

Messages de Synchronisation

1. StateSync

Envoi :

{
    "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
        }
    },
    "timestamp": 1703001600,
    "message_id": "msg-123"
}

Réception :

{
    "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
        }
    },
    "timestamp": 1703001600,
    "message_id": "msg-124"
}

2. HealthSync

Envoi :

{
    "type": "sync",
    "sync_type": "HealthSync",
    "relay_id": "relay-1",
    "payload": {
        "health": {
            "status": "healthy",
            "memory_usage": "128MB",
            "cpu_usage": "5%",
            "disk_usage": "2GB",
            "network_latency": "45ms"
        }
    },
    "timestamp": 1703001600,
    "message_id": "msg-125"
}

3. MetricsSync

Envoi :

{
    "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
        }
    },
    "timestamp": 1703001600,
    "message_id": "msg-126"
}

Messages de Notification

1. Payment Detected

{
    "type": "notification",
    "notification_type": "payment_detected",
    "data": {
        "txid": "abc123def456789...",
        "block_height": 12345,
        "block_hash": "def789abc123456...",
        "amount": "0.001",
        "address": "sp1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
        "confirmations": 1,
        "timestamp": 1703001600
    },
    "timestamp": 1703001600
}

2. Block Mined

{
    "type": "notification",
    "notification_type": "block_mined",
    "data": {
        "block_height": 12346,
        "block_hash": "ghi012jkl345678...",
        "transactions": 150,
        "size": "1024000",
        "timestamp": 1703001600
    },
    "timestamp": 1703001600
}

3. Relay Connected

{
    "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
    },
    "timestamp": 1703001600
}

Messages de Contrôle

1. Ping/Pong

Ping :

{
    "type": "ping",
    "client_id": "my-client-123",
    "timestamp": 1703001600
}

Pong :

{
    "type": "pong",
    "relay_id": "relay-1",
    "timestamp": 1703001600
}

2. Subscribe/Unsubscribe

Subscribe :

{
    "type": "subscribe",
    "subscriptions": ["notifications", "health", "metrics"],
    "client_id": "my-client-123",
    "timestamp": 1703001600
}

Unsubscribe :

{
    "type": "unsubscribe",
    "subscriptions": ["metrics"],
    "client_id": "my-client-123",
    "timestamp": 1703001600
}

HTTP REST API

Endpoints de Base

1. Health Check

GET /health

Description : Vérifier l'état de santé du service

Réponse :

{
    "status": "healthy",
    "uptime": 3600,
    "version": "1.0.0",
    "timestamp": 1703001600,
    "services": {
        "bitcoin_core": "connected",
        "blindbit": "connected",
        "websocket": "listening",
        "sync_manager": "active"
    }
}

Codes de réponse :

  • 200 : Service en bonne santé
  • 503 : Service indisponible

2. Métriques

GET /metrics

Description : Obtenir les métriques de performance

Réponse :

{
    "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
    },
    "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
    }
}

3. Configuration

GET /config

Description : Obtenir la configuration actuelle

Réponse :

{
    "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
}

Endpoints de Gestion des Relais

4. Liste des Relais

GET /relays

Description : Obtenir la liste des relais connus

Paramètres de requête :

  • status : Filtrer par statut (healthy, warning, critical)
  • limit : Limiter le nombre de résultats (défaut: 100)

Réponse :

{
    "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
        },
        {
            "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
        }
    ],
    "total": 2,
    "healthy": 2,
    "warning": 0,
    "critical": 0
}

5. Détails d'un Relais

GET /relays/{relay_id}

Description : Obtenir les détails d'un relais spécifique

Réponse :

{
    "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
    },
    "configuration": {
        "network": "signet",
        "dev_mode": true
    }
}

Codes de réponse :

  • 200 : Relais trouvé
  • 404 : Relais non trouvé

Endpoints de Synchronisation

6. Statut de Synchronisation

GET /sync/status

Description : Obtenir le statut de la synchronisation

Réponse :

{
    "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
    }
}

7. Forcer la Synchronisation

POST /sync/force

Description : Forcer une synchronisation immédiate

Corps de la requête :

{
    "sync_types": ["StateSync", "HealthSync"],
    "target_relays": ["relay-2", "relay-3"]
}

Réponse :

{
    "status": "sync_triggered",
    "sync_types": ["StateSync", "HealthSync"],
    "target_relays": ["relay-2", "relay-3"],
    "timestamp": 1703001600,
    "estimated_duration": "30s"
}

8. Historique des Synchronisations

GET /sync/history

Description : Obtenir l'historique des synchronisations

Paramètres de requête :

  • limit : Nombre d'entrées (défaut: 50)
  • since : Timestamp de début
  • until : Timestamp de fin
  • sync_type : Filtrer par type de synchronisation

Réponse :

{
    "history": [
        {
            "timestamp": 1703001600,
            "sync_type": "StateSync",
            "target_relay": "relay-2",
            "status": "success",
            "duration": 45,
            "message_id": "msg-123"
        },
        {
            "timestamp": 1703001570,
            "sync_type": "HealthSync",
            "target_relay": "relay-3",
            "status": "success",
            "duration": 32,
            "message_id": "msg-122"
        }
    ],
    "total": 2,
    "successful": 2,
    "failed": 0
}

Endpoints de Bitcoin Core

9. Informations Bitcoin

GET /bitcoin/info

Description : Obtenir les informations Bitcoin Core

Réponse :

{
    "blockchain_info": {
        "chain": "signet",
        "blocks": 12345,
        "headers": 12345,
        "bestblockhash": "abc123...",
        "difficulty": 1.0,
        "verificationprogress": 0.9999,
        "initialblockdownload": false
    },
    "network_info": {
        "connections": 8,
        "connections_in": 4,
        "connections_out": 4
    },
    "mempool_info": {
        "size": 150,
        "bytes": 1024000,
        "usage": 2048000
    }
}

10. Bloc Spécifique

GET /bitcoin/blocks/{block_hash}

Description : Obtenir les détails d'un bloc

Réponse :

{
    "hash": "abc123...",
    "height": 12345,
    "version": 536870912,
    "merkleroot": "def456...",
    "time": 1703001600,
    "mediantime": 1703001500,
    "nonce": 123456,
    "bits": "207fffff",
    "difficulty": 1.0,
    "size": 1024,
    "strippedsize": 512,
    "weight": 4096,
    "tx": [
        "txid1...",
        "txid2..."
    ]
}

Endpoints de Logs

11. Logs

GET /logs

Description : Obtenir les logs du service

Paramètres de requête :

  • level : Niveau de log (debug, info, warn, error)
  • limit : Nombre de lignes (défaut: 100)
  • since : Timestamp de début
  • search : Recherche dans les logs

Réponse :

{
    "logs": [
        {
            "timestamp": "2024-12-19T10:00:00Z",
            "level": "info",
            "message": "Relay started successfully",
            "relay_id": "relay-1"
        },
        {
            "timestamp": "2024-12-19T10:00:30Z",
            "level": "info",
            "message": "Sync completed",
            "relay_id": "relay-1",
            "sync_type": "StateSync"
        }
    ],
    "total": 2,
    "levels": {
        "debug": 0,
        "info": 2,
        "warn": 0,
        "error": 0
    }
}

Endpoints de Configuration

12. Mettre à Jour la Configuration

PUT /config

Description : Mettre à jour la configuration

Corps de la requête :

{
    "sync": {
        "interval": 60,
        "health_interval": 120
    },
    "dev_mode": false
}

Réponse :

{
    "status": "updated",
    "changes": [
        "sync.interval: 30 -> 60",
        "sync.health_interval: 60 -> 120",
        "dev_mode: true -> false"
    ],
    "timestamp": 1703001600
}

13. Redémarrer le Service

POST /restart

Description : Redémarrer le service

Réponse :

{
    "status": "restarting",
    "timestamp": 1703001600,
    "estimated_duration": "30s"
}

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 Complet

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 Complet

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

# 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

Limites et Quotas

WebSocket

  • Connexions simultanées : 1000 par relais
  • Taille des messages : 1MB maximum
  • Heartbeat : 30 secondes
  • Timeout de connexion : 60 secondes
  • Rate limiting : 1000 messages/minute par client

HTTP REST

  • Taux limite : 1000 requêtes/minute par IP
  • Taille des requêtes : 10MB maximum
  • Timeout : 30 secondes
  • Connexions simultanées : 100 par IP
  • Rate limiting : 100 requêtes/minute par endpoint

Sécurité

Authentification

  • WebSocket : Authentification optionnelle via handshake
  • HTTP : Authentification basique (à configurer)
  • Rate limiting : Protection contre les abus

Validation

  • Validation JSON des messages
  • Validation des types de données
  • Protection contre les injections
  • Validation des URLs et paramètres

Chiffrement

  • WebSocket : WSS (WebSocket Secure) recommandé
  • HTTP : HTTPS recommandé
  • Certificats : Certificats SSL/TLS valides

Monitoring

Métriques Clés

  • Latence : Temps de réponse des APIs
  • Débit : Messages/requêtes par seconde
  • Erreurs : Taux d'erreur par endpoint
  • Connexions : Nombre de connexions actives
  • Synchronisation : Taux de succès des syncs

Alertes

  • Service indisponible
  • Latence élevée (> 1s)
  • Taux d'erreur élevé (> 5%)
  • Mémoire/CPU élevés
  • Échecs de synchronisation

Cette API permet une intégration complète et professionnelle avec sdk_relay pour tous types de clients. 🚀