package router import ( "io" "net/http" "net/url" "somehole.com/common/log" ) type response struct { Status int Header Header Body Body } type Response[RSB ResponseBuilder] struct { response } func NewResponse[RSB ResponseBuilder](rsb RSB) *Response[RSB] { return &Response[RSB]{*rsb.Response()} } 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(map[string][]string) (err Error) Values(map[string][]string) (err Error) Body(body io.ReadCloser) (err Error) Request() *request } func (*Response[RSB]) ResponseBuilder() ResponseBuilder { var rsb RSB return rsb.New() } type ResponseBuilder interface { mustEmbedDefaultResponseBuilder() New() (rsb ResponseBuilder) Header(header Header) (err Error) Write(body []byte) (err Error) Response() *response } 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, RSB ResponseBuilder] func(req *Request[RQB]) (res *Response[RSB], err Error) type server[RQB RequestBuilder, RSB ResponseBuilder] struct { logger log.Logger serve [numServeStages][]ServeFunc[RQB, RSB] } func NewServer[RQB RequestBuilder, RSB ResponseBuilder](serve ServeFunc[RQB, RSB]) (srv *server[RQB, RSB]) { srv = &server[RQB, RSB]{ serve: [numServeStages][]ServeFunc[RQB, RSB]{}, } srv.serve[serveMain] = append(srv.serve[serveMain], serve) return srv } func (srv *server[RQB, RSB]) SetLogger(logger log.Logger) *server[RQB, RSB] { srv.logger = logger return srv } func (srv *server[RQB, RSB]) addServeFunc(when serveStage, serve ServeFunc[RQB, RSB]) *server[RQB, RSB] { if srv.serve[when] == nil { srv.serve[when] = make([]ServeFunc[RQB, RSB], 0) } srv.serve[when] = append(srv.serve[when], serve) return srv } func (srv *server[RQB, RSB]) PreServeFunc(serve ServeFunc[RQB, RSB]) *server[RQB, RSB] { return srv.addServeFunc(servePre, serve) } func (srv *server[RQB, RSB]) AddServeFunc(serve ServeFunc[RQB, RSB]) *server[RQB, RSB] { return srv.addServeFunc(serveMain, serve) } func (srv *server[RQB, RSB]) PostServeFunc(serve ServeFunc[RQB, RSB]) *server[RQB, RSB] { return srv.addServeFunc(servePost, serve) } func (srv *server[RQB, RSB]) 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(r.Header)); !ok { return } if ok := wr.handleError(rqb.Body(r.Body)); !ok { return } r.ParseForm() if ok := wr.handleError(rqb.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 { wr.Header().Add(key, v) } } } if len(res.Body) > 0 { wr.Write(res.Body) } } } }