refactor(server): decouple services and improve architecture
- Introduce interfaces for all major services (JWT, PostAI, Comment, Message, Notification, QRCodeLogin, Upload, Vote, etc.) to support dependency inversion. - Move query parameters from `internal/dto` to a new `internal/query` package to separate request payloads from data transfer objects. - Refactor `internal/router` to use embedded `RouterDeps` for cleaner dependency management. - Decouple handlers from repositories by injecting services instead of direct repository access, ensuring proper layering. - Improve database initialization by moving it from `internal/model` to `internal/database`. - Optimize message decryption by implementing a more efficient `BatchDecrypt` method in `MessageEncryptor` using a worker pool. - Enhance error handling and security by implementing fail-fast checks for encryption key length during startup. - Clean up unused code, including the `avatar` package and several unused DTOs.
This commit is contained in:
@@ -8,20 +8,30 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
apperrors "with_you/internal/errors"
|
||||
"with_you/internal/cache"
|
||||
"with_you/internal/dto"
|
||||
apperrors "with_you/internal/errors"
|
||||
"with_you/internal/model"
|
||||
"with_you/internal/pkg/hook"
|
||||
"with_you/internal/repository"
|
||||
)
|
||||
|
||||
// VoteService 投票服务
|
||||
type VoteService struct {
|
||||
// VoteService 投票服务接口
|
||||
type VoteService interface {
|
||||
CreateVotePost(ctx context.Context, userID string, req *dto.CreateVotePostRequest) (*dto.PostResponse, error)
|
||||
GetVoteOptions(postID string) ([]dto.VoteOptionDTO, error)
|
||||
GetVoteResult(postID, userID string) (*dto.VoteResultDTO, error)
|
||||
Vote(ctx context.Context, postID, userID, optionID string) error
|
||||
Unvote(ctx context.Context, postID, userID string) error
|
||||
UpdateVoteOption(ctx context.Context, postID, optionID, userID, content string) error
|
||||
}
|
||||
|
||||
// voteService 投票服务实现
|
||||
type voteService struct {
|
||||
voteRepo repository.VoteRepository
|
||||
postRepo repository.PostRepository
|
||||
cache cache.Cache
|
||||
postAIService *PostAIService
|
||||
postAIService PostAIService
|
||||
systemMessageService SystemMessageService
|
||||
hookManager *hook.Manager
|
||||
logService *LogService
|
||||
@@ -31,12 +41,12 @@ func NewVoteService(
|
||||
voteRepo repository.VoteRepository,
|
||||
postRepo repository.PostRepository,
|
||||
cache cache.Cache,
|
||||
postAIService *PostAIService,
|
||||
postAIService PostAIService,
|
||||
systemMessageService SystemMessageService,
|
||||
hookManager *hook.Manager,
|
||||
logService *LogService,
|
||||
) *VoteService {
|
||||
return &VoteService{
|
||||
) VoteService {
|
||||
return &voteService{
|
||||
voteRepo: voteRepo,
|
||||
postRepo: postRepo,
|
||||
cache: cache,
|
||||
@@ -48,7 +58,7 @@ func NewVoteService(
|
||||
}
|
||||
|
||||
// CreateVotePost 创建投票帖子
|
||||
func (s *VoteService) CreateVotePost(ctx context.Context, userID string, req *dto.CreateVotePostRequest) (*dto.PostResponse, error) {
|
||||
func (s *voteService) CreateVotePost(ctx context.Context, userID string, req *dto.CreateVotePostRequest) (*dto.PostResponse, error) {
|
||||
if len(req.VoteOptions) < 2 {
|
||||
return nil, errors.New("投票选项至少需要2个")
|
||||
}
|
||||
@@ -108,7 +118,7 @@ func (s *VoteService) CreateVotePost(ctx context.Context, userID string, req *dt
|
||||
return s.convertToPostResponse(createdPost, userID), nil
|
||||
}
|
||||
|
||||
func (s *VoteService) reviewVotePostAsync(postID, userID, title, content string, images []string) {
|
||||
func (s *voteService) reviewVotePostAsync(postID, userID, title, content string, images []string) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Printf("[ERROR] Panic in vote post moderation async flow, fallback publish post=%s panic=%v", postID, r)
|
||||
@@ -183,7 +193,7 @@ func (s *VoteService) reviewVotePostAsync(postID, userID, title, content string,
|
||||
cache.InvalidatePostList(s.cache)
|
||||
}
|
||||
|
||||
func (s *VoteService) updateModerationStatusWithRetry(postID string, status model.PostStatus, rejectReason string, reviewedBy string) error {
|
||||
func (s *voteService) updateModerationStatusWithRetry(postID string, status model.PostStatus, rejectReason string, reviewedBy string) error {
|
||||
const maxAttempts = 3
|
||||
const retryDelay = 200 * time.Millisecond
|
||||
|
||||
@@ -203,7 +213,7 @@ func (s *VoteService) updateModerationStatusWithRetry(postID string, status mode
|
||||
return lastErr
|
||||
}
|
||||
|
||||
func (s *VoteService) notifyModerationRejected(userID, reason string) {
|
||||
func (s *voteService) notifyModerationRejected(userID, reason string) {
|
||||
if s.systemMessageService == nil || strings.TrimSpace(userID) == "" {
|
||||
return
|
||||
}
|
||||
@@ -224,7 +234,7 @@ func (s *VoteService) notifyModerationRejected(userID, reason string) {
|
||||
}
|
||||
|
||||
// resolveVoteOptions 解析投票选项(优先从 segments 读取,兼容旧数据从 vote_options 表读取)
|
||||
func (s *VoteService) resolveVoteOptions(postID string, segments model.MessageSegments) ([]dto.VoteOptionDTO, error) {
|
||||
func (s *voteService) resolveVoteOptions(postID string, segments model.MessageSegments) ([]dto.VoteOptionDTO, error) {
|
||||
if len(segments) > 0 {
|
||||
voteData := dto.ExtractVoteSegmentData(segments)
|
||||
if voteData != nil {
|
||||
@@ -262,7 +272,7 @@ func (s *VoteService) resolveVoteOptions(postID string, segments model.MessageSe
|
||||
}
|
||||
|
||||
// GetVoteOptions 获取投票选项(优先从 segments 读取,兼容旧数据从 vote_options 表读取)
|
||||
func (s *VoteService) GetVoteOptions(postID string) ([]dto.VoteOptionDTO, error) {
|
||||
func (s *voteService) GetVoteOptions(postID string) ([]dto.VoteOptionDTO, error) {
|
||||
post, err := s.postRepo.GetByID(postID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -272,7 +282,7 @@ func (s *VoteService) GetVoteOptions(postID string) ([]dto.VoteOptionDTO, error)
|
||||
}
|
||||
|
||||
// GetVoteResult 获取投票结果(包含用户投票状态)
|
||||
func (s *VoteService) GetVoteResult(postID, userID string) (*dto.VoteResultDTO, error) {
|
||||
func (s *voteService) GetVoteResult(postID, userID string) (*dto.VoteResultDTO, error) {
|
||||
post, err := s.postRepo.GetByID(postID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -306,7 +316,7 @@ func (s *VoteService) GetVoteResult(postID, userID string) (*dto.VoteResultDTO,
|
||||
}
|
||||
|
||||
// Vote 投票
|
||||
func (s *VoteService) Vote(ctx context.Context, postID, userID, optionID string) error {
|
||||
func (s *voteService) Vote(ctx context.Context, postID, userID, optionID string) error {
|
||||
// 调用voteRepo.Vote
|
||||
err := s.voteRepo.Vote(postID, userID, optionID)
|
||||
if err != nil {
|
||||
@@ -320,7 +330,7 @@ func (s *VoteService) Vote(ctx context.Context, postID, userID, optionID string)
|
||||
}
|
||||
|
||||
// Unvote 取消投票
|
||||
func (s *VoteService) Unvote(ctx context.Context, postID, userID string) error {
|
||||
func (s *voteService) Unvote(ctx context.Context, postID, userID string) error {
|
||||
// 调用voteRepo.Unvote
|
||||
err := s.voteRepo.Unvote(postID, userID)
|
||||
if err != nil {
|
||||
@@ -334,7 +344,7 @@ func (s *VoteService) Unvote(ctx context.Context, postID, userID string) error {
|
||||
}
|
||||
|
||||
// UpdateVoteOption 更新投票选项(作者权限)
|
||||
func (s *VoteService) UpdateVoteOption(ctx context.Context, postID, optionID, userID, content string) error {
|
||||
func (s *voteService) UpdateVoteOption(ctx context.Context, postID, optionID, userID, content string) error {
|
||||
// 获取帖子信息
|
||||
post, err := s.postRepo.GetByID(postID)
|
||||
if err != nil {
|
||||
@@ -351,7 +361,7 @@ func (s *VoteService) UpdateVoteOption(ctx context.Context, postID, optionID, us
|
||||
}
|
||||
|
||||
// convertToPostResponse 将Post模型转换为PostResponse DTO
|
||||
func (s *VoteService) convertToPostResponse(post *model.Post, currentUserID string) *dto.PostResponse {
|
||||
func (s *voteService) convertToPostResponse(post *model.Post, currentUserID string) *dto.PostResponse {
|
||||
if post == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user