chore: import 分组规范 + 文档同步 + config 修复
This commit is contained in:
12
.env.example
12
.env.example
@@ -30,6 +30,13 @@ SERVER_READ_TIMEOUT=30s
|
|||||||
SERVER_WRITE_TIMEOUT=30s
|
SERVER_WRITE_TIMEOUT=30s
|
||||||
SERVER_SWAGGER_ENABLED=true
|
SERVER_SWAGGER_ENABLED=true
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 应用环境
|
||||||
|
# =============================================================================
|
||||||
|
# 用于 service 层 IsTestEnvironment() 短路验证码/邮件等
|
||||||
|
# 取值:development / test / production
|
||||||
|
ENVIRONMENT=production
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 数据库配置
|
# 数据库配置
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -133,6 +140,11 @@ JWT_EXPIRE_HOURS=168
|
|||||||
LOG_LEVEL=info
|
LOG_LEVEL=info
|
||||||
LOG_FORMAT=json
|
LOG_FORMAT=json
|
||||||
LOG_OUTPUT=logs/app.log
|
LOG_OUTPUT=logs/app.log
|
||||||
|
# 日志轮转参数(用于 lumberjack)
|
||||||
|
LOG_MAX_SIZE=100 # 单文件最大 MB
|
||||||
|
LOG_MAX_BACKUPS=3 # 保留旧文件数
|
||||||
|
LOG_MAX_AGE=28 # 旧文件最大保留天数
|
||||||
|
LOG_COMPRESS=true # 是否压缩旧文件
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 安全配置
|
# 安全配置
|
||||||
|
|||||||
60
README.md
60
README.md
@@ -33,21 +33,32 @@
|
|||||||
|
|
||||||
```
|
```
|
||||||
backend/
|
backend/
|
||||||
├── cmd/server/ # 应用入口(main.go)
|
├── cmd/server/ # 应用入口(main.go:极简 fx 装配)
|
||||||
├── internal/
|
├── internal/
|
||||||
│ ├── handler/ # HTTP Handler 与 Swagger 注解
|
│ ├── app/ # uber-go/fx 装配层(唯一依赖注入入口)
|
||||||
│ ├── service/ # 业务逻辑
|
│ │ ├── module.go # 聚合根 Module
|
||||||
│ ├── repository/ # 数据访问
|
│ │ ├── infra_module.go # Logger/DB/Redis/Storage/Email/JWT/Casbin + Lifecycle
|
||||||
│ ├── model/ # GORM 数据模型
|
│ │ ├── container_module.go # Container 聚合 + 路由/HTTP/任务生命周期
|
||||||
│ ├── types/ # 请求/响应 DTO
|
│ │ ├── repository_module.go # Repository Provider(占位,Container 模式暂未启用)
|
||||||
│ ├── middleware/ # Gin 中间件
|
│ │ ├── service_module.go # Service Provider(占位)
|
||||||
│ └── task/ # 定时任务与后台作业
|
│ │ ├── handler_module.go # Handler Provider(占位)
|
||||||
├── pkg/ # 可复用组件(config、database、auth、logger、redis、storage 等)
|
│ │ ├── server_module.go # HTTP 服务器模块(占位)
|
||||||
├── docs/ # swagger 生成产物(docs.go / swagger.json / swagger.yaml)
|
│ │ └── task_module.go # 后台任务模块(占位)
|
||||||
├── start.sh # 启动脚本(自动 swag init)
|
│ ├── container/ # 过渡期手动 DI 容器(fx 迁移期的聚合层)
|
||||||
├── docker-compose.yml # 本地容器编排
|
│ ├── handler/ # HTTP Handler 与 Swagger 注解
|
||||||
├── .env.example # 环境变量示例
|
│ ├── service/ # 业务逻辑(接口 + 实现)
|
||||||
└── go.mod # Go Module 定义
|
│ ├── repository/ # 数据访问(接口 + GORM 实现)
|
||||||
|
│ ├── model/ # GORM 数据模型与响应结构
|
||||||
|
│ ├── types/ # 请求/响应 DTO
|
||||||
|
│ ├── errors/ # 统一错误定义(apperrors)
|
||||||
|
│ ├── middleware/ # Gin 中间件
|
||||||
|
│ └── task/ # 定时任务与后台作业
|
||||||
|
├── pkg/ # 可复用组件(config、database、auth、logger、redis、storage、email、utils)
|
||||||
|
├── docs/ # swagger 生成产物(docs.go / swagger.json / swagger.yaml)
|
||||||
|
├── start.sh # 启动脚本(自动 swag init)
|
||||||
|
├── docker-compose.yml # 本地容器编排
|
||||||
|
├── .env.example # 环境变量示例
|
||||||
|
└── go.mod # Go Module 定义
|
||||||
```
|
```
|
||||||
|
|
||||||
## ✅ 前置要求
|
## ✅ 前置要求
|
||||||
@@ -113,6 +124,9 @@ backend/
|
|||||||
| `JWT_SECRET` | JWT 签名密钥 | `change-me` |
|
| `JWT_SECRET` | JWT 签名密钥 | `change-me` |
|
||||||
| `EMAIL_ENABLED` | 是否开启邮件服务 | `true` |
|
| `EMAIL_ENABLED` | 是否开启邮件服务 | `true` |
|
||||||
| `EMAIL_SMTP_HOST` / `EMAIL_SMTP_PORT` | SMTP 配置 | `smtp.example.com` / `587` |
|
| `EMAIL_SMTP_HOST` / `EMAIL_SMTP_PORT` | SMTP 配置 | `smtp.example.com` / `587` |
|
||||||
|
| `ENVIRONMENT` | 应用环境(用于 service 层 `IsTestEnvironment()` 短路) | `production` |
|
||||||
|
| `SECURITY_ALLOWED_ORIGINS` | CORS 允许的来源(逗号分隔) | `*` |
|
||||||
|
| `SECURITY_ALLOWED_DOMAINS` | 头像/材质 URL 允许的域名(逗号分隔) | `localhost,127.0.0.1` |
|
||||||
|
|
||||||
更多变量请参考 `.env.example` 与 `.env.docker.example`。
|
更多变量请参考 `.env.example` 与 `.env.docker.example`。
|
||||||
|
|
||||||
@@ -132,11 +146,21 @@ golangci-lint run (若已安装)
|
|||||||
|
|
||||||
## 🧱 架构说明
|
## 🧱 架构说明
|
||||||
|
|
||||||
- **分层设计**:Handler -> Service -> Repository -> Model,层次清晰、职责单一。
|
- **分层设计**:Handler → Service → Repository → Model,层次清晰、职责单一。
|
||||||
- **依赖管理器**:`pkg/*/manager.go` 使用 `sync.Once` 实现线程安全单例(DB / Redis / Logger / Storage / Email / Auth / Config)。
|
- Handler 不得直连 `*gorm.DB` 或 `*Repository`,必须通过 Service。
|
||||||
|
- Service 不得持有 `*gorm.DB`,所有数据访问通过 Repository 接口。
|
||||||
|
- **依赖注入(uber-go/fx)**:
|
||||||
|
- `internal/app/` 是唯一的依赖装配入口。每个基础设施 / 仓储 / 服务作为 `fx.Provider` 注册。
|
||||||
|
- **生命周期管理**:DB / Redis / Storage / Logger / HTTP Server / Task Runner 通过 `fx.Lifecycle` 的 `OnStart` / `OnStop` Hook 统一管理,彻底替代散落在 `main()` 的 `defer Close()` 链。
|
||||||
|
- **优雅关闭**:`fx.New(app.Module(cfg)).Run()` 监听 `SIGINT` / `SIGTERM`,按依赖逆序触发 `OnStop`,先关 HTTP Server(30s 超时),再关 Task Runner,最后关 DB/Redis。
|
||||||
|
- **Dev/Test 自动回退**:Redis 连接失败且环境为 `development` / `test` / `dev` / `USE_MINIREDIS=true` 时自动启用 `miniredis`。
|
||||||
|
- **启动时错误检查**:循环依赖、缺失 Provider、Provider 返回 error 全部在 `fx.New()` 阶段立即检测。
|
||||||
|
- **错误与响应统一**:
|
||||||
|
- 错误统一在 `internal/errors/`(别名 `apperrors`),通过 `errors.Is/As` 匹配。
|
||||||
|
- 响应统一使用 `model.Response` / `model.PaginationResponse` / `model.NewErrorResponse`。
|
||||||
|
- Middleware 错误响应也走 `model.NewErrorResponse`,不再使用裸 `gin.H`。
|
||||||
|
- **配置优先级**:`config.Load()` 读取 `.env` → 环境变量 → viper 默认值;`*config.Config` 由 `fx.Supply` 注入。
|
||||||
- **Swagger 注解**:所有 Handler、模型、DTO 均补齐 `@Summary` / `@Description` / `@Success`,可直接生成 OpenAPI 文档。
|
- **Swagger 注解**:所有 Handler、模型、DTO 均补齐 `@Summary` / `@Description` / `@Success`,可直接生成 OpenAPI 文档。
|
||||||
- **配置优先级**:`.env` -> 系统环境变量,所有配置均可通过容器注入。
|
|
||||||
- **自动任务**:`internal/task` 承载后台作业,可按需扩展。
|
|
||||||
|
|
||||||
## 📝 Swagger 说明
|
## 📝 Swagger 说明
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package container
|
package container
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"carrotskin/internal/repository"
|
"carrotskin/internal/repository"
|
||||||
"carrotskin/internal/service"
|
"carrotskin/internal/service"
|
||||||
"carrotskin/pkg/auth"
|
"carrotskin/pkg/auth"
|
||||||
@@ -9,8 +12,6 @@ import (
|
|||||||
"carrotskin/pkg/email"
|
"carrotskin/pkg/email"
|
||||||
"carrotskin/pkg/redis"
|
"carrotskin/pkg/redis"
|
||||||
"carrotskin/pkg/storage"
|
"carrotskin/pkg/storage"
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|||||||
@@ -128,7 +128,6 @@ func NewInternalError(message string, err error) *AppError {
|
|||||||
// 注意:原此处的 Is/As/Wrap 函数(透传标准库)已删除。
|
// 注意:原此处的 Is/As/Wrap 函数(透传标准库)已删除。
|
||||||
// 请直接使用标准库 errors.Is / errors.As / fmt.Errorf。
|
// 请直接使用标准库 errors.Is / errors.As / fmt.Errorf。
|
||||||
|
|
||||||
|
|
||||||
// YggdrasilErrorResponse Yggdrasil协议标准错误响应格式
|
// YggdrasilErrorResponse Yggdrasil协议标准错误响应格式
|
||||||
type YggdrasilErrorResponse struct {
|
type YggdrasilErrorResponse struct {
|
||||||
Error string `json:"error"` // 错误的简要描述(机器可读)
|
Error string `json:"error"` // 错误的简要描述(机器可读)
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
apperrors "carrotskin/internal/errors"
|
|
||||||
"carrotskin/internal/container"
|
"carrotskin/internal/container"
|
||||||
|
apperrors "carrotskin/internal/errors"
|
||||||
"carrotskin/internal/model"
|
"carrotskin/internal/model"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"carrotskin/internal/container"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"carrotskin/internal/container"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"carrotskin/internal/container"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"carrotskin/internal/container"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
apperrors "carrotskin/internal/errors"
|
|
||||||
"carrotskin/internal/model"
|
|
||||||
"carrotskin/internal/types"
|
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
apperrors "carrotskin/internal/errors"
|
||||||
|
"carrotskin/internal/model"
|
||||||
|
"carrotskin/internal/types"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"carrotskin/internal/container"
|
"carrotskin/internal/container"
|
||||||
"carrotskin/internal/model"
|
"carrotskin/internal/model"
|
||||||
"carrotskin/internal/types"
|
"carrotskin/internal/types"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ package handler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
"carrotskin/internal/container"
|
"carrotskin/internal/container"
|
||||||
"carrotskin/internal/errors"
|
"carrotskin/internal/errors"
|
||||||
"carrotskin/internal/model"
|
"carrotskin/internal/model"
|
||||||
"carrotskin/pkg/utils"
|
"carrotskin/pkg/utils"
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"carrotskin/internal/model"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"carrotskin/internal/model"
|
||||||
|
|
||||||
"carrotskin/pkg/auth"
|
"carrotskin/pkg/auth"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"carrotskin/internal/model"
|
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"carrotskin/internal/model"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"carrotskin/internal/model"
|
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"carrotskin/internal/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UserRepository 用户仓储接口
|
// UserRepository 用户仓储接口
|
||||||
@@ -11,7 +12,7 @@ type UserRepository interface {
|
|||||||
FindByID(ctx context.Context, id int64) (*model.User, error)
|
FindByID(ctx context.Context, id int64) (*model.User, error)
|
||||||
FindByUsername(ctx context.Context, username string) (*model.User, error)
|
FindByUsername(ctx context.Context, username string) (*model.User, error)
|
||||||
FindByEmail(ctx context.Context, email string) (*model.User, error)
|
FindByEmail(ctx context.Context, email string) (*model.User, error)
|
||||||
FindByIDs(ctx context.Context, ids []int64) ([]*model.User, error) // 批量查询
|
FindByIDs(ctx context.Context, ids []int64) ([]*model.User, error) // 批量查询
|
||||||
List(ctx context.Context, page, pageSize int) ([]*model.User, int64, error) // 分页列表(管理员)
|
List(ctx context.Context, page, pageSize int) ([]*model.User, int64, error) // 分页列表(管理员)
|
||||||
Update(ctx context.Context, user *model.User) error
|
Update(ctx context.Context, user *model.User) error
|
||||||
UpdateFields(ctx context.Context, id int64, fields map[string]interface{}) error
|
UpdateFields(ctx context.Context, id int64, fields map[string]interface{}) error
|
||||||
@@ -66,10 +67,9 @@ type TextureRepository interface {
|
|||||||
GetUserFavorites(ctx context.Context, userID int64, page, pageSize int) ([]*model.Texture, int64, error)
|
GetUserFavorites(ctx context.Context, userID int64, page, pageSize int) ([]*model.Texture, int64, error)
|
||||||
CountByUploaderID(ctx context.Context, uploaderID int64) (int64, error)
|
CountByUploaderID(ctx context.Context, uploaderID int64) (int64, error)
|
||||||
ListForAdmin(ctx context.Context, page, pageSize int) ([]*model.Texture, int64, error) // 管理员列表(含 Uploader 预加载)
|
ListForAdmin(ctx context.Context, page, pageSize int) ([]*model.Texture, int64, error) // 管理员列表(含 Uploader 预加载)
|
||||||
FindByIDForAdmin(ctx context.Context, id int64) (*model.Texture, error) // 管理员查询(无权限过滤)
|
FindByIDForAdmin(ctx context.Context, id int64) (*model.Texture, error) // 管理员查询(无权限过滤)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// YggdrasilRepository Yggdrasil仓储接口
|
// YggdrasilRepository Yggdrasil仓储接口
|
||||||
type YggdrasilRepository interface {
|
type YggdrasilRepository interface {
|
||||||
GetPasswordByID(ctx context.Context, id int64) (string, error)
|
GetPasswordByID(ctx context.Context, id int64) (string, error)
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"carrotskin/internal/model"
|
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"carrotskin/internal/model"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"carrotskin/internal/model"
|
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"carrotskin/internal/model"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"carrotskin/internal/model"
|
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"carrotskin/internal/model"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"carrotskin/internal/model"
|
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"carrotskin/internal/model"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -34,9 +35,3 @@ func (r *yggdrasilRepository) ResetPassword(ctx context.Context, id int64, passw
|
|||||||
func (r *yggdrasilRepository) Create(ctx context.Context, yggdrasil *model.Yggdrasil) error {
|
func (r *yggdrasilRepository) Create(ctx context.Context, yggdrasil *model.Yggdrasil) error {
|
||||||
return r.db.WithContext(ctx).Create(yggdrasil).Error
|
return r.db.WithContext(ctx).Create(yggdrasil).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"carrotskin/pkg/config"
|
|
||||||
"carrotskin/pkg/redis"
|
|
||||||
"carrotskin/pkg/utils"
|
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"carrotskin/pkg/config"
|
||||||
|
"carrotskin/pkg/redis"
|
||||||
|
"carrotskin/pkg/utils"
|
||||||
|
|
||||||
"github.com/wenlng/go-captcha-assets/resources/imagesv2"
|
"github.com/wenlng/go-captcha-assets/resources/imagesv2"
|
||||||
"github.com/wenlng/go-captcha-assets/resources/tiles"
|
"github.com/wenlng/go-captcha-assets/resources/tiles"
|
||||||
"github.com/wenlng/go-captcha/v2/slide"
|
"github.com/wenlng/go-captcha/v2/slide"
|
||||||
|
|||||||
@@ -2,11 +2,12 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"carrotskin/internal/model"
|
|
||||||
"carrotskin/pkg/storage"
|
|
||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"carrotskin/internal/model"
|
||||||
|
"carrotskin/pkg/storage"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
apperrors "carrotskin/internal/errors"
|
|
||||||
"carrotskin/internal/model"
|
|
||||||
"carrotskin/internal/repository"
|
|
||||||
"carrotskin/pkg/database"
|
|
||||||
"carrotskin/pkg/utils"
|
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
@@ -14,6 +9,12 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
apperrors "carrotskin/internal/errors"
|
||||||
|
"carrotskin/internal/model"
|
||||||
|
"carrotskin/internal/repository"
|
||||||
|
"carrotskin/pkg/database"
|
||||||
|
"carrotskin/pkg/utils"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"carrotskin/internal/model"
|
|
||||||
"carrotskin/internal/repository"
|
|
||||||
"carrotskin/pkg/redis"
|
|
||||||
"context"
|
"context"
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
@@ -18,6 +15,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"carrotskin/internal/model"
|
||||||
|
"carrotskin/internal/repository"
|
||||||
|
"carrotskin/pkg/redis"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,6 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
apperrors "carrotskin/internal/errors"
|
|
||||||
"carrotskin/internal/model"
|
|
||||||
"carrotskin/internal/repository"
|
|
||||||
"carrotskin/pkg/database"
|
|
||||||
"carrotskin/pkg/storage"
|
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
@@ -16,6 +11,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
apperrors "carrotskin/internal/errors"
|
||||||
|
"carrotskin/internal/model"
|
||||||
|
"carrotskin/internal/repository"
|
||||||
|
"carrotskin/pkg/database"
|
||||||
|
"carrotskin/pkg/storage"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"carrotskin/internal/model"
|
|
||||||
"carrotskin/internal/repository"
|
|
||||||
"carrotskin/pkg/auth"
|
|
||||||
"carrotskin/pkg/utils"
|
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"carrotskin/internal/model"
|
||||||
|
"carrotskin/internal/repository"
|
||||||
|
"carrotskin/pkg/auth"
|
||||||
|
"carrotskin/pkg/utils"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
apperrors "carrotskin/internal/errors"
|
apperrors "carrotskin/internal/errors"
|
||||||
"carrotskin/internal/model"
|
"carrotskin/internal/model"
|
||||||
"carrotskin/internal/repository"
|
"carrotskin/internal/repository"
|
||||||
"carrotskin/pkg/auth"
|
"carrotskin/pkg/auth"
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
apperrors "carrotskin/internal/errors"
|
|
||||||
"carrotskin/internal/repository"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
apperrors "carrotskin/internal/errors"
|
||||||
|
"carrotskin/internal/repository"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -109,4 +110,3 @@ func (s *yggdrasilCertificateService) GeneratePlayerCertificate(ctx context.Cont
|
|||||||
func (s *yggdrasilCertificateService) GetPublicKey(ctx context.Context) (string, error) {
|
func (s *yggdrasilCertificateService) GetPublicKey(ctx context.Context) (string, error) {
|
||||||
return s.signatureService.GetPublicKeyFromRedis(ctx)
|
return s.signatureService.GetPublicKeyFromRedis(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"carrotskin/internal/model"
|
|
||||||
"carrotskin/internal/repository"
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"carrotskin/internal/model"
|
||||||
|
"carrotskin/internal/repository"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"carrotskin/internal/model"
|
"carrotskin/internal/model"
|
||||||
"carrotskin/internal/repository"
|
"carrotskin/internal/repository"
|
||||||
"carrotskin/pkg/redis"
|
"carrotskin/pkg/redis"
|
||||||
"carrotskin/pkg/utils"
|
"carrotskin/pkg/utils"
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
apperrors "carrotskin/internal/errors"
|
|
||||||
"carrotskin/pkg/redis"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
apperrors "carrotskin/internal/errors"
|
||||||
|
"carrotskin/pkg/redis"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -259,6 +259,7 @@ func setupEnvMappings() {
|
|||||||
viper.BindEnv("server.read_timeout", "SERVER_READ_TIMEOUT")
|
viper.BindEnv("server.read_timeout", "SERVER_READ_TIMEOUT")
|
||||||
viper.BindEnv("server.write_timeout", "SERVER_WRITE_TIMEOUT")
|
viper.BindEnv("server.write_timeout", "SERVER_WRITE_TIMEOUT")
|
||||||
viper.BindEnv("server.swagger_enabled", "SERVER_SWAGGER_ENABLED")
|
viper.BindEnv("server.swagger_enabled", "SERVER_SWAGGER_ENABLED")
|
||||||
|
viper.BindEnv("environment", "ENVIRONMENT")
|
||||||
|
|
||||||
// 数据库配置
|
// 数据库配置
|
||||||
viper.BindEnv("database.driver", "DATABASE_DRIVER")
|
viper.BindEnv("database.driver", "DATABASE_DRIVER")
|
||||||
@@ -306,6 +307,10 @@ func setupEnvMappings() {
|
|||||||
viper.BindEnv("log.level", "LOG_LEVEL")
|
viper.BindEnv("log.level", "LOG_LEVEL")
|
||||||
viper.BindEnv("log.format", "LOG_FORMAT")
|
viper.BindEnv("log.format", "LOG_FORMAT")
|
||||||
viper.BindEnv("log.output", "LOG_OUTPUT")
|
viper.BindEnv("log.output", "LOG_OUTPUT")
|
||||||
|
viper.BindEnv("log.max_size", "LOG_MAX_SIZE")
|
||||||
|
viper.BindEnv("log.max_backups", "LOG_MAX_BACKUPS")
|
||||||
|
viper.BindEnv("log.max_age", "LOG_MAX_AGE")
|
||||||
|
viper.BindEnv("log.compress", "LOG_COMPRESS")
|
||||||
|
|
||||||
// 邮件配置
|
// 邮件配置
|
||||||
viper.BindEnv("email.enabled", "EMAIL_ENABLED")
|
viper.BindEnv("email.enabled", "EMAIL_ENABLED")
|
||||||
@@ -457,10 +462,7 @@ func overrideFromEnv(config *Config) {
|
|||||||
config.Email.Enabled = emailEnabled == "true" || emailEnabled == "True" || emailEnabled == "TRUE" || emailEnabled == "1"
|
config.Email.Enabled = emailEnabled == "true" || emailEnabled == "True" || emailEnabled == "TRUE" || emailEnabled == "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理环境配置
|
// 处理环境配置(已由 BindEnv("environment", "ENVIRONMENT") + AutomaticEnv 处理)
|
||||||
if env := os.Getenv("ENVIRONMENT"); env != "" {
|
|
||||||
config.Environment = env
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理安全配置
|
// 处理安全配置
|
||||||
if allowedOrigins := os.Getenv("SECURITY_ALLOWED_ORIGINS"); allowedOrigins != "" {
|
if allowedOrigins := os.Getenv("SECURITY_ALLOWED_ORIGINS"); allowedOrigins != "" {
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"carrotskin/internal/model"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"carrotskin/internal/model"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package logger
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"carrotskin/pkg/config"
|
"carrotskin/pkg/config"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
)
|
)
|
||||||
@@ -50,7 +50,7 @@ func New(cfg config.LogConfig) (*zap.Logger, error) {
|
|||||||
if err := os.MkdirAll(logDir, 0755); err != nil {
|
if err := os.MkdirAll(logDir, 0755); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := os.OpenFile(cfg.Output, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
file, err := os.OpenFile(cfg.Output, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ func (s *StorageClient) GetBucket(name string) (string, error) {
|
|||||||
return bucket, nil
|
return bucket, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// BuildFileURL 构建文件的公开访问URL
|
// BuildFileURL 构建文件的公开访问URL
|
||||||
func (s *StorageClient) BuildFileURL(bucketName, objectName string) string {
|
func (s *StorageClient) BuildFileURL(bucketName, objectName string) string {
|
||||||
return fmt.Sprintf("%s/%s/%s", s.publicURL, bucketName, objectName)
|
return fmt.Sprintf("%s/%s/%s", s.publicURL, bucketName, objectName)
|
||||||
|
|||||||
Reference in New Issue
Block a user