cerrado @ cb6060a60d71ce1be1591bb10f499916155160de

 1package ext
 2
 3import (
 4	"errors"
 5	"fmt"
 6	"log/slog"
 7	"net/http"
 8
 9	"git.gabrielgio.me/cerrado/pkg/service"
10	"git.gabrielgio.me/cerrado/templates"
11	"github.com/go-git/go-git/v5/plumbing"
12)
13
14type (
15	Router struct {
16		middlewares []Middleware
17		router      *http.ServeMux
18	}
19	HandlerFunc         func(http.ResponseWriter, *Request)
20	Middleware          func(next HandlerFunc) HandlerFunc
21	ErrorRequestHandler func(w http.ResponseWriter, r *Request) error
22)
23
24func NewRouter() *Router {
25	return &Router{
26		router: http.NewServeMux(),
27	}
28}
29
30func (r *Router) Handler() http.Handler {
31	return r.router
32}
33
34func (r *Router) AddMiddleware(middleware Middleware) {
35	r.middlewares = append(r.middlewares, middleware)
36}
37
38func wrapError(next ErrorRequestHandler) HandlerFunc {
39	return func(w http.ResponseWriter, r *Request) {
40		if err := next(w, r); err != nil {
41			if errors.Is(err, service.ErrRepositoryNotFound) ||
42				errors.Is(err, plumbing.ErrReferenceNotFound) {
43				NotFound(w, r)
44			} else {
45				slog.Error("Internal Server Error", "error", err)
46				InternalServerError(w, r, err)
47			}
48		}
49	}
50}
51
52func (r *Router) run(next ErrorRequestHandler) http.HandlerFunc {
53	return func(w http.ResponseWriter, re *http.Request) {
54		req := wrapError(next)
55		for _, r := range r.middlewares {
56			req = r(req)
57		}
58		req(w, &Request{Request: re})
59	}
60}
61
62func (r *Router) HandleFunc(path string, handler ErrorRequestHandler) {
63	r.router.HandleFunc(path, r.run(handler))
64}
65
66func NotFound(w http.ResponseWriter, r *Request) {
67	w.WriteHeader(http.StatusNotFound)
68	templates.WritePageTemplate(w, &templates.ErrorPage{
69		Message: "Not Found",
70	}, r.Context())
71}
72
73func BadRequest(w http.ResponseWriter, r *Request, msg string) {
74	w.WriteHeader(http.StatusBadRequest)
75	templates.WritePageTemplate(w, &templates.ErrorPage{
76		Message: msg,
77	}, r.Context())
78}
79
80func Redirect(w http.ResponseWriter, location string) {
81	w.Header().Add("location", location)
82	w.WriteHeader(http.StatusTemporaryRedirect)
83}
84
85func InternalServerError(w http.ResponseWriter, r *Request, err error) {
86	w.WriteHeader(http.StatusInternalServerError)
87	templates.WritePageTemplate(w, &templates.ErrorPage{
88		Message: fmt.Sprintf("Internal Server Error:\n%s", err.Error()),
89	}, r.Context())
90}