package router import ( "io" "net/http" "net/url" "somehole.com/common/log" ) type Response struct { Status int Header Header Body Body } type Error interface { Error(e Error) (err Error) Status() (code int) String() (out string) Response() (res *Response) } type request struct { Url url.URL Header Header Values Values Body Body } type Request[RQB RequestBuilder] struct { request } func NewRequest[RQB RequestBuilder](rqb RQB) *Request[RQB] { return &Request[RQB]{*rqb.Request()} } func (*Request[RQB]) RequestBuilder() RequestBuilder { var rqb RQB return rqb.New() } type RequestBuilder interface { mustEmbedDefaultRequestBuilder() New() (rqb RequestBuilder) Allowed(method string) (err Error) Url(url url.URL) (err Error) Header(header Header) (err Error) Values(values Values) (err Error) Body(body io.ReadCloser) (err Error) Request() *request } type writer struct { http.ResponseWriter log.Logger } func (w *writer) handleError(err Error) (ok bool) { if err != nil { res := err.Response() for key, value := range res.Header { for _, v := range value { w.Header().Add(key, v) } } w.WriteHeader(res.Status) w.Write(res.Body) w.Logf(log.LevelError, err.String()) return false } return true } type serveStage uint8 const ( servePre serveStage = iota serveMain servePost numServeStages ) type ServeFunc[RQB RequestBuilder] func(req *Request[RQB]) (res *Response, err Error) type server[RQB RequestBuilder] struct { logger log.Logger serve [numServeStages][]ServeFunc[RQB] } func NewServer[RQB RequestBuilder](serve ServeFunc[RQB]) (srv *server[RQB]) { srv = &server[RQB]{ serve: [numServeStages][]ServeFunc[RQB]{}, } srv.serve[serveMain] = append(srv.serve[serveMain], serve) return srv } func (srv *server[RQB]) SetLogger(logger log.Logger) *server[RQB] { srv.logger = logger return srv } func (srv *server[RQB]) addServeFunc(when serveStage, serve ServeFunc[RQB]) *server[RQB] { if srv.serve[when] == nil { srv.serve[when] = make([]ServeFunc[RQB], 0) } srv.serve[when] = append(srv.serve[when], serve) return srv } func (srv *server[RQB]) PreServeFunc(serve ServeFunc[RQB]) *server[RQB] { return srv.addServeFunc(servePre, serve) } func (srv *server[RQB]) AddServeFunc(serve ServeFunc[RQB]) *server[RQB] { return srv.addServeFunc(serveMain, serve) } func (srv *server[RQB]) PostServeFunc(serve ServeFunc[RQB]) *server[RQB] { return srv.addServeFunc(servePost, serve) } func (srv *server[RQB]) ServeHTTP(w http.ResponseWriter, r *http.Request) { var rqb RQB rqb = rqb.New().(RQB) wr := writer{ResponseWriter: w, Logger: srv.logger} if ok := wr.handleError(rqb.Allowed(r.Method)); !ok { return } if ok := wr.handleError(rqb.Url(*r.URL)); !ok { return } if ok := wr.handleError(rqb.Header(Header(r.Header))); !ok { return } if ok := wr.handleError(rqb.Body(r.Body)); !ok { return } r.ParseForm() if ok := wr.handleError(rqb.Values(Values(r.Form))); !ok { return } for _, stage := range srv.serve { for _, s := range stage { res, err := s(NewRequest(rqb)) if ok := wr.handleError(err); !ok { return } if res.Header != nil { for key, value := range res.Header { for _, v := range value { w.Header().Add(key, v) } } } if len(res.Body) > 0 { wr.Write(res.Body) } } } }