// Usage: rcond
package main import ( "flag" "fmt" "log" "os" "github.com/0x1d/rcond/pkg/cluster" "github.com/0x1d/rcond/pkg/config" http "github.com/0x1d/rcond/pkg/http" ) func usage() { fmt.Println("Usage: rcond ") flag.PrintDefaults() } func main() { appConfig, err := loadConfig() if err != nil { usage() fmt.Printf("\nFailed to load config: %v\n", err) os.Exit(1) } clusterAgent := startClusterAgent(appConfig) startApiServer(appConfig, clusterAgent) select {} } func loadConfig() (*config.Config, error) { configPath := "/etc/rcond/config.yaml" appConfig := &config.Config{} help := false flag.StringVar(&configPath, "config", configPath, "Path to the configuration file") flag.StringVar(&appConfig.Rcond.Addr, "addr", "", "Address to bind the HTTP server to") flag.StringVar(&appConfig.Rcond.ApiToken, "token", "", "API token to use for authentication") flag.BoolVar(&help, "help", false, "Show help") flag.Parse() if help { usage() os.Exit(0) } // Load config from file if _, err := os.Stat(configPath); !os.IsNotExist(err) { configFile, err := config.LoadConfig(configPath) if err != nil { return nil, err } appConfig = configFile } // Override config values from environment variables and flags overrideConfigValuesFromEnv(map[string]*string{ "RCOND_ADDR": &appConfig.Rcond.Addr, "RCOND_API_TOKEN": &appConfig.Rcond.ApiToken, }) overrideConfigValuesFromFlag(map[string]*string{ "addr": &appConfig.Rcond.Addr, "token": &appConfig.Rcond.ApiToken, }) // Validate required fields if err := validateRequiredFields(map[string]*string{ "addr": &appConfig.Rcond.Addr, "token": &appConfig.Rcond.ApiToken, }); err != nil { return nil, err } return appConfig, nil } func startApiServer(appConfig *config.Config, clusterAgent *cluster.Agent) *http.Server { srv := http.NewServer(appConfig) srv.WithClusterAgent(clusterAgent) srv.RegisterRoutes() log.Printf("Starting API server on %s", appConfig.Rcond.Addr) if err := srv.Start(); err != nil { log.Fatal(err) } return srv } func startClusterAgent(appConfig *config.Config) *cluster.Agent { clusterConfig := &appConfig.Cluster if clusterConfig.Enabled { log.Printf("Starting cluster agent on %s:%d", clusterConfig.BindAddr, clusterConfig.BindPort) clusterAgent, err := cluster.NewAgent(clusterConfig, cluster.ClusterEventsMap()) if err != nil { log.Fatal(err) } // join nodes in the cluster if the join addresses are provided if len(clusterConfig.Join) > 0 { clusterAgent.Join(clusterConfig.Join, true) } return clusterAgent } return nil } func overrideConfigValuesFromEnv(envMap map[string]*string) { for varName, configValue := range envMap { if envValue, ok := os.LookupEnv(varName); ok { *configValue = envValue } } } func overrideConfigValuesFromFlag(flagMap map[string]*string) { for flagName, configValue := range flagMap { if flagValue := flag.Lookup(flagName).Value.String(); flagValue != "" { *configValue = flagValue } } } func validateRequiredFields(fields map[string]*string) error { for name, value := range fields { if *value == "" { return fmt.Errorf("%s is required", name) } } return nil }