Files
bzzz/pkg/dht/real_dht.go
anthonyrawlins d96c931a29 Resolve import cycles and migrate to chorus.services module path
This comprehensive refactoring addresses critical architectural issues:

IMPORT CYCLE RESOLUTION:
• pkg/crypto ↔ pkg/slurp/roles: Created pkg/security/access_levels.go
• pkg/ucxl → pkg/dht: Created pkg/storage/interfaces.go
• pkg/slurp/leader → pkg/election → pkg/slurp/storage: Moved types to pkg/election/interfaces.go

MODULE PATH MIGRATION:
• Changed from github.com/anthonyrawlins/bzzz to chorus.services/bzzz
• Updated all import statements across 115+ files
• Maintains compatibility while removing personal GitHub account dependency

TYPE SYSTEM IMPROVEMENTS:
• Resolved duplicate type declarations in crypto package
• Added missing type definitions (RoleStatus, TimeRestrictions, KeyStatus, KeyRotationResult)
• Proper interface segregation to prevent future cycles

ARCHITECTURAL BENEFITS:
• Build now progresses past structural issues to normal dependency resolution
• Cleaner separation of concerns between packages
• Eliminates circular dependencies that prevented compilation
• Establishes foundation for scalable codebase growth

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-17 10:04:25 +10:00

322 lines
8.6 KiB
Go

package dht
import (
"context"
"fmt"
"strings"
"sync"
"time"
bzzconfig "chorus.services/bzzz/pkg/config"
)
// RealDHT implements DHT interface - simplified implementation for Phase 2
// In production, this would use libp2p Kademlia DHT
type RealDHT struct {
config *bzzconfig.HybridConfig
ctx context.Context
cancel context.CancelFunc
// Simplified storage for Phase 2
storage map[string][]byte
providers map[string][]string
storageMu sync.RWMutex
// Statistics
stats *RealDHTStats
statsMu sync.RWMutex
logger Logger
}
// RealDHTStats tracks real DHT performance metrics
type RealDHTStats struct {
ConnectedPeers int `json:"connected_peers"`
TotalKeys int `json:"total_keys"`
TotalProviders int `json:"total_providers"`
BootstrapNodes []string `json:"bootstrap_nodes"`
NodeID string `json:"node_id"`
Addresses []string `json:"addresses"`
Uptime time.Duration `json:"uptime_seconds"`
LastBootstrap time.Time `json:"last_bootstrap"`
// Operation counters
PutOperations uint64 `json:"put_operations"`
GetOperations uint64 `json:"get_operations"`
ProvideOperations uint64 `json:"provide_operations"`
FindProviderOps uint64 `json:"find_provider_operations"`
// Performance metrics
AvgLatency time.Duration `json:"avg_latency_ms"`
ErrorCount uint64 `json:"error_count"`
ErrorRate float64 `json:"error_rate"`
}
// NewRealDHT creates a new simplified real DHT implementation for Phase 2
func NewRealDHT(config *bzzconfig.HybridConfig) (DHT, error) {
ctx, cancel := context.WithCancel(context.Background())
realDHT := &RealDHT{
config: config,
ctx: ctx,
cancel: cancel,
storage: make(map[string][]byte),
providers: make(map[string][]string),
stats: &RealDHTStats{
BootstrapNodes: config.GetDHTBootstrapNodes(),
NodeID: "real-dht-node-" + fmt.Sprintf("%d", time.Now().Unix()),
Addresses: []string{"127.0.0.1:8080"}, // Simplified for Phase 2
LastBootstrap: time.Now(),
},
logger: &defaultLogger{},
}
// Simulate bootstrap process
if err := realDHT.bootstrap(); err != nil {
realDHT.logger.Warn("DHT bootstrap failed", "error", err)
// Don't fail completely - DHT can still work without bootstrap
}
realDHT.logger.Info("Real DHT initialized (Phase 2 simplified)",
"node_id", realDHT.stats.NodeID,
"bootstrap_nodes", config.GetDHTBootstrapNodes())
return realDHT, nil
}
// PutValue stores a key-value pair in the DHT
func (r *RealDHT) PutValue(ctx context.Context, key string, value []byte) error {
start := time.Now()
defer func() {
r.updateStats("put", time.Since(start), nil)
}()
// Simulate network latency for real DHT
time.Sleep(10 * time.Millisecond)
r.storageMu.Lock()
r.storage[key] = make([]byte, len(value))
copy(r.storage[key], value)
r.storageMu.Unlock()
r.logger.Debug("Real DHT PutValue successful", "key", key, "size", len(value))
return nil
}
// GetValue retrieves a value by key from the DHT
func (r *RealDHT) GetValue(ctx context.Context, key string) ([]byte, error) {
start := time.Now()
// Simulate network latency for real DHT
time.Sleep(15 * time.Millisecond)
r.storageMu.RLock()
value, exists := r.storage[key]
r.storageMu.RUnlock()
latency := time.Since(start)
if !exists {
r.updateStats("get", latency, ErrNotFound)
return nil, ErrNotFound
}
// Return a copy to avoid data races
result := make([]byte, len(value))
copy(result, value)
r.updateStats("get", latency, nil)
r.logger.Debug("Real DHT GetValue successful", "key", key, "size", len(result))
return result, nil
}
// Provide announces that this node provides a value for the given key
func (r *RealDHT) Provide(ctx context.Context, key, providerId string) error {
start := time.Now()
defer func() {
r.updateStats("provide", time.Since(start), nil)
}()
// Simulate network latency for real DHT
time.Sleep(5 * time.Millisecond)
r.storageMu.Lock()
if r.providers[key] == nil {
r.providers[key] = make([]string, 0)
}
// Add provider if not already present
found := false
for _, p := range r.providers[key] {
if p == providerId {
found = true
break
}
}
if !found {
r.providers[key] = append(r.providers[key], providerId)
}
r.storageMu.Unlock()
r.logger.Debug("Real DHT Provide successful", "key", key, "provider_id", providerId)
return nil
}
// FindProviders finds providers for the given key
func (r *RealDHT) FindProviders(ctx context.Context, key string) ([]string, error) {
start := time.Now()
// Simulate network latency for real DHT
time.Sleep(20 * time.Millisecond)
r.storageMu.RLock()
providers, exists := r.providers[key]
r.storageMu.RUnlock()
var result []string
if exists {
// Return a copy
result = make([]string, len(providers))
copy(result, providers)
} else {
result = make([]string, 0)
}
r.updateStats("find_providers", time.Since(start), nil)
r.logger.Debug("Real DHT FindProviders successful", "key", key, "provider_count", len(result))
return result, nil
}
// GetStats returns current DHT statistics
func (r *RealDHT) GetStats() DHTStats {
r.statsMu.RLock()
defer r.statsMu.RUnlock()
// Update stats
r.storageMu.RLock()
keyCount := len(r.storage)
providerCount := len(r.providers)
r.storageMu.RUnlock()
r.stats.TotalKeys = keyCount
r.stats.TotalProviders = providerCount
r.stats.ConnectedPeers = len(r.config.GetDHTBootstrapNodes()) // Simulate connected peers
r.stats.Uptime = time.Since(r.stats.LastBootstrap)
// Convert to common DHTStats format
return DHTStats{
TotalKeys: r.stats.TotalKeys,
TotalPeers: r.stats.ConnectedPeers,
Latency: r.stats.AvgLatency,
ErrorCount: int(r.stats.ErrorCount),
ErrorRate: r.stats.ErrorRate,
Uptime: r.stats.Uptime,
}
}
// GetDetailedStats returns real DHT specific statistics
func (r *RealDHT) GetDetailedStats() *RealDHTStats {
r.statsMu.RLock()
defer r.statsMu.RUnlock()
// Update dynamic stats
r.stats.ConnectedPeers = len(r.host.Network().Peers())
r.stats.Uptime = time.Since(r.stats.LastBootstrap)
// Return a copy
stats := *r.stats
return &stats
}
// Close shuts down the real DHT
func (r *RealDHT) Close() error {
r.logger.Info("Shutting down real DHT")
r.cancel()
// Clean up storage
r.storageMu.Lock()
r.storage = nil
r.providers = nil
r.storageMu.Unlock()
return nil
}
// Bootstrap connects to bootstrap nodes and initializes routing table
func (r *RealDHT) bootstrap() error {
r.logger.Info("Bootstrapping real DHT (Phase 2 simplified)", "bootstrap_nodes", r.config.GetDHTBootstrapNodes())
// Simulate bootstrap process
bootstrapNodes := r.config.GetDHTBootstrapNodes()
if len(bootstrapNodes) == 0 {
r.logger.Warn("No bootstrap nodes configured")
}
// Simulate connecting to bootstrap nodes
time.Sleep(100 * time.Millisecond) // Simulate bootstrap time
r.statsMu.Lock()
r.stats.LastBootstrap = time.Now()
r.stats.ConnectedPeers = len(bootstrapNodes)
r.statsMu.Unlock()
r.logger.Info("Real DHT bootstrap completed (simulated)", "connected_peers", len(bootstrapNodes))
return nil
}
// updateStats updates internal performance statistics
func (r *RealDHT) updateStats(operation string, latency time.Duration, err error) {
r.statsMu.Lock()
defer r.statsMu.Unlock()
// Update operation counters
switch operation {
case "put":
r.stats.PutOperations++
case "get":
r.stats.GetOperations++
case "provide":
r.stats.ProvideOperations++
case "find_providers":
r.stats.FindProviderOps++
}
// Update latency (exponential moving average)
totalOps := r.stats.PutOperations + r.stats.GetOperations + r.stats.ProvideOperations + r.stats.FindProviderOps
if totalOps > 0 {
weight := 1.0 / float64(totalOps)
r.stats.AvgLatency = time.Duration(float64(r.stats.AvgLatency)*(1-weight) + float64(latency)*weight)
}
// Update error statistics
if err != nil {
r.stats.ErrorCount++
if totalOps > 0 {
r.stats.ErrorRate = float64(r.stats.ErrorCount) / float64(totalOps)
}
}
}
// defaultLogger provides a basic logger implementation
type defaultLogger struct{}
func (l *defaultLogger) Info(msg string, fields ...interface{}) {
fmt.Printf("[INFO] %s %v\n", msg, fields)
}
func (l *defaultLogger) Warn(msg string, fields ...interface{}) {
fmt.Printf("[WARN] %s %v\n", msg, fields)
}
func (l *defaultLogger) Error(msg string, fields ...interface{}) {
fmt.Printf("[ERROR] %s %v\n", msg, fields)
}
func (l *defaultLogger) Debug(msg string, fields ...interface{}) {
fmt.Printf("[DEBUG] %s %v\n", msg, fields)
}
// ErrNotFound indicates a key was not found in the DHT
var ErrNotFound = fmt.Errorf("key not found")