spark-server/internal/module/square/logic/service.go
DESKTOP-L8OUL9F\gfl0034 d604cffe84 fix: 发现流补上已有机器人的短帖
发现列表之前没有机器人帖。打开广场发现时,给已有机器人各写一条原创短帖。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-18 22:40:51 +08:00

106 lines
3.9 KiB
Go

package logic
import (
"context"
"sync"
"sync/atomic"
friendentity "spark-server/internal/module/friend/entity"
"spark-server/internal/module/square/entity"
userentity "spark-server/internal/module/user/entity"
"spark-server/internal/pkg/media"
"go.uber.org/zap"
)
// Repository persists square data. Model implements it.
type Repository interface {
CreatePost(ctx context.Context, post *entity.Post, audience []int64) error
CreateBotPost(ctx context.Context, post *entity.Post) error
GetPost(ctx context.Context, id int64) (*entity.Post, error)
ListPublicFeed(ctx context.Context, channel entity.Channel, q entity.FeedListQuery) ([]*entity.Post, error)
ListByAuthor(ctx context.Context, channel entity.Channel, authorID, cursor int64, limit int) ([]*entity.Post, error)
SoftDeletePost(ctx context.Context, userID, postID int64) (*entity.Post, error)
SoftDeleteExpiredBotPosts(ctx context.Context, nowMS int64, limit int) ([]*entity.Post, error)
ListAudience(ctx context.Context, postIDs []int64) (map[int64][]int64, error)
ListLikes(ctx context.Context, postIDs []int64) (map[int64][]*entity.Like, error)
AddLike(ctx context.Context, like *entity.Like) (created bool, err error)
RemoveLike(ctx context.Context, postID, userID int64) error
ListComments(ctx context.Context, postIDs []int64) (map[int64][]*entity.Comment, error)
GetComment(ctx context.Context, id int64) (*entity.Comment, error)
AddComment(ctx context.Context, c *entity.Comment) error
SoftDeleteComment(ctx context.Context, id int64) error
CreateNotices(ctx context.Context, rows []*entity.Notice) error
ListNotices(ctx context.Context, userID int64, channel entity.Channel, cursor int64, limit int) ([]*entity.Notice, error)
MarkNoticesRead(ctx context.Context, userID int64, channel entity.Channel, cursor int64) error
GetNoticeState(ctx context.Context, userID int64, channel entity.Channel) (*entity.NoticeState, error)
LatestNoticeID(ctx context.Context, userID int64, channel entity.Channel) (int64, error)
AdvanceNoticeRead(ctx context.Context, userID int64, channel entity.Channel, noticeID int64) error
ListAllByAuthor(ctx context.Context, authorID int64) ([]*entity.Post, error)
PurgeUser(ctx context.Context, userID int64) error
}
// Friends is the friend graph used for audience and block checks.
type Friends interface {
AreFriends(ctx context.Context, a, b int64) (bool, error)
ListBlockedPeerIDs(ctx context.Context, userID int64) ([]int64, error)
Relation(ctx context.Context, userID, peerID int64) (*friendentity.Relation, error)
BlockedEither(ctx context.Context, a, b int64) (bool, error)
}
// Users loads profile cards.
type Users interface {
Get(ctx context.Context, id int64) (*userentity.User, error)
GetByEmail(ctx context.Context, email string) (*userentity.User, error)
}
// Objects deletes square media. Nil skips GC.
type Objects interface {
Delete(ctx context.Context, key string) error
}
// IDGen issues Snowflake ids.
type IDGen interface {
NextID() (int64, error)
}
// Service is the square use-case layer.
type Service struct {
repo Repository
friends Friends
users Users
objects Objects
ids IDGen
burst *burst
media media.Policy
log *zap.Logger
discoverMu sync.Mutex
discoverReady atomic.Bool
}
func NewService(repo Repository, friends Friends, users Users, objects Objects, ids IDGen) *Service {
return &Service{repo: repo, friends: friends, users: users, objects: objects, ids: ids, burst: newBurst(), log: zap.NewNop()}
}
// ConfigureMedia sets user-path media detection (bots compress via squarebot MediaCompressor).
func (s *Service) ConfigureMedia(p media.Policy, log *zap.Logger) {
if s == nil {
return
}
s.media = p
if log != nil {
s.log = log
}
}
func (s *Service) ready() bool {
return s != nil && s.repo != nil && s.friends != nil && s.users != nil && s.ids != nil
}
func normalizeChannel(ch entity.Channel) entity.Channel {
if ch == "" {
return entity.ChannelSquare
}
return ch
}