package main import ( "context" "errors" "fmt" "net/http" "os" "os/signal" "syscall" "time" "ruben/inventory2/internal/domains/raw_events" "ruben/inventory2/internal/site" "ruben/inventory2/internal/webhooks" ) const ( etsyAPIKeystring = "38ncokqh0jih5jshfk8iv4n5" etsyAPISharedSecret = "jaaw0tyizf" ) func main() { if err := runApp(context.Background()); err != nil { panic(err) } fmt.Println("application shutdown") } func runApp(ctx context.Context) error { ctx, shutdown := context.WithCancel(ctx) defer shutdown() // connect to the database db, err := raw_events.NewStore(ctx) if err != nil { return fmt.Errorf("failed to initialize the raw event store: %w", err) } // start http server srvErrCh := runServer(ctx, db) // wait for interrupt signal or unrecoverable failure, then shutdown osSignalCh := make(chan os.Signal, 1) signal.Notify(osSignalCh, syscall.SIGINT, syscall.SIGTERM) var serverAlreadyShutdown bool select { case s := <-osSignalCh: fmt.Println("application received shutdown signal:", s) fmt.Println("shutting down") case err := <-srvErrCh: serverAlreadyShutdown = true fmt.Println("server shutdown unexpectedly") if err != nil { fmt.Println("server encountered error:", err) } } shutdown() // capture application errors that occurred during or caused shutdown var errs []error if !serverAlreadyShutdown { if err := <-srvErrCh; err != nil { errs = append(errs, fmt.Errorf("server experienced an error: %w", err)) } fmt.Println("server shut down") } return errors.Join(errs...) } func runServer(ctx context.Context, db *raw_events.Store) <-chan error { srv := &http.Server{ Addr: ":8082", // local Handler: buildHTTPHandler(db), } ctx, cancel := context.WithCancel(ctx) alreadyShutdownCh := make(chan struct{}, 1) runningErrCh := make(chan error, 1) go func() { defer close(runningErrCh) defer cancel() defer close(alreadyShutdownCh) fmt.Println("server running on 8082...") if err := srv.ListenAndServe(); err != nil { if !errors.Is(err, http.ErrServerClosed) { runningErrCh <- fmt.Errorf("server experienced error: %w", err) } } }() shutdownErrCh := make(chan error, 1) go func() { defer close(shutdownErrCh) select { case <-alreadyShutdownCh: return case <-ctx.Done(): } shutdownCtx, cancelShutdown := context.WithTimeout(context.Background(), 60*time.Second) defer cancelShutdown() if err := srv.Shutdown(shutdownCtx); err != nil { shutdownErrCh <- fmt.Errorf("error occurred attempting to shutdown server: %w", err) } }() errCh := make(chan error, 1) go func() { defer close(errCh) err1 := <-runningErrCh err2 := <-shutdownErrCh if err := errors.Join(err1, err2); err != nil { errCh <- err } }() return errCh } func buildHTTPHandler(db *raw_events.Store) http.Handler { mux := http.NewServeMux() mux.Handle("/webhooks/", http.StripPrefix("/webhooks", webhooks.New(db))) mux.Handle("/site/", http.StripPrefix("/site", site.NewSiteHandler("./internal/site", db))) mux.Handle("/", http.RedirectHandler("/site", http.StatusPermanentRedirect)) return mux }