Initial backend repository commit.
Set up project files and add .gitignore to exclude local build/runtime artifacts. Made-with: Cursor
This commit is contained in:
169
internal/service/notification_service.go
Normal file
169
internal/service/notification_service.go
Normal file
@@ -0,0 +1,169 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"carrot_bbs/internal/cache"
|
||||
"carrot_bbs/internal/model"
|
||||
"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) *NotificationService {
|
||||
return &NotificationService{
|
||||
notificationRepo: notificationRepo,
|
||||
cache: cache.GetCache(),
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 错误定义
|
||||
var ErrUnauthorizedNotification = &ServiceError{Code: 403, Message: "unauthorized to delete this notification"}
|
||||
Reference in New Issue
Block a user