package main import ( "context" "errors" "log" "net/http" "os" "os/signal" "path/filepath" "syscall" "time" "ymhut-box/server/feedback-mailer/internal/auth" "ymhut-box/server/feedback-mailer/internal/config" "ymhut-box/server/feedback-mailer/internal/db" "ymhut-box/server/feedback-mailer/internal/web" ) func main() { baseDir := findBaseDir() cfg, err := config.Load(baseDir) if err != nil { log.Fatalf("load config: %v", err) } store, err := db.Open(cfg) if err != nil { log.Fatalf("open database: %v", err) } defer store.Close() authService := auth.NewService(cfg) router := web.NewRouter(cfg, store, authService) addr := cfg.Listen if addr == "" { addr = ":8080" } log.Printf("YMhut Box feedback service listening on %s", addr) server := &http.Server{Addr: addr, Handler: router} go func() { if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { log.Fatalf("serve: %v", err) } }() ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer stop() <-ctx.Done() shutdownCtx, cancel := context.WithTimeout(context.Background(), 8*time.Second) defer cancel() if err := server.Shutdown(shutdownCtx); err != nil { log.Fatalf("shutdown: %v", err) } log.Println("YMhut Box feedback service stopped") } func findBaseDir() string { if value := os.Getenv("YMHUT_FEEDBACK_HOME"); value != "" { if abs, err := filepath.Abs(value); err == nil { return abs } return value } if wd, err := os.Getwd(); err == nil && looksLikeServiceRoot(wd) { return wd } exe, err := os.Executable() if err == nil { return filepath.Dir(exe) } wd, err := os.Getwd() if err == nil { return wd } return "." } func looksLikeServiceRoot(path string) bool { for _, name := range []string{"config.txt", "admin-web", "web"} { if _, err := os.Stat(filepath.Join(path, name)); err == nil { return true } } return false }