package logic import ( "context" "spark-server/internal/module/moment/entity" "spark-server/internal/pkg/errs" ) func (s *Service) Feed(ctx context.Context, viewerID, cursor int64, limit int) (*ListResult, error) { if !s.ready() || viewerID <= 0 { return nil, errs.ErrUnauthorized } limit = entity.ClampLimit(limit) authors, err := s.feedAuthors(ctx, viewerID) if err != nil { return nil, err } picked := make([]*entity.Post, 0, limit) for range entity.OverfetchRounds { batch, err := s.repo.ListByAuthors(ctx, authors, cursor, entity.Overfetch) if err != nil { return nil, err } if len(batch) == 0 { break } vis, err := s.visFor(ctx, viewerID, batch, false) if err != nil { return nil, err } for _, p := range batch { cursor = p.ID if !vis.canSee(p) { continue } picked = append(picked, p) if len(picked) >= limit { break } } if len(picked) >= limit || len(batch) < entity.Overfetch { break } } return s.listResult(ctx, viewerID, picked, false) } func (s *Service) feedAuthors(ctx context.Context, viewerID int64) ([]int64, error) { ids, err := s.friends.ListFriendIDs(ctx, viewerID) if err != nil { return nil, err } hideHim, err := s.repo.HideHimIDs(ctx, viewerID) if err != nil { return nil, err } skip := idSet(hideHim) blocked, err := s.friends.ListBlockedPeerIDs(ctx, viewerID) if err != nil { return nil, err } for _, id := range blocked { skip[id] = true } out := make([]int64, 0, len(ids)+1) out = append(out, viewerID) for _, id := range ids { if !skip[id] { out = append(out, id) } } return out, nil } func (s *Service) listResult(ctx context.Context, viewer int64, posts []*entity.Post, full bool) (*ListResult, error) { views, err := s.attachViews(ctx, viewer, posts, full) if err != nil { return nil, err } next := int64(0) if len(posts) > 0 { next = posts[len(posts)-1].ID } return &ListResult{Items: views, NextCursor: next}, nil }