package main import ( "context" "errors" "flag" "fmt" "os" "os/signal" "sync" "syscall" "rgdd.se/silent-ct/internal/manager" "rgdd.se/silent-ct/internal/options" "rgdd.se/silent-ct/pkg/monitor" "rgdd.se/silent-ct/pkg/server" ) func main() { opts, err := options.New(os.Args[0], os.Args[1:]) if err != nil { if errors.Is(err, flag.ErrHelp) { os.Exit(0) } die("options: %v", err) } var c options.Config if err := c.FromFile(opts.ConfigFile); err != nil { die("configuration: %v", err) } fmt.Printf("%v\n", c) srv, err := server.New(server.Config{Address: opts.ListenAddr, Nodes: c.Nodes}) if err != nil { die("create new server: %v", err) } mon, err := monitor.New(monitor.Config{Callback: &c.Monitor}) if err != nil { die("create new monitor: %v", err) } mgr, err := manager.New(manager.Config{Nodes: c.Nodes}) if err != nil { die("create new manager: %v", err) } configCh := make(chan []monitor.MessageLogConfig) defer close(configCh) progressCh := make(chan monitor.MessageLogProgress) defer close(progressCh) submitCh := make(chan server.MessageNodeSubmission) defer close(submitCh) errorCh := make(chan error) defer close(errorCh) ctx, cancel := context.WithCancel(context.Background()) var wg sync.WaitGroup defer wg.Wait() wg.Add(1) go func() { defer wg.Done() defer cancel() await(ctx) }() wg.Add(1) go func() { defer wg.Done() defer cancel() if err := srv.Run(ctx, submitCh, errorCh); err != nil { die("server: %v\n", err) } }() wg.Add(1) go func() { defer wg.Done() defer cancel() mon.Run(ctx, configCh, progressCh, errorCh) }() wg.Add(1) go func() { defer wg.Done() defer cancel() if err := mgr.Run(ctx, submitCh, progressCh, configCh, errorCh); err != nil { die("manager: %v\n", err) } }() } func await(ctx context.Context) { sigs := make(chan os.Signal, 1) defer close(sigs) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) select { case <-sigs: case <-ctx.Done(): } } func die(format string, args ...interface{}) { fmt.Printf("fatal: "+format, args) os.Exit(1) }