182 lines
3.9 KiB
Go
182 lines
3.9 KiB
Go
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/pkg/u"
|
|
"platform/web/auth"
|
|
g "platform/web/globals"
|
|
"platform/web/globals/orm"
|
|
m "platform/web/models"
|
|
q "platform/web/queries"
|
|
"runtime"
|
|
"strconv"
|
|
"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("Server started on :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("Server stopped")
|
|
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 {
|
|
c.Locals("authtype", auth.PayloadNone.ToStr())
|
|
c.Locals("authid", 0)
|
|
return false
|
|
},
|
|
Done: func(c *fiber.Ctx, logBytes []byte) {
|
|
go func(ip, ua, method, path string, status int, 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 authInfo = strings.Split(strings.TrimSpace(logVars[1]), " ")
|
|
var authType = auth.PayloadTypeFromStr(strings.TrimSpace(authInfo[0]))
|
|
authID, err := strconv.Atoi(strings.TrimSpace(authInfo[1]))
|
|
if err != nil {
|
|
slog.Error("负载ID解析错误", slog.Any("err", err))
|
|
return
|
|
}
|
|
|
|
var latency = strings.TrimSpace(logVars[4])
|
|
|
|
var errStr = strings.TrimSpace(logVars[5])
|
|
|
|
var item = &m.LogsRequest{
|
|
Identity: int32(authType),
|
|
IP: ip,
|
|
Ua: u.P(ua),
|
|
Method: method,
|
|
Path: path,
|
|
Latency: latency,
|
|
Status: int32(status),
|
|
Error: &errStr,
|
|
Time: orm.LocalDateTime(reqTime),
|
|
}
|
|
if authID != 0 {
|
|
item.Visitor = u.P(int32(authID))
|
|
}
|
|
|
|
err = q.LogsRequest.Create(item)
|
|
if err != nil {
|
|
slog.Error("日志记录错误", slog.Any("err", err))
|
|
return
|
|
}
|
|
}(c.IP(), c.Get("User-Agent"), c.Method(), c.Path(), c.Response().StatusCode(), logBytes)
|
|
},
|
|
})
|
|
}
|
|
|
|
func newRecover() fiber.Handler {
|
|
return recover.New()
|
|
}
|
|
|
|
// endregion
|