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}