diff options
Diffstat (limited to 'internal/processing/workers/surfacetimeline.go')
| -rw-r--r-- | internal/processing/workers/surfacetimeline.go | 110 |
1 files changed, 107 insertions, 3 deletions
diff --git a/internal/processing/workers/surfacetimeline.go b/internal/processing/workers/surfacetimeline.go index b1177cd28..0e30f54f7 100644 --- a/internal/processing/workers/surfacetimeline.go +++ b/internal/processing/workers/surfacetimeline.go @@ -20,6 +20,7 @@ package workers import ( "context" + apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model" "code.superseriousbusiness.org/gotosocial/internal/cache/timeline" "code.superseriousbusiness.org/gotosocial/internal/gtscontext" "code.superseriousbusiness.org/gotosocial/internal/gtserror" @@ -37,6 +38,7 @@ import ( // the account, notifications for any local accounts that want // to know when this account posts, and conversations containing the status. func (s *Surface) timelineAndNotifyStatus(ctx context.Context, status *gtsmodel.Status) error { + // Ensure status fully populated; including account, mentions, etc. if err := s.State.DB.PopulateStatus(ctx, status); err != nil { return gtserror.Newf("error populating status with id %s: %w", status.ID, err) @@ -59,6 +61,11 @@ func (s *Surface) timelineAndNotifyStatus(ctx context.Context, status *gtsmodel. }) } + // Stream the status for public timelines for all local users as update msg. + if err := s.timelineStatusForPublic(ctx, status, s.Stream.Update); err != nil { + return err + } + // Timeline the status for each local follower of this account. This will // also handle notifying any followers with notify set to true on their follow. homeTimelinedAccountIDs := s.timelineAndNotifyStatusForFollowers(ctx, status, follows) @@ -68,16 +75,18 @@ func (s *Surface) timelineAndNotifyStatus(ctx context.Context, status *gtsmodel. return gtserror.Newf("error timelining status %s for tag followers: %w", status.ID, err) } - // Notify each local account that's mentioned by this status. + // Notify each local account mentioned by status. if err := s.notifyMentions(ctx, status); err != nil { return gtserror.Newf("error notifying status mentions for status %s: %w", status.ID, err) } - // Update any conversations containing this status, and send conversation notifications. + // Update any conversations containing this status, and get notifications for them. notifications, err := s.Conversations.UpdateConversationsForStatus(ctx, status) if err != nil { return gtserror.Newf("error updating conversations for status %s: %w", status.ID, err) } + + // Stream these conversation notfications. for _, notification := range notifications { s.Stream.Conversation(ctx, notification.AccountID, notification.Conversation) } @@ -85,6 +94,95 @@ func (s *Surface) timelineAndNotifyStatus(ctx context.Context, status *gtsmodel. return nil } +// timelineStatusForPublic timelines the given status +// to LOCAL and PUBLIC (i.e. federated) timelines. +func (s *Surface) timelineStatusForPublic( + ctx context.Context, + status *gtsmodel.Status, + streamFn func(context.Context, *gtsmodel.Account, *apimodel.Status, string), +) error { + // Nil check function + // outside main loop. + if streamFn == nil { + panic("nil func") + } + + if status.Visibility != gtsmodel.VisibilityPublic || + status.BoostOfID != "" { + // Fast code path, if it's not "public" + // or a boost, don't public timeline it. + return nil + } + + // Get a list of all our local users. + users, err := s.State.DB.GetAllUsers(ctx) + if err != nil { + return gtserror.Newf("error getting local users: %v", err) + } + + // Iterate our list of users. + isLocal := status.IsLocal() + for _, user := range users { + + // Check whether this status should be visible this user on public timelines. + visible, err := s.VisFilter.StatusPublicTimelineable(ctx, user.Account, status) + if err != nil { + log.Errorf(ctx, "error checking status %s visibility: %v", status.URI, err) + continue + } + + if !visible { + continue + } + + // Check whether this status is muted in any form by this user. + muted, err := s.MuteFilter.StatusMuted(ctx, user.Account, status) + if err != nil { + log.Errorf(ctx, "error checking status %s mutes: %v", status.URI, err) + continue + } + + if muted { + continue + } + + // Get status-filter results for this status in context by this user. + filtered, hidden, err := s.StatusFilter.StatusFilterResultsInContext(ctx, + user.Account, + status, + gtsmodel.FilterContextPublic, + ) + if err != nil { + log.Errorf(ctx, "error getting status %s filter results: %v", status.URI, err) + continue + } + + if hidden { + continue + } + + // Now all checks / filters are passed, convert status to frontend model. + apiStatus, err := s.Converter.StatusToAPIStatus(ctx, status, user.Account) + if err != nil { + log.Errorf(ctx, "error converting status %s: %v", status.URI, err) + continue + } + + // Set API model filter results. + apiStatus.Filtered = filtered + + if isLocal { + // This is local status, send it to local timeline stream. + streamFn(ctx, user.Account, apiStatus, stream.TimelineLocal) + } + + // For public timeline stream, send all local / remote statuses. + streamFn(ctx, user.Account, apiStatus, stream.TimelinePublic) + } + + return nil +} + // timelineAndNotifyStatusForFollowers iterates through the given // slice of followers of the account that posted the given status, // adding the status to list timelines + home timelines of each @@ -409,8 +507,9 @@ func (s *Surface) timelineAndNotifyStatusForTagFollowers( status = status.BoostOf } + var errs gtserror.MultiError + // Insert the status into the home timeline of each tag follower. - errs := gtserror.MultiError{} for _, tagFollowerAccount := range tagFollowerAccounts { _ = s.timelineStatus(ctx, s.State.Caches.Timelines.Home.MustGet(tagFollowerAccount.ID), @@ -537,6 +636,11 @@ func (s *Surface) timelineStatusUpdate(ctx context.Context, status *gtsmodel.Sta }) } + // Stream the status update for public timelines for all of our local users. + if err := s.timelineStatusForPublic(ctx, status, s.Stream.StatusUpdate); err != nil { + return err + } + // Push updated status to streams for each local follower of this account. homeTimelinedAccountIDs := s.timelineStatusUpdateForFollowers(ctx, status, follows) |
