package fiber import ( "errors" "html/template" "strconv" "time" cache "git.dmitriygnatenko.ru/dima/go-common/cache/ttl_memory_cache" "git.dmitriygnatenko.ru/dima/go-common/db" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/recover" "github.com/gofiber/template/html/v2" "git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/middleware/language" "git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/repositories" "git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/services/auth" "git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/services/config" "git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/services/i18n" ) const ( appName = "dmitriygnatenko" templatesPath = "./../../internal/templates" staticPath = "../../web" metricsURI = "/metrics" ) type ServiceProvider interface { ConfigService() *config.Service AuthService() *auth.Service CacheService() *cache.Cache TransactionManager() *db.TxManager ArticleRepository() *repositories.ArticleRepository TagRepository() *repositories.TagRepository ArticleTagRepository() *repositories.ArticleTagRepository UserRepository() *repositories.UserRepository } func Init(sp ServiceProvider) (*fiber.App, error) { fiberApp := fiber.New(getConfig(sp)) // Configure web root fiberApp.Static("/", staticPath) // Configure CORS middleware fiberApp.Use(cors.New(getCORSConfig(sp))) // Configure recover middleware fiberApp.Use(recover.New()) // Configure language middleware fiberApp.Use(language.New()) // Metrics addMetrics(fiberApp, sp) // Public handlers addPublicHandlers(fiberApp, sp) // Protected handlers addAdminHandlers(fiberApp, sp) return fiberApp, nil } func getConfig(sp ServiceProvider) fiber.Config { return fiber.Config{ AppName: appName, DisableStartupMessage: true, Views: getViewsEngine(sp), ErrorHandler: getErrorHandler(), } } func getCORSConfig(sp ServiceProvider) cors.Config { return cors.Config{ AllowOrigins: sp.ConfigService().CORSAllowOrigins(), AllowMethods: sp.ConfigService().CORSAllowMethods(), } } func getViewsEngine(sp ServiceProvider) *html.Engine { engine := html.New(templatesPath, ".html") // nolint:gocritic engine.AddFunc("now", func() time.Time { return time.Now() }) // nolint:gosec engine.AddFunc("noescape", func(str string) template.HTML { return template.HTML(str) }) engine.AddFunc("gridsep", func(i, l int) bool { i++ return i%3 == 0 && i != l }) engine.AddFunc("version", func() string { return strconv.FormatUint(uint64(sp.ConfigService().StaticVersion()), 10) }) return engine } func getErrorHandler() fiber.ErrorHandler { return func(fctx *fiber.Ctx, err error) error { lang := i18n.Language(fctx) errCode := fiber.StatusInternalServerError var e *fiber.Error if errors.As(err, &e) { errCode = e.Code } var renderData fiber.Map if errCode == fiber.StatusNotFound { renderData = fiber.Map{ "pageTitle": i18n.T(lang, "page_not_found_err_title"), "code": fiber.StatusNotFound, "text": i18n.T(lang, "page_not_found_err_desc"), } } else { renderData = fiber.Map{ "pageTitle": i18n.T(lang, "internal_err_title"), "code": fiber.StatusInternalServerError, "text": i18n.T(lang, "internal_err_desc"), } } renderData["headTitle"] = i18n.T(lang, "head_title") return fctx.Render("error", renderData, "_layout") } }