package port import ( "net/http" "sync" "gitea.dwysokinski.me/twhelp/corev3/internal/app" "gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/apimodel" "gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/swgui" "github.com/getkin/kin-openapi/openapi3" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" ) type apiHTTPHandler struct { versionSvc *app.VersionService serverSvc *app.ServerService tribeSvc *app.TribeService playerSvc *app.PlayerService villageSvc *app.VillageService ennoblementSvc *app.EnnoblementService tribeChangeSvc *app.TribeChangeService errorRenderer apiErrorRenderer openAPISchema func() (*openapi3.T, error) } func WithOpenAPIConfig(oapiCfg OpenAPIConfig) APIHTTPHandlerOption { return func(cfg *apiHTTPHandlerConfig) { cfg.openAPI = oapiCfg } } func NewAPIHTTPHandler( versionSvc *app.VersionService, serverSvc *app.ServerService, tribeSvc *app.TribeService, playerSvc *app.PlayerService, villageSvc *app.VillageService, ennoblementSvc *app.EnnoblementService, tribeChangeSvc *app.TribeChangeService, opts ...APIHTTPHandlerOption, ) http.Handler { cfg := newAPIHTTPHandlerConfig(opts...) h := &apiHTTPHandler{ versionSvc: versionSvc, serverSvc: serverSvc, tribeSvc: tribeSvc, playerSvc: playerSvc, villageSvc: villageSvc, ennoblementSvc: ennoblementSvc, tribeChangeSvc: tribeChangeSvc, openAPISchema: sync.OnceValues(func() (*openapi3.T, error) { return getOpenAPISchema(cfg.openAPI) }), } r := chi.NewRouter() if cfg.openAPI.Enabled { r.Group(func(r chi.Router) { if cfg.openAPI.SwaggerEnabled { r.HandleFunc("/v2/swagger", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, r.RequestURI+"/", http.StatusMovedPermanently) }) r.Handle("/v2/swagger/*", swgui.Handler( cfg.openAPI.BasePath+"/v2/swagger", cfg.openAPI.BasePath+"/v2/openapi3.json", )) } r.Get("/v2/openapi3.json", h.sendOpenAPIJSON) }) } // these handlers must be set after the swagger/openapi routes // because we don't want to override the default handlers for those routes r.NotFound(h.handleNotFound) r.MethodNotAllowed(h.handleMethodNotAllowed) return apimodel.HandlerWithOptions(h, apimodel.ChiServerOptions{ BaseRouter: r, Middlewares: []apimodel.MiddlewareFunc{ middleware.NoCache, h.versionMiddleware, h.serverMiddleware, h.tribeMiddleware, h.playerMiddleware, h.villageMiddleware, }, ErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) { h.errorRenderer.render(w, r, err) }, }) } func (h *apiHTTPHandler) handleNotFound(w http.ResponseWriter, r *http.Request) { h.errorRenderer.render(w, r, apiError{ status: http.StatusNotFound, code: "route-not-found", message: "route not found", }) } func (h *apiHTTPHandler) handleMethodNotAllowed(w http.ResponseWriter, r *http.Request) { h.errorRenderer.render(w, r, apiError{ status: http.StatusMethodNotAllowed, code: "method-not-allowed", message: "method not allowed", }) }