 9bdcbe0447
			
		
	
	9bdcbe0447
	
	
	
		
			
			Major integrations and fixes: - Added BACKBEAT SDK integration for P2P operation timing - Implemented beat-aware status tracking for distributed operations - Added Docker secrets support for secure license management - Resolved KACHING license validation via HTTPS/TLS - Updated docker-compose configuration for clean stack deployment - Disabled rollback policies to prevent deployment failures - Added license credential storage (CHORUS-DEV-MULTI-001) Technical improvements: - BACKBEAT P2P operation tracking with phase management - Enhanced configuration system with file-based secrets - Improved error handling for license validation - Clean separation of KACHING and CHORUS deployment stacks 🤖 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/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
 | |
| } |