package runtime import ( "fmt" "os" "chorus.services/bzzz/pkg/config" ) // ConfigValidator validates configuration for specific binary types type ConfigValidator struct { binaryType BinaryType } // NewConfigValidator creates a new config validator func NewConfigValidator(binaryType BinaryType) *ConfigValidator { return &ConfigValidator{ binaryType: binaryType, } } // ValidateForBinary validates configuration for the specified binary type func (v *ConfigValidator) ValidateForBinary(cfg *config.Config) error { // Common validation if err := v.validateCommonConfig(cfg); err != nil { return fmt.Errorf("common config validation failed: %w", err) } // Binary-specific validation switch v.binaryType { case BinaryTypeAgent: return v.validateAgentConfig(cfg) case BinaryTypeHAP: return v.validateHAPConfig(cfg) default: return fmt.Errorf("unknown binary type: %v", v.binaryType) } } // validateCommonConfig validates common configuration for all binary types func (v *ConfigValidator) validateCommonConfig(cfg *config.Config) error { if cfg == nil { return fmt.Errorf("configuration is nil") } // Validate agent configuration if cfg.Agent.ID == "" { return fmt.Errorf("agent ID is required") } // Validate basic capabilities if len(cfg.Agent.Capabilities) == 0 { return fmt.Errorf("at least one capability is required") } // P2P validation is handled in the main config validation return nil } // validateAgentConfig validates agent-specific configuration func (v *ConfigValidator) validateAgentConfig(cfg *config.Config) error { // Agent needs models for task execution if len(cfg.Agent.Models) == 0 { return fmt.Errorf("agent requires at least one model") } // Agent needs specialization if cfg.Agent.Specialization == "" { return fmt.Errorf("agent specialization is required") } // Validate max tasks if cfg.Agent.MaxTasks <= 0 { return fmt.Errorf("agent max_tasks must be greater than 0") } return nil } // validateHAPConfig validates HAP-specific configuration func (v *ConfigValidator) validateHAPConfig(cfg *config.Config) error { // HAP has different requirements than agent // Models are optional for HAP (it facilitates human interaction) // HAP should have role configuration for proper P2P participation if cfg.Agent.Role == "" { return fmt.Errorf("HAP requires a role for P2P participation") } return nil } // ValidateMultiBinaryDeployment validates that agent and HAP configs are compatible func ValidateMultiBinaryDeployment(agentConfig, hapConfig *config.Config) error { validators := []func(*config.Config, *config.Config) error{ validateP2PCompatibility, validatePortAssignments, validateAgentIdentities, validateEncryptionKeys, } for _, validator := range validators { if err := validator(agentConfig, hapConfig); err != nil { return err } } return nil } // validateP2PCompatibility ensures both configs can participate in same P2P mesh func validateP2PCompatibility(agentConfig, hapConfig *config.Config) error { // Check bootstrap peers compatibility for V2 DHT if len(agentConfig.V2.DHT.BootstrapPeers) != len(hapConfig.V2.DHT.BootstrapPeers) { return fmt.Errorf("bootstrap peers configuration differs between agent and HAP") } return nil } // validatePortAssignments ensures no port conflicts func validatePortAssignments(agentConfig, hapConfig *config.Config) error { // Check UCXI ports if enabled if agentConfig.UCXL.Enabled && hapConfig.UCXL.Enabled { if agentConfig.UCXL.Server.Port == hapConfig.UCXL.Server.Port { return fmt.Errorf("UCXI port conflict: both configs use port %d", agentConfig.UCXL.Server.Port) } } return nil } // validateAgentIdentities ensures agent IDs don't conflict func validateAgentIdentities(agentConfig, hapConfig *config.Config) error { if agentConfig.Agent.ID == hapConfig.Agent.ID { return fmt.Errorf("agent ID conflict: both configs use ID %s", agentConfig.Agent.ID) } return nil } // validateEncryptionKeys ensures encryption compatibility func validateEncryptionKeys(agentConfig, hapConfig *config.Config) error { // TODO: Implement encryption validation when V2 Security is available // Both should use same encryption settings for compatibility // if agentConfig.V2.Security.EncryptionEnabled != hapConfig.V2.Security.EncryptionEnabled { // return fmt.Errorf("encryption settings mismatch") // } return nil } // CheckForRunningInstance checks if another instance is already running func CheckForRunningInstance(agentID string, binaryType BinaryType) error { lockFile := fmt.Sprintf("/tmp/bzzz-%s-%s.lock", agentID, binaryType) if _, err := os.Stat(lockFile); err == nil { return fmt.Errorf("instance already running: %s %s", binaryType, agentID) } // Create lock file return os.WriteFile(lockFile, []byte(fmt.Sprintf("%d", os.Getpid())), 0644) } // RemoveInstanceLock removes the instance lock file func RemoveInstanceLock(agentID string, binaryType BinaryType) error { lockFile := fmt.Sprintf("/tmp/bzzz-%s-%s.lock", agentID, binaryType) return os.Remove(lockFile) } // GetConfigPath determines the configuration file path func GetConfigPath() string { configPath := os.Getenv("BZZZ_CONFIG_PATH") if configPath == "" { configPath = ".bzzz/config.yaml" } return configPath } // NeedsSetup checks if the system needs to run setup mode func NeedsSetup() bool { configPath := GetConfigPath() return config.IsSetupRequired(configPath) }