Discovery Neo Oclib

This commit is contained in:
mr
2026-05-27 16:17:00 +02:00
parent 7f951afd41
commit 6ce6e6fe7d
20 changed files with 1436 additions and 1133 deletions
+51 -3
View File
@@ -27,6 +27,10 @@ const ProtocolConsidersResource = "/opencloud/resource/considers/1.0"
const ProtocolMinioConfigResource = "/opencloud/minio/config/1.0"
const ProtocolAdmiraltyConfigResource = "/opencloud/admiralty/config/1.0"
// ProtocolSourcePresignResource routes PB_SOURCE_PRESIGN to the resource-owner peer.
// The owner generates a pre-signed Minio URL and responds via PB_CONSIDERS.
const ProtocolSourcePresignResource = "/opencloud/resource/source-presign/1.0"
const ProtocolSearchResource = "/opencloud/resource/search/1.0"
const ProtocolCreateResource = "/opencloud/resource/create/1.0"
const ProtocolUpdateResource = "/opencloud/resource/update/1.0"
@@ -43,6 +47,7 @@ var protocols = map[protocol.ID]*common.ProtocolInfo{
ProtocolVerifyResource: {WaitResponse: true, TTL: 1 * time.Minute},
ProtocolMinioConfigResource: {WaitResponse: true, TTL: 1 * time.Minute},
ProtocolAdmiraltyConfigResource: {WaitResponse: true, TTL: 1 * time.Minute},
ProtocolSourcePresignResource: {WaitResponse: true, TTL: 1 * time.Minute},
ProtocolObserve: {WaitResponse: true, TTL: 1 * time.Minute},
}
@@ -63,8 +68,8 @@ type StreamService struct {
// IsPeerKnown, when set, is called at stream open for every inbound protocol.
// Return false to reset the stream immediately. Left nil until wired by the node.
IsPeerKnown func(pid pp.ID) bool
// dnt is the Disconnection Network Tolerance cache for outbound streams.
dnt *dntCache
// DTN is the Disconnection Network Tolerance cache for outbound streams.
dnt *DTNCache
// observeCache tracks running heartbeat goroutines on the OBSERVED side.
observeCache *observeCache
// hbBatcher accumulates incoming heartbeats (observing side) and flushes
@@ -78,6 +83,12 @@ type StreamService struct {
// observeUsers tracks which users are observing which peers so streams are
// closed only when the last observer for a peer disconnects.
observeUsers *userPeerIndex
// observeMetrics accumulates connection-quality data per observed peer (observing side).
// Keys are peer_id strings; values are *PeerObserveMetrics.
observeMetrics sync.Map
// DTNNudge receives peer IDs for which an immediate DTN retry should be
// attempted (e.g. when the peer just reconnected via PendingCallers).
dntNudge chan string
}
func InitStream(ctx context.Context, h host.Host, key pp.ID, maxNode int, node common.DiscoveryPeer) (*StreamService, error) {
@@ -92,6 +103,7 @@ func InitStream(ctx context.Context, h host.Host, key pp.ID, maxNode int, node c
dnt: newDNTCache(),
observeCache: newObserveCache(),
observeUsers: newUserPeerIndex(),
dntNudge: make(chan string, 32),
}
service.hbBatcher = newHeartbeatBatcher(flushObserveBatch)
for proto := range protocols {
@@ -105,6 +117,23 @@ func InitStream(ctx context.Context, h host.Host, key pp.ID, maxNode int, node c
return service, nil
}
// PendingContacts returns the peer IDs that have at least one critical DTN
// entry pending. Called on each heartbeat tick to populate PendingContact.
func (s *StreamService) PendingContacts() []string {
return s.dnt.peersWithPending()
}
// NudgeContacts signals the DTN loop to retry immediately for the given peer
// IDs (typically received via HeartbeatResponse.PendingCallers).
func (s *StreamService) NudgeContacts(peerIDs []string) {
for _, id := range peerIDs {
select {
case s.dntNudge <- id:
default:
}
}
}
// gate wraps a stream handler with IsPeerKnown validation.
// If the peer is unknown the entire connection is closed and the handler is not called.
// IsPeerKnown is read at stream-open time so it works even when set after InitStream.
@@ -117,6 +146,17 @@ func (s *StreamService) gatePrivilege(h func(network.Stream)) func(network.Strea
},
}, "", false, 0, 1)
if len(d.Data) == 0 {
stream.Reset()
return
}
master := d.Data[0].(*peer.Peer)
if stream.Conn().RemotePeer().String() != master.PeerID {
logger := oclib.GetLogger()
logger.Warn().
Str("remote", stream.Conn().RemotePeer().String()).
Str("master", master.PeerID).
Msg("[gate] nano rejected stream from non-master peer")
stream.Reset()
return
}
}
@@ -162,9 +202,17 @@ func (s *StreamService) HandleResponse(stream network.Stream) {
Stream: stream,
Expiry: time.Now().UTC().Add(expiry + 1*time.Minute),
}
// ProtocolObserve uses a bidirectional long-lived stream: the remote writes
// heartbeats back on the same stream, and may later send a close event.
// Use a persistent readLoop so we can receive both heartbeats and close events.
protoInfo := protocols[stream.Protocol()]
if stream.Protocol() == ProtocolObserve {
protoInfo = &common.ProtocolInfo{PersistantStream: true}
}
go s.readLoop(s.Streams[stream.Protocol()][stream.Conn().RemotePeer()],
stream.Conn().RemotePeer(),
stream.Protocol(), protocols[stream.Protocol()])
stream.Protocol(), protoInfo)
}
func (s *StreamService) connectToPartners() error {