2026-01-30 16:57:36 +01:00
|
|
|
package indexer
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2026-02-20 12:42:18 +01:00
|
|
|
"oc-discovery/conf"
|
2026-01-30 16:57:36 +01:00
|
|
|
"oc-discovery/daemons/node/common"
|
2026-02-04 11:35:19 +01:00
|
|
|
"sync"
|
2026-01-30 16:57:36 +01:00
|
|
|
|
2026-02-02 09:05:58 +01:00
|
|
|
oclib "cloud.o-forge.io/core/oc-lib"
|
2026-02-18 13:29:50 +01:00
|
|
|
dht "github.com/libp2p/go-libp2p-kad-dht"
|
2026-01-30 16:57:36 +01:00
|
|
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
2026-02-18 13:29:50 +01:00
|
|
|
record "github.com/libp2p/go-libp2p-record"
|
2026-01-30 16:57:36 +01:00
|
|
|
"github.com/libp2p/go-libp2p/core/host"
|
2026-03-03 16:38:24 +01:00
|
|
|
pp "github.com/libp2p/go-libp2p/core/peer"
|
2026-01-30 16:57:36 +01:00
|
|
|
)
|
|
|
|
|
|
2026-02-20 12:42:18 +01:00
|
|
|
// IndexerService manages the indexer node's state: stream records, DHT, pubsub.
|
2026-01-30 16:57:36 +01:00
|
|
|
type IndexerService struct {
|
|
|
|
|
*common.LongLivedStreamRecordedService[PeerRecord]
|
|
|
|
|
PS *pubsub.PubSub
|
2026-02-18 13:29:50 +01:00
|
|
|
DHT *dht.IpfsDHT
|
2026-01-30 16:57:36 +01:00
|
|
|
isStrictIndexer bool
|
2026-02-04 11:35:19 +01:00
|
|
|
mu sync.RWMutex
|
2026-02-20 12:42:18 +01:00
|
|
|
IsNative bool
|
|
|
|
|
Native *NativeState // non-nil when IsNative == true
|
2026-03-03 16:38:24 +01:00
|
|
|
nameIndex *nameIndexState
|
2026-01-30 16:57:36 +01:00
|
|
|
}
|
|
|
|
|
|
2026-02-20 12:42:18 +01:00
|
|
|
// NewIndexerService creates an IndexerService.
|
|
|
|
|
// If ps is nil, this is a strict indexer (no pre-existing gossip sub from a node).
|
|
|
|
|
func NewIndexerService(h host.Host, ps *pubsub.PubSub, maxNode int, isNative bool) *IndexerService {
|
2026-02-02 09:05:58 +01:00
|
|
|
logger := oclib.GetLogger()
|
|
|
|
|
logger.Info().Msg("open indexer mode...")
|
2026-01-30 16:57:36 +01:00
|
|
|
var err error
|
|
|
|
|
ix := &IndexerService{
|
2026-02-20 12:42:18 +01:00
|
|
|
LongLivedStreamRecordedService: common.NewStreamRecordedService[PeerRecord](h, maxNode),
|
2026-01-30 16:57:36 +01:00
|
|
|
isStrictIndexer: ps == nil,
|
2026-02-20 12:42:18 +01:00
|
|
|
IsNative: isNative,
|
2026-01-30 16:57:36 +01:00
|
|
|
}
|
2026-02-20 12:42:18 +01:00
|
|
|
if ps == nil {
|
2026-01-30 16:57:36 +01:00
|
|
|
ps, err = pubsub.NewGossipSub(context.Background(), ix.Host)
|
|
|
|
|
if err != nil {
|
2026-02-20 12:42:18 +01:00
|
|
|
panic(err) // can't run your indexer without a propagation pubsub
|
2026-01-30 16:57:36 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ix.PS = ps
|
2026-02-20 12:42:18 +01:00
|
|
|
|
2026-03-03 16:38:24 +01:00
|
|
|
if ix.isStrictIndexer && !isNative {
|
2026-02-02 09:05:58 +01:00
|
|
|
logger.Info().Msg("connect to indexers as strict indexer...")
|
2026-03-03 16:38:24 +01:00
|
|
|
common.ConnectToIndexers(h, conf.GetConfig().MinIndexer, conf.GetConfig().MaxIndexer, ix.Host.ID())
|
2026-02-02 09:05:58 +01:00
|
|
|
logger.Info().Msg("subscribe to decentralized search flow as strict indexer...")
|
2026-03-03 16:38:24 +01:00
|
|
|
go ix.SubscribeToSearch(ix.PS, nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !isNative {
|
|
|
|
|
logger.Info().Msg("init distributed name index...")
|
|
|
|
|
ix.initNameIndex(ps)
|
|
|
|
|
ix.LongLivedStreamRecordedService.AfterDelete = func(pid pp.ID, name, did string) {
|
|
|
|
|
ix.publishNameEvent(NameIndexDelete, name, pid.String(), did)
|
|
|
|
|
}
|
2026-02-04 11:35:19 +01:00
|
|
|
}
|
2026-02-20 12:42:18 +01:00
|
|
|
|
2026-02-18 13:29:50 +01:00
|
|
|
if ix.DHT, err = dht.New(
|
|
|
|
|
context.Background(),
|
|
|
|
|
ix.Host,
|
|
|
|
|
dht.Mode(dht.ModeServer),
|
2026-03-03 16:38:24 +01:00
|
|
|
dht.ProtocolPrefix("oc"), // 🔥 réseau privé
|
2026-02-18 13:29:50 +01:00
|
|
|
dht.Validator(record.NamespacedValidator{
|
2026-02-20 12:42:18 +01:00
|
|
|
"node": PeerRecordValidator{},
|
|
|
|
|
"indexer": IndexerRecordValidator{}, // for native indexer registry
|
2026-03-03 16:38:24 +01:00
|
|
|
"name": DefaultValidator{},
|
|
|
|
|
"pid": DefaultValidator{},
|
2026-02-18 13:29:50 +01:00
|
|
|
}),
|
|
|
|
|
); err != nil {
|
2026-03-03 16:38:24 +01:00
|
|
|
logger.Info().Msg(err.Error())
|
2026-02-18 13:29:50 +01:00
|
|
|
return nil
|
2026-01-30 16:57:36 +01:00
|
|
|
}
|
2026-02-20 12:42:18 +01:00
|
|
|
|
|
|
|
|
// InitNative must happen after DHT is ready
|
|
|
|
|
if isNative {
|
|
|
|
|
ix.InitNative()
|
|
|
|
|
} else {
|
|
|
|
|
ix.initNodeHandler()
|
2026-03-03 16:38:24 +01:00
|
|
|
// Register with configured natives so this indexer appears in their cache
|
|
|
|
|
if nativeAddrs := conf.GetConfig().NativeIndexerAddresses; nativeAddrs != "" {
|
|
|
|
|
common.StartNativeRegistration(ix.Host, nativeAddrs)
|
|
|
|
|
}
|
2026-02-20 12:42:18 +01:00
|
|
|
}
|
2026-01-30 16:57:36 +01:00
|
|
|
return ix
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ix *IndexerService) Close() {
|
2026-02-18 13:29:50 +01:00
|
|
|
ix.DHT.Close()
|
|
|
|
|
ix.PS.UnregisterTopicValidator(common.TopicPubSubSearch)
|
2026-03-03 16:38:24 +01:00
|
|
|
if ix.nameIndex != nil {
|
|
|
|
|
ix.PS.UnregisterTopicValidator(TopicNameIndex)
|
|
|
|
|
}
|
2026-01-30 16:57:36 +01:00
|
|
|
for _, s := range ix.StreamRecords {
|
|
|
|
|
for _, ss := range s {
|
|
|
|
|
ss.HeartbeatStream.Stream.Close()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|