package site import ( "fmt" "log/slog" "net/http" "path" "sync" ) type counter struct { hits map[string]int mu sync.Mutex } type handler struct { logger *slog.Logger requestsCounter *counter } func newHandler(logger *slog.Logger) *handler { return &handler{ logger: logger, requestsCounter: &counter{hits: make(map[string]int)}, } } func (h *handler) LoggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { h.logger.Debug("Received request", "path", r.URL.Path) next.ServeHTTP(w, r) h.logger.Debug("Finished Request", "path", r.URL.Path) }) } func (h *handler) RequestsCounterMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { h.requestsCounter.mu.Lock() h.requestsCounter.hits[r.URL.Path] += 1 h.requestsCounter.mu.Unlock() next.ServeHTTP(w, r) }) } func (h *handler) Ping(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Pong") } func (h *handler) Index(w http.ResponseWriter, r *http.Request) { h.logger.Info(r.URL.Path) if template, isOk := templates[path.Base(r.URL.Path)]; isOk { h.logger.Info("Found template") template.ExecuteTemplate(w, "base", nil) } else { h.logger.Info("default template") templates["index"].ExecuteTemplate(w, "base", nil) } } func (h *handler) FileServer(w http.ResponseWriter, r *http.Request) { h.logger.Info("handled by file server router") http.FileServer(http.FS(staticContent)).ServeHTTP(w, r) } func (h *handler) Metrics(w http.ResponseWriter, r *http.Request) { h.requestsCounter.mu.Lock() defer h.requestsCounter.mu.Unlock() for path, hits := range h.requestsCounter.hits { fmt.Fprintf(w, "http_requests_total{handler=\"%s\"} %d\n", path, hits) } } func (h *handler) Healthz(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Ok") } func (h *handler) NotFound(w http.ResponseWriter, r *http.Request) { http.Error(w, "Page Not Found", http.StatusNotFound) }