oc-discovery -> conf

This commit is contained in:
mr
2026-04-08 10:04:41 +02:00
parent 46dee0a6cb
commit 29b26d366e
21 changed files with 1934 additions and 119 deletions

View File

@@ -8,6 +8,7 @@ import (
"oc-discovery/conf"
"oc-discovery/daemons/node/common"
"oc-discovery/daemons/node/indexer"
"oc-discovery/daemons/node/location"
"oc-discovery/daemons/node/pubsub"
"oc-discovery/daemons/node/stream"
"sync"
@@ -108,7 +109,11 @@ func InitNode(isNode bool, isIndexer bool) (*Node, error) {
return nil
}
fresh := *node.peerRecord
fresh.PeerRecordPayload.ExpiryDate = time.Now().UTC().Add(2 * time.Minute)
ttl := time.Duration(fresh.TTLSeconds) * time.Second
if ttl <= 0 {
ttl = indexer.DefaultTTLSeconds * time.Second
}
fresh.PeerRecordPayload.ExpiryDate = time.Now().UTC().Add(ttl)
payload, _ := json.Marshal(fresh.PeerRecordPayload)
fresh.Signature, err = priv.Sign(payload)
if err != nil {
@@ -170,10 +175,24 @@ func InitNode(isNode bool, isIndexer bool) (*Node, error) {
if err != nil || evt.From == node.PeerID.String() {
return
}
fmt.Println("PUBSUB SendResponse bef peerrece")
if p, err := node.GetPeerRecord(ctx, evt.From); err == nil && len(p) > 0 && m["search"] != nil {
fmt.Println("PUBSUB SendResponse af peerrece", m)
node.StreamService.SendResponse(p[0], &evt, fmt.Sprintf("%v", m["search"]))
}
}
node.AllowInbound = func(remotePeer pp.ID, isNew bool) error {
if isNew {
// DB blacklist check: blocks reconnection after EvictPeer + blacklist.
if !node.isPeerKnown(remotePeer) {
return errors.New("peer is blacklisted or unknown")
}
if !node.ConnGuard.Allow() {
return errors.New("connection rate limit exceeded, retry later")
}
}
return nil
}
logger.Info().Msg("subscribe to decentralized search flow...")
go node.SubscribeToSearch(node.PS, &f)
logger.Info().Msg("connect to NATS")
@@ -187,6 +206,39 @@ func InitNode(isNode bool, isIndexer bool) (*Node, error) {
return node, nil
}
// isPeerKnown is the stream-level gate: returns true if pid is allowed.
// Check order (fast → slow):
// 1. In-memory stream records — currently heartbeating to this indexer.
// 2. Local DB by peer_id — known peer, blacklist enforced here.
// 3. DHT /pid/{peerID} → /node/{DID} — registered on any indexer.
//
// ProtocolHeartbeat and ProtocolPublish handlers do NOT call this — they are
// the streams through which a node first makes itself known.
func (d *Node) isPeerKnown(pid pp.ID) bool {
// 1. Fast path: active heartbeat session.
d.StreamMU.RLock()
_, active := d.StreamRecords[common.ProtocolHeartbeat][pid]
d.StreamMU.RUnlock()
if active {
return true
}
// 2. Local DB: known peer (handles blacklist).
access := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil)
results := access.Search(&dbs.Filters{
And: map[string][]dbs.Filter{
"peer_id": {{Operator: dbs.EQUAL.String(), Value: pid.String()}},
},
}, pid.String(), false)
for _, item := range results.Data {
p, ok := item.(*peer.Peer)
if !ok || p.PeerID != pid.String() {
continue
}
return p.Relation != peer.BLACKLIST
}
return true
}
func (d *Node) Close() {
if d.isIndexer && d.IndexerService != nil {
d.IndexerService.Close()
@@ -211,11 +263,16 @@ func (d *Node) publishPeerRecord(
continue
}
stream := common.Indexers.Streams.GetPerID(common.ProtocolPublish, ad.Info.ID)
ttl := time.Duration(rec.TTLSeconds) * time.Second
if ttl <= 0 {
ttl = indexer.DefaultTTLSeconds * time.Second
}
base := indexer.PeerRecordPayload{
Name: rec.Name,
DID: rec.DID,
PubKey: rec.PubKey,
ExpiryDate: time.Now().UTC().Add(2 * time.Minute),
TTLSeconds: rec.TTLSeconds,
ExpiryDate: time.Now().UTC().Add(ttl),
}
payload, _ := json.Marshal(base)
rec.PeerRecordPayload = base
@@ -377,13 +434,12 @@ func (d *Node) claimInfo(
}
now := time.Now().UTC()
expiry := now.Add(150 * time.Second)
pRec := indexer.PeerRecordPayload{
Name: name,
DID: did, // REAL PEER ID
PubKey: pubBytes,
ExpiryDate: expiry,
TTLSeconds: indexer.DefaultTTLSeconds,
ExpiryDate: now.Add(indexer.DefaultTTLSeconds * time.Second),
}
d.PeerID = d.Host.ID()
payload, _ := json.Marshal(pRec)
@@ -400,6 +456,7 @@ func (d *Node) claimInfo(
rec.StreamAddress = "/ip4/" + conf.GetConfig().Hostname + "/tcp/" + fmt.Sprintf("%v", conf.GetConfig().NodeEndpointPort) + "/p2p/" + rec.PeerID
rec.NATSAddress = oclib.GetConfig().NATSUrl
rec.WalletAddress = "my-wallet"
rec.Location = location.Geolocate(conf.GetConfig().LocationGranularity)
if err := d.publishPeerRecord(rec); err != nil {
return nil, err
@@ -424,6 +481,55 @@ func (d *Node) claimInfo(
}
}
// DeleteRecord broadcasts a signed tombstone to all connected indexers, signalling
// that this node is voluntarily leaving the network.
// Each indexer verifies the signature, stores the tombstone in the DHT (replacing
// the live record), and evicts the peer from its active pool.
// After a successful call, d.peerRecord is set to nil.
func (d *Node) DeleteRecord() error {
if d.peerRecord == nil {
return errors.New("no peer record to delete")
}
priv, err := tools.LoadKeyFromFilePrivate()
if err != nil {
return err
}
pubBytes, err := crypto.MarshalPublicKey(priv.GetPublic())
if err != nil {
return err
}
tp := indexer.TombstonePayload{
DID: d.peerRecord.DID,
PeerID: d.PeerID.String(),
DeletedAt: time.Now().UTC(),
}
payloadBytes, _ := json.Marshal(tp)
sig, err := priv.Sign(payloadBytes)
if err != nil {
return err
}
ts := &indexer.TombstoneRecord{
TombstonePayload: tp,
PubKey: pubBytes,
Tombstone: true,
Signature: sig,
}
data, _ := json.Marshal(ts)
for _, ad := range common.Indexers.GetAddrs() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
s, err := d.Host.NewStream(ctx, ad.Info.ID, common.ProtocolDelete)
cancel()
if err != nil {
continue
}
s.SetDeadline(time.Now().Add(5 * time.Second))
s.Write(data)
s.Close()
}
d.peerRecord = nil
return nil
}
/*
TODO:
- Le booking est un flow neuf décentralisé :