Better refactoring, better logging
Save
- commit
- 42483f8c0404e5aeaf454d82bc410954ee92effb
- author
- bnema · · 2023-09-02 09:51 UTC
- committer
- bnema · · 2023-09-04 06:59 UTC
- parent
- 60d6353
- signature
- unsigned
15 files · +219 -99
M cmd/main.go +12 -9
| @@ -1,22 +1,25 @@ | |||
| 1 | 1 | package main | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | - | "gogs.bnema.dev/gordon-echo/internal" | |
| 4 | + | "gogs.bnema.dev/gordon-echo/internal/app" | |
| 5 | 5 | "gogs.bnema.dev/gordon-echo/internal/http/routes" | |
| 6 | 6 | ) | |
| 7 | 7 | ||
| 8 | 8 | func main() { | |
| 9 | - | // Setup logging | |
| 10 | - | internal.SetupLogging() | |
| 11 | - | ||
| 12 | - | // Initialize loggers | |
| 13 | - | appLogger := internal.InitializeAppLogger() | |
| 14 | - | echoLogger := internal.InitializeHTTPLogger() | |
| 9 | + | // Initialize Gordon | |
| 10 | + | gordon, err := app.NewApp() | |
| 11 | + | if err != nil { | |
| 12 | + | // Handle initialization error and exit | |
| 13 | + | gordon.APPLogger.Error().Err(err).Msg("Failed to initialize app") | |
| 14 | + | return | |
| 15 | + | } | |
| 15 | 16 | ||
| 16 | 17 | // Initialize echo server with routes and middlewares | |
| 17 | - | e := routes.NewRouter(appLogger, echoLogger) | |
| 18 | + | e := routes.NewRouter(gordon.APPLogger.Logger, gordon.HTTPLogger.Logger) | |
| 18 | 19 | ||
| 19 | 20 | if err := e.Start(":1323"); err != nil { | |
| 20 | - | appLogger.Error().Err(err).Msg("Failed to start the server") | |
| 21 | + | gordon.APPLogger.Error().Err(err).Msg("Failed to start the server") | |
| 21 | 22 | } | |
| 23 | + | // Graceful shutdown | |
| 24 | + | gordon.APPLogger.Info().Msg("Server is shutting down...") | |
| 22 | 25 | } | |
| @@ -1,22 +1,25 @@ | |||||
| 1 | package main | 1 | package main | ||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | - | "gogs.bnema.dev/gordon-echo/internal" | 4 | + | "gogs.bnema.dev/gordon-echo/internal/app" |
| 5 | "gogs.bnema.dev/gordon-echo/internal/http/routes" | 5 | "gogs.bnema.dev/gordon-echo/internal/http/routes" | ||
| 6 | ) | 6 | ) | ||
| 7 | 7 | ||||
| 8 | func main() { | 8 | func main() { | ||
| 9 | - | // Setup logging | 9 | + | // Initialize Gordon |
| 10 | - | internal.SetupLogging() | 10 | + | gordon, err := app.NewApp() |
| 11 | - | 11 | + | if err != nil { | |
| 12 | - | // Initialize loggers | 12 | + | // Handle initialization error and exit |
| 13 | - | appLogger := internal.InitializeAppLogger() | 13 | + | gordon.APPLogger.Error().Err(err).Msg("Failed to initialize app") |
| 14 | - | echoLogger := internal.InitializeHTTPLogger() | 14 | + | return |
| 15 | + | } | |||
| 15 | 16 | ||||
| 16 | // Initialize echo server with routes and middlewares | 17 | // Initialize echo server with routes and middlewares | ||
| 17 | - | e := routes.NewRouter(appLogger, echoLogger) | 18 | + | e := routes.NewRouter(gordon.APPLogger.Logger, gordon.HTTPLogger.Logger) |
| 18 | 19 | ||||
| 19 | if err := e.Start(":1323"); err != nil { | 20 | if err := e.Start(":1323"); err != nil { | ||
| 20 | - | appLogger.Error().Err(err).Msg("Failed to start the server") | 21 | + | gordon.APPLogger.Error().Err(err).Msg("Failed to start the server") |
| 21 | } | 22 | } | ||
| 23 | + | // Graceful shutdown | |||
| 24 | + | gordon.APPLogger.Info().Msg("Server is shutting down...") | |||
| 22 | } | 25 | } | ||
D internal/app.go +0 -42
| @@ -1,42 +0,0 @@ | |||
| 1 | - | package internal | |
| 2 | - | ||
| 3 | - | import ( | |
| 4 | - | "os" | |
| 5 | - | ||
| 6 | - | "github.com/rs/zerolog" | |
| 7 | - | "gogs.bnema.dev/gordon-echo/pkg/utils" | |
| 8 | - | ) | |
| 9 | - | ||
| 10 | - | // Define the main app struct | |
| 11 | - | type App struct { | |
| 12 | - | // Define the app logger | |
| 13 | - | Logger *utils.Logger | |
| 14 | - | // Define the app config | |
| 15 | - | } | |
| 16 | - | ||
| 17 | - | func InitializeAppLogger() zerolog.Logger { | |
| 18 | - | appLogFile, err := os.OpenFile("logs/app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | |
| 19 | - | if err != nil { | |
| 20 | - | panic(err) | |
| 21 | - | } | |
| 22 | - | appConsoleWriter := zerolog.ConsoleWriter{Out: os.Stdout} | |
| 23 | - | appMulti := zerolog.MultiLevelWriter(appLogFile, appConsoleWriter) | |
| 24 | - | return zerolog.New(appMulti).With().Timestamp().Str("type", "app").Logger() | |
| 25 | - | } | |
| 26 | - | ||
| 27 | - | func InitializeHTTPLogger() zerolog.Logger { | |
| 28 | - | httpLogFile, err := os.OpenFile("logs/http.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | |
| 29 | - | if err != nil { | |
| 30 | - | panic(err) | |
| 31 | - | } | |
| 32 | - | httpConsoleWriter := zerolog.ConsoleWriter{Out: os.Stdout} | |
| 33 | - | httpMulti := zerolog.MultiLevelWriter(httpLogFile, httpConsoleWriter) | |
| 34 | - | return zerolog.New(httpMulti).With().Timestamp().Logger() | |
| 35 | - | } | |
| 36 | - | ||
| 37 | - | func SetupLogging() { | |
| 38 | - | err := utils.CreateLogsDir() | |
| 39 | - | if err != nil { | |
| 40 | - | panic(err) | |
| 41 | - | } | |
| 42 | - | } | |
| @@ -1,42 +0,0 @@ | |||||
| 1 | - | package internal | |||
| 2 | - | ||||
| 3 | - | import ( | |||
| 4 | - | "os" | |||
| 5 | - | ||||
| 6 | - | "github.com/rs/zerolog" | |||
| 7 | - | "gogs.bnema.dev/gordon-echo/pkg/utils" | |||
| 8 | - | ) | |||
| 9 | - | ||||
| 10 | - | // Define the main app struct | |||
| 11 | - | type App struct { | |||
| 12 | - | // Define the app logger | |||
| 13 | - | Logger *utils.Logger | |||
| 14 | - | // Define the app config | |||
| 15 | - | } | |||
| 16 | - | ||||
| 17 | - | func InitializeAppLogger() zerolog.Logger { | |||
| 18 | - | appLogFile, err := os.OpenFile("logs/app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | |||
| 19 | - | if err != nil { | |||
| 20 | - | panic(err) | |||
| 21 | - | } | |||
| 22 | - | appConsoleWriter := zerolog.ConsoleWriter{Out: os.Stdout} | |||
| 23 | - | appMulti := zerolog.MultiLevelWriter(appLogFile, appConsoleWriter) | |||
| 24 | - | return zerolog.New(appMulti).With().Timestamp().Str("type", "app").Logger() | |||
| 25 | - | } | |||
| 26 | - | ||||
| 27 | - | func InitializeHTTPLogger() zerolog.Logger { | |||
| 28 | - | httpLogFile, err := os.OpenFile("logs/http.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | |||
| 29 | - | if err != nil { | |||
| 30 | - | panic(err) | |||
| 31 | - | } | |||
| 32 | - | httpConsoleWriter := zerolog.ConsoleWriter{Out: os.Stdout} | |||
| 33 | - | httpMulti := zerolog.MultiLevelWriter(httpLogFile, httpConsoleWriter) | |||
| 34 | - | return zerolog.New(httpMulti).With().Timestamp().Logger() | |||
| 35 | - | } | |||
| 36 | - | ||||
| 37 | - | func SetupLogging() { | |||
| 38 | - | err := utils.CreateLogsDir() | |||
| 39 | - | if err != nil { | |||
| 40 | - | panic(err) | |||
| 41 | - | } | |||
| 42 | - | } | |||
A internal/app/app.go +69 -0
| @@ -0,0 +1,69 @@ | |||
| 1 | + | package app | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "html/template" | |
| 5 | + | "os" | |
| 6 | + | ||
| 7 | + | "github.com/rs/zerolog" | |
| 8 | + | "gogs.bnema.dev/gordon-echo/pkg/utils" | |
| 9 | + | ) | |
| 10 | + | ||
| 11 | + | // Define the main app struct | |
| 12 | + | type App struct { | |
| 13 | + | // Define the app logger | |
| 14 | + | APPLogger *utils.Logger | |
| 15 | + | // Define the HTTP logger | |
| 16 | + | HTTPLogger *utils.Logger | |
| 17 | + | // Define the app config | |
| 18 | + | Template *template.Template | |
| 19 | + | // Define the app renderer | |
| 20 | + | Renderer *utils.Renderer | |
| 21 | + | } | |
| 22 | + | ||
| 23 | + | func NewApp() (*App, error) { | |
| 24 | + | app := &App{} | |
| 25 | + | ||
| 26 | + | // Initialize the general application logger | |
| 27 | + | appLogger, err := initializeAppLogger() | |
| 28 | + | if err != nil { | |
| 29 | + | return nil, err | |
| 30 | + | } | |
| 31 | + | app.APPLogger = &utils.Logger{Logger: appLogger} | |
| 32 | + | ||
| 33 | + | // Initialize the HTTP logger | |
| 34 | + | httpLogger, err := initializeHTTPLogger() | |
| 35 | + | if err != nil { | |
| 36 | + | return nil, err | |
| 37 | + | } | |
| 38 | + | app.HTTPLogger = &utils.Logger{Logger: httpLogger} | |
| 39 | + | ||
| 40 | + | return app, nil | |
| 41 | + | } | |
| 42 | + | func initializeAppLogger() (zerolog.Logger, error) { | |
| 43 | + | appLogFile, err := os.OpenFile("logs/app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | |
| 44 | + | if err != nil { | |
| 45 | + | return zerolog.Logger{}, err | |
| 46 | + | } | |
| 47 | + | ||
| 48 | + | appConsoleWriter := zerolog.ConsoleWriter{Out: os.Stdout} | |
| 49 | + | appMulti := zerolog.MultiLevelWriter(appLogFile, appConsoleWriter) | |
| 50 | + | return zerolog.New(appMulti).With().Timestamp().Str("type", "app").Logger(), nil | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | func initializeHTTPLogger() (zerolog.Logger, error) { | |
| 54 | + | httpLogFile, err := os.OpenFile("logs/http.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | |
| 55 | + | if err != nil { | |
| 56 | + | return zerolog.Logger{}, err | |
| 57 | + | } | |
| 58 | + | ||
| 59 | + | httpConsoleWriter := zerolog.ConsoleWriter{Out: os.Stdout} | |
| 60 | + | httpMulti := zerolog.MultiLevelWriter(httpLogFile, httpConsoleWriter) | |
| 61 | + | return zerolog.New(httpMulti).With().Timestamp().Logger(), nil | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | func SetupLogging() { | |
| 65 | + | err := utils.CreateLogsDir() | |
| 66 | + | if err != nil { | |
| 67 | + | panic(err) | |
| 68 | + | } | |
| 69 | + | } | |
| @@ -0,0 +1,69 @@ | |||||
| 1 | + | package app | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "html/template" | |||
| 5 | + | "os" | |||
| 6 | + | ||||
| 7 | + | "github.com/rs/zerolog" | |||
| 8 | + | "gogs.bnema.dev/gordon-echo/pkg/utils" | |||
| 9 | + | ) | |||
| 10 | + | ||||
| 11 | + | // Define the main app struct | |||
| 12 | + | type App struct { | |||
| 13 | + | // Define the app logger | |||
| 14 | + | APPLogger *utils.Logger | |||
| 15 | + | // Define the HTTP logger | |||
| 16 | + | HTTPLogger *utils.Logger | |||
| 17 | + | // Define the app config | |||
| 18 | + | Template *template.Template | |||
| 19 | + | // Define the app renderer | |||
| 20 | + | Renderer *utils.Renderer | |||
| 21 | + | } | |||
| 22 | + | ||||
| 23 | + | func NewApp() (*App, error) { | |||
| 24 | + | app := &App{} | |||
| 25 | + | ||||
| 26 | + | // Initialize the general application logger | |||
| 27 | + | appLogger, err := initializeAppLogger() | |||
| 28 | + | if err != nil { | |||
| 29 | + | return nil, err | |||
| 30 | + | } | |||
| 31 | + | app.APPLogger = &utils.Logger{Logger: appLogger} | |||
| 32 | + | ||||
| 33 | + | // Initialize the HTTP logger | |||
| 34 | + | httpLogger, err := initializeHTTPLogger() | |||
| 35 | + | if err != nil { | |||
| 36 | + | return nil, err | |||
| 37 | + | } | |||
| 38 | + | app.HTTPLogger = &utils.Logger{Logger: httpLogger} | |||
| 39 | + | ||||
| 40 | + | return app, nil | |||
| 41 | + | } | |||
| 42 | + | func initializeAppLogger() (zerolog.Logger, error) { | |||
| 43 | + | appLogFile, err := os.OpenFile("logs/app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | |||
| 44 | + | if err != nil { | |||
| 45 | + | return zerolog.Logger{}, err | |||
| 46 | + | } | |||
| 47 | + | ||||
| 48 | + | appConsoleWriter := zerolog.ConsoleWriter{Out: os.Stdout} | |||
| 49 | + | appMulti := zerolog.MultiLevelWriter(appLogFile, appConsoleWriter) | |||
| 50 | + | return zerolog.New(appMulti).With().Timestamp().Str("type", "app").Logger(), nil | |||
| 51 | + | } | |||
| 52 | + | ||||
| 53 | + | func initializeHTTPLogger() (zerolog.Logger, error) { | |||
| 54 | + | httpLogFile, err := os.OpenFile("logs/http.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | |||
| 55 | + | if err != nil { | |||
| 56 | + | return zerolog.Logger{}, err | |||
| 57 | + | } | |||
| 58 | + | ||||
| 59 | + | httpConsoleWriter := zerolog.ConsoleWriter{Out: os.Stdout} | |||
| 60 | + | httpMulti := zerolog.MultiLevelWriter(httpLogFile, httpConsoleWriter) | |||
| 61 | + | return zerolog.New(httpMulti).With().Timestamp().Logger(), nil | |||
| 62 | + | } | |||
| 63 | + | ||||
| 64 | + | func SetupLogging() { | |||
| 65 | + | err := utils.CreateLogsDir() | |||
| 66 | + | if err != nil { | |||
| 67 | + | panic(err) | |||
| 68 | + | } | |||
| 69 | + | } | |||
M internal/http/handlers/default.go +1 -1
| @@ -10,7 +10,7 @@ import ( | |||
| 10 | 10 | ) | |
| 11 | 11 | ||
| 12 | 12 | func DefaultHTTPErrorHandler(err error, c echo.Context) { | |
| 13 | - | renderer, err := utils.GetRenderer("500.gohtml", ui.PublicFS) | |
| 13 | + | renderer, err := utils.GetRenderer("500.gohtml", ui.PublicFS, utils.NewLogger()) | |
| 14 | 14 | if err != nil { | |
| 15 | 15 | c.String(http.StatusInternalServerError, fmt.Sprintf("%v", err)) | |
| 16 | 16 | } | |
| @@ -10,7 +10,7 @@ import ( | |||||
| 10 | ) | 10 | ) | ||
| 11 | 11 | ||||
| 12 | func DefaultHTTPErrorHandler(err error, c echo.Context) { | 12 | func DefaultHTTPErrorHandler(err error, c echo.Context) { | ||
| 13 | - | renderer, err := utils.GetRenderer("500.gohtml", ui.PublicFS) | 13 | + | renderer, err := utils.GetRenderer("500.gohtml", ui.PublicFS, utils.NewLogger()) |
| 14 | if err != nil { | 14 | if err != nil { | ||
| 15 | c.String(http.StatusInternalServerError, fmt.Sprintf("%v", err)) | 15 | c.String(http.StatusInternalServerError, fmt.Sprintf("%v", err)) | ||
| 16 | } | 16 | } | ||
R internal/http/handlers/404.go → internal/http/handlers/errors.go +22 -3 renamed, 54% similar
| @@ -9,10 +9,16 @@ import ( | |||
| 9 | 9 | "gogs.bnema.dev/gordon-echo/pkg/utils" | |
| 10 | 10 | ) | |
| 11 | 11 | ||
| 12 | - | func Custom404Handler(err error, c echo.Context) { | |
| 12 | + | type ErrorHandler struct { | |
| 13 | + | Err error | |
| 14 | + | C echo.Context | |
| 15 | + | ErrorNumber int | |
| 16 | + | } | |
| 17 | + | ||
| 18 | + | func Error404Handler(err error, c echo.Context) { | |
| 13 | 19 | if he, ok := err.(*echo.HTTPError); ok { | |
| 14 | 20 | if he.Code == http.StatusNotFound { | |
| 15 | - | renderer, err := utils.GetRenderer("404.gohtml", ui.PublicFS) | |
| 21 | + | renderer, err := utils.GetRenderer("404.gohtml", ui.PublicFS, utils.NewLogger()) | |
| 16 | 22 | if err != nil { | |
| 17 | 23 | c.String(http.StatusInternalServerError, fmt.Sprintf("%v", err)) | |
| 18 | 24 | } | |
| @@ -33,5 +39,18 @@ func Custom404Handler(err error, c echo.Context) { | |||
| 33 | 39 | } | |
| 34 | 40 | } | |
| 35 | 41 | ||
| 36 | - | DefaultHTTPErrorHandler(err, c) | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | func Error200Handler(err error, c echo.Context) { | |
| 45 | + | // Just print the error for now | |
| 46 | + | fmt.Println(err) | |
| 47 | + | } | |
| 48 | + | ||
| 49 | + | func Error403Handler(err error, c echo.Context) { | |
| 50 | + | // Just print the error for now | |
| 51 | + | fmt.Println(err) | |
| 52 | + | } | |
| 53 | + | ||
| 54 | + | func ErrorNumberHandler(err error, c echo.Context) { | |
| 55 | + | // For Each Error Code, we can have a different handler | |
| 37 | 56 | } | |
| @@ -9,10 +9,16 @@ import ( | |||||
| 9 | "gogs.bnema.dev/gordon-echo/pkg/utils" | 9 | "gogs.bnema.dev/gordon-echo/pkg/utils" | ||
| 10 | ) | 10 | ) | ||
| 11 | 11 | ||||
| 12 | - | func Custom404Handler(err error, c echo.Context) { | 12 | + | type ErrorHandler struct { |
| 13 | + | Err error | |||
| 14 | + | C echo.Context | |||
| 15 | + | ErrorNumber int | |||
| 16 | + | } | |||
| 17 | + | ||||
| 18 | + | func Error404Handler(err error, c echo.Context) { | |||
| 13 | if he, ok := err.(*echo.HTTPError); ok { | 19 | if he, ok := err.(*echo.HTTPError); ok { | ||
| 14 | if he.Code == http.StatusNotFound { | 20 | if he.Code == http.StatusNotFound { | ||
| 15 | - | renderer, err := utils.GetRenderer("404.gohtml", ui.PublicFS) | 21 | + | renderer, err := utils.GetRenderer("404.gohtml", ui.PublicFS, utils.NewLogger()) |
| 16 | if err != nil { | 22 | if err != nil { | ||
| 17 | c.String(http.StatusInternalServerError, fmt.Sprintf("%v", err)) | 23 | c.String(http.StatusInternalServerError, fmt.Sprintf("%v", err)) | ||
| 18 | } | 24 | } | ||
| @@ -33,5 +39,18 @@ func Custom404Handler(err error, c echo.Context) { | |||||
| 33 | } | 39 | } | ||
| 34 | } | 40 | } | ||
| 35 | 41 | ||||
| 36 | - | DefaultHTTPErrorHandler(err, c) | 42 | + | } |
| 43 | + | ||||
| 44 | + | func Error200Handler(err error, c echo.Context) { | |||
| 45 | + | // Just print the error for now | |||
| 46 | + | fmt.Println(err) | |||
| 47 | + | } | |||
| 48 | + | ||||
| 49 | + | func Error403Handler(err error, c echo.Context) { | |||
| 50 | + | // Just print the error for now | |||
| 51 | + | fmt.Println(err) | |||
| 52 | + | } | |||
| 53 | + | ||||
| 54 | + | func ErrorNumberHandler(err error, c echo.Context) { | |||
| 55 | + | // For Each Error Code, we can have a different handler | |||
| 37 | } | 56 | } | ||
M internal/http/handlers/htmx.go +9 -2
| @@ -1,6 +1,7 @@ | |||
| 1 | 1 | package handlers | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | + | "fmt" | |
| 4 | 5 | "net/http" | |
| 5 | 6 | ||
| 6 | 7 | "github.com/labstack/echo/v4" | |
| @@ -8,13 +9,18 @@ import ( | |||
| 8 | 9 | "gogs.bnema.dev/gordon-echo/pkg/utils" | |
| 9 | 10 | ) | |
| 10 | 11 | ||
| 12 | + | var logger = utils.NewLogger() | |
| 13 | + | ||
| 11 | 14 | func HTMXHandler(c echo.Context) error { | |
| 12 | 15 | // Detect and extract HTMX data from the request | |
| 13 | - | htmxRequest := htmx.GetRequest(c) | |
| 16 | + | htmxRequest, err := htmx.GetRequest(c) | |
| 17 | + | if err != nil { | |
| 18 | + | return logger.Debug().GetCtx().Err() | |
| 19 | + | } | |
| 14 | 20 | ||
| 15 | 21 | // If the request is not an HTMX request, return an error | |
| 16 | 22 | if !htmxRequest.Enabled { | |
| 17 | - | return c.String(http.StatusBadRequest, "Non-HTMX request") | |
| 23 | + | return logger.Error().GetCtx().Err() | |
| 18 | 24 | } | |
| 19 | 25 | ||
| 20 | 26 | // If it's a GET request, handle the fragment | |
| @@ -29,6 +35,7 @@ func HTMXHandler(c echo.Context) error { | |||
| 29 | 35 | ||
| 30 | 36 | func HTMXFragmentHandler(c echo.Context) error { | |
| 31 | 37 | fragment := c.Request().Header.Get("X-Fragment") | |
| 38 | + | fmt.Println(fragment) | |
| 32 | 39 | if fragment == "" { | |
| 33 | 40 | return c.String(http.StatusBadRequest, "Missing fragment header") | |
| 34 | 41 | } | |
| @@ -1,6 +1,7 @@ | |||||
| 1 | package handlers | 1 | package handlers | ||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | + | "fmt" | |||
| 4 | "net/http" | 5 | "net/http" | ||
| 5 | 6 | ||||
| 6 | "github.com/labstack/echo/v4" | 7 | "github.com/labstack/echo/v4" | ||
| @@ -8,13 +9,18 @@ import ( | |||||
| 8 | "gogs.bnema.dev/gordon-echo/pkg/utils" | 9 | "gogs.bnema.dev/gordon-echo/pkg/utils" | ||
| 9 | ) | 10 | ) | ||
| 10 | 11 | ||||
| 12 | + | var logger = utils.NewLogger() | |||
| 13 | + | ||||
| 11 | func HTMXHandler(c echo.Context) error { | 14 | func HTMXHandler(c echo.Context) error { | ||
| 12 | // Detect and extract HTMX data from the request | 15 | // Detect and extract HTMX data from the request | ||
| 13 | - | htmxRequest := htmx.GetRequest(c) | 16 | + | htmxRequest, err := htmx.GetRequest(c) |
| 17 | + | if err != nil { | |||
| 18 | + | return logger.Debug().GetCtx().Err() | |||
| 19 | + | } | |||
| 14 | 20 | ||||
| 15 | // If the request is not an HTMX request, return an error | 21 | // If the request is not an HTMX request, return an error | ||
| 16 | if !htmxRequest.Enabled { | 22 | if !htmxRequest.Enabled { | ||
| 17 | - | return c.String(http.StatusBadRequest, "Non-HTMX request") | 23 | + | return logger.Error().GetCtx().Err() |
| 18 | } | 24 | } | ||
| 19 | 25 | ||||
| 20 | // If it's a GET request, handle the fragment | 26 | // If it's a GET request, handle the fragment | ||
| @@ -29,6 +35,7 @@ func HTMXHandler(c echo.Context) error { | |||||
| 29 | 35 | ||||
| 30 | func HTMXFragmentHandler(c echo.Context) error { | 36 | func HTMXFragmentHandler(c echo.Context) error { | ||
| 31 | fragment := c.Request().Header.Get("X-Fragment") | 37 | fragment := c.Request().Header.Get("X-Fragment") | ||
| 38 | + | fmt.Println(fragment) | |||
| 32 | if fragment == "" { | 39 | if fragment == "" { | ||
| 33 | return c.String(http.StatusBadRequest, "Missing fragment header") | 40 | return c.String(http.StatusBadRequest, "Missing fragment header") | ||
| 34 | } | 41 | } | ||
M internal/http/routes/admin_routes.go +19 -6
| @@ -3,20 +3,31 @@ package routes | |||
| 3 | 3 | import ( | |
| 4 | 4 | "fmt" | |
| 5 | 5 | "net/http" | |
| 6 | + | "strings" | |
| 6 | 7 | ||
| 7 | 8 | "github.com/labstack/echo/v4" | |
| 8 | 9 | "gogs.bnema.dev/gordon-echo/internal/ui" | |
| 9 | 10 | "gogs.bnema.dev/gordon-echo/pkg/utils" | |
| 10 | 11 | ) | |
| 11 | 12 | ||
| 13 | + | func getPreferredLanguage(c echo.Context) string { | |
| 14 | + | header := c.Request().Header.Get("Accept-Language") | |
| 15 | + | // Check the header value, parse it and determine the primary language. | |
| 16 | + | // For this example, let's assume English and French only. | |
| 17 | + | if strings.Contains(header, "fr") { | |
| 18 | + | return "fr" | |
| 19 | + | } | |
| 20 | + | return "en" // Default to English | |
| 21 | + | } | |
| 22 | + | ||
| 12 | 23 | func AdminRoute(c echo.Context) error { | |
| 13 | - | staticData, err := utils.LoadDataFromYAML() | |
| 14 | - | fmt.Println(staticData) | |
| 24 | + | staticData, err := utils.ReadDataFromYAML() | |
| 15 | 25 | if err != nil { | |
| 16 | 26 | return err | |
| 17 | 27 | } | |
| 18 | 28 | ||
| 19 | - | lang := c.Param("lang") | |
| 29 | + | lang := getPreferredLanguage(c) | |
| 30 | + | fmt.Println(lang) | |
| 20 | 31 | ||
| 21 | 32 | switch lang { | |
| 22 | 33 | case "fr": | |
| @@ -25,14 +36,16 @@ func AdminRoute(c echo.Context) error { | |||
| 25 | 36 | staticData.CurrentLang = staticData.EN | |
| 26 | 37 | } | |
| 27 | 38 | ||
| 28 | - | renderer, err := utils.GetRenderer("index.gohtml", ui.PublicFS) | |
| 39 | + | renderer, err := utils.GetRenderer("index.gohtml", ui.PublicFS, utils.NewLogger()) | |
| 29 | 40 | if err != nil { | |
| 30 | 41 | return err | |
| 31 | 42 | } | |
| 32 | 43 | ||
| 33 | - | html, err := renderer.Render(staticData) | |
| 44 | + | html, err := renderer.Render(staticData.CurrentLang) | |
| 34 | 45 | if err != nil { | |
| 35 | - | return c.String(http.StatusInternalServerError, fmt.Sprintf("%v", err)) | |
| 46 | + | // Return the error into NewLogger() to log it | |
| 47 | + | utils.NewLogger().Error() | |
| 48 | + | return err | |
| 36 | 49 | } | |
| 37 | 50 | ||
| 38 | 51 | return c.HTML(http.StatusOK, html) | |
| @@ -3,20 +3,31 @@ package routes | |||||
| 3 | import ( | 3 | import ( | ||
| 4 | "fmt" | 4 | "fmt" | ||
| 5 | "net/http" | 5 | "net/http" | ||
| 6 | + | "strings" | |||
| 6 | 7 | ||||
| 7 | "github.com/labstack/echo/v4" | 8 | "github.com/labstack/echo/v4" | ||
| 8 | "gogs.bnema.dev/gordon-echo/internal/ui" | 9 | "gogs.bnema.dev/gordon-echo/internal/ui" | ||
| 9 | "gogs.bnema.dev/gordon-echo/pkg/utils" | 10 | "gogs.bnema.dev/gordon-echo/pkg/utils" | ||
| 10 | ) | 11 | ) | ||
| 11 | 12 | ||||
| 13 | + | func getPreferredLanguage(c echo.Context) string { | |||
| 14 | + | header := c.Request().Header.Get("Accept-Language") | |||
| 15 | + | // Check the header value, parse it and determine the primary language. | |||
| 16 | + | // For this example, let's assume English and French only. | |||
| 17 | + | if strings.Contains(header, "fr") { | |||
| 18 | + | return "fr" | |||
| 19 | + | } | |||
| 20 | + | return "en" // Default to English | |||
| 21 | + | } | |||
| 22 | + | ||||
| 12 | func AdminRoute(c echo.Context) error { | 23 | func AdminRoute(c echo.Context) error { | ||
| 13 | - | staticData, err := utils.LoadDataFromYAML() | 24 | + | staticData, err := utils.ReadDataFromYAML() |
| 14 | - | fmt.Println(staticData) | |||
| 15 | if err != nil { | 25 | if err != nil { | ||
| 16 | return err | 26 | return err | ||
| 17 | } | 27 | } | ||
| 18 | 28 | ||||
| 19 | - | lang := c.Param("lang") | 29 | + | lang := getPreferredLanguage(c) |
| 30 | + | fmt.Println(lang) | |||
| 20 | 31 | ||||
| 21 | switch lang { | 32 | switch lang { | ||
| 22 | case "fr": | 33 | case "fr": | ||
| @@ -25,14 +36,16 @@ func AdminRoute(c echo.Context) error { | |||||
| 25 | staticData.CurrentLang = staticData.EN | 36 | staticData.CurrentLang = staticData.EN | ||
| 26 | } | 37 | } | ||
| 27 | 38 | ||||
| 28 | - | renderer, err := utils.GetRenderer("index.gohtml", ui.PublicFS) | 39 | + | renderer, err := utils.GetRenderer("index.gohtml", ui.PublicFS, utils.NewLogger()) |
| 29 | if err != nil { | 40 | if err != nil { | ||
| 30 | return err | 41 | return err | ||
| 31 | } | 42 | } | ||
| 32 | 43 | ||||
| 33 | - | html, err := renderer.Render(staticData) | 44 | + | html, err := renderer.Render(staticData.CurrentLang) |
| 34 | if err != nil { | 45 | if err != nil { | ||
| 35 | - | return c.String(http.StatusInternalServerError, fmt.Sprintf("%v", err)) | 46 | + | // Return the error into NewLogger() to log it |
| 47 | + | utils.NewLogger().Error() | |||
| 48 | + | return err | |||
| 36 | } | 49 | } | ||
| 37 | 50 | ||||
| 38 | return c.HTML(http.StatusOK, html) | 51 | return c.HTML(http.StatusOK, html) | ||
M internal/http/routes/router.go +2 -3
| @@ -20,10 +20,9 @@ func NewRouter(appLogger, echoLogger zerolog.Logger) *echo.Echo { | |||
| 20 | 20 | } | |
| 21 | 21 | ||
| 22 | 22 | func bindStaticAdminUI(e *echo.Echo) *echo.Echo { | |
| 23 | - | e.GET("/admin/:lang", AdminRoute) | |
| 23 | + | e.GET("/admin", AdminRoute) | |
| 24 | 24 | e.GET("/htmx", handlers.HTMXHandler) | |
| 25 | 25 | e.GET("/*", StaticRoute) | |
| 26 | - | e.HTTPErrorHandler = handlers.Custom404Handler | |
| 27 | - | e.HTTPErrorHandler = handlers.DefaultHTTPErrorHandler | |
| 26 | + | e.HTTPErrorHandler = handlers.ErrorNumberHandler | |
| 28 | 27 | return e | |
| 29 | 28 | } | |
| @@ -20,10 +20,9 @@ func NewRouter(appLogger, echoLogger zerolog.Logger) *echo.Echo { | |||||
| 20 | } | 20 | } | ||
| 21 | 21 | ||||
| 22 | func bindStaticAdminUI(e *echo.Echo) *echo.Echo { | 22 | func bindStaticAdminUI(e *echo.Echo) *echo.Echo { | ||
| 23 | - | e.GET("/admin/:lang", AdminRoute) | 23 | + | e.GET("/admin", AdminRoute) |
| 24 | e.GET("/htmx", handlers.HTMXHandler) | 24 | e.GET("/htmx", handlers.HTMXHandler) | ||
| 25 | e.GET("/*", StaticRoute) | 25 | e.GET("/*", StaticRoute) | ||
| 26 | - | e.HTTPErrorHandler = handlers.Custom404Handler | 26 | + | e.HTTPErrorHandler = handlers.ErrorNumberHandler |
| 27 | - | e.HTTPErrorHandler = handlers.DefaultHTTPErrorHandler | |||
| 28 | return e | 27 | return e | ||
| 29 | } | 28 | } | ||
M internal/ui/public/500.gohtml +1 -1
| @@ -7,6 +7,6 @@ | |||
| 7 | 7 | </head> | |
| 8 | 8 | <body> | |
| 9 | 9 | <h1>500 Internal Server Error</h1> | |
| 10 | - | <p>Something went wrong</p> | |
| 10 | + | <p>Something went really wrong o/</p> | |
| 11 | 11 | </body> | |
| 12 | 12 | </html> | |
| @@ -7,6 +7,6 @@ | |||||
| 7 | </head> | 7 | </head> | ||
| 8 | <body> | 8 | <body> | ||
| 9 | <h1>500 Internal Server Error</h1> | 9 | <h1>500 Internal Server Error</h1> | ||
| 10 | - | <p>Something went wrong</p> | 10 | + | <p>Something went really wrong o/</p> |
| 11 | </body> | 11 | </body> | ||
| 12 | </html> | 12 | </html> | ||
M internal/ui/public/index.gohtml +1 -1
| @@ -3,7 +3,7 @@ | |||
| 3 | 3 | <head> | |
| 4 | 4 | <meta charset="UTF-8" /> | |
| 5 | 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| 6 | - | <title>{{.website.title}}</title> | |
| 6 | + | <title>{{ .Header.Meta.Title }}</title> | |
| 7 | 7 | <!-- Custom CSS from assets/css --> | |
| 8 | 8 | <link rel="stylesheet" href="assets/css/custom.css" /> | |
| 9 | 9 | <!-- Alpine --> | |
| @@ -3,7 +3,7 @@ | |||||
| 3 | <head> | 3 | <head> | ||
| 4 | <meta charset="UTF-8" /> | 4 | <meta charset="UTF-8" /> | ||
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| 6 | - | <title>{{.website.title}}</title> | 6 | + | <title>{{ .Header.Meta.Title }}</title> |
| 7 | <!-- Custom CSS from assets/css --> | 7 | <!-- Custom CSS from assets/css --> | ||
| 8 | <link rel="stylesheet" href="assets/css/custom.css" /> | 8 | <link rel="stylesheet" href="assets/css/custom.css" /> | ||
| 9 | <!-- Alpine --> | 9 | <!-- Alpine --> | ||
M internal/ui/templates/components.gohtml +14 -5
| @@ -1,6 +1,15 @@ | |||
| 1 | + | <div id="header"> | |
| 2 | + | <h1 | |
| 3 | + | class="text-5xl fw100 animate-bounce-alt animate-count-infinite animate-duration-1s" | |
| 4 | + | > | |
| 5 | + | {{ .Body.Header.HelloWorld }} | |
| 6 | + | </h1> | |
| 7 | + | </div> | |
| 1 | 8 | ||
| 2 | - | ||
| 3 | - | ||
| 4 | - | <div id ="hello"> | |
| 5 | - | <h1 class="text-5xl fw100 animate-bounce-alt animate-count-infinite animate-duration-1s">Hello World from components.html</h1> | |
| 6 | - | </div>⏎̸ | |
| 9 | + | <div id="hello"> | |
| 10 | + | <h1 | |
| 11 | + | class="text-5xl fw100 animate-bounce-alt animate-count-infinite animate-duration-1s" | |
| 12 | + | > | |
| 13 | + | {{ .Body.Div.Hello }} | |
| 14 | + | </h1> | |
| 15 | + | </div> | |
| @@ -1,6 +1,15 @@ | |||||
| 1 | + | <div id="header"> | |||
| 2 | + | <h1 | |||
| 3 | + | class="text-5xl fw100 animate-bounce-alt animate-count-infinite animate-duration-1s" | |||
| 4 | + | > | |||
| 5 | + | {{ .Body.Header.HelloWorld }} | |||
| 6 | + | </h1> | |||
| 7 | + | </div> | |||
| 1 | 8 | ||||
| 2 | - | 9 | + | <div id="hello"> | |
| 3 | - | 10 | + | <h1 | |
| 4 | - | <div id ="hello"> | 11 | + | class="text-5xl fw100 animate-bounce-alt animate-count-infinite animate-duration-1s" |
| 5 | - | <h1 class="text-5xl fw100 animate-bounce-alt animate-count-infinite animate-duration-1s">Hello World from components.html</h1> | 12 | + | > |
| 6 | - | </div>⏎̸ | 13 | + | {{ .Body.Div.Hello }} |
| 14 | + | </h1> | |||
| 15 | + | </div> | |||
M internal/ui/templates/strings.yaml +20 -6
| @@ -1,9 +1,23 @@ | |||
| 1 | 1 | en: | |
| 2 | - | website: | |
| 3 | - | title: Admin Dashboard | |
| 4 | - | user: John Doe | |
| 2 | + | header: | |
| 3 | + | meta: | |
| 4 | + | title: Gordon - Admin Dashboard | |
| 5 | + | description: Admin dashboard for Gordon | |
| 6 | + | keywords: gordon, admin, dashboard | |
| 7 | + | body: | |
| 8 | + | header: | |
| 9 | + | helloworld: Hello World! | |
| 10 | + | div: | |
| 11 | + | hello: Hello component loaded from a template! | |
| 5 | 12 | ||
| 6 | 13 | fr: | |
| 7 | - | website: | |
| 8 | - | title: Tableau de bord administrateur | |
| 9 | - | user: Jean Dupont⏎̸ | |
| 14 | + | header: | |
| 15 | + | meta: | |
| 16 | + | title: Gordon - Tableau de bord administrateur | |
| 17 | + | description: Tableau de bord administrateur pour Gordon | |
| 18 | + | keywords: gordon, admin, dashboard | |
| 19 | + | body: | |
| 20 | + | header: | |
| 21 | + | helloworld: Bonjour le monde! | |
| 22 | + | div: | |
| 23 | + | hello: Composant de salut chargé à partir d'un modèle! | |
| @@ -1,9 +1,23 @@ | |||||
| 1 | en: | 1 | en: | ||
| 2 | - | website: | 2 | + | header: |
| 3 | - | title: Admin Dashboard | 3 | + | meta: |
| 4 | - | user: John Doe | 4 | + | title: Gordon - Admin Dashboard |
| 5 | + | description: Admin dashboard for Gordon | |||
| 6 | + | keywords: gordon, admin, dashboard | |||
| 7 | + | body: | |||
| 8 | + | header: | |||
| 9 | + | helloworld: Hello World! | |||
| 10 | + | div: | |||
| 11 | + | hello: Hello component loaded from a template! | |||
| 5 | 12 | ||||
| 6 | fr: | 13 | fr: | ||
| 7 | - | website: | 14 | + | header: |
| 8 | - | title: Tableau de bord administrateur | 15 | + | meta: |
| 9 | - | user: Jean Dupont⏎̸ | 16 | + | title: Gordon - Tableau de bord administrateur |
| 17 | + | description: Tableau de bord administrateur pour Gordon | |||
| 18 | + | keywords: gordon, admin, dashboard | |||
| 19 | + | body: | |||
| 20 | + | header: | |||
| 21 | + | helloworld: Bonjour le monde! | |||
| 22 | + | div: | |||
| 23 | + | hello: Composant de salut chargé à partir d'un modèle! | |||
M pkg/htmx/htmx.go +7 -3
| @@ -47,8 +47,8 @@ type ( | |||
| 47 | 47 | ) | |
| 48 | 48 | ||
| 49 | 49 | // GetRequest extracts HTMX data from the request | |
| 50 | - | func GetRequest(ctx echo.Context) Request { | |
| 51 | - | return Request{ | |
| 50 | + | func GetRequest(ctx echo.Context) (Request, error) { | |
| 51 | + | request := Request{ | |
| 52 | 52 | Enabled: ctx.Request().Header.Get(HeaderRequest) == "true", | |
| 53 | 53 | Boosted: ctx.Request().Header.Get(HeaderBoosted) == "true", | |
| 54 | 54 | Trigger: ctx.Request().Header.Get(HeaderTrigger), | |
| @@ -56,10 +56,12 @@ func GetRequest(ctx echo.Context) Request { | |||
| 56 | 56 | Target: ctx.Request().Header.Get(HeaderTarget), | |
| 57 | 57 | Prompt: ctx.Request().Header.Get(HeaderPrompt), | |
| 58 | 58 | } | |
| 59 | + | ||
| 60 | + | return request, nil | |
| 59 | 61 | } | |
| 60 | 62 | ||
| 61 | 63 | // Apply applies data from a Response to a server response | |
| 62 | - | func (r Response) Apply(ctx echo.Context) { | |
| 64 | + | func (r Response) Apply(ctx echo.Context) error { | |
| 63 | 65 | if r.Push != "" { | |
| 64 | 66 | ctx.Response().Header().Set(HeaderPush, r.Push) | |
| 65 | 67 | } | |
| @@ -81,4 +83,6 @@ func (r Response) Apply(ctx echo.Context) { | |||
| 81 | 83 | if r.NoContent { | |
| 82 | 84 | ctx.Response().Status = http.StatusNoContent | |
| 83 | 85 | } | |
| 86 | + | ||
| 87 | + | return nil | |
| 84 | 88 | } | |
| @@ -47,8 +47,8 @@ type ( | |||||
| 47 | ) | 47 | ) | ||
| 48 | 48 | ||||
| 49 | // GetRequest extracts HTMX data from the request | 49 | // GetRequest extracts HTMX data from the request | ||
| 50 | - | func GetRequest(ctx echo.Context) Request { | 50 | + | func GetRequest(ctx echo.Context) (Request, error) { |
| 51 | - | return Request{ | 51 | + | request := Request{ |
| 52 | Enabled: ctx.Request().Header.Get(HeaderRequest) == "true", | 52 | Enabled: ctx.Request().Header.Get(HeaderRequest) == "true", | ||
| 53 | Boosted: ctx.Request().Header.Get(HeaderBoosted) == "true", | 53 | Boosted: ctx.Request().Header.Get(HeaderBoosted) == "true", | ||
| 54 | Trigger: ctx.Request().Header.Get(HeaderTrigger), | 54 | Trigger: ctx.Request().Header.Get(HeaderTrigger), | ||
| @@ -56,10 +56,12 @@ func GetRequest(ctx echo.Context) Request { | |||||
| 56 | Target: ctx.Request().Header.Get(HeaderTarget), | 56 | Target: ctx.Request().Header.Get(HeaderTarget), | ||
| 57 | Prompt: ctx.Request().Header.Get(HeaderPrompt), | 57 | Prompt: ctx.Request().Header.Get(HeaderPrompt), | ||
| 58 | } | 58 | } | ||
| 59 | + | ||||
| 60 | + | return request, nil | |||
| 59 | } | 61 | } | ||
| 60 | 62 | ||||
| 61 | // Apply applies data from a Response to a server response | 63 | // Apply applies data from a Response to a server response | ||
| 62 | - | func (r Response) Apply(ctx echo.Context) { | 64 | + | func (r Response) Apply(ctx echo.Context) error { |
| 63 | if r.Push != "" { | 65 | if r.Push != "" { | ||
| 64 | ctx.Response().Header().Set(HeaderPush, r.Push) | 66 | ctx.Response().Header().Set(HeaderPush, r.Push) | ||
| 65 | } | 67 | } | ||
| @@ -81,4 +83,6 @@ func (r Response) Apply(ctx echo.Context) { | |||||
| 81 | if r.NoContent { | 83 | if r.NoContent { | ||
| 82 | ctx.Response().Status = http.StatusNoContent | 84 | ctx.Response().Status = http.StatusNoContent | ||
| 83 | } | 85 | } | ||
| 86 | + | ||||
| 87 | + | return nil | |||
| 84 | } | 88 | } | ||
M pkg/utils/parser.go +31 -15
| @@ -8,28 +8,42 @@ import ( | |||
| 8 | 8 | "gopkg.in/yaml.v3" | |
| 9 | 9 | ) | |
| 10 | 10 | ||
| 11 | - | type Data struct { | |
| 12 | - | EN StaticData `yaml:"en"` | |
| 13 | - | FR StaticData `yaml:"fr"` | |
| 14 | - | CurrentLang StaticData `yaml:"-"` | |
| 15 | - | Website struct { | |
| 16 | - | Title string `yaml:"title"` | |
| 17 | - | User string `yaml:"user"` | |
| 18 | - | } `yaml:"website"` | |
| 11 | + | // Yaml Parser | |
| 12 | + | type Meta struct { | |
| 13 | + | Title string `yaml:"title"` | |
| 14 | + | Description string `yaml:"description"` | |
| 15 | + | Keywords string `yaml:"keywords"` | |
| 19 | 16 | } | |
| 20 | 17 | ||
| 21 | - | type StaticData struct { | |
| 22 | - | Title string `yaml:"title"` | |
| 23 | - | User string `yaml:"user"` | |
| 18 | + | type Header struct { | |
| 19 | + | Meta Meta `yaml:"meta"` | |
| 20 | + | HelloWorld string `yaml:"helloworld"` | |
| 24 | 21 | } | |
| 25 | 22 | ||
| 26 | - | // LoadDataFromYAML loads the data from the given YAML file | |
| 27 | - | func LoadDataFromYAML() (Data, error) { | |
| 28 | - | var data Data | |
| 23 | + | type Body struct { | |
| 24 | + | Header Header `yaml:"header"` | |
| 25 | + | Div struct { | |
| 26 | + | Hello string `yaml:"hello"` | |
| 27 | + | } `yaml:"div"` | |
| 28 | + | } | |
| 29 | + | ||
| 30 | + | type LangData struct { | |
| 31 | + | Header Header `yaml:"header"` | |
| 32 | + | Body Body `yaml:"body"` | |
| 33 | + | } | |
| 34 | + | ||
| 35 | + | type YamlData struct { | |
| 36 | + | EN LangData `yaml:"en"` | |
| 37 | + | FR LangData `yaml:"fr"` | |
| 38 | + | CurrentLang LangData | |
| 39 | + | } | |
| 40 | + | ||
| 41 | + | // ReadDataFromYAML loads the data from the given YAML file | |
| 42 | + | func ReadDataFromYAML() (YamlData, error) { | |
| 43 | + | var data YamlData | |
| 29 | 44 | ||
| 30 | 45 | // Open the YAML file inside the ui/components directory | |
| 31 | 46 | file, err := ui.TemplateFS.Open("strings.yaml") | |
| 32 | - | fmt.Println(file) | |
| 33 | 47 | if err != nil { | |
| 34 | 48 | return data, fmt.Errorf("failed to open strings.yaml: %w", err) | |
| 35 | 49 | } | |
| @@ -48,3 +62,5 @@ func LoadDataFromYAML() (Data, error) { | |||
| 48 | 62 | ||
| 49 | 63 | return data, nil | |
| 50 | 64 | } | |
| 65 | + | ||
| 66 | + | // Json Parser | |
| @@ -8,28 +8,42 @@ import ( | |||||
| 8 | "gopkg.in/yaml.v3" | 8 | "gopkg.in/yaml.v3" | ||
| 9 | ) | 9 | ) | ||
| 10 | 10 | ||||
| 11 | - | type Data struct { | 11 | + | // Yaml Parser |
| 12 | - | EN StaticData `yaml:"en"` | 12 | + | type Meta struct { |
| 13 | - | FR StaticData `yaml:"fr"` | 13 | + | Title string `yaml:"title"` |
| 14 | - | CurrentLang StaticData `yaml:"-"` | 14 | + | Description string `yaml:"description"` |
| 15 | - | Website struct { | 15 | + | Keywords string `yaml:"keywords"` |
| 16 | - | Title string `yaml:"title"` | |||
| 17 | - | User string `yaml:"user"` | |||
| 18 | - | } `yaml:"website"` | |||
| 19 | } | 16 | } | ||
| 20 | 17 | ||||
| 21 | - | type StaticData struct { | 18 | + | type Header struct { |
| 22 | - | Title string `yaml:"title"` | 19 | + | Meta Meta `yaml:"meta"` |
| 23 | - | User string `yaml:"user"` | 20 | + | HelloWorld string `yaml:"helloworld"` |
| 24 | } | 21 | } | ||
| 25 | 22 | ||||
| 26 | - | // LoadDataFromYAML loads the data from the given YAML file | 23 | + | type Body struct { |
| 27 | - | func LoadDataFromYAML() (Data, error) { | 24 | + | Header Header `yaml:"header"` |
| 28 | - | var data Data | 25 | + | Div struct { |
| 26 | + | Hello string `yaml:"hello"` | |||
| 27 | + | } `yaml:"div"` | |||
| 28 | + | } | |||
| 29 | + | ||||
| 30 | + | type LangData struct { | |||
| 31 | + | Header Header `yaml:"header"` | |||
| 32 | + | Body Body `yaml:"body"` | |||
| 33 | + | } | |||
| 34 | + | ||||
| 35 | + | type YamlData struct { | |||
| 36 | + | EN LangData `yaml:"en"` | |||
| 37 | + | FR LangData `yaml:"fr"` | |||
| 38 | + | CurrentLang LangData | |||
| 39 | + | } | |||
| 40 | + | ||||
| 41 | + | // ReadDataFromYAML loads the data from the given YAML file | |||
| 42 | + | func ReadDataFromYAML() (YamlData, error) { | |||
| 43 | + | var data YamlData | |||
| 29 | 44 | ||||
| 30 | // Open the YAML file inside the ui/components directory | 45 | // Open the YAML file inside the ui/components directory | ||
| 31 | file, err := ui.TemplateFS.Open("strings.yaml") | 46 | file, err := ui.TemplateFS.Open("strings.yaml") | ||
| 32 | - | fmt.Println(file) | |||
| 33 | if err != nil { | 47 | if err != nil { | ||
| 34 | return data, fmt.Errorf("failed to open strings.yaml: %w", err) | 48 | return data, fmt.Errorf("failed to open strings.yaml: %w", err) | ||
| 35 | } | 49 | } | ||
| @@ -48,3 +62,5 @@ func LoadDataFromYAML() (Data, error) { | |||||
| 48 | 62 | ||||
| 49 | return data, nil | 63 | return data, nil | ||
| 50 | } | 64 | } | ||
| 65 | + | ||||
| 66 | + | // Json Parser | |||
M pkg/utils/render.go +11 -2
| @@ -10,21 +10,28 @@ import ( | |||
| 10 | 10 | type Renderer struct { | |
| 11 | 11 | Template *template.Template | |
| 12 | 12 | ParseError error | |
| 13 | + | Logger *Logger | |
| 13 | 14 | } | |
| 14 | 15 | ||
| 15 | 16 | // Render function renders the template with the given data | |
| 16 | 17 | func (r *Renderer) Render(data interface{}) (string, error) { | |
| 17 | 18 | if r.ParseError != nil { | |
| 19 | + | r.Logger.Error().Err(r.ParseError).Msg("Parse error") | |
| 20 | + | ||
| 18 | 21 | return "", r.ParseError | |
| 19 | 22 | } | |
| 20 | 23 | ||
| 21 | 24 | if r.Template == nil { | |
| 22 | - | return "", errors.New("invalid or nil template") | |
| 25 | + | err := errors.New("invalid or nil template") | |
| 26 | + | r.Logger.Error().Err(r.ParseError).Msg("Parse error") | |
| 27 | + | ||
| 28 | + | return "", err | |
| 23 | 29 | } | |
| 24 | 30 | ||
| 25 | 31 | buf := new(bytes.Buffer) | |
| 26 | 32 | err := r.Template.Execute(buf, data) | |
| 27 | 33 | if err != nil { | |
| 34 | + | r.Logger.Error().Err(err).Msg("Render error") | |
| 28 | 35 | return "", err | |
| 29 | 36 | } | |
| 30 | 37 | ||
| @@ -32,12 +39,14 @@ func (r *Renderer) Render(data interface{}) (string, error) { | |||
| 32 | 39 | } | |
| 33 | 40 | ||
| 34 | 41 | // GetRenderer function returns a new Renderer instance | |
| 35 | - | func GetRenderer(filename string, fs fs.FS) (*Renderer, error) { | |
| 42 | + | func GetRenderer(filename string, fs fs.FS, logger *Logger) (*Renderer, error) { | |
| 36 | 43 | tmpl, err := template.New(filename).ParseFS(fs, filename) | |
| 37 | 44 | if err != nil { | |
| 45 | + | logger.Error().Err(err).Msg("Failed to parse template") | |
| 38 | 46 | return nil, err | |
| 39 | 47 | } | |
| 40 | 48 | return &Renderer{ | |
| 41 | 49 | Template: tmpl, | |
| 50 | + | Logger: logger, | |
| 42 | 51 | }, nil | |
| 43 | 52 | } | |
| @@ -10,21 +10,28 @@ import ( | |||||
| 10 | type Renderer struct { | 10 | type Renderer struct { | ||
| 11 | Template *template.Template | 11 | Template *template.Template | ||
| 12 | ParseError error | 12 | ParseError error | ||
| 13 | + | Logger *Logger | |||
| 13 | } | 14 | } | ||
| 14 | 15 | ||||
| 15 | // Render function renders the template with the given data | 16 | // Render function renders the template with the given data | ||
| 16 | func (r *Renderer) Render(data interface{}) (string, error) { | 17 | func (r *Renderer) Render(data interface{}) (string, error) { | ||
| 17 | if r.ParseError != nil { | 18 | if r.ParseError != nil { | ||
| 19 | + | r.Logger.Error().Err(r.ParseError).Msg("Parse error") | |||
| 20 | + | ||||
| 18 | return "", r.ParseError | 21 | return "", r.ParseError | ||
| 19 | } | 22 | } | ||
| 20 | 23 | ||||
| 21 | if r.Template == nil { | 24 | if r.Template == nil { | ||
| 22 | - | return "", errors.New("invalid or nil template") | 25 | + | err := errors.New("invalid or nil template") |
| 26 | + | r.Logger.Error().Err(r.ParseError).Msg("Parse error") | |||
| 27 | + | ||||
| 28 | + | return "", err | |||
| 23 | } | 29 | } | ||
| 24 | 30 | ||||
| 25 | buf := new(bytes.Buffer) | 31 | buf := new(bytes.Buffer) | ||
| 26 | err := r.Template.Execute(buf, data) | 32 | err := r.Template.Execute(buf, data) | ||
| 27 | if err != nil { | 33 | if err != nil { | ||
| 34 | + | r.Logger.Error().Err(err).Msg("Render error") | |||
| 28 | return "", err | 35 | return "", err | ||
| 29 | } | 36 | } | ||
| 30 | 37 | ||||
| @@ -32,12 +39,14 @@ func (r *Renderer) Render(data interface{}) (string, error) { | |||||
| 32 | } | 39 | } | ||
| 33 | 40 | ||||
| 34 | // GetRenderer function returns a new Renderer instance | 41 | // GetRenderer function returns a new Renderer instance | ||
| 35 | - | func GetRenderer(filename string, fs fs.FS) (*Renderer, error) { | 42 | + | func GetRenderer(filename string, fs fs.FS, logger *Logger) (*Renderer, error) { |
| 36 | tmpl, err := template.New(filename).ParseFS(fs, filename) | 43 | tmpl, err := template.New(filename).ParseFS(fs, filename) | ||
| 37 | if err != nil { | 44 | if err != nil { | ||
| 45 | + | logger.Error().Err(err).Msg("Failed to parse template") | |||
| 38 | return nil, err | 46 | return nil, err | ||
| 39 | } | 47 | } | ||
| 40 | return &Renderer{ | 48 | return &Renderer{ | ||
| 41 | Template: tmpl, | 49 | Template: tmpl, | ||
| 50 | + | Logger: logger, | |||
| 42 | }, nil | 51 | }, nil | ||
| 43 | } | 52 | } | ||