feat(router): support for middlewares

This commit is contained in:
Guz
2024-10-07 15:40:06 -03:00
parent bb0c4b371a
commit 1c7131c216
2 changed files with 89 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
package middleware
import (
"errors"
"fmt"
"net/http"
)
type Middleware interface {
Serve(r http.HandlerFunc) http.HandlerFunc
}
type MiddlewaredReponse struct {
w http.ResponseWriter
statuses []int
bodyWrites [][]byte
}
func NewMiddlewaredResponse(w http.ResponseWriter) *MiddlewaredReponse {
return &MiddlewaredReponse{w, []int{500}, [][]byte{[]byte("")}}
}
func (m *MiddlewaredReponse) WriteHeader(s int) {
m.statuses = append(m.statuses, s)
}
func (m *MiddlewaredReponse) Header() http.Header {
return m.w.Header()
}
func (m *MiddlewaredReponse) Write(b []byte) (int, error) {
m.bodyWrites = append(m.bodyWrites, b)
return len(b), nil
}
func (m *MiddlewaredReponse) ReallyWriteHeader() (int, error) {
status := m.statuses[len(m.statuses)-1]
m.w.WriteHeader(status)
bytes := 0
for _, b := range m.bodyWrites {
by, err := m.w.Write(b)
if err != nil {
return bytes, errors.Join(
fmt.Errorf(
"Failed to write to response in middleware."+
"\nStatuses are %v"+
"\nTried to write %v bytes"+
"\nTried to write response:\n%s",
m.statuses, bytes, string(b),
),
err,
)
}
bytes += by
}
return bytes, nil
}

View File

@@ -3,11 +3,14 @@ package router
import (
"fmt"
"net/http"
"forge.capytal.company/capytalcode/project-comicverse/router/middleware"
)
type Router struct {
mux *http.ServeMux
serveHttp http.HandlerFunc
middlewares []middleware.Middleware
}
type RouterOpts struct {
@@ -48,7 +51,35 @@ func (rt *Router) HandleRoutes(routes []Route) {
}
}
func (r *Router) AddMiddleware(m middleware.Middleware) {
r.middlewares = append(r.middlewares, m)
}
func (rt *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if len(rt.middlewares) > 0 {
rt.serveHttp = rt.wrapMiddlewares(rt.middlewares, rt.serveHttp)
}
rt.serveHttp(w, r)
}
func (r *Router) wrapMiddlewares(ms []middleware.Middleware, h http.HandlerFunc) http.HandlerFunc {
wh := h.ServeHTTP
for _, m := range ms {
wh = m.Serve(wh)
}
return func(w http.ResponseWriter, r *http.Request) {
mw := middleware.NewMiddlewaredResponse(w)
wh(mw, r)
if _, err := mw.ReallyWriteHeader(); err != nil {
_, _ = w.Write(
[]byte(
fmt.Sprintf(
"Error while trying to write middlewared response.\n%s",
err.Error(),
),
),
)
}
}
}