package leader import ( "context" "fmt" "log" "sync" "time" "github.com/anthonyrawlins/bzzz/pkg/election" "github.com/anthonyrawlins/bzzz/pkg/dht" "github.com/anthonyrawlins/bzzz/pkg/slurp/intelligence" "github.com/anthonyrawlins/bzzz/pkg/slurp/storage" slurpContext "github.com/anthonyrawlins/bzzz/pkg/slurp/context" ) // ElectionIntegratedContextManager integrates SLURP context management with BZZZ election system type ElectionIntegratedContextManager struct { *LeaderContextManager // Embed the base context manager // Election integration electionMu sync.RWMutex slurpElection election.SLURPElection electionTerm int64 // Leadership state tracking leadershipEvents chan LeadershipEvent eventHandlers []LeadershipEventHandler // Integration configuration config *ElectionIntegrationConfig // Synchronization integrationWg sync.WaitGroup integrationStop chan struct{} } // LeadershipEvent represents a leadership change event type LeadershipEvent struct { Type LeadershipEventType `json:"type"` // Type of event OldLeaderID string `json:"old_leader_id"` // Previous leader NewLeaderID string `json:"new_leader_id"` // New leader Term int64 `json:"term"` // Election term Timestamp time.Time `json:"timestamp"` // When event occurred NodeID string `json:"node_id"` // Node reporting event Metadata map[string]interface{} `json:"metadata"` // Additional event data } // LeadershipEventType represents types of leadership events type LeadershipEventType string const ( LeadershipEventBecameLeader LeadershipEventType = "became_leader" // Node became leader LeadershipEventLostLeadership LeadershipEventType = "lost_leadership" // Node lost leadership LeadershipEventLeaderChanged LeadershipEventType = "leader_changed" // Leader changed (any node) LeadershipEventElectionStart LeadershipEventType = "election_start" // Election started LeadershipEventElectionEnd LeadershipEventType = "election_end" // Election completed LeadershipEventFailover LeadershipEventType = "failover" // Leadership failover ) // LeadershipEventHandler handles leadership events type LeadershipEventHandler func(event LeadershipEvent) error // ElectionIntegrationConfig configures election integration type ElectionIntegrationConfig struct { // Event processing EventBufferSize int `json:"event_buffer_size"` // Event buffer size EventProcessingTimeout time.Duration `json:"event_processing_timeout"` // Event processing timeout MaxEventHandlers int `json:"max_event_handlers"` // Maximum event handlers // Leadership transition TransitionTimeout time.Duration `json:"transition_timeout"` // Leadership transition timeout StatePreservation bool `json:"state_preservation"` // Preserve state on transition GracefulShutdown bool `json:"graceful_shutdown"` // Graceful shutdown on leadership loss // Monitoring HealthCheckInterval time.Duration `json:"health_check_interval"` // Health check interval MetricsReporting bool `json:"metrics_reporting"` // Enable metrics reporting DetailedLogging bool `json:"detailed_logging"` // Enable detailed logging } // NewElectionIntegratedContextManager creates a new election-integrated context manager func NewElectionIntegratedContextManager( slurpElection election.SLURPElection, dht dht.DHT, intelligence intelligence.IntelligenceEngine, storage storage.ContextStore, resolver slurpContext.ContextResolver, config *ElectionIntegrationConfig, ) (*ElectionIntegratedContextManager, error) { if config == nil { config = DefaultElectionIntegrationConfig() } // Create base context manager baseManager := NewContextManager( &electionAdapter{slurpElection}, // Adapt SLURP election to base election interface dht, intelligence, storage, resolver, ) eicm := &ElectionIntegratedContextManager{ LeaderContextManager: baseManager.(*LeaderContextManager), slurpElection: slurpElection, leadershipEvents: make(chan LeadershipEvent, config.EventBufferSize), eventHandlers: make([]LeadershipEventHandler, 0, config.MaxEventHandlers), config: config, integrationStop: make(chan struct{}), } // Register with election system if err := slurpElection.RegisterContextManager(eicm); err != nil { return nil, fmt.Errorf("failed to register with election system: %w", err) } // Set up election callbacks callbacks := &election.ContextLeadershipCallbacks{ OnBecomeContextLeader: eicm.onBecomeContextLeader, OnLoseContextLeadership: eicm.onLoseContextLeadership, OnContextLeaderChanged: eicm.onContextLeaderChanged, OnContextGenerationStarted: eicm.onContextGenerationStarted, OnContextGenerationStopped: eicm.onContextGenerationStopped, OnContextFailover: eicm.onContextFailover, OnContextError: eicm.onContextError, } if err := slurpElection.SetContextLeadershipCallbacks(callbacks); err != nil { return nil, fmt.Errorf("failed to set election callbacks: %w", err) } // Start event processing eicm.integrationWg.Add(1) go eicm.processLeadershipEvents() if config.DetailedLogging { log.Printf("✅ Election-integrated context manager created") } return eicm, nil } // IsLeader returns whether this node is the current leader (overrides base implementation) func (eicm *ElectionIntegratedContextManager) IsLeader() bool { return eicm.slurpElection.IsContextLeader() } // WaitForLeadership blocks until this node becomes leader func (eicm *ElectionIntegratedContextManager) WaitForLeadership(ctx context.Context) error { ticker := time.NewTicker(1 * time.Second) defer ticker.Stop() for { select { case <-ctx.Done(): return ctx.Err() case <-ticker.C: if eicm.IsLeader() { return nil } } } } // GetLeaderInfo returns information about current leader func (eicm *ElectionIntegratedContextManager) GetLeaderInfo() (*LeaderInfo, error) { return eicm.slurpElection.GetContextLeaderInfo() } // TransferLeadership initiates graceful leadership transfer func (eicm *ElectionIntegratedContextManager) TransferLeadership(ctx context.Context, targetNodeID string) error { return eicm.slurpElection.TransferContextLeadership(ctx, targetNodeID) } // RequestFromLeader allows non-leader nodes to request context from leader func (eicm *ElectionIntegratedContextManager) RequestFromLeader(req *ContextGenerationRequest) (*ContextGenerationResult, error) { if eicm.IsLeader() { // We are the leader, process directly if err := eicm.RequestContextGeneration(req); err != nil { return &ContextGenerationResult{ RequestID: req.ID, Success: false, Error: err.Error(), GeneratedAt: time.Now(), GeneratedBy: eicm.getNodeID(), }, nil } // TODO: Wait for completion and return result // For now, return success return &ContextGenerationResult{ RequestID: req.ID, Success: true, GeneratedAt: time.Now(), GeneratedBy: eicm.getNodeID(), }, nil } // We are not the leader, forward to leader return eicm.forwardToLeader(req) } // AddLeadershipEventHandler adds a handler for leadership events func (eicm *ElectionIntegratedContextManager) AddLeadershipEventHandler(handler LeadershipEventHandler) error { eicm.electionMu.Lock() defer eicm.electionMu.Unlock() if len(eicm.eventHandlers) >= eicm.config.MaxEventHandlers { return fmt.Errorf("maximum event handlers (%d) reached", eicm.config.MaxEventHandlers) } eicm.eventHandlers = append(eicm.eventHandlers, handler) return nil } // GetElectionTerm returns current election term func (eicm *ElectionIntegratedContextManager) GetElectionTerm() int64 { eicm.electionMu.RLock() defer eicm.electionMu.RUnlock() return eicm.electionTerm } // GetElectionStatus returns current election integration status func (eicm *ElectionIntegratedContextManager) GetElectionStatus() *ElectionIntegrationStatus { eicm.electionMu.RLock() defer eicm.electionMu.RUnlock() return &ElectionIntegrationStatus{ IsIntegrated: true, IsContextLeader: eicm.IsLeader(), CurrentTerm: eicm.electionTerm, EventHandlers: len(eicm.eventHandlers), PendingEvents: len(eicm.leadershipEvents), LastUpdate: time.Now(), } } // Election callback implementations func (eicm *ElectionIntegratedContextManager) onBecomeContextLeader(ctx context.Context, term int64) error { if eicm.config.DetailedLogging { log.Printf("đŸŽ¯ Became context leader (term: %d)", term) } eicm.electionMu.Lock() eicm.electionTerm = term eicm.electionMu.Unlock() event := LeadershipEvent{ Type: LeadershipEventBecameLeader, NewLeaderID: eicm.getNodeID(), Term: term, Timestamp: time.Now(), NodeID: eicm.getNodeID(), } eicm.emitEvent(event) return nil } func (eicm *ElectionIntegratedContextManager) onLoseContextLeadership(ctx context.Context, newLeader string) error { if eicm.config.DetailedLogging { log.Printf("📤 Lost context leadership to %s", newLeader) } event := LeadershipEvent{ Type: LeadershipEventLostLeadership, OldLeaderID: eicm.getNodeID(), NewLeaderID: newLeader, Term: eicm.electionTerm, Timestamp: time.Now(), NodeID: eicm.getNodeID(), } eicm.emitEvent(event) // Graceful shutdown if configured if eicm.config.GracefulShutdown { return eicm.performGracefulShutdown(ctx) } return nil } func (eicm *ElectionIntegratedContextManager) onContextLeaderChanged(oldLeader, newLeader string, term int64) { if eicm.config.DetailedLogging { log.Printf("🔄 Context leader changed: %s -> %s (term: %d)", oldLeader, newLeader, term) } eicm.electionMu.Lock() eicm.electionTerm = term eicm.electionMu.Unlock() event := LeadershipEvent{ Type: LeadershipEventLeaderChanged, OldLeaderID: oldLeader, NewLeaderID: newLeader, Term: term, Timestamp: time.Now(), NodeID: eicm.getNodeID(), } eicm.emitEvent(event) } func (eicm *ElectionIntegratedContextManager) onContextGenerationStarted(leaderID string) { if eicm.config.DetailedLogging { log.Printf("🚀 Context generation started by %s", leaderID) } event := LeadershipEvent{ Type: LeadershipEventElectionEnd, NewLeaderID: leaderID, Term: eicm.electionTerm, Timestamp: time.Now(), NodeID: eicm.getNodeID(), Metadata: map[string]interface{}{ "generation_started": true, }, } eicm.emitEvent(event) } func (eicm *ElectionIntegratedContextManager) onContextGenerationStopped(leaderID string, reason string) { if eicm.config.DetailedLogging { log.Printf("âšī¸ Context generation stopped by %s (reason: %s)", leaderID, reason) } event := LeadershipEvent{ Type: LeadershipEventElectionEnd, OldLeaderID: leaderID, Term: eicm.electionTerm, Timestamp: time.Now(), NodeID: eicm.getNodeID(), Metadata: map[string]interface{}{ "generation_stopped": true, "reason": reason, }, } eicm.emitEvent(event) } func (eicm *ElectionIntegratedContextManager) onContextFailover(oldLeader, newLeader string, duration time.Duration) { if eicm.config.DetailedLogging { log.Printf("🔄 Context failover: %s -> %s (duration: %v)", oldLeader, newLeader, duration) } event := LeadershipEvent{ Type: LeadershipEventFailover, OldLeaderID: oldLeader, NewLeaderID: newLeader, Term: eicm.electionTerm, Timestamp: time.Now(), NodeID: eicm.getNodeID(), Metadata: map[string]interface{}{ "failover_duration": duration, }, } eicm.emitEvent(event) } func (eicm *ElectionIntegratedContextManager) onContextError(err error, severity election.ErrorSeverity) { if eicm.config.DetailedLogging { log.Printf("âš ī¸ Context error (%s): %v", severity, err) } // TODO: Handle errors based on severity // Could trigger failover for critical errors } // Event processing func (eicm *ElectionIntegratedContextManager) emitEvent(event LeadershipEvent) { select { case eicm.leadershipEvents <- event: // Event queued successfully default: // Event buffer full, log warning log.Printf("âš ī¸ Leadership event buffer full, dropping event: %s", event.Type) } } func (eicm *ElectionIntegratedContextManager) processLeadershipEvents() { defer eicm.integrationWg.Done() for { select { case event := <-eicm.leadershipEvents: eicm.handleLeadershipEvent(event) case <-eicm.integrationStop: return } } } func (eicm *ElectionIntegratedContextManager) handleLeadershipEvent(event LeadershipEvent) { eicm.electionMu.RLock() handlers := make([]LeadershipEventHandler, len(eicm.eventHandlers)) copy(handlers, eicm.eventHandlers) eicm.electionMu.RUnlock() for _, handler := range handlers { ctx, cancel := context.WithTimeout(context.Background(), eicm.config.EventProcessingTimeout) func() { defer cancel() defer func() { if r := recover(); r != nil { log.Printf("❌ Event handler panicked: %v", r) } }() if err := handler(event); err != nil { log.Printf("âš ī¸ Event handler error: %v", err) } }() } } // Utility methods func (eicm *ElectionIntegratedContextManager) getNodeID() string { // TODO: Get actual node ID from election system or config return "node-" + fmt.Sprintf("%d", time.Now().Unix()) } func (eicm *ElectionIntegratedContextManager) forwardToLeader(req *ContextGenerationRequest) (*ContextGenerationResult, error) { // TODO: Implement request forwarding to current leader return &ContextGenerationResult{ RequestID: req.ID, Success: false, Error: "request forwarding not implemented", GeneratedAt: time.Now(), }, nil } func (eicm *ElectionIntegratedContextManager) performGracefulShutdown(ctx context.Context) error { // TODO: Implement graceful shutdown logic // - Finish current tasks // - Transfer pending tasks // - Clean up resources return nil } // Stop gracefully stops the integrated context manager func (eicm *ElectionIntegratedContextManager) Stop() { if eicm.config.DetailedLogging { log.Printf("🛑 Stopping election-integrated context manager") } // Signal stop to event processing close(eicm.integrationStop) // Wait for event processing to complete eicm.integrationWg.Wait() // Stop base context manager if eicm.LeaderContextManager != nil { // TODO: Add Stop method to base context manager } if eicm.config.DetailedLogging { log.Printf("✅ Election-integrated context manager stopped") } } // Supporting types // ElectionIntegrationStatus represents status of election integration type ElectionIntegrationStatus struct { IsIntegrated bool `json:"is_integrated"` // Whether integration is active IsContextLeader bool `json:"is_context_leader"` // Whether this node is context leader CurrentTerm int64 `json:"current_term"` // Current election term EventHandlers int `json:"event_handlers"` // Number of event handlers PendingEvents int `json:"pending_events"` // Number of pending events LastUpdate time.Time `json:"last_update"` // When status was last updated } // DefaultElectionIntegrationConfig returns default integration configuration func DefaultElectionIntegrationConfig() *ElectionIntegrationConfig { return &ElectionIntegrationConfig{ EventBufferSize: 100, EventProcessingTimeout: 10 * time.Second, MaxEventHandlers: 10, TransitionTimeout: 30 * time.Second, StatePreservation: true, GracefulShutdown: true, HealthCheckInterval: 30 * time.Second, MetricsReporting: true, DetailedLogging: false, } } // electionAdapter adapts SLURPElection to base Election interface type electionAdapter struct { slurpElection election.SLURPElection } func (ea *electionAdapter) IsLeader() bool { return ea.slurpElection.IsContextLeader() } func (ea *electionAdapter) GetCurrentAdmin() string { return ea.slurpElection.GetCurrentAdmin() } func (ea *electionAdapter) Start() error { return ea.slurpElection.Start() } func (ea *electionAdapter) Stop() { ea.slurpElection.Stop() } func (ea *electionAdapter) TriggerElection(trigger election.ElectionTrigger) { ea.slurpElection.TriggerElection(trigger) } func (ea *electionAdapter) IsCurrentAdmin() bool { return ea.slurpElection.IsCurrentAdmin() } func (ea *electionAdapter) GetElectionState() election.ElectionState { return ea.slurpElection.GetElectionState() } func (ea *electionAdapter) SetCallbacks(onAdminChanged func(string, string), onElectionComplete func(string)) { ea.slurpElection.SetCallbacks(onAdminChanged, onElectionComplete) } func (ea *electionAdapter) SendAdminHeartbeat() error { return ea.slurpElection.SendAdminHeartbeat() }