package web import ( "context" "database/sql" "net/http" http_pprof "net/http/pprof" runtime_pprof "runtime/pprof" "sync" "time" "github.com/martinlehoux/biking_home/strava" "github.com/martinlehoux/kagamigo/kcore" ) const dateFormat = "2006-01-02" type Server struct { db *sql.DB configPath string oauthMu sync.Mutex oauthState string returnToURL string syncMu sync.Mutex syncActive bool enablePprof bool } type syncClient interface { List(from, to time.Time) ([]strava.Activity, error) Get(id int64) (strava.Activity, []byte, error) } func NewServer(db *sql.DB, configPath string) *Server { return &Server{db: db, configPath: configPath} } func (s *Server) WithPprof(enabled bool) *Server { s.enablePprof = enabled return s } func (s *Server) Handler() http.Handler { mux := http.NewServeMux() mux.Handle("GET /static/", http.FileServer(http.FS(staticFiles))) handleRoute(mux, "GET /", s.handleRides) handleRoute(mux, "GET /rides/{id}", s.handleRide) handleRoute(mux, "GET /analytics", s.handleAnalytics) handleRoute(mux, "POST /rides/{id}/official-climbs", s.handleCreateOfficialClimb) handleRoute(mux, "GET /sync", s.handleSyncForm) handleRoute(mux, "POST /sync", s.handleSync) handleRoute(mux, "GET /strava/login", s.handleStravaLogin) handleRoute(mux, "GET /strava/callback", s.handleStravaCallback) if s.enablePprof { registerPprof(mux) } return kcore.RecoverMiddleware(mux) } func handleRoute(mux *http.ServeMux, pattern string, handler http.HandlerFunc) { mux.HandleFunc(pattern, withPprofLabel(pattern, handler)) } func withPprofLabel(route string, next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { runtime_pprof.Do(r.Context(), runtime_pprof.Labels("route", route), func(ctx context.Context) { next(w, r.WithContext(ctx)) }) } } func registerPprof(mux *http.ServeMux) { mux.HandleFunc("GET /debug/pprof/", http_pprof.Index) mux.HandleFunc("GET /debug/pprof/cmdline", http_pprof.Cmdline) mux.HandleFunc("GET /debug/pprof/profile", http_pprof.Profile) mux.HandleFunc("GET /debug/pprof/symbol", http_pprof.Symbol) mux.HandleFunc("GET /debug/pprof/trace", http_pprof.Trace) for _, name := range []string{"allocs", "block", "goroutine", "heap", "mutex", "threadcreate"} { mux.Handle("GET /debug/pprof/"+name, http_pprof.Handler(name)) } } func (s *Server) ListenAndServe(addr string) error { return http.ListenAndServe(addr, s.Handler()) }