summaryrefslogtreecommitdiff
path: root/internal/timeline
diff options
context:
space:
mode:
Diffstat (limited to 'internal/timeline')
-rw-r--r--internal/timeline/index.go50
-rw-r--r--internal/timeline/manager.go2
-rw-r--r--internal/timeline/postindex.go15
-rw-r--r--internal/timeline/prepare.go18
-rw-r--r--internal/timeline/preparedposts.go18
-rw-r--r--internal/timeline/timeline.go7
6 files changed, 46 insertions, 64 deletions
diff --git a/internal/timeline/index.go b/internal/timeline/index.go
index 56f5c14df..bc1bf996b 100644
--- a/internal/timeline/index.go
+++ b/internal/timeline/index.go
@@ -10,41 +10,6 @@ import (
)
func (t *timeline) IndexBefore(statusID string, include bool, amount int) error {
- // filtered := []*gtsmodel.Status{}
- // offsetStatus := statusID
-
- // grabloop:
- // for len(filtered) < amount {
- // statuses, err := t.db.GetStatusesWhereFollowing(t.accountID, amount, offsetStatus, include, true)
- // if err != nil {
- // if _, ok := err.(db.ErrNoEntries); !ok {
- // return fmt.Errorf("IndexBeforeAndIncluding: error getting statuses from db: %s", err)
- // }
- // break grabloop // we just don't have enough statuses left in the db so index what we've got and then bail
- // }
-
- // for _, s := range statuses {
- // relevantAccounts, err := t.db.PullRelevantAccountsFromStatus(s)
- // if err != nil {
- // continue
- // }
- // visible, err := t.db.StatusVisible(s, t.account, relevantAccounts)
- // if err != nil {
- // continue
- // }
- // if visible {
- // filtered = append(filtered, s)
- // }
- // offsetStatus = s.ID
- // }
- // }
-
- // for _, s := range filtered {
- // if err := t.IndexOne(s.CreatedAt, s.ID); err != nil {
- // return fmt.Errorf("IndexBeforeAndIncluding: error indexing status with id %s: %s", s.ID, err)
- // }
- // }
-
return nil
}
@@ -63,15 +28,11 @@ grabloop:
}
for _, s := range statuses {
- relevantAccounts, err := t.db.PullRelevantAccountsFromStatus(s)
+ timelineable, err := t.filter.StatusHometimelineable(s, t.account)
if err != nil {
continue
}
- visible, err := t.db.StatusVisible(s, t.account, relevantAccounts)
- if err != nil {
- continue
- }
- if visible {
+ if timelineable {
filtered = append(filtered, s)
}
offsetStatus = s.ID
@@ -79,7 +40,7 @@ grabloop:
}
for _, s := range filtered {
- if err := t.IndexOne(s.CreatedAt, s.ID); err != nil {
+ if err := t.IndexOne(s.CreatedAt, s.ID, s.BoostOfID); err != nil {
return fmt.Errorf("IndexBehindAndIncluding: error indexing status with id %s: %s", s.ID, err)
}
}
@@ -91,12 +52,13 @@ func (t *timeline) IndexOneByID(statusID string) error {
return nil
}
-func (t *timeline) IndexOne(statusCreatedAt time.Time, statusID string) error {
+func (t *timeline) IndexOne(statusCreatedAt time.Time, statusID string, boostOfID string) error {
t.Lock()
defer t.Unlock()
postIndexEntry := &postIndexEntry{
- statusID: statusID,
+ statusID: statusID,
+ boostOfID: boostOfID,
}
return t.postIndex.insertIndexed(postIndexEntry)
diff --git a/internal/timeline/manager.go b/internal/timeline/manager.go
index 9d28b5060..c389a6b8a 100644
--- a/internal/timeline/manager.go
+++ b/internal/timeline/manager.go
@@ -105,7 +105,7 @@ func (m *manager) Ingest(status *gtsmodel.Status, timelineAccountID string) erro
t := m.getOrCreateTimeline(timelineAccountID)
l.Trace("ingesting status")
- return t.IndexOne(status.CreatedAt, status.ID)
+ return t.IndexOne(status.CreatedAt, status.ID, status.BoostOfID)
}
func (m *manager) IngestAndPrepare(status *gtsmodel.Status, timelineAccountID string) error {
diff --git a/internal/timeline/postindex.go b/internal/timeline/postindex.go
index 2ab65e087..7142035a7 100644
--- a/internal/timeline/postindex.go
+++ b/internal/timeline/postindex.go
@@ -10,7 +10,8 @@ type postIndex struct {
}
type postIndexEntry struct {
- statusID string
+ statusID string
+ boostOfID string
}
func (p *postIndex) insertIndexed(i *postIndexEntry) error {
@@ -25,14 +26,26 @@ func (p *postIndex) insertIndexed(i *postIndexEntry) error {
}
var insertMark *list.Element
+ var position int
// We need to iterate through the index to make sure we put this post in the appropriate place according to when it was created.
// We also need to make sure we're not inserting a duplicate post -- this can happen sometimes and it's not nice UX (*shudder*).
for e := p.data.Front(); e != nil; e = e.Next() {
+ position = position + 1
+
entry, ok := e.Value.(*postIndexEntry)
if !ok {
return errors.New("index: could not parse e as a postIndexEntry")
}
+ // don't insert this if it's a boost of a status we've seen recently
+ if i.boostOfID != "" {
+ if i.boostOfID == entry.boostOfID || i.boostOfID == entry.statusID {
+ if position < boostReinsertionDepth {
+ return nil
+ }
+ }
+ }
+
// if the post to index is newer than e, insert it before e in the list
if insertMark == nil {
if i.statusID > entry.statusID {
diff --git a/internal/timeline/prepare.go b/internal/timeline/prepare.go
index 1fb1cd714..cd740993c 100644
--- a/internal/timeline/prepare.go
+++ b/internal/timeline/prepare.go
@@ -163,24 +163,8 @@ func (t *timeline) prepare(statusID string) error {
t.account = timelineOwnerAccount
}
- // to convert the status we need relevant accounts from it, so pull them out here
- relevantAccounts, err := t.db.PullRelevantAccountsFromStatus(gtsStatus)
- if err != nil {
- return err
- }
-
- // check if this is a boost...
- var reblogOfStatus *gtsmodel.Status
- if gtsStatus.BoostOfID != "" {
- s := &gtsmodel.Status{}
- if err := t.db.GetByID(gtsStatus.BoostOfID, s); err != nil {
- return err
- }
- reblogOfStatus = s
- }
-
// serialize the status (or, at least, convert it to a form that's ready to be serialized)
- apiModelStatus, err := t.tc.StatusToMasto(gtsStatus, relevantAccounts.StatusAuthor, t.account, relevantAccounts.BoostedAccount, relevantAccounts.ReplyToAccount, reblogOfStatus)
+ apiModelStatus, err := t.tc.StatusToMasto(gtsStatus, t.account)
if err != nil {
return err
}
diff --git a/internal/timeline/preparedposts.go b/internal/timeline/preparedposts.go
index 429ce5415..1976189c8 100644
--- a/internal/timeline/preparedposts.go
+++ b/internal/timeline/preparedposts.go
@@ -28,14 +28,32 @@ func (p *preparedPosts) insertPrepared(i *preparedPostsEntry) error {
}
var insertMark *list.Element
+ var position int
// We need to iterate through the index to make sure we put this post in the appropriate place according to when it was created.
// We also need to make sure we're not inserting a duplicate post -- this can happen sometimes and it's not nice UX (*shudder*).
for e := p.data.Front(); e != nil; e = e.Next() {
+ position = position + 1
+
entry, ok := e.Value.(*preparedPostsEntry)
if !ok {
return errors.New("index: could not parse e as a preparedPostsEntry")
}
+ // don't insert this if it's a boost of a status we've seen recently
+ if i.prepared.Reblog != nil {
+ if entry.prepared.Reblog != nil && i.prepared.Reblog.ID == entry.prepared.Reblog.ID {
+ if position < boostReinsertionDepth {
+ return nil
+ }
+ }
+
+ if i.prepared.Reblog.ID == entry.statusID {
+ if position < boostReinsertionDepth {
+ return nil
+ }
+ }
+ }
+
// if the post to index is newer than e, insert it before e in the list
if insertMark == nil {
if i.statusID > entry.statusID {
diff --git a/internal/timeline/timeline.go b/internal/timeline/timeline.go
index 7408436dc..363c0999c 100644
--- a/internal/timeline/timeline.go
+++ b/internal/timeline/timeline.go
@@ -27,8 +27,11 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/typeutils"
+ "github.com/superseriousbusiness/gotosocial/internal/visibility"
)
+const boostReinsertionDepth = 50
+
// Timeline represents a timeline for one account, and contains indexed and prepared posts.
type Timeline interface {
/*
@@ -59,7 +62,7 @@ type Timeline interface {
*/
// IndexOne puts a status into the timeline at the appropriate place according to its 'createdAt' property.
- IndexOne(statusCreatedAt time.Time, statusID string) error
+ IndexOne(statusCreatedAt time.Time, statusID string, boostOfID string) error
// OldestIndexedPostID returns the id of the rearmost (ie., the oldest) indexed post, or an error if something goes wrong.
// If nothing goes wrong but there's no oldest post, an empty string will be returned so make sure to check for this.
@@ -109,6 +112,7 @@ type timeline struct {
accountID string
account *gtsmodel.Account
db db.DB
+ filter visibility.Filter
tc typeutils.TypeConverter
log *logrus.Logger
sync.Mutex
@@ -121,6 +125,7 @@ func NewTimeline(accountID string, db db.DB, typeConverter typeutils.TypeConvert
preparedPosts: &preparedPosts{},
accountID: accountID,
db: db,
+ filter: visibility.NewFilter(db, log),
tc: typeConverter,
log: log,
}