- Réorganisation des tests par catégorie (unit, integration, connectivity, external) - Création de scripts d'exécution automatisés pour les tests - Création de guides techniques complets (ARCHITECTURE.md, API.md) - Transfert des informations depuis specs/ vers docs/ - Nettoyage et archivage des fichiers obsolètes - Documentation complète des tests avec exemples - Scripts de maintenance et nettoyage automatique - Structure professionnelle prête pour l'évolution
9.3 KiB
9.3 KiB
Découverte des Nœuds et Ajout de Nœuds Externes
Comment les relais découvrent-ils initialement les autres nœuds ?
1. Découverte automatique (actuelle)
Actuellement, les relais utilisent une découverte statique basée sur les noms de conteneurs Docker :
// Dans sync.rs - discover_relays()
let relay_hosts = vec![
"sdk_relay_1",
"sdk_relay_2",
"sdk_relay_3",
];
Mécanisme :
- Chaque relais a une liste prédéfinie des autres relais
- Au démarrage, il tente de se connecter à chaque relais de la liste
- Il ignore son propre nom (
relay_id
) - Il ajoute les relais découverts à sa liste
known_relays
2. Configuration par relay_id
Chaque relais a un relay_id
unique dans sa configuration :
# .conf.docker.relay1
relay_id=relay-1
# .conf.docker.relay2
relay_id=relay-2
# .conf.docker.relay3
relay_id=relay-3
3. Partage de la liste des relais
Une fois connectés, les relais partagent leur liste de relais connus via des messages RelaySync
:
// Création d'un message RelaySync
pub fn create_relay_sync(&self) -> Result<SyncMessage> {
let known_relays = self.known_relays.lock().unwrap();
let relays: Vec<RelayInfo> = known_relays.values().cloned().collect();
let payload = SyncPayload::RelayData {
relays,
network_topology,
};
Ok(SyncMessage::new(SyncType::RelaySync, self.relay_id.clone(), payload))
}
Comment ajouter un nœud externe ?
Option 1: Modification de la liste statique
Pour ajouter un nœud externe, il faut modifier le code source :
// Dans sync.rs - discover_relays()
let relay_hosts = vec![
"sdk_relay_1",
"sdk_relay_2",
"sdk_relay_3",
"external-relay-1", // ← Nouveau nœud externe
"external-relay-2", // ← Autre nœud externe
];
Avantages :
- Simple à implémenter
- Contrôle total sur les nœuds autorisés
Inconvénients :
- Nécessite une recompilation
- Pas flexible pour l'ajout dynamique
- Centralisé
Option 2: Configuration externe (recommandée)
Créer un fichier de configuration pour les nœuds externes :
# external_nodes.conf
[relays]
external-relay-1 = "external-relay-1.example.com:8090"
external-relay-2 = "external-relay-2.example.com:8090"
external-relay-3 = "192.168.1.100:8090"
[discovery]
auto_discover = true
bootstrap_nodes = [
"bootstrap-1.4nk.net:8090",
"bootstrap-2.4nk.net:8090"
]
Modification du code pour supporter la configuration :
pub struct DiscoveryConfig {
pub external_relays: HashMap<String, String>,
pub auto_discover: bool,
pub bootstrap_nodes: Vec<String>,
}
impl SyncManager {
pub fn load_discovery_config(&self) -> Result<DiscoveryConfig> {
// Charger depuis external_nodes.conf
}
pub async fn discover_relays(&self) -> Result<()> {
let config = self.load_discovery_config()?;
// Découverte locale (Docker)
for host in &["sdk_relay_1", "sdk_relay_2", "sdk_relay_3"] {
// ... logique existante
}
// Découverte externe
for (relay_id, address) in &config.external_relays {
let relay_info = RelayInfo {
relay_id: relay_id.clone(),
address: address.clone(),
// ... autres champs
};
self.add_relay(relay_info)?;
}
// Découverte via bootstrap nodes
if config.auto_discover {
for bootstrap in &config.bootstrap_nodes {
self.discover_via_bootstrap(bootstrap).await?;
}
}
Ok(())
}
}
Option 3: Découverte via DNS
Utiliser des enregistrements DNS pour la découverte :
pub async fn discover_via_dns(&self, domain: &str) -> Result<()> {
// Résoudre les enregistrements SRV ou A
let addresses = dns_lookup::get_host_addresses(domain)?;
for addr in addresses {
let relay_info = RelayInfo {
relay_id: format!("relay-{}", addr),
address: format!("{}:8090", addr),
// ... autres champs
};
self.add_relay(relay_info)?;
}
Ok(())
}
Option 4: Découverte via API REST
Créer une API pour l'enregistrement des nœuds :
// Endpoint pour enregistrer un nouveau nœud
POST /api/relays/register
{
"relay_id": "external-relay-1",
"address": "external-relay-1.example.com:8090",
"capabilities": ["sync", "mesh"],
"version": "1.0.0"
}
// Endpoint pour récupérer la liste des nœuds
GET /api/relays/list
Implémentation recommandée
1. Créer un fichier de configuration externe
# Créer le fichier de configuration
cat > 4NK/4NK_node/sdk_relay/external_nodes.conf << EOF
[relays]
# Nœuds externes connus
external-relay-1 = "external-relay-1.example.com:8090"
external-relay-2 = "192.168.1.100:8090"
[discovery]
auto_discover = true
bootstrap_nodes = [
"bootstrap-1.4nk.net:8090"
]
[security]
allowed_domains = [
"*.4nk.net",
"*.example.com"
]
EOF
2. Modifier le code pour supporter la configuration
// Dans sync.rs
use std::fs;
use toml;
#[derive(Debug, Deserialize)]
struct ExternalConfig {
relays: HashMap<String, String>,
discovery: DiscoverySettings,
security: SecuritySettings,
}
#[derive(Debug, Deserialize)]
struct DiscoverySettings {
auto_discover: bool,
bootstrap_nodes: Vec<String>,
}
#[derive(Debug, Deserialize)]
struct SecuritySettings {
allowed_domains: Vec<String>,
}
impl SyncManager {
pub fn load_external_config(&self) -> Result<ExternalConfig> {
let config_content = fs::read_to_string("external_nodes.conf")?;
let config: ExternalConfig = toml::from_str(&config_content)?;
Ok(config)
}
pub async fn discover_relays(&self) -> Result<()> {
// Découverte locale (existante)
let local_hosts = vec!["sdk_relay_1", "sdk_relay_2", "sdk_relay_3"];
for host in local_hosts {
// ... logique existante
}
// Découverte externe (nouvelle)
if let Ok(config) = self.load_external_config() {
for (relay_id, address) in &config.relays {
let relay_info = RelayInfo {
relay_id: relay_id.clone(),
address: address.clone(),
sp_address: "".to_string(),
version: "1.0.0".to_string(),
uptime: 0,
last_seen: SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs(),
capabilities: vec!["sync".to_string(), "mesh".to_string()],
health_status: HealthStatus::Healthy,
};
self.add_relay(relay_info)?;
}
}
Ok(())
}
}
3. Script pour ajouter un nœud externe
#!/bin/bash
# add_external_node.sh
RELAY_ID=$1
ADDRESS=$2
CONFIG_FILE="4NK/4NK_node/sdk_relay/external_nodes.conf"
if [ -z "$RELAY_ID" ] || [ -z "$ADDRESS" ]; then
echo "Usage: $0 <relay_id> <address:port>"
echo "Example: $0 external-relay-1 external-relay-1.example.com:8090"
exit 1
fi
# Ajouter le nœud à la configuration
echo "Adding external node: $RELAY_ID -> $ADDRESS"
# Vérifier si le fichier existe
if [ ! -f "$CONFIG_FILE" ]; then
cat > "$CONFIG_FILE" << EOF
[relays]
[discovery]
auto_discover = true
bootstrap_nodes = []
[security]
allowed_domains = ["*.4nk.net"]
EOF
fi
# Ajouter le nœud
sed -i "/^\[relays\]$/a $RELAY_ID = \"$ADDRESS\"" "$CONFIG_FILE"
echo "✅ External node added successfully!"
echo "🔄 Restart relays to apply changes:"
echo " docker-compose restart sdk_relay_1 sdk_relay_2 sdk_relay_3"
Sécurité et validation
Validation des nœuds externes
impl SyncManager {
pub fn validate_external_relay(&self, relay_info: &RelayInfo) -> Result<bool> {
// Vérifier le format de l'adresse
if !self.is_valid_address(&relay_info.address) {
return Ok(false);
}
// Vérifier le domaine autorisé
if !self.is_allowed_domain(&relay_info.address) {
return Ok(false);
}
// Vérifier la connectivité
if !self.can_connect_to_relay(&relay_info.address).await? {
return Ok(false);
}
Ok(true)
}
pub async fn can_connect_to_relay(&self, address: &str) -> Result<bool> {
// Test de connectivité WebSocket
// ... logique de test
}
}
Gestion des nœuds malveillants
impl SyncManager {
pub fn blacklist_relay(&self, relay_id: &str, reason: &str) {
// Ajouter à la liste noire
// Arrêter les connexions
// Notifier les autres relais
}
pub fn rate_limit_relay(&self, relay_id: &str) {
// Limiter le nombre de messages
// Surveiller les comportements suspects
}
}
Conclusion
Recommandation : Utiliser l'Option 2 (Configuration externe) car elle offre :
- Flexibilité : Ajout de nœuds sans recompilation
- Sécurité : Contrôle des domaines autorisés
- Évolutivité : Support pour la découverte automatique
- Simplicité : Configuration par fichier
Prochaines étapes :
- Implémenter le support de
external_nodes.conf
- Créer le script
add_external_node.sh
- Ajouter la validation et la sécurité
- Tester avec des nœuds externes