Add custom request context thing
This commit is contained in:
parent
cc521e0245
commit
465c877241
|
@ -46,6 +46,10 @@ func Fatal() *zerolog.Event {
|
||||||
return log.Fatal().Timestamp().Stack()
|
return log.Fatal().Timestamp().Stack()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func With() zerolog.Context {
|
||||||
|
return log.With()
|
||||||
|
}
|
||||||
|
|
||||||
type PrettyZerologWriter struct {
|
type PrettyZerologWriter struct {
|
||||||
wd string
|
wd string
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
package website
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"git.handmade.network/hmn/hmn/src/logging"
|
||||||
|
"git.handmade.network/hmn/hmn/src/templates"
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HMNRouter struct {
|
||||||
|
HttpRouter *httprouter.Router
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HMNRouter) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
r.HttpRouter.ServeHTTP(rw, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HMNRouter) Handle(method, route string, handler HMNHandler) {
|
||||||
|
r.HttpRouter.Handle(method, route, handleHmnHandler(route, handler))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HMNRouter) GET(route string, handler HMNHandler) {
|
||||||
|
r.Handle(http.MethodGet, route, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HMNRouter) ServeFiles(path string, root http.FileSystem) {
|
||||||
|
r.HttpRouter.ServeFiles(path, root)
|
||||||
|
}
|
||||||
|
|
||||||
|
type HMNHandler func(c *RequestContext, p httprouter.Params)
|
||||||
|
|
||||||
|
type RequestContext struct {
|
||||||
|
StatusCode int
|
||||||
|
Body io.ReadWriter
|
||||||
|
Logger zerolog.Context
|
||||||
|
|
||||||
|
rw http.ResponseWriter
|
||||||
|
req *http.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRequestContext(rw http.ResponseWriter, req *http.Request, route string) *RequestContext {
|
||||||
|
return &RequestContext{
|
||||||
|
StatusCode: http.StatusOK,
|
||||||
|
Body: new(bytes.Buffer),
|
||||||
|
Logger: logging.With().Str("route", route),
|
||||||
|
|
||||||
|
rw: rw,
|
||||||
|
req: req,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RequestContext) Context() context.Context {
|
||||||
|
return c.req.Context()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RequestContext) URL() *url.URL {
|
||||||
|
return c.req.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RequestContext) Headers() http.Header {
|
||||||
|
return c.rw.Header()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RequestContext) WriteTemplate(name string, data interface{}) error {
|
||||||
|
return templates.Templates[name].Execute(c.Body, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleHmnHandler(route string, h HMNHandler) httprouter.Handle {
|
||||||
|
return func(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||||
|
c := newRequestContext(rw, r, route)
|
||||||
|
h(c, p)
|
||||||
|
|
||||||
|
rw.WriteHeader(c.StatusCode)
|
||||||
|
io.Copy(rw, c.Body)
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,14 +14,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type websiteRoutes struct {
|
type websiteRoutes struct {
|
||||||
*httprouter.Router
|
*HMNRouter
|
||||||
|
|
||||||
conn *pgxpool.Pool
|
conn *pgxpool.Pool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWebsiteRoutes(conn *pgxpool.Pool) http.Handler {
|
func NewWebsiteRoutes(conn *pgxpool.Pool) http.Handler {
|
||||||
routes := &websiteRoutes{
|
routes := &websiteRoutes{
|
||||||
Router: httprouter.New(),
|
HMNRouter: &HMNRouter{HttpRouter: httprouter.New()},
|
||||||
conn: conn,
|
conn: conn,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,21 +33,8 @@ func NewWebsiteRoutes(conn *pgxpool.Pool) http.Handler {
|
||||||
return routes
|
return routes
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
func (s *websiteRoutes) Index(c *RequestContext, p httprouter.Params) {
|
||||||
TODO: Make a custom context thing so that routes won't directly use a response writer.
|
err := c.WriteTemplate("index.html", templates.BaseData{
|
||||||
|
|
||||||
This should store up a body, desired headers, status codes, etc. Doing this allows us to
|
|
||||||
make middleware that can write headers after an aborted request.
|
|
||||||
|
|
||||||
This context should also provide a sub-logger with request fields so we can easily see
|
|
||||||
which URLs are having problems.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO: Make all these routes automatically pull general template data
|
|
||||||
// TODO:
|
|
||||||
|
|
||||||
func (s *websiteRoutes) Index(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
||||||
err := templates.Templates["index.html"].Execute(rw, templates.BaseData{
|
|
||||||
Project: templates.Project{
|
Project: templates.Project{
|
||||||
Name: "Handmade Network",
|
Name: "Handmade Network",
|
||||||
Color: "cd4e31",
|
Color: "cd4e31",
|
||||||
|
@ -66,7 +53,7 @@ func (s *websiteRoutes) Index(rw http.ResponseWriter, r *http.Request, p httprou
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *websiteRoutes) Project(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
func (s *websiteRoutes) Project(c *RequestContext, p httprouter.Params) {
|
||||||
id := p.ByName("id")
|
id := p.ByName("id")
|
||||||
row := s.conn.QueryRow(context.Background(), "SELECT name FROM handmade_project WHERE id = $1", p.ByName("id"))
|
row := s.conn.QueryRow(context.Background(), "SELECT name FROM handmade_project WHERE id = $1", p.ByName("id"))
|
||||||
var name string
|
var name string
|
||||||
|
@ -75,14 +62,14 @@ func (s *websiteRoutes) Project(rw http.ResponseWriter, r *http.Request, p httpr
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rw.Write([]byte(fmt.Sprintf("(%s) %s\n", id, name)))
|
c.Body.Write([]byte(fmt.Sprintf("(%s) %s\n", id, name)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *websiteRoutes) ProjectCSS(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
func (s *websiteRoutes) ProjectCSS(c *RequestContext, p httprouter.Params) {
|
||||||
color := r.URL.Query().Get("color")
|
color := c.URL().Query().Get("color")
|
||||||
if color == "" {
|
if color == "" {
|
||||||
rw.WriteHeader(http.StatusBadRequest)
|
c.StatusCode = http.StatusBadRequest
|
||||||
rw.Write([]byte("You must provide a 'color' parameter.\n"))
|
c.Body.Write([]byte("You must provide a 'color' parameter.\n"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,8 +81,8 @@ func (s *websiteRoutes) ProjectCSS(rw http.ResponseWriter, r *http.Request, p ht
|
||||||
Theme: "dark",
|
Theme: "dark",
|
||||||
}
|
}
|
||||||
|
|
||||||
rw.Header().Add("Content-Type", "text/css")
|
c.Headers().Add("Content-Type", "text/css")
|
||||||
err := templates.Templates["project.css"].Execute(rw, templateData)
|
err := c.WriteTemplate("project.css", templateData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Error().Err(err).Msg("failed to generate project CSS")
|
logging.Error().Err(err).Msg("failed to generate project CSS")
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in New Issue