router/server.go
2024-10-10 14:59:55 -04:00

185 lines
3.9 KiB
Go

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)
}
}
}
}