2025-03-15 16:07:45 +08:00
|
|
|
package web
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"github.com/gofiber/fiber/v2"
|
2025-03-18 17:57:07 +08:00
|
|
|
"github.com/gofiber/fiber/v2/middleware/logger"
|
|
|
|
|
"github.com/gofiber/fiber/v2/middleware/requestid"
|
2025-04-01 11:26:37 +08:00
|
|
|
"github.com/google/uuid"
|
|
|
|
|
"github.com/jxskiss/base62"
|
2025-05-08 13:18:54 +08:00
|
|
|
"log/slog"
|
|
|
|
|
"net/http"
|
2025-04-21 13:57:57 +08:00
|
|
|
_ "net/http/pprof"
|
2025-05-08 13:18:54 +08:00
|
|
|
"platform/web/auth"
|
|
|
|
|
"platform/web/core"
|
|
|
|
|
g "platform/web/globals"
|
|
|
|
|
m "platform/web/models"
|
|
|
|
|
q "platform/web/queries"
|
|
|
|
|
"runtime"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
2025-04-21 13:57:57 +08:00
|
|
|
)
|
2025-03-15 16:07:45 +08:00
|
|
|
|
2025-05-08 13:18:54 +08:00
|
|
|
// region web
|
|
|
|
|
|
2025-03-15 16:07:45 +08:00
|
|
|
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 {
|
2025-03-31 09:09:05 +08:00
|
|
|
|
2025-04-16 14:01:30 +08:00
|
|
|
// inits
|
|
|
|
|
g.InitBaiyin()
|
|
|
|
|
g.InitAlipay()
|
2025-04-17 18:29:44 +08:00
|
|
|
// g.InitWechatPay()
|
2025-04-18 17:47:54 +08:00
|
|
|
g.InitAliyun()
|
2025-04-30 15:18:45 +08:00
|
|
|
g.InitValidator()
|
2025-04-16 14:01:30 +08:00
|
|
|
|
2025-04-01 11:26:37 +08:00
|
|
|
// config
|
2025-03-18 17:57:07 +08:00
|
|
|
s.fiber = fiber.New(fiber.Config{
|
2025-04-30 15:18:45 +08:00
|
|
|
ProxyHeader: fiber.HeaderXForwardedFor,
|
2025-03-18 17:57:07 +08:00
|
|
|
ErrorHandler: ErrorHandler,
|
|
|
|
|
})
|
|
|
|
|
|
2025-05-08 13:18:54 +08:00
|
|
|
// middlewares
|
|
|
|
|
s.fiber.Use(useRequestId())
|
|
|
|
|
s.fiber.Use(useLogger())
|
2025-03-18 17:57:07 +08:00
|
|
|
|
2025-05-08 13:18:54 +08:00
|
|
|
// routes
|
2025-03-18 17:57:07 +08:00
|
|
|
ApplyRouters(s.fiber)
|
2025-03-15 16:07:45 +08:00
|
|
|
|
2025-04-01 10:51:32 +08:00
|
|
|
// pprof
|
2025-03-31 09:09:05 +08:00
|
|
|
go func() {
|
2025-04-01 10:51:32 +08:00
|
|
|
runtime.SetBlockProfileRate(1)
|
2025-03-31 09:09:05 +08:00
|
|
|
err := http.ListenAndServe(":6060", nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("pprof 服务错误", slog.Any("err", err))
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
2025-04-01 11:26:37 +08:00
|
|
|
// listen
|
2025-04-21 13:57:57 +08:00
|
|
|
slog.Info("Server started on :8080")
|
|
|
|
|
err := s.fiber.Listen(":8080")
|
2025-03-15 16:07:45 +08:00
|
|
|
if err != nil {
|
2025-03-18 17:57:07 +08:00
|
|
|
slog.Error("Failed to start server", slog.Any("err", err))
|
2025-03-15 16:07:45 +08:00
|
|
|
}
|
|
|
|
|
|
2025-03-18 17:57:07 +08:00
|
|
|
slog.Info("Server stopped")
|
2025-03-15 16:07:45 +08:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) Stop() {
|
|
|
|
|
err := s.fiber.Shutdown()
|
|
|
|
|
if err != nil {
|
2025-03-18 17:57:07 +08:00
|
|
|
slog.Error("Failed to shutdown server", slog.Any("err", err))
|
2025-03-15 16:07:45 +08:00
|
|
|
}
|
|
|
|
|
}
|
2025-05-08 13:18:54 +08:00
|
|
|
|
|
|
|
|
// endregion
|
|
|
|
|
|
|
|
|
|
// region requestid
|
|
|
|
|
|
|
|
|
|
func useRequestId() fiber.Handler {
|
|
|
|
|
return requestid.New(requestid.Config{
|
|
|
|
|
Generator: func() string {
|
|
|
|
|
binary, _ := uuid.New().MarshalBinary()
|
|
|
|
|
return base62.EncodeToString(binary)
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// endregion
|
|
|
|
|
|
|
|
|
|
// region logger
|
|
|
|
|
|
|
|
|
|
func useLogger() fiber.Handler {
|
|
|
|
|
return logger.New(logger.Config{
|
|
|
|
|
Format: "🚀 ${time} | ${locals:authtype} ${locals:authid} | ${method} ${path} | ${status} | ${latency} | ${error}\n",
|
|
|
|
|
TimeFormat: "2006-01-02 15:04:05",
|
|
|
|
|
TimeZone: "Asia/Shanghai",
|
|
|
|
|
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 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{
|
|
|
|
|
IP: c.IP(),
|
|
|
|
|
Ua: c.Get("User-Agent"),
|
|
|
|
|
Method: c.Method(),
|
|
|
|
|
Path: c.Path(),
|
|
|
|
|
Latency: latency,
|
|
|
|
|
Status: int32(c.Response().StatusCode()),
|
|
|
|
|
Error: errStr,
|
|
|
|
|
Time: core.LocalDateTime(reqTime),
|
|
|
|
|
}
|
|
|
|
|
if authType != nil {
|
|
|
|
|
item.Identity = int32(*authType)
|
|
|
|
|
}
|
|
|
|
|
if authID != 0 {
|
|
|
|
|
item.Visitor = int32(authID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = q.LogsRequest.Create(item)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("日志记录错误", slog.Any("err", err))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// endregion
|