mirror of
https://github.com/luxfi/session.git
synced 2026-10-30 15:17:14 +00:00
274 lines
5.6 KiB
Go
274 lines
5.6 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package network
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/luxfi/session/core"
|
|
)
|
|
|
|
// PeerState represents the state of a peer connection.
|
|
type PeerState uint8
|
|
|
|
const (
|
|
PeerStateDisconnected PeerState = iota
|
|
PeerStateConnecting
|
|
PeerStateConnected
|
|
PeerStateDisconnecting
|
|
)
|
|
|
|
func (s PeerState) String() string {
|
|
switch s {
|
|
case PeerStateDisconnected:
|
|
return "disconnected"
|
|
case PeerStateConnecting:
|
|
return "connecting"
|
|
case PeerStateConnected:
|
|
return "connected"
|
|
case PeerStateDisconnecting:
|
|
return "disconnecting"
|
|
default:
|
|
return "unknown"
|
|
}
|
|
}
|
|
|
|
// Peer represents a network peer.
|
|
type Peer struct {
|
|
// ID is the peer's node ID
|
|
ID core.ID `json:"id"`
|
|
|
|
// Addr is the peer's network address
|
|
Addr string `json:"addr"`
|
|
|
|
// State is the connection state
|
|
State PeerState `json:"state"`
|
|
|
|
// PublicKey is the peer's public key (PQ-safe)
|
|
PublicKey []byte `json:"publicKey,omitempty"`
|
|
|
|
// LastSeen is when the peer was last seen
|
|
LastSeen time.Time `json:"lastSeen"`
|
|
|
|
// ConnectedAt is when the connection was established
|
|
ConnectedAt time.Time `json:"connectedAt,omitempty"`
|
|
|
|
// MessagesSent is the count of messages sent to this peer
|
|
MessagesSent uint64 `json:"messagesSent"`
|
|
|
|
// MessagesReceived is the count of messages received from this peer
|
|
MessagesReceived uint64 `json:"messagesReceived"`
|
|
|
|
// Latency is the measured round-trip latency
|
|
Latency time.Duration `json:"latency"`
|
|
|
|
// conn is the underlying connection
|
|
conn Connection
|
|
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
// NewPeer creates a new peer.
|
|
func NewPeer(id core.ID, addr string) *Peer {
|
|
return &Peer{
|
|
ID: id,
|
|
Addr: addr,
|
|
State: PeerStateDisconnected,
|
|
LastSeen: time.Now(),
|
|
}
|
|
}
|
|
|
|
// SetConnection sets the peer's connection.
|
|
func (p *Peer) SetConnection(conn Connection) {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
p.conn = conn
|
|
p.State = PeerStateConnected
|
|
p.ConnectedAt = time.Now()
|
|
p.LastSeen = time.Now()
|
|
}
|
|
|
|
// Connection returns the peer's connection.
|
|
func (p *Peer) Connection() Connection {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
return p.conn
|
|
}
|
|
|
|
// Disconnect disconnects the peer.
|
|
func (p *Peer) Disconnect() error {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
|
|
if p.conn != nil {
|
|
err := p.conn.Close()
|
|
p.conn = nil
|
|
p.State = PeerStateDisconnected
|
|
return err
|
|
}
|
|
p.State = PeerStateDisconnected
|
|
return nil
|
|
}
|
|
|
|
// UpdateLatency updates the peer's latency measurement.
|
|
func (p *Peer) UpdateLatency(latency time.Duration) {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
// Exponential moving average
|
|
if p.Latency == 0 {
|
|
p.Latency = latency
|
|
} else {
|
|
p.Latency = (p.Latency*7 + latency) / 8
|
|
}
|
|
}
|
|
|
|
// IncrementSent increments the sent message counter.
|
|
func (p *Peer) IncrementSent() {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
p.MessagesSent++
|
|
p.LastSeen = time.Now()
|
|
}
|
|
|
|
// IncrementReceived increments the received message counter.
|
|
func (p *Peer) IncrementReceived() {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
p.MessagesReceived++
|
|
p.LastSeen = time.Now()
|
|
}
|
|
|
|
// PeerManager manages the set of peers.
|
|
type PeerManager struct {
|
|
peers map[core.ID]*Peer
|
|
byAddr map[string]core.ID
|
|
maxPeers int
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
// NewPeerManager creates a new peer manager.
|
|
func NewPeerManager(maxPeers int) *PeerManager {
|
|
return &PeerManager{
|
|
peers: make(map[core.ID]*Peer),
|
|
byAddr: make(map[string]core.ID),
|
|
maxPeers: maxPeers,
|
|
}
|
|
}
|
|
|
|
// Add adds a peer.
|
|
func (pm *PeerManager) Add(peer *Peer) error {
|
|
pm.mu.Lock()
|
|
defer pm.mu.Unlock()
|
|
|
|
if len(pm.peers) >= pm.maxPeers {
|
|
return ErrMaxPeersReached
|
|
}
|
|
|
|
pm.peers[peer.ID] = peer
|
|
pm.byAddr[peer.Addr] = peer.ID
|
|
|
|
return nil
|
|
}
|
|
|
|
// Remove removes a peer.
|
|
func (pm *PeerManager) Remove(id core.ID) {
|
|
pm.mu.Lock()
|
|
defer pm.mu.Unlock()
|
|
|
|
if peer, ok := pm.peers[id]; ok {
|
|
delete(pm.byAddr, peer.Addr)
|
|
delete(pm.peers, id)
|
|
}
|
|
}
|
|
|
|
// Get gets a peer by ID.
|
|
func (pm *PeerManager) Get(id core.ID) (*Peer, bool) {
|
|
pm.mu.RLock()
|
|
defer pm.mu.RUnlock()
|
|
peer, ok := pm.peers[id]
|
|
return peer, ok
|
|
}
|
|
|
|
// GetByAddr gets a peer by address.
|
|
func (pm *PeerManager) GetByAddr(addr string) (*Peer, bool) {
|
|
pm.mu.RLock()
|
|
defer pm.mu.RUnlock()
|
|
|
|
id, ok := pm.byAddr[addr]
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
return pm.peers[id], true
|
|
}
|
|
|
|
// All returns all peers.
|
|
func (pm *PeerManager) All() []*Peer {
|
|
pm.mu.RLock()
|
|
defer pm.mu.RUnlock()
|
|
|
|
peers := make([]*Peer, 0, len(pm.peers))
|
|
for _, p := range pm.peers {
|
|
peers = append(peers, p)
|
|
}
|
|
return peers
|
|
}
|
|
|
|
// Connected returns all connected peers.
|
|
func (pm *PeerManager) Connected() []*Peer {
|
|
pm.mu.RLock()
|
|
defer pm.mu.RUnlock()
|
|
|
|
var connected []*Peer
|
|
for _, p := range pm.peers {
|
|
if p.State == PeerStateConnected {
|
|
connected = append(connected, p)
|
|
}
|
|
}
|
|
return connected
|
|
}
|
|
|
|
// ConnectedIDs returns IDs of all connected peers.
|
|
func (pm *PeerManager) ConnectedIDs() []core.ID {
|
|
pm.mu.RLock()
|
|
defer pm.mu.RUnlock()
|
|
|
|
var ids []core.ID
|
|
for _, p := range pm.peers {
|
|
if p.State == PeerStateConnected {
|
|
ids = append(ids, p.ID)
|
|
}
|
|
}
|
|
return ids
|
|
}
|
|
|
|
// Count returns the total number of peers.
|
|
func (pm *PeerManager) Count() int {
|
|
pm.mu.RLock()
|
|
defer pm.mu.RUnlock()
|
|
return len(pm.peers)
|
|
}
|
|
|
|
// CountConnected returns the number of connected peers.
|
|
func (pm *PeerManager) CountConnected() int {
|
|
pm.mu.RLock()
|
|
defer pm.mu.RUnlock()
|
|
|
|
count := 0
|
|
for _, p := range pm.peers {
|
|
if p.State == PeerStateConnected {
|
|
count++
|
|
}
|
|
}
|
|
return count
|
|
}
|
|
|
|
// ErrMaxPeersReached is returned when the maximum number of peers is reached.
|
|
var ErrMaxPeersReached = Error("maximum peers reached")
|
|
|
|
// Error is a network error type.
|
|
type Error string
|
|
|
|
func (e Error) Error() string { return string(e) }
|