Files
shop-go/cmd/shop/main.go
T

132 lines
4.0 KiB
Go

package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"shop/internal/auth"
"shop/internal/config"
"shop/internal/database"
"shop/internal/handlers"
"shop/internal/middleware"
"shop/internal/repository"
"shop/internal/upload"
"shop/internal/version"
)
func main() {
ctx := context.Background()
cfg := config.Load()
pool, err := database.Connect(ctx)
if err != nil {
log.Fatalf("database: %v", err)
}
defer pool.Close()
if err := database.Migrate(ctx, pool); err != nil {
log.Fatalf("migrate: %v", err)
}
productRepo := repository.NewProductRepository(pool)
adminRepo := repository.NewAdminRepository(pool)
statsRepo := repository.NewStatsRepository(pool)
userRepo := repository.NewUserRepository(pool)
cartRepo := repository.NewCartRepository(pool)
orderRepo := repository.NewOrderRepository(pool)
storage, err := upload.NewStorage(cfg.UploadDir)
if err != nil {
log.Fatalf("upload storage: %v", err)
}
if cfg.AdminEmail != "" && cfg.AdminPassword != "" {
if err := adminRepo.Upsert(ctx, cfg.AdminEmail, cfg.AdminPassword); err != nil {
log.Fatalf("admin seed: %v", err)
}
log.Printf("admin ready: %s", cfg.AdminEmail)
}
tmpl, err := handlers.ParseTemplates()
if err != nil {
log.Fatalf("templates: %v", err)
}
adminSession := auth.NewSession(cfg.SessionSecret, "shop_admin_session", "/admin")
userSession := auth.NewSession(cfg.SessionSecret, "shop_user_session", "/")
cartSession := auth.NewSession(cfg.SessionSecret, "shop_cart_key", "/")
customer := handlers.NewCustomerHandler(
productRepo, userRepo, cartRepo, orderRepo, statsRepo,
userSession, cartSession, tmpl,
)
admin := handlers.NewAdminHandler(adminRepo, productRepo, statsRepo, storage, adminSession, tmpl)
mux := http.NewServeMux()
mux.Handle("GET /static/", http.StripPrefix("/static/", handlers.StaticHandler()))
mux.Handle("GET /uploads/", storage.FileServer())
mux.HandleFunc("GET /health", customer.Health)
mux.HandleFunc("GET /{$}", customer.Home)
mux.HandleFunc("GET /register", customer.RegisterPage)
mux.HandleFunc("POST /register", customer.Register)
mux.HandleFunc("GET /login", customer.LoginPage)
mux.HandleFunc("POST /login", customer.Login)
mux.HandleFunc("POST /logout", customer.Logout)
mux.HandleFunc("GET /cart", customer.CartPage)
mux.HandleFunc("POST /cart/add", customer.CartAdd)
mux.HandleFunc("POST /cart/update", customer.CartUpdate)
mux.HandleFunc("POST /cart/remove", customer.CartRemove)
mux.HandleFunc("GET /checkout", customer.CheckoutPage)
mux.HandleFunc("POST /checkout", customer.Checkout)
mux.HandleFunc("GET /account", customer.Account)
mux.HandleFunc("POST /account", customer.Account)
mux.HandleFunc("GET /admin/login", admin.LoginPage)
mux.HandleFunc("POST /admin/login", admin.Login)
mux.HandleFunc("POST /admin/logout", admin.Logout)
mux.HandleFunc("GET /admin/{$}", admin.Dashboard)
mux.HandleFunc("GET /admin/products", admin.ProductList)
mux.HandleFunc("GET /admin/products/new", admin.ProductNew)
mux.HandleFunc("POST /admin/products/save", admin.ProductSave)
mux.HandleFunc("GET /admin/products/{id}/edit", admin.ProductEdit)
mux.HandleFunc("POST /admin/products/{id}/delete", admin.ProductDelete)
mux.HandleFunc("POST /admin/products/{id}/images/{imageId}/delete", admin.ImageDelete)
addr := ":" + getEnv("APP_PORT", "8080")
srv := &http.Server{
Addr: addr,
Handler: middleware.TrustProxy(mux),
ReadTimeout: 15 * time.Second,
WriteTimeout: 60 * time.Second,
IdleTimeout: 60 * time.Second,
}
go func() {
log.Printf("Shop %s listening on %s", version.Version, addr)
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen: %v", err)
}
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
_ = srv.Shutdown(shutdownCtx)
}
func getEnv(key, fallback string) string {
if v := os.Getenv(key); v != "" {
return v
}
return fallback
}