feat: Enhance dependency injection and service integration

- Updated main.go to initialize email service and include it in the dependency injection container.
- Refactored handlers to utilize context in service method calls, improving consistency and error handling.
- Introduced new service options for upload, security, and captcha services, enhancing modularity and testability.
- Removed unused repository implementations to streamline the codebase.

This commit continues the effort to improve the architecture by ensuring all services are properly injected and utilized across the application.
This commit is contained in:
lan
2025-12-02 22:52:33 +08:00
parent 792e96b238
commit 034e02e93a
54 changed files with 2305 additions and 2708 deletions

View File

@@ -3,16 +3,22 @@ package service
import (
"carrotskin/internal/model"
"carrotskin/internal/repository"
"carrotskin/pkg/database"
"context"
"errors"
"fmt"
"time"
"go.uber.org/zap"
)
// textureServiceImpl TextureService的实现
type textureServiceImpl struct {
// textureService TextureService的实现
type textureService struct {
textureRepo repository.TextureRepository
userRepo repository.UserRepository
cache *database.CacheManager
cacheKeys *database.CacheKeyBuilder
cacheInv *database.CacheInvalidator
logger *zap.Logger
}
@@ -20,16 +26,20 @@ type textureServiceImpl struct {
func NewTextureService(
textureRepo repository.TextureRepository,
userRepo repository.UserRepository,
cacheManager *database.CacheManager,
logger *zap.Logger,
) TextureService {
return &textureServiceImpl{
return &textureService{
textureRepo: textureRepo,
userRepo: userRepo,
cache: cacheManager,
cacheKeys: database.NewCacheKeyBuilder(""),
cacheInv: database.NewCacheInvalidator(cacheManager),
logger: logger,
}
}
func (s *textureServiceImpl) Create(uploaderID int64, name, description, textureType, url, hash string, size int, isPublic, isSlim bool) (*model.Texture, error) {
func (s *textureService) Create(ctx context.Context, uploaderID int64, name, description, textureType, url, hash string, size int, isPublic, isSlim bool) (*model.Texture, error) {
// 验证用户存在
user, err := s.userRepo.FindByID(uploaderID)
if err != nil || user == nil {
@@ -71,34 +81,82 @@ func (s *textureServiceImpl) Create(uploaderID int64, name, description, texture
return nil, err
}
// 清除用户的 texture 列表缓存(所有分页)
s.cacheInv.BatchInvalidate(ctx, fmt.Sprintf("texture:user:%d:*", uploaderID))
return texture, nil
}
func (s *textureServiceImpl) GetByID(id int64) (*model.Texture, error) {
texture, err := s.textureRepo.FindByID(id)
func (s *textureService) GetByID(ctx context.Context, id int64) (*model.Texture, error) {
// 尝试从缓存获取
cacheKey := s.cacheKeys.Texture(id)
var texture model.Texture
if err := s.cache.Get(ctx, cacheKey, &texture); err == nil {
if texture.Status == -1 {
return nil, errors.New("材质已删除")
}
return &texture, nil
}
// 缓存未命中,从数据库查询
texture2, err := s.textureRepo.FindByID(id)
if err != nil {
return nil, err
}
if texture == nil {
if texture2 == nil {
return nil, ErrTextureNotFound
}
if texture.Status == -1 {
if texture2.Status == -1 {
return nil, errors.New("材质已删除")
}
return texture, nil
// 存入缓存异步5分钟过期
if texture2 != nil {
go func() {
_ = s.cache.Set(context.Background(), cacheKey, texture2, 5*time.Minute)
}()
}
return texture2, nil
}
func (s *textureServiceImpl) GetByUserID(uploaderID int64, page, pageSize int) ([]*model.Texture, int64, error) {
func (s *textureService) GetByUserID(ctx context.Context, uploaderID int64, page, pageSize int) ([]*model.Texture, int64, error) {
page, pageSize = NormalizePagination(page, pageSize)
return s.textureRepo.FindByUploaderID(uploaderID, page, pageSize)
// 尝试从缓存获取(包含分页参数)
cacheKey := s.cacheKeys.TextureList(uploaderID, page)
var cachedResult struct {
Textures []*model.Texture
Total int64
}
if err := s.cache.Get(ctx, cacheKey, &cachedResult); err == nil {
return cachedResult.Textures, cachedResult.Total, nil
}
// 缓存未命中,从数据库查询
textures, total, err := s.textureRepo.FindByUploaderID(uploaderID, page, pageSize)
if err != nil {
return nil, 0, err
}
// 存入缓存异步2分钟过期
go func() {
result := struct {
Textures []*model.Texture
Total int64
}{Textures: textures, Total: total}
_ = s.cache.Set(context.Background(), cacheKey, result, 2*time.Minute)
}()
return textures, total, nil
}
func (s *textureServiceImpl) Search(keyword string, textureType model.TextureType, publicOnly bool, page, pageSize int) ([]*model.Texture, int64, error) {
func (s *textureService) Search(ctx context.Context, keyword string, textureType model.TextureType, publicOnly bool, page, pageSize int) ([]*model.Texture, int64, error) {
page, pageSize = NormalizePagination(page, pageSize)
return s.textureRepo.Search(keyword, textureType, publicOnly, page, pageSize)
}
func (s *textureServiceImpl) Update(textureID, uploaderID int64, name, description string, isPublic *bool) (*model.Texture, error) {
func (s *textureService) Update(ctx context.Context, textureID, uploaderID int64, name, description string, isPublic *bool) (*model.Texture, error) {
// 获取材质并验证权限
texture, err := s.textureRepo.FindByID(textureID)
if err != nil {
@@ -129,10 +187,14 @@ func (s *textureServiceImpl) Update(textureID, uploaderID int64, name, descripti
}
}
// 清除 texture 缓存和用户列表缓存
s.cacheInv.OnUpdate(ctx, s.cacheKeys.Texture(textureID))
s.cacheInv.BatchInvalidate(ctx, fmt.Sprintf("texture:user:%d:*", uploaderID))
return s.textureRepo.FindByID(textureID)
}
func (s *textureServiceImpl) Delete(textureID, uploaderID int64) error {
func (s *textureService) Delete(ctx context.Context, textureID, uploaderID int64) error {
// 获取材质并验证权限
texture, err := s.textureRepo.FindByID(textureID)
if err != nil {
@@ -145,10 +207,19 @@ func (s *textureServiceImpl) Delete(textureID, uploaderID int64) error {
return ErrTextureNoPermission
}
return s.textureRepo.Delete(textureID)
err = s.textureRepo.Delete(textureID)
if err != nil {
return err
}
// 清除 texture 缓存和用户列表缓存
s.cacheInv.OnDelete(ctx, s.cacheKeys.Texture(textureID))
s.cacheInv.BatchInvalidate(ctx, fmt.Sprintf("texture:user:%d:*", uploaderID))
return nil
}
func (s *textureServiceImpl) ToggleFavorite(userID, textureID int64) (bool, error) {
func (s *textureService) ToggleFavorite(ctx context.Context, userID, textureID int64) (bool, error) {
// 确保材质存在
texture, err := s.textureRepo.FindByID(textureID)
if err != nil {
@@ -184,12 +255,12 @@ func (s *textureServiceImpl) ToggleFavorite(userID, textureID int64) (bool, erro
return true, nil
}
func (s *textureServiceImpl) GetUserFavorites(userID int64, page, pageSize int) ([]*model.Texture, int64, error) {
func (s *textureService) GetUserFavorites(ctx context.Context, userID int64, page, pageSize int) ([]*model.Texture, int64, error) {
page, pageSize = NormalizePagination(page, pageSize)
return s.textureRepo.GetUserFavorites(userID, page, pageSize)
}
func (s *textureServiceImpl) CheckUploadLimit(uploaderID int64, maxTextures int) error {
func (s *textureService) CheckUploadLimit(ctx context.Context, uploaderID int64, maxTextures int) error {
count, err := s.textureRepo.CountByUploaderID(uploaderID)
if err != nil {
return err