@startuml dht_discovery title Découverte DHT : Provide/FindProviders + SelectByFillRate + dhtCache indexeur participant "Indexer A\n(nouveau)" as IA participant "DHT Network" as DHT participant "Node B\n(bootstrap)" as NodeB participant "Indexer A\n(existant)" as IAexist == Inscription indexeur dans la DHT == note over IA: Démarrage IndexerService\nstartDHTProvide(fillRateFn) IA -> IA: Attend adresse routable (max 60s)\nnon-loopback disponible IA -> DHT: DHT.Bootstrap(ctx)\n→ routing table warmup loop ticker RecommendedHeartbeatInterval (~20s) IA -> DHT: DHT.Provide(IndexerCID, true)\n← IndexerCID = CID(sha256("/opencloud/indexers")) note over DHT: L'indexeur est annoncé comme provider.\nTTL géré par libp2p-kad-dht.\nAuto-expire si Provide() s'arrête. end == Cache DHT passif de l'indexeur == note over IA: startDHTCacheRefresh()\ngoroutine arrière-plan IA -> IA: Initial delay 30s (routing table warmup) loop ticker 2min IA -> DHT: DiscoverIndexersFromDHT(h, dht, 30)\n← FindProviders(IndexerCID, max=30) DHT --> IA: []AddrInfo (jusqu'à 30 candidats) IA -> IA: Filtre self\nSelectByFillRate(filtered, nil, 10)\n→ diversité /24, prior f=0.5 (fill rates inconnus) IA -> IA: dhtCache = selected (max 10)\n→ utilisé pour Suggestions dans BuildHeartbeatResponse end == Découverte côté Node au bootstrap == NodeB -> NodeB: ConnectToIndexers → seeds ajoutés\nSendHeartbeat démarré NodeB -> NodeB: goroutine proactive (après 5s warmup) alt discoveryDHT == nil (node pur, pas d'IndexerService) NodeB -> DHT: initNodeDHT(h, seeds)\n← DHT client mode, bootstrappé sur seeds end NodeB -> DHT: DiscoverIndexersFromDHT(h, discoveryDHT, need+extra) DHT --> NodeB: []AddrInfo candidats NodeB -> NodeB: Filtre self\nSelectByFillRate(candidates, fillRates, need)\n→ pondération w(F) = F×(1-F)\n F=0.2 → w=0.16 (très probable)\n F=0.5 → w=0.25 (max)\n F=0.8 → w=0.16 (peu probable)\n→ filtre diversité /24 loop Pour chaque candidat retenu NodeB -> NodeB: Indexers.SetAddr(key, &addrInfo)\nNudgeIt() → heartbeat immédiat end note over NodeB: Pool enrichi au-delà des seeds.\nScoring commence au premier heartbeat.\nSeeds restent IsSeed=true (stickiness). @enduml