FIRST
CI / Go Backend (push) Canceled after 0s

This commit is contained in:
xyou
2026-08-07 23:39:47 +08:00
parent f2105bf14c
commit 9500c4c80a
52 changed files with 3801 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
package config
import (
"fmt"
"os"
"strconv"
)
// ServiceConfig holds configuration shared across all microservices.
type ServiceConfig struct {
Name string // 服务名称,如 auth-service
Port string // 监听端口
// 基础设施连接(骨架阶段仅定义,暂不使用)
PostgresDSN string
RedisAddr string
MinIOAddr string
RabbitMQURL string
// 运行环境: debug / release
GinMode string
}
// Load 从环境变量加载配置,fallback 到默认值。
// serviceName 和 defaultPort 用于在没有设置环境变量时提供默认值。
func Load(serviceName, defaultPort string) *ServiceConfig {
cfg := &ServiceConfig{
Name: serviceName,
Port: envOr("SERVICE_PORT", defaultPort),
PostgresDSN: envOr("POSTGRES_DSN", "postgres://mrcc:mrcc_dev_2026@localhost:5432/mrcc?sslmode=disable"),
RedisAddr: envOr("REDIS_ADDR", "localhost:6379"),
MinIOAddr: envOr("MINIO_ADDR", "localhost:9000"),
RabbitMQURL: envOr("RABBITMQ_URL", "amqp://mrcc:mrcc_dev_2026@localhost:5672/"),
GinMode: envOr("GIN_MODE", "debug"),
}
return cfg
}
// Address 返回 :port 格式的监听地址
func (c *ServiceConfig) Address() string {
return fmt.Sprintf(":%s", c.Port)
}
func envOr(key, fallback string) string {
if v := os.Getenv(key); v != "" {
return v
}
return fallback
}
func envIntOr(key string, fallback int) int {
if v := os.Getenv(key); v != "" {
if n, err := strconv.Atoi(v); err == nil {
return n
}
}
return fallback
}
+60
View File
@@ -0,0 +1,60 @@
package httpserver
import (
"time"
"github.com/gin-gonic/gin"
"mrcc/internal/config"
"mrcc/pkg/response"
)
// New 创建一个配置好中间件的 Gin 实例,并注册 /health 端点。
func New(cfg *config.ServiceConfig) *gin.Engine {
gin.SetMode(cfg.GinMode)
r := gin.New()
// 中间件
r.Use(gin.Recovery())
r.Use(gin.LoggerWithFormatter(func(p gin.LogFormatterParams) string {
return p.TimeStamp.Format(time.RFC3339) + " | " + p.Method + " | " + p.Path + " | " +
itoa(p.StatusCode) + " | " + p.Latency.String() + "\n"
}))
// CORS
r.Use(func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
})
// 健康检查
r.GET("/health", func(c *gin.Context) {
response.OK(c, gin.H{
"service": cfg.Name,
"status": "running",
})
})
return r
}
func itoa(n int) string {
if n == 0 {
return "0"
}
buf := [10]byte{}
pos := len(buf)
for n > 0 {
pos--
buf[pos] = byte('0' + n%10)
n /= 10
}
return string(buf[pos:])
}
+26
View File
@@ -0,0 +1,26 @@
package logger
import (
"log/slog"
"os"
)
// 全局默认 logger,使用 JSON handler 输出到 stdout。
var defaultLogger *slog.Logger
func init() {
defaultLogger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelInfo,
}))
slog.SetDefault(defaultLogger)
}
// Default 返回全局 logger 实例
func Default() *slog.Logger {
return defaultLogger
}
// WithService 返回带有 service 字段的 logger
func WithService(name string) *slog.Logger {
return defaultLogger.With("service", name)
}