package fw import ( "fmt" "github.com/go-chi/chi/v5" "net/http" "runtime/debug" ) type MiddlewareFunc[U any] func(U, ActionFunc) (Response, Error) type HandlerFunc[U any] func(U) (Response, Error) type ActionFunc func() (Response, Error) type RouterManager[S, D any] struct { mux *chi.Mux storage S fnMakeContainer func(S, http.ResponseWriter, *http.Request) D fnCloseContainer func(D) debug bool logger Logger middlewares []MiddlewareFunc[D] } func NewRouterManager[S, D any](mux *chi.Mux, storage S, fnMakeContainer func(S, http.ResponseWriter, *http.Request) D, fnCloseContainer func(D), debug bool, logger Logger) *RouterManager[S, D] { return &RouterManager[S, D]{ mux: mux, storage: storage, fnMakeContainer: fnMakeContainer, fnCloseContainer: fnCloseContainer, debug: debug, logger: logger, middlewares: make([]MiddlewareFunc[D], 0), } } func (it *RouterManager[S, D]) Use(middlewares ...MiddlewareFunc[D]) { it.middlewares = append(it.middlewares, middlewares...) } func (it *RouterManager[S, D]) Group(relativePath string) *Group[S, D] { return NewGroup(it, relativePath, it.middlewares...) } func (it *RouterManager[S, D]) NotFound(handler HandlerFunc[D], middlewares ...MiddlewareFunc[D]) { it.mux.NotFound(it.makeHandler(handler, append(it.middlewares, middlewares...))) } func (it *RouterManager[S, D]) NoMethod(handler HandlerFunc[D], middlewares ...MiddlewareFunc[D]) { it.mux.MethodNotAllowed(it.makeHandler(handler, append(it.middlewares, middlewares...))) } func (it *RouterManager[S, D]) Get(relativePath string, handler HandlerFunc[D], middlewares ...MiddlewareFunc[D]) { it.mux.Get(relativePath, it.makeHandler(handler, append(it.middlewares, middlewares...))) } func (it *RouterManager[S, D]) Post(relativePath string, handler HandlerFunc[D], middlewares ...MiddlewareFunc[D]) { it.mux.Post(relativePath, it.makeHandler(handler, append(it.middlewares, middlewares...))) } func (it *RouterManager[S, D]) List(methods []string, relativePath string, handler HandlerFunc[D], middlewares ...MiddlewareFunc[D]) { for _, m := range methods { it.mux.Method(m, relativePath, it.makeHandler(handler, append(it.middlewares, middlewares...))) } } func (it *RouterManager[S, D]) Common(relativePath string, handler HandlerFunc[D], middlewares ...MiddlewareFunc[D]) { it.List([]string{http.MethodGet, http.MethodPost, http.MethodOptions}, relativePath, handler, middlewares...) } func (it *RouterManager[S, D]) All(relativePath string, handler HandlerFunc[D], middlewares ...MiddlewareFunc[D]) { it.List([]string{ http.MethodGet, http.MethodHead, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete, http.MethodConnect, http.MethodOptions, http.MethodTrace, }, relativePath, handler, middlewares..., ) } type Group[S, D any] struct { routerManager *RouterManager[S, D] mux *chi.Mux middlewares []MiddlewareFunc[D] } func NewGroup[S, D any](routerManager *RouterManager[S, D], relativePath string, middlewares ...MiddlewareFunc[D]) *Group[S, D] { mux := chi.NewRouter() routerManager.mux.Mount(relativePath, mux) return &Group[S, D]{ routerManager: routerManager, mux: mux, middlewares: middlewares, } } func (it *Group[S, D]) Use(middlewares ...MiddlewareFunc[D]) { it.middlewares = append(it.middlewares, middlewares...) } func (it *Group[S, D]) Group(relativePath string, middlewares ...MiddlewareFunc[D]) *Group[S, D] { mux := chi.NewRouter() it.mux.Mount(relativePath, mux) return &Group[S, D]{ routerManager: it.routerManager, mux: mux, middlewares: append(it.middlewares, middlewares...), } } func (it *Group[S, D]) NotFound(handler HandlerFunc[D], middlewares ...MiddlewareFunc[D]) { it.mux.NotFound(it.routerManager.makeHandler(handler, append(it.middlewares, middlewares...))) } func (it *Group[S, D]) NoMethod(handler HandlerFunc[D], middlewares ...MiddlewareFunc[D]) { it.mux.MethodNotAllowed(it.routerManager.makeHandler(handler, append(it.middlewares, middlewares...))) } func (it *Group[S, D]) Get(relativePath string, handler HandlerFunc[D], middlewares ...MiddlewareFunc[D]) { it.mux.Get(relativePath, it.routerManager.makeHandler(handler, append(it.middlewares, middlewares...))) } func (it *Group[S, D]) Post(relativePath string, handler HandlerFunc[D], middlewares ...MiddlewareFunc[D]) { it.mux.Post(relativePath, it.routerManager.makeHandler(handler, append(it.middlewares, middlewares...))) } func (it *Group[S, D]) List(methods []string, relativePath string, handler HandlerFunc[D], middlewares ...MiddlewareFunc[D]) { for _, m := range methods { it.mux.Method(m, relativePath, it.routerManager.makeHandler(handler, append(it.middlewares, middlewares...))) } } func (it *Group[S, D]) Common(relativePath string, handler HandlerFunc[D], middlewares ...MiddlewareFunc[D]) { it.List([]string{http.MethodGet, http.MethodPost, http.MethodOptions}, relativePath, handler, middlewares...) } func (it *Group[S, D]) All(relativePath string, handler HandlerFunc[D], middlewares ...MiddlewareFunc[D]) { it.List([]string{ http.MethodGet, http.MethodHead, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete, http.MethodConnect, http.MethodOptions, http.MethodTrace, }, relativePath, handler, middlewares..., ) } func (it *RouterManager[S, D]) makeHandler(handler HandlerFunc[D], middlewares []MiddlewareFunc[D]) http.HandlerFunc { return func(writer http.ResponseWriter, request *http.Request) { var err Error defer func() { if err_ := recover(); err_ != nil { err = ErrPanic(fmt.Errorf("panic: %v", err_), debug.Stack()) it.errorsHandler(writer, err, it.debug, it.logger) } }() container := it.fnMakeContainer(it.storage, writer, request) defer it.fnCloseContainer(container) err = it.pipeline(handler, middlewares, container) if err != nil { it.errorsHandler(writer, err, it.debug, it.logger) } } } func (it *RouterManager[S, D]) pipeline(endpoint HandlerFunc[D], middlewares []MiddlewareFunc[D], container D) (err Error) { handler := func() (Response, Error) { return endpoint(container) } for i := len(middlewares) - 1; i >= 0; i-- { handler = it.createMiddleware(handler, middlewares[i], container) } resp, err := handler() if err != nil { _ = err.Tap() } if resp != nil { err = ErrStr("response должен быть отображен в middleware, по всей видимости этот шаг был пропущен") } return } func (it *RouterManager[T, U]) createMiddleware(next ActionFunc, middleware MiddlewareFunc[U], container U) ActionFunc { return func() (Response, Error) { return middleware(container, next) } } func (it *RouterManager[T, U]) errorsHandler(writer http.ResponseWriter, err Error, debugOn bool, logger Logger) { if logger != nil { logger.Error(err.Message(), err.Trace()) } message := "" if debugOn { message = fmt.Sprintf("
%s", err.Error()) } message = fmt.Sprintf("