package common import ( "fmt" "log" "os" "os/signal" "syscall" ) type ( Doer interface { Start() error RegisterHandler(string, func() any) OnShutdown() } Application interface { Start(while chan struct{}) RegisterPlugin(PluginFn) error Shutdown() } App struct { doer Doer } ) func NewApp(d Doer) *App { return &App{ doer: d, } } func (a *App) Start(while chan struct{}) error { go func() { sigint := make(chan os.Signal, 1) signal.Notify(sigint, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) <-sigint fmt.Println("Received signal:", sigint) a.Shutdown() close(while) }() err := a.doer.Start() if err != nil { log.Fatalf("Failed to start app. Reason: %v\n", err) close(while) } <-while return err } func (a *App) RegisterPlugin(p Plugin) error { a.doer.RegisterHandler(p.name, p.fn) return nil } func (a *App) Shutdown() { a.doer.OnShutdown() }