首次提交:初始化项目代码
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
package di
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"cloudnest/internal/application/auth"
|
||||
"cloudnest/internal/application/captcha"
|
||||
"cloudnest/internal/application/email"
|
||||
"cloudnest/internal/application/file"
|
||||
"cloudnest/internal/config"
|
||||
"cloudnest/internal/domain/auth/repository"
|
||||
fileRepo "cloudnest/internal/domain/file/repository"
|
||||
"cloudnest/internal/infrastructure/database"
|
||||
infrastructureRepo "cloudnest/internal/infrastructure/repository"
|
||||
"cloudnest/internal/infrastructure/storage"
|
||||
"cloudnest/internal/interface/http/handler"
|
||||
"cloudnest/internal/interface/http/routes"
|
||||
"cloudnest/internal/middleware"
|
||||
"cloudnest/internal/pkg/logger"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/dig"
|
||||
)
|
||||
|
||||
type Container struct {
|
||||
*dig.Container
|
||||
}
|
||||
|
||||
func New() *Container {
|
||||
c := dig.New()
|
||||
|
||||
c.Provide(func() *config.Config {
|
||||
return config.Load()
|
||||
})
|
||||
|
||||
c.Provide(func(cfg *config.Config) (*database.MySQLClient, error) {
|
||||
return database.NewMySQLClient(cfg.Database.DSN())
|
||||
})
|
||||
|
||||
c.Provide(func(cfg *config.Config) (*database.RedisClient, error) {
|
||||
return database.NewRedisClient(cfg.Cache.Addr(), cfg.Cache.Password, cfg.Cache.DB)
|
||||
})
|
||||
|
||||
c.Provide(func(cfg *config.Config) (*storage.MinioClient, error) {
|
||||
return storage.NewMinioClient(
|
||||
cfg.Storage.Endpoint,
|
||||
cfg.Storage.AccessKeyID,
|
||||
cfg.Storage.SecretAccessKey,
|
||||
cfg.Storage.UseSSL,
|
||||
)
|
||||
})
|
||||
|
||||
c.Provide(func(mysql *database.MySQLClient) repository.UserRepository {
|
||||
return infrastructureRepo.NewUserRepository(mysql)
|
||||
})
|
||||
|
||||
c.Provide(func(minio *storage.MinioClient) fileRepo.FileRepository {
|
||||
return infrastructureRepo.NewFileRepository(minio)
|
||||
})
|
||||
|
||||
c.Provide(func(mysql *database.MySQLClient) *infrastructureRepo.FileMetaRepository {
|
||||
return infrastructureRepo.NewFileMetaRepository(mysql)
|
||||
})
|
||||
|
||||
c.Provide(func(userRepo repository.UserRepository, emailService *email.EmailService, cfg *config.Config) *auth.AuthService {
|
||||
return auth.NewAuthService(userRepo, emailService, cfg.JWT.Secret, cfg.JWT.ExpiresIn)
|
||||
})
|
||||
|
||||
c.Provide(func(fRepo fileRepo.FileRepository, fMetaRepo *infrastructureRepo.FileMetaRepository, cfg *config.Config) *file.FileService {
|
||||
return file.NewFileService(fRepo, fMetaRepo, cfg.Storage.BucketName)
|
||||
})
|
||||
|
||||
c.Provide(func(redis *database.RedisClient) *captcha.CaptchaService {
|
||||
return captcha.NewCaptchaService(redis)
|
||||
})
|
||||
|
||||
c.Provide(func(cfg *config.Config, redis *database.RedisClient) *email.EmailService {
|
||||
return email.NewEmailService(&cfg.Email, redis)
|
||||
})
|
||||
|
||||
c.Provide(func(service *auth.AuthService, captchaService *captcha.CaptchaService, emailService *email.EmailService) *handler.AuthHandler {
|
||||
return handler.NewAuthHandler(service, captchaService, emailService)
|
||||
})
|
||||
|
||||
c.Provide(func(emailService *email.EmailService, captchaService *captcha.CaptchaService) *handler.EmailHandler {
|
||||
return handler.NewEmailHandler(emailService, captchaService)
|
||||
})
|
||||
|
||||
c.Provide(func(service *file.FileService, authService *auth.AuthService) *handler.FileHandler {
|
||||
return handler.NewFileHandler(service, authService)
|
||||
})
|
||||
|
||||
c.Provide(func(service *captcha.CaptchaService) *handler.CaptchaHandler {
|
||||
return handler.NewCaptchaHandler(service)
|
||||
})
|
||||
|
||||
return &Container{c}
|
||||
}
|
||||
|
||||
// BuildEngine builds the Gin engine with routes based on service type.
|
||||
// BuildEngine 根据服务类型构建 Gin 引擎并注册路由。
|
||||
//
|
||||
// Parameters:
|
||||
// - serviceType: The type of service (auth or file).
|
||||
//
|
||||
// Returns:
|
||||
// - *gin.Engine: The configured Gin engine.
|
||||
// - error: Any error that occurred during setup.
|
||||
//
|
||||
// 参数:
|
||||
// - serviceType: 服务类型 (auth 或 file)。
|
||||
//
|
||||
// 返回值:
|
||||
// - *gin.Engine: 配置好的 Gin 引擎。
|
||||
// - error: 设置过程中发生的任何错误。
|
||||
func (c *Container) BuildEngine(serviceType routes.ServiceType) (*gin.Engine, error) {
|
||||
var engine *gin.Engine
|
||||
err := c.Invoke(func(cfg *config.Config, authHandler *handler.AuthHandler, fileHandler *handler.FileHandler, captchaHandler *handler.CaptchaHandler, emailHandler *handler.EmailHandler) {
|
||||
engine = gin.New()
|
||||
|
||||
engine.RedirectTrailingSlash = false
|
||||
engine.RedirectFixedPath = false
|
||||
|
||||
engine.Use(gin.Recovery())
|
||||
engine.Use(middleware.CORS())
|
||||
engine.Use(middleware.ErrorHandler())
|
||||
|
||||
engine.GET("/healthz", func(ctx *gin.Context) {
|
||||
ctx.JSON(http.StatusOK, gin.H{"status": "ok"})
|
||||
})
|
||||
|
||||
routes.SetupRoutes(engine, serviceType, authHandler, fileHandler, captchaHandler, emailHandler, cfg.JWT.Secret)
|
||||
|
||||
logger.Info("engine built successfully")
|
||||
})
|
||||
|
||||
return engine, err
|
||||
}
|
||||
|
||||
// BuildAuthEngine builds the Gin engine for auth service.
|
||||
// BuildAuthEngine 为认证服务构建 Gin 引擎。
|
||||
//
|
||||
// This method only registers authentication routes.
|
||||
//
|
||||
// 此方法只注册认证路由。
|
||||
func (c *Container) BuildAuthEngine() (*gin.Engine, error) {
|
||||
return c.BuildEngine(routes.ServiceTypeAuth)
|
||||
}
|
||||
|
||||
// BuildFileEngine builds the Gin engine for file service.
|
||||
// BuildFileEngine 为文件服务构建 Gin 引擎。
|
||||
//
|
||||
// This method only registers file management routes.
|
||||
//
|
||||
// 此方法只注册文件管理路由。
|
||||
func (c *Container) BuildFileEngine() (*gin.Engine, error) {
|
||||
return c.BuildEngine(routes.ServiceTypeFile)
|
||||
}
|
||||
|
||||
func (c *Container) InitializeServices() error {
|
||||
return c.Invoke(func(mysql *database.MySQLClient, redis *database.RedisClient, minio *storage.MinioClient, cfg *config.Config) error {
|
||||
if err := mysql.Migrate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := minio.EnsureBucket(cfg.Storage.BucketName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Info("all services initialized")
|
||||
|
||||
go startRecycleBinCleaner(cfg, mysql, minio)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func startRecycleBinCleaner(cfg *config.Config, mysql *database.MySQLClient, minio *storage.MinioClient) {
|
||||
expireDays := cfg.Storage.RecycleBinExpireDays
|
||||
if expireDays <= 0 {
|
||||
expireDays = 7
|
||||
}
|
||||
|
||||
fMetaRepo := infrastructureRepo.NewFileMetaRepository(mysql)
|
||||
fRepo := infrastructureRepo.NewFileRepository(minio)
|
||||
|
||||
ticker := time.NewTicker(24 * time.Hour)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
logger.Info("starting recycle bin cleanup", "expire_days", expireDays)
|
||||
|
||||
expiredFiles, err := fMetaRepo.CleanExpiredRecycleBin(expireDays)
|
||||
if err != nil {
|
||||
logger.Error("failed to clean recycle bin", "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, df := range expiredFiles {
|
||||
if err := fRepo.Delete(df.UserCode, df.FileKey); err != nil {
|
||||
logger.Error("failed to delete file from storage", "file_key", df.FileKey, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info("recycle bin cleanup completed", "files_cleaned", len(expiredFiles))
|
||||
|
||||
<-ticker.C
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user