package main import ( "log" "net/http" "os" "strings" "github.com/joho/godotenv" "plumber" "plumber/internal/blob" "plumber/internal/store" "plumber/internal/web" ) func main() { _ = godotenv.Load() listen := listenAddr() st, err := store.Connect(os.Getenv("DATABASE_URL"), env("DATA_PATH", "data.db"), plumber.SchemaSQL) if err != nil { log.Fatalf("database: %v", err) } defer st.Close() if os.Getenv("DATABASE_URL") != "" { log.Printf("database: postgres") } else { log.Printf("database: sqlite") } uploader := blob.NewSpaces(blob.SpacesConfig{ Key: os.Getenv("SPACES_KEY"), Secret: os.Getenv("SPACES_SECRET"), Region: os.Getenv("SPACES_REGION"), Bucket: os.Getenv("SPACES_BUCKET"), Endpoint: os.Getenv("SPACES_ENDPOINT"), CDNBase: os.Getenv("SPACES_CDN_BASE"), }) if uploader.Enabled() { log.Printf("avatars: digitalocean spaces") } else { log.Printf("avatars: uploads disabled (set SPACES_* to enable)") } srv, err := web.New(st, st.SessionStore(), plumber.TemplateFS, plumber.StaticFS, web.Config{ AdminUsername: os.Getenv("ADMIN_USERNAME"), SecureCookie: os.Getenv("SECURE_COOKIE") == "1", Blob: uploader, }) if err != nil { log.Fatalf("server: %v", err) } log.Printf("listening on %s", listen) if err := http.ListenAndServe(listen, srv.Handler()); err != nil { log.Fatal(err) } } // listenAddr prefers PORT (App Platform / PaaS), then LISTEN, then :8080. func listenAddr() string { if p := strings.TrimSpace(os.Getenv("PORT")); p != "" { if strings.HasPrefix(p, ":") { return p } return ":" + p } return env("LISTEN", ":8080") } func env(key, fallback string) string { v := strings.TrimSpace(os.Getenv(key)) if v == "" { return fallback } return v }