package web import ( "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/fiber/v2/middleware/recover" "github.com/gofiber/fiber/v2/middleware/requestid" "github.com/google/uuid" "github.com/jxskiss/base62" "log/slog" "net/http" _ "net/http/pprof" "platform/web/auth" g "platform/web/globals" q "platform/web/queries" "runtime" "strings" "time" ) // region web type Config struct { Listen string } type Server struct { config *Config fiber *fiber.App } func New(config *Config) (*Server, error) { _config := config if config == nil { _config = &Config{} } return &Server{ config: _config, }, nil } func (s *Server) Run() error { // inits g.Init() q.SetDefault(g.DB) // config s.fiber = fiber.New(fiber.Config{ ProxyHeader: fiber.HeaderXForwardedFor, ErrorHandler: ErrorHandler, }) // middlewares s.fiber.Use(newRecover()) s.fiber.Use(newRequestId()) s.fiber.Use(newLogger()) // routes ApplyRouters(s.fiber) // pprof go func() { runtime.SetBlockProfileRate(1) err := http.ListenAndServe(":6060", nil) if err != nil { slog.Error("pprof 服务错误", slog.Any("err", err)) } }() // listen slog.Info("服务开始监听 :8080") err := s.fiber.Listen("0.0.0.0:8080") if err != nil { slog.Error("Failed to start server", slog.Any("err", err)) } slog.Info("服务已停止") return nil } func (s *Server) Stop() { err := g.ExitRedis() if err != nil { slog.Error("Failed to close Redis connection", slog.Any("err", err)) } err = g.ExitOrm() if err != nil { slog.Error("Failed to close database connection", slog.Any("err", err)) } err = s.fiber.Shutdown() if err != nil { slog.Error("Failed to shutdown server", slog.Any("err", err)) } } // endregion // region middlewares func newRequestId() fiber.Handler { return requestid.New(requestid.Config{ Generator: func() string { binary, _ := uuid.New().MarshalBinary() return base62.EncodeToString(binary) }, }) } func newLogger() fiber.Handler { return logger.New(logger.Config{ DisableColors: true, Format: "🚀 ${time} | ${locals:authtype} ${locals:authid} | ${method} ${path} | ${status} | ${latency} | ${error}\n", TimeFormat: "2006-01-02 15:04:05", TimeZone: "Asia/Shanghai", Next: func(c *fiber.Ctx) bool { authCtx, ok := c.Locals("auth").(*auth.Context) if ok { c.Locals("authtype", authCtx.Payload.Type.ToStr()) c.Locals("authid", authCtx.Payload.Id) } else { c.Locals("authtype", auth.PayloadNone.ToStr()) c.Locals("authid", 0) } return false }, Done: func(c *fiber.Ctx, logBytes []byte) { var logStr = strings.TrimPrefix(string(logBytes), "🚀") var logVars = strings.Split(logStr, "|") var reqTimeStr = strings.TrimSpace(logVars[0]) reqTime, err := time.ParseInLocation("2006-01-02 15:04:05", reqTimeStr, time.Local) if err != nil { slog.Error("时间解析错误", slog.Any("err", err)) return } var latency = strings.TrimSpace(logVars[4]) var errStr = strings.TrimSpace(logVars[5]) slog.Info("接口请求", slog.String("identity", c.Locals("authtype").(string)), slog.Int("visitor", c.Locals("authid").(int)), slog.String("ip", c.IP()), slog.String("ua", c.Get("User-Agent")), slog.String("method", c.Method()), slog.String("path", c.Path()), slog.Int("status", c.Response().StatusCode()), slog.String("error", errStr), slog.String("latency", latency), slog.Time("time", reqTime), ) }, }) } func newRecover() fiber.Handler { return recover.New(recover.Config{ EnableStackTrace: true, }) } // endregion