Files
backend/internal/service/notification_service.go
lafay c6848aba06
All checks were successful
Build Backend / build (push) Successful in 12m45s
Build Backend / build-docker (push) Successful in 2m40s
refactor: update repository interfaces and improve dependency injection
- Refactored repository structures to use interfaces instead of concrete types, enhancing flexibility and testability.
- Updated various repository methods to accept interfaces, allowing for better dependency management.
- Modified wire generation to accommodate new repository interfaces, ensuring proper service injection throughout the application.
- Enhanced handler methods to utilize DTOs for filtering and data handling, improving code clarity and maintainability.
2026-03-26 18:14:16 +08:00

177 lines
4.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"context"
"time"
"carrot_bbs/internal/cache"
apperrors "carrot_bbs/internal/errors"
"carrot_bbs/internal/model"
"carrot_bbs/internal/pkg/cursor"
"carrot_bbs/internal/repository"
)
// 缓存TTL常量
const (
NotificationUnreadCountTTL = 30 * time.Second // 通知未读数缓存30秒
NotificationNullTTL = 5 * time.Second
NotificationCacheJitter = 0.1
)
// NotificationService 通知服务
type NotificationService struct {
notificationRepo repository.NotificationRepository
cache cache.Cache
}
// NewNotificationService 创建通知服务
func NewNotificationService(notificationRepo repository.NotificationRepository, cacheBackend cache.Cache) *NotificationService {
return &NotificationService{
notificationRepo: notificationRepo,
cache: cacheBackend,
}
}
// Create 创建通知
func (s *NotificationService) Create(ctx context.Context, userID string, notificationType model.NotificationType, title, content string) (*model.Notification, error) {
notification := &model.Notification{
UserID: userID,
Type: notificationType,
Title: title,
Content: content,
IsRead: false,
}
err := s.notificationRepo.Create(notification)
if err != nil {
return nil, err
}
// 失效未读数缓存
cache.InvalidateUnreadSystem(s.cache, userID)
return notification, nil
}
// GetByUserID 获取用户通知
func (s *NotificationService) GetByUserID(ctx context.Context, userID string, page, pageSize int, unreadOnly bool) ([]*model.Notification, int64, error) {
return s.notificationRepo.GetByUserID(userID, page, pageSize, unreadOnly)
}
// MarkAsRead 标记为已读
func (s *NotificationService) MarkAsRead(ctx context.Context, id string) error {
err := s.notificationRepo.MarkAsRead(id)
if err != nil {
return err
}
// 注意这里无法获取userID所以不在缓存中失效
// 调用方应该使用MarkAsReadWithUserID方法
return nil
}
// MarkAsReadWithUserID 标记为已读带用户ID用于缓存失效
func (s *NotificationService) MarkAsReadWithUserID(ctx context.Context, id, userID string) error {
err := s.notificationRepo.MarkAsRead(id)
if err != nil {
return err
}
// 失效未读数缓存
cache.InvalidateUnreadSystem(s.cache, userID)
return nil
}
// MarkAllAsRead 标记所有为已读
func (s *NotificationService) MarkAllAsRead(ctx context.Context, userID string) error {
err := s.notificationRepo.MarkAllAsRead(userID)
if err != nil {
return err
}
// 失效未读数缓存
cache.InvalidateUnreadSystem(s.cache, userID)
return nil
}
// Delete 删除通知
func (s *NotificationService) Delete(ctx context.Context, id string) error {
return s.notificationRepo.Delete(id)
}
// GetUnreadCount 获取未读数量(带缓存)
func (s *NotificationService) GetUnreadCount(ctx context.Context, userID string) (int64, error) {
cacheSettings := cache.GetSettings()
unreadTTL := cacheSettings.UnreadCountTTL
if unreadTTL <= 0 {
unreadTTL = NotificationUnreadCountTTL
}
nullTTL := cacheSettings.NullTTL
if nullTTL <= 0 {
nullTTL = NotificationNullTTL
}
jitter := cacheSettings.JitterRatio
if jitter <= 0 {
jitter = NotificationCacheJitter
}
// 生成缓存键
cacheKey := cache.UnreadSystemKey(userID)
return cache.GetOrLoadTyped[int64](
s.cache,
cacheKey,
unreadTTL,
jitter,
nullTTL,
func() (int64, error) {
return s.notificationRepo.GetUnreadCount(userID)
},
)
}
// DeleteNotification 删除通知(带用户验证)
func (s *NotificationService) DeleteNotification(ctx context.Context, id, userID string) error {
// 先检查通知是否属于该用户
notification, err := s.notificationRepo.GetByID(id)
if err != nil {
return err
}
if notification.UserID != userID {
return ErrUnauthorizedNotification
}
err = s.notificationRepo.Delete(id)
if err != nil {
return err
}
// 失效未读数缓存
cache.InvalidateUnreadSystem(s.cache, userID)
return nil
}
// ClearAllNotifications 清空所有通知
func (s *NotificationService) ClearAllNotifications(ctx context.Context, userID string) error {
err := s.notificationRepo.DeleteAllByUserID(userID)
if err != nil {
return err
}
// 失效未读数缓存
cache.InvalidateUnreadSystem(s.cache, userID)
return nil
}
// GetNotificationsByCursor 游标分页获取用户通知
func (s *NotificationService) GetNotificationsByCursor(ctx context.Context, userID string, unreadOnly bool, req *cursor.PageRequest) (*cursor.CursorPageResult[*model.Notification], error) {
return s.notificationRepo.GetNotificationsByCursor(ctx, userID, unreadOnly, req)
}
// 错误定义
var ErrUnauthorizedNotification = apperrors.ErrUnauthorizedNotification