2 files changed,
56 insertions(+),
2 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2026-01-28 18:40:04 +0200
Authored at:
2026-01-23 20:16:39 +0200
Change ID:
puktuymontoyukwmpknvlltopqztpuxv
Parent:
1043e31
M
internal/handlers/handlers.go
路路路 18 18 t *template.Template 19 19 } 20 20 21 -func InitRoutes(cfg *config.Config) *http.ServeMux { 21 +func InitRoutes(cfg *config.Config) http.Handler { 22 22 tmpls := template.Must(template.New(""). 23 23 Funcs(templateFuncs). 24 24 ParseFS(web.TemplatesFS, "*")) 路路路 36 36 mux.HandleFunc("GET /{name}/log/{ref}", h.logHandler) 37 37 mux.HandleFunc("GET /{name}/commit/{ref}", h.commitHandler) 38 38 mux.HandleFunc("GET /{name}/refs/{$}", h.refsHandler) 39 - return mux 39 + 40 + handler := h.recoverMiddleware(mux) 41 + return h.loggingMiddleware(handler) 40 42 } 41 43 42 44 func (h *handlers) serveStatic(w http.ResponseWriter, r *http.Request) {
M
internal/handlers/util.go
路路路 1 1 package handlers 2 2 3 3 import ( 4 + "fmt" 4 5 "log/slog" 5 6 "net/http" 7 + "time" 6 8 ) 7 9 8 10 func (h *handlers) templ(w http.ResponseWriter, name string, data any) { 路路路 23 25 w.WriteHeader(http.StatusInternalServerError) 24 26 h.templ(w, "500", nil) 25 27 } 28 + 29 +func (h *handlers) recoverMiddleware(next http.Handler) http.Handler { 30 + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 31 + defer func() { 32 + if err := recover(); err != nil { 33 + h.write500(w, fmt.Errorf("panic: %v", err)) 34 + } 35 + }() 36 + next.ServeHTTP(w, r) 37 + }) 38 +} 39 + 40 +func (h *handlers) loggingMiddleware(next http.Handler) http.Handler { 41 + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 42 + start := time.Now() 43 + wrapped := wrapResponseWriter(w) 44 + next.ServeHTTP(wrapped, r) 45 + 46 + slog.Info("http request", 47 + "method", r.Method, 48 + "path", r.URL.Path, 49 + "status", wrapped.status, 50 + "latency", time.Since(start).String(), 51 + ) 52 + }) 53 +} 54 + 55 +type responseWriter struct { 56 + http.ResponseWriter 57 + status int 58 + wroteHeader bool 59 +} 60 + 61 +func wrapResponseWriter(w http.ResponseWriter) *responseWriter { 62 + return &responseWriter{ResponseWriter: w} 63 +} 64 + 65 +func (rw *responseWriter) Status() int { 66 + return rw.status 67 +} 68 + 69 +func (rw *responseWriter) WriteHeader(code int) { 70 + if rw.wroteHeader { 71 + return 72 + } 73 + 74 + rw.status = code 75 + rw.ResponseWriter.WriteHeader(code) 76 + rw.wroteHeader = true 77 +}