package main import ( "context" "fmt" "log" "net/http" "os" "github.com/go-chi/chi/v5" chimiddleware "github.com/go-chi/chi/v5/middleware" "github.com/jackc/pgx/v5/pgxpool" "github.com/joho/godotenv" "quake2dropzone/internal/auth" "quake2dropzone/internal/files" "quake2dropzone/internal/middleware" ) func main() { _ = godotenv.Load() dsn := os.Getenv("DATABASE_URL") if dsn == "" { host := os.Getenv("DB_HOST") if host == "" { host = "localhost" } port := os.Getenv("DB_PORT") if port == "" { port = "15432" } name := os.Getenv("DB_NAME") if name == "" { name = "dropzone" } user := os.Getenv("DB_USER") if user == "" { user = "dropzone" } pass := os.Getenv("DB_PASSWORD") dsn = fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", user, pass, host, port, name) } jwtSecret := os.Getenv("JWT_SECRET") if jwtSecret == "" { jwtSecret = "change-me-in-production" } diskRoot := os.Getenv("DISK_ROOT") if diskRoot == "" { diskRoot = "./diskroot" } port := os.Getenv("PORT") if port == "" { port = "8080" } db, err := pgxpool.New(context.Background(), dsn) if err != nil { log.Fatalf("failed to connect to database: %v", err) } defer db.Close() if err := db.Ping(context.Background()); err != nil { log.Fatalf("database ping failed: %v", err) } log.Println("connected to database") r := chi.NewRouter() r.Use(chimiddleware.Logger) r.Use(chimiddleware.Recoverer) r.Get("/api/health", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) // Public endpoints r.Post("/api/auth/login", auth.NewLoginHandler(db, jwtSecret)) r.Get("/api/files/public", files.PublicListHandler(diskRoot)) r.Get("/api/files/public/*", files.PublicListHandler(diskRoot)) useXAccel := os.Getenv("NGINX_ACCEL") == "true" r.Get("/api/files/download/public/*", files.PublicDownloadHandler(diskRoot, useXAccel)) r.Get("/api/files/raw/public/*", files.PublicRawHandler(diskRoot)) r.Get("/api/captcha", files.CaptchaHandler(jwtSecret)) r.Post("/api/files/zip/public", files.PublicZipHandler(diskRoot, jwtSecret)) // Protected endpoints (example) r.Group(func(r chi.Router) { r.Use(middleware.AuthRequired(jwtSecret)) r.Get("/api/me", func(w http.ResponseWriter, r *http.Request) { claims := middleware.GetClaims(r) fmt.Fprintf(w, `{"username":%q,"role":%q}`, claims.Username, claims.Role) }) }) // Admin-only endpoints (example) r.Group(func(r chi.Router) { r.Use(middleware.AuthRequired(jwtSecret)) r.Use(middleware.AdminRequired) r.Get("/api/admin/users", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`{"users":[]}`)) }) }) log.Printf("server listening on :%s", port) if err := http.ListenAndServe(":"+port, r); err != nil { log.Fatalf("server error: %v", err) } }