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>
246 lines
6.2 KiB
Go
246 lines
6.2 KiB
Go
package ucxi
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"chorus.services/bzzz/pkg/ucxl"
|
|
)
|
|
|
|
// BasicAddressResolver provides a basic implementation of AddressResolver
|
|
type BasicAddressResolver struct {
|
|
// In-memory registry for announced content
|
|
registry map[string]*ResolvedContent
|
|
mutex sync.RWMutex
|
|
|
|
// P2P integration hooks (to be implemented later)
|
|
announceHook func(ctx context.Context, addr *ucxl.Address, content *Content) error
|
|
discoverHook func(ctx context.Context, pattern *ucxl.Address) ([]*ResolvedContent, error)
|
|
|
|
// Configuration
|
|
defaultTTL time.Duration
|
|
nodeID string
|
|
}
|
|
|
|
// NewBasicAddressResolver creates a new basic address resolver
|
|
func NewBasicAddressResolver(nodeID string) *BasicAddressResolver {
|
|
return &BasicAddressResolver{
|
|
registry: make(map[string]*ResolvedContent),
|
|
defaultTTL: 5 * time.Minute,
|
|
nodeID: nodeID,
|
|
}
|
|
}
|
|
|
|
// SetAnnounceHook sets a hook function for content announcements (for P2P integration)
|
|
func (r *BasicAddressResolver) SetAnnounceHook(hook func(ctx context.Context, addr *ucxl.Address, content *Content) error) {
|
|
r.announceHook = hook
|
|
}
|
|
|
|
// SetDiscoverHook sets a hook function for content discovery (for P2P integration)
|
|
func (r *BasicAddressResolver) SetDiscoverHook(hook func(ctx context.Context, pattern *ucxl.Address) ([]*ResolvedContent, error)) {
|
|
r.discoverHook = hook
|
|
}
|
|
|
|
// Resolve resolves a UCXL address to content
|
|
func (r *BasicAddressResolver) Resolve(ctx context.Context, addr *ucxl.Address) (*ResolvedContent, error) {
|
|
if addr == nil {
|
|
return nil, fmt.Errorf("address cannot be nil")
|
|
}
|
|
|
|
key := r.generateRegistryKey(addr)
|
|
|
|
r.mutex.RLock()
|
|
resolved, exists := r.registry[key]
|
|
r.mutex.RUnlock()
|
|
|
|
if exists {
|
|
// Check if content is still valid (TTL)
|
|
if time.Now().Before(resolved.Resolved.Add(resolved.TTL)) {
|
|
return resolved, nil
|
|
}
|
|
|
|
// Content expired, remove from registry
|
|
r.mutex.Lock()
|
|
delete(r.registry, key)
|
|
r.mutex.Unlock()
|
|
}
|
|
|
|
// Try wildcard matching if exact match not found
|
|
if !exists {
|
|
if match := r.findWildcardMatch(addr); match != nil {
|
|
return match, nil
|
|
}
|
|
}
|
|
|
|
// If we have a discover hook, try P2P discovery
|
|
if r.discoverHook != nil {
|
|
results, err := r.discoverHook(ctx, addr)
|
|
if err == nil && len(results) > 0 {
|
|
// Cache the first result and return it
|
|
result := results[0]
|
|
r.cacheResolvedContent(key, result)
|
|
return result, nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("address not found: %s", addr.String())
|
|
}
|
|
|
|
// Announce announces content at a UCXL address
|
|
func (r *BasicAddressResolver) Announce(ctx context.Context, addr *ucxl.Address, content *Content) error {
|
|
if addr == nil {
|
|
return fmt.Errorf("address cannot be nil")
|
|
}
|
|
if content == nil {
|
|
return fmt.Errorf("content cannot be nil")
|
|
}
|
|
|
|
key := r.generateRegistryKey(addr)
|
|
|
|
resolved := &ResolvedContent{
|
|
Address: addr,
|
|
Content: content,
|
|
Source: r.nodeID,
|
|
Resolved: time.Now(),
|
|
TTL: r.defaultTTL,
|
|
}
|
|
|
|
// Store in local registry
|
|
r.mutex.Lock()
|
|
r.registry[key] = resolved
|
|
r.mutex.Unlock()
|
|
|
|
// Call P2P announce hook if available
|
|
if r.announceHook != nil {
|
|
if err := r.announceHook(ctx, addr, content); err != nil {
|
|
// Log but don't fail - local announcement succeeded
|
|
// In a real implementation, this would be logged properly
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Discover discovers content matching a pattern
|
|
func (r *BasicAddressResolver) Discover(ctx context.Context, pattern *ucxl.Address) ([]*ResolvedContent, error) {
|
|
if pattern == nil {
|
|
return nil, fmt.Errorf("pattern cannot be nil")
|
|
}
|
|
|
|
var results []*ResolvedContent
|
|
|
|
// Search local registry
|
|
r.mutex.RLock()
|
|
for _, resolved := range r.registry {
|
|
// Check if content is still valid (TTL)
|
|
if time.Now().After(resolved.Resolved.Add(resolved.TTL)) {
|
|
continue
|
|
}
|
|
|
|
// Check if address matches pattern
|
|
if resolved.Address.Matches(pattern) {
|
|
results = append(results, resolved)
|
|
}
|
|
}
|
|
r.mutex.RUnlock()
|
|
|
|
// Try P2P discovery if hook is available
|
|
if r.discoverHook != nil {
|
|
p2pResults, err := r.discoverHook(ctx, pattern)
|
|
if err == nil {
|
|
// Merge P2P results with local results
|
|
// Cache P2P results for future use
|
|
for _, result := range p2pResults {
|
|
key := r.generateRegistryKey(result.Address)
|
|
r.cacheResolvedContent(key, result)
|
|
results = append(results, result)
|
|
}
|
|
}
|
|
}
|
|
|
|
return results, nil
|
|
}
|
|
|
|
// findWildcardMatch searches for wildcard matches in the registry
|
|
func (r *BasicAddressResolver) findWildcardMatch(target *ucxl.Address) *ResolvedContent {
|
|
r.mutex.RLock()
|
|
defer r.mutex.RUnlock()
|
|
|
|
for _, resolved := range r.registry {
|
|
// Check if content is still valid (TTL)
|
|
if time.Now().After(resolved.Resolved.Add(resolved.TTL)) {
|
|
continue
|
|
}
|
|
|
|
// Check if target matches the registered address pattern
|
|
if target.Matches(resolved.Address) {
|
|
return resolved
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// generateRegistryKey generates a unique key for registry storage
|
|
func (r *BasicAddressResolver) generateRegistryKey(addr *ucxl.Address) string {
|
|
return fmt.Sprintf("%s:%s@%s:%s/%s",
|
|
addr.Agent, addr.Role, addr.Project, addr.Task, addr.TemporalSegment.String())
|
|
}
|
|
|
|
// cacheResolvedContent caches resolved content in the local registry
|
|
func (r *BasicAddressResolver) cacheResolvedContent(key string, resolved *ResolvedContent) {
|
|
r.mutex.Lock()
|
|
defer r.mutex.Unlock()
|
|
r.registry[key] = resolved
|
|
}
|
|
|
|
// GetRegistryStats returns statistics about the registry
|
|
func (r *BasicAddressResolver) GetRegistryStats() map[string]interface{} {
|
|
r.mutex.RLock()
|
|
defer r.mutex.RUnlock()
|
|
|
|
active := 0
|
|
expired := 0
|
|
now := time.Now()
|
|
|
|
for _, resolved := range r.registry {
|
|
if now.Before(resolved.Resolved.Add(resolved.TTL)) {
|
|
active++
|
|
} else {
|
|
expired++
|
|
}
|
|
}
|
|
|
|
return map[string]interface{}{
|
|
"total_entries": len(r.registry),
|
|
"active_entries": active,
|
|
"expired_entries": expired,
|
|
"node_id": r.nodeID,
|
|
}
|
|
}
|
|
|
|
// CleanupExpired removes expired entries from the registry
|
|
func (r *BasicAddressResolver) CleanupExpired() int {
|
|
r.mutex.Lock()
|
|
defer r.mutex.Unlock()
|
|
|
|
now := time.Now()
|
|
removed := 0
|
|
|
|
for key, resolved := range r.registry {
|
|
if now.After(resolved.Resolved.Add(resolved.TTL)) {
|
|
delete(r.registry, key)
|
|
removed++
|
|
}
|
|
}
|
|
|
|
return removed
|
|
}
|
|
|
|
// SetDefaultTTL sets the default TTL for cached content
|
|
func (r *BasicAddressResolver) SetDefaultTTL(ttl time.Duration) {
|
|
r.defaultTTL = ttl
|
|
} |