package main import ( "log" "net/http" "os" "path/filepath" "strings" "time" "github.com/alexedwards/scs/v2" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/joho/godotenv" "golang.org/x/time/rate" "github.com/weltonmoura/initpage/internal/config" "github.com/weltonmoura/initpage/internal/db" "github.com/weltonmoura/initpage/internal/handlers" mw "github.com/weltonmoura/initpage/internal/middleware" "github.com/weltonmoura/initpage/internal/sync" ) func main() { _ = godotenv.Load() cfg := config.Load() dbConn, err := db.Init(cfg.DBPath) if err != nil { log.Fatal(err) } defer dbConn.Close() sessionManager := scs.New() sessionManager.Lifetime = 24 * time.Hour sessionManager.Cookie.HttpOnly = true sessionManager.Cookie.SameSite = http.SameSiteLaxMode sessionManager.Cookie.Secure = strings.HasPrefix(cfg.AppOrigin, "https://") authH := &handlers.Auth{DB: dbConn, SM: sessionManager, Cfg: cfg} syncH := &sync.Sync{DB: dbConn} rl := mw.NewIPRateLimiter(rate.Every(time.Minute/10), 10) // ~10 req/min rl.Cleanup() r := chi.NewRouter() r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Use(middleware.RealIP) r.Use(sessionManager.LoadAndSave) base := strings.TrimRight(cfg.BasePath, "/") r.Route(base+"/api", func(api chi.Router) { api.Group(func(g chi.Router) { g.Use(mw.RateLimit(rl)) g.Post("/auth/register", authH.Register) g.Post("/auth/login", authH.Login) }) api.Post("/auth/logout", authH.Logout) api.Get("/auth/me", authH.Me) api.Group(func(g chi.Router) { g.Use(mw.AuthRequired(sessionManager)) g.Use(mw.LoadUserID(sessionManager)) g.Get("/sync", syncH.Get) g.Put("/sync", syncH.Put) }) }) // servir frontend workDir, _ := os.Getwd() webDir := filepath.Join(workDir, "web") fileServer := http.FileServer(http.Dir(webDir)) r.Get(base, func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, filepath.Join(webDir, "index.html")) }) r.Get(base+"/", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, filepath.Join(webDir, "index.html")) }) r.Get(base+"/*", func(w http.ResponseWriter, r *http.Request) { // strip base path p := strings.TrimPrefix(r.URL.Path, base) if p == "" { p = "/" } // tenta servir arquivo full := filepath.Join(webDir, filepath.Clean(strings.TrimPrefix(p, "/"))) if st, err := os.Stat(full); err == nil && !st.IsDir() { http.StripPrefix(base, fileServer).ServeHTTP(w, r) return } http.ServeFile(w, r, filepath.Join(webDir, "index.html")) }) log.Printf("Servidor rodando em :%s base=%s", cfg.Port, base) log.Fatal(http.ListenAndServe(":"+cfg.Port, r)) }