mirror of
https://github.com/karust/openserp.git
synced 2026-08-05 16:53:54 +08:00
145 lines
3.1 KiB
Go
145 lines
3.1 KiB
Go
package core
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type JSONErrorResponse struct {
|
|
Error string `json:"error"`
|
|
Code int `json:"code"`
|
|
Message string `json:"message,omitempty"`
|
|
}
|
|
|
|
type CORSConfig struct {
|
|
AllowOrigins string
|
|
AllowMethods string
|
|
AllowHeaders string
|
|
MaxAge int
|
|
}
|
|
|
|
func DefaultCORSConfig() CORSConfig {
|
|
return CORSConfig{
|
|
AllowOrigins: "*",
|
|
AllowMethods: "GET, POST, OPTIONS",
|
|
AllowHeaders: "Origin, Content-Type, Accept, Authorization, X-Use-Proxy",
|
|
MaxAge: 86400,
|
|
}
|
|
}
|
|
|
|
func CORSMiddleware(cfg CORSConfig) fiber.Handler {
|
|
cfg = normalizeCORSConfig(cfg)
|
|
|
|
return func(c *fiber.Ctx) error {
|
|
c.Set("Access-Control-Allow-Origin", cfg.AllowOrigins)
|
|
c.Set("Access-Control-Allow-Methods", cfg.AllowMethods)
|
|
c.Set("Access-Control-Allow-Headers", cfg.AllowHeaders)
|
|
c.Set("Access-Control-Max-Age", fmt.Sprintf("%d", cfg.MaxAge))
|
|
|
|
if c.Method() == "OPTIONS" {
|
|
return c.SendStatus(fiber.StatusNoContent)
|
|
}
|
|
return c.Next()
|
|
}
|
|
}
|
|
|
|
// normalizeCORSConfig keeps CORS behavior predictable when config provides partial values.
|
|
func normalizeCORSConfig(cfg CORSConfig) CORSConfig {
|
|
defaults := DefaultCORSConfig()
|
|
|
|
if strings.TrimSpace(cfg.AllowOrigins) == "" {
|
|
cfg.AllowOrigins = defaults.AllowOrigins
|
|
}
|
|
if strings.TrimSpace(cfg.AllowMethods) == "" {
|
|
cfg.AllowMethods = defaults.AllowMethods
|
|
}
|
|
if strings.TrimSpace(cfg.AllowHeaders) == "" {
|
|
cfg.AllowHeaders = defaults.AllowHeaders
|
|
}
|
|
if cfg.MaxAge <= 0 {
|
|
cfg.MaxAge = defaults.MaxAge
|
|
}
|
|
|
|
return cfg
|
|
}
|
|
|
|
func RequestLoggerMiddleware() fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
start := time.Now()
|
|
err := c.Next()
|
|
|
|
latency := time.Since(start)
|
|
status := c.Response().StatusCode()
|
|
if err != nil {
|
|
if e, ok := err.(*fiber.Error); ok {
|
|
status = e.Code
|
|
} else {
|
|
status = fiber.StatusInternalServerError
|
|
}
|
|
}
|
|
|
|
logFields := logrus.Fields{
|
|
"method": c.Method(),
|
|
"path": c.Path(),
|
|
"status": status,
|
|
"latency": latency.String(),
|
|
"ip": c.IP(),
|
|
}
|
|
if query := c.Query("text"); query != "" {
|
|
logFields["query"] = query
|
|
}
|
|
|
|
entry := logrus.WithFields(logFields)
|
|
if status >= 500 {
|
|
entry.Errorf("%s - request failed", c.Path())
|
|
} else if status >= 400 {
|
|
entry.Warnf("%s - request error", c.Path())
|
|
} else {
|
|
entry.Infof("%s - request completed", c.Path())
|
|
}
|
|
|
|
return err
|
|
}
|
|
}
|
|
|
|
func JSONErrorMiddleware() fiber.ErrorHandler {
|
|
return func(c *fiber.Ctx, err error) error {
|
|
code := fiber.StatusInternalServerError
|
|
if e, ok := err.(*fiber.Error); ok {
|
|
code = e.Code
|
|
}
|
|
|
|
resp := JSONErrorResponse{
|
|
Error: statusText(code),
|
|
Code: code,
|
|
Message: err.Error(),
|
|
}
|
|
|
|
c.Set("Content-Type", "application/json")
|
|
return c.Status(code).JSON(resp)
|
|
}
|
|
}
|
|
|
|
func statusText(code int) string {
|
|
switch {
|
|
case code == 400:
|
|
return "bad_request"
|
|
case code == 404:
|
|
return "not_found"
|
|
case code == 429:
|
|
return "rate_limited"
|
|
case code == 503:
|
|
return "service_unavailable"
|
|
case code >= 400 && code < 500:
|
|
return "client_error"
|
|
case code >= 500:
|
|
return "server_error"
|
|
default:
|
|
return "error"
|
|
}
|
|
}
|