summaryrefslogtreecommitdiff
path: root/internal/timeline
diff options
context:
space:
mode:
authorLibravatar tobi <31960611+tsmethurst@users.noreply.github.com>2021-08-25 15:34:33 +0200
committerLibravatar GitHub <noreply@github.com>2021-08-25 15:34:33 +0200
commit2dc9fc1626507bb54417fc4a1920b847cafb27a2 (patch)
tree4ddeac479b923db38090aac8bd9209f3646851c1 /internal/timeline
parentManually approves followers (#146) (diff)
downloadgotosocial-2dc9fc1626507bb54417fc4a1920b847cafb27a2.tar.xz
Pg to bun (#148)
* start moving to bun * changing more stuff * more * and yet more * tests passing * seems stable now * more big changes * small fix * little fixes
Diffstat (limited to 'internal/timeline')
-rw-r--r--internal/timeline/get.go41
-rw-r--r--internal/timeline/get_test.go37
-rw-r--r--internal/timeline/index.go31
-rw-r--r--internal/timeline/index_test.go47
-rw-r--r--internal/timeline/manager.go79
-rw-r--r--internal/timeline/manager_test.go37
-rw-r--r--internal/timeline/prepare.go35
-rw-r--r--internal/timeline/remove.go5
-rw-r--r--internal/timeline/timeline.go41
9 files changed, 182 insertions, 171 deletions
diff --git a/internal/timeline/get.go b/internal/timeline/get.go
index d800da4e3..a00613dc0 100644
--- a/internal/timeline/get.go
+++ b/internal/timeline/get.go
@@ -20,6 +20,7 @@ package timeline
import (
"container/list"
+ "context"
"errors"
"fmt"
@@ -29,7 +30,7 @@ import (
const retries = 5
-func (t *timeline) Get(amount int, maxID string, sinceID string, minID string, prepareNext bool) ([]*apimodel.Status, error) {
+func (t *timeline) Get(ctx context.Context, amount int, maxID string, sinceID string, minID string, prepareNext bool) ([]*apimodel.Status, error) {
l := t.log.WithFields(logrus.Fields{
"func": "Get",
"accountID": t.accountID,
@@ -46,14 +47,15 @@ func (t *timeline) Get(amount int, maxID string, sinceID string, minID string, p
// no params are defined to just fetch from the top
// this is equivalent to a user asking for the top x posts from their timeline
if maxID == "" && sinceID == "" && minID == "" {
- statuses, err = t.GetXFromTop(amount)
+ statuses, err = t.GetXFromTop(ctx, amount)
// aysnchronously prepare the next predicted query so it's ready when the user asks for it
if len(statuses) != 0 {
nextMaxID := statuses[len(statuses)-1].ID
if prepareNext {
// already cache the next query to speed up scrolling
go func() {
- if err := t.prepareNextQuery(amount, nextMaxID, "", ""); err != nil {
+ // use context.Background() because we don't want the query to abort when the request finishes
+ if err := t.prepareNextQuery(context.Background(), amount, nextMaxID, "", ""); err != nil {
l.Errorf("error preparing next query: %s", err)
}
}()
@@ -65,14 +67,15 @@ func (t *timeline) Get(amount int, maxID string, sinceID string, minID string, p
// this is equivalent to a user asking for the next x posts from their timeline, starting from maxID
if maxID != "" && sinceID == "" {
attempts := 0
- statuses, err = t.GetXBehindID(amount, maxID, &attempts)
+ statuses, err = t.GetXBehindID(ctx, amount, maxID, &attempts)
// aysnchronously prepare the next predicted query so it's ready when the user asks for it
if len(statuses) != 0 {
nextMaxID := statuses[len(statuses)-1].ID
if prepareNext {
// already cache the next query to speed up scrolling
go func() {
- if err := t.prepareNextQuery(amount, nextMaxID, "", ""); err != nil {
+ // use context.Background() because we don't want the query to abort when the request finishes
+ if err := t.prepareNextQuery(context.Background(), amount, nextMaxID, "", ""); err != nil {
l.Errorf("error preparing next query: %s", err)
}
}()
@@ -83,25 +86,25 @@ func (t *timeline) Get(amount int, maxID string, sinceID string, minID string, p
// maxID is defined and sinceID || minID are as well, so take a slice between them
// this is equivalent to a user asking for posts older than x but newer than y
if maxID != "" && sinceID != "" {
- statuses, err = t.GetXBetweenID(amount, maxID, minID)
+ statuses, err = t.GetXBetweenID(ctx, amount, maxID, minID)
}
if maxID != "" && minID != "" {
- statuses, err = t.GetXBetweenID(amount, maxID, minID)
+ statuses, err = t.GetXBetweenID(ctx, amount, maxID, minID)
}
// maxID isn't defined, but sinceID || minID are, so take x before
// this is equivalent to a user asking for posts newer than x (eg., refreshing the top of their timeline)
if maxID == "" && sinceID != "" {
- statuses, err = t.GetXBeforeID(amount, sinceID, true)
+ statuses, err = t.GetXBeforeID(ctx, amount, sinceID, true)
}
if maxID == "" && minID != "" {
- statuses, err = t.GetXBeforeID(amount, minID, true)
+ statuses, err = t.GetXBeforeID(ctx, amount, minID, true)
}
return statuses, err
}
-func (t *timeline) GetXFromTop(amount int) ([]*apimodel.Status, error) {
+func (t *timeline) GetXFromTop(ctx context.Context, amount int) ([]*apimodel.Status, error) {
// make a slice of statuses with the length we need to return
statuses := make([]*apimodel.Status, 0, amount)
@@ -111,7 +114,7 @@ func (t *timeline) GetXFromTop(amount int) ([]*apimodel.Status, error) {
// make sure we have enough posts prepared to return
if t.preparedPosts.data.Len() < amount {
- if err := t.PrepareFromTop(amount); err != nil {
+ if err := t.PrepareFromTop(ctx, amount); err != nil {
return nil, err
}
}
@@ -133,7 +136,7 @@ func (t *timeline) GetXFromTop(amount int) ([]*apimodel.Status, error) {
return statuses, nil
}
-func (t *timeline) GetXBehindID(amount int, behindID string, attempts *int) ([]*apimodel.Status, error) {
+func (t *timeline) GetXBehindID(ctx context.Context, amount int, behindID string, attempts *int) ([]*apimodel.Status, error) {
l := t.log.WithFields(logrus.Fields{
"func": "GetXBehindID",
"amount": amount,
@@ -174,10 +177,10 @@ findMarkLoop:
// we didn't find it, so we need to make sure it's indexed and prepared and then try again
// this can happen when a user asks for really old posts
if behindIDMark == nil {
- if err := t.PrepareBehind(behindID, amount); err != nil {
+ if err := t.PrepareBehind(ctx, behindID, amount); err != nil {
return nil, fmt.Errorf("GetXBehindID: error preparing behind and including ID %s", behindID)
}
- oldestID, err := t.OldestPreparedPostID()
+ oldestID, err := t.OldestPreparedPostID(ctx)
if err != nil {
return nil, err
}
@@ -194,12 +197,12 @@ findMarkLoop:
return statuses, nil
}
l.Trace("trying GetXBehindID again")
- return t.GetXBehindID(amount, behindID, attempts)
+ return t.GetXBehindID(ctx, amount, behindID, attempts)
}
// make sure we have enough posts prepared behind it to return what we're being asked for
if t.preparedPosts.data.Len() < amount+position {
- if err := t.PrepareBehind(behindID, amount); err != nil {
+ if err := t.PrepareBehind(ctx, behindID, amount); err != nil {
return nil, err
}
}
@@ -224,7 +227,7 @@ serveloop:
return statuses, nil
}
-func (t *timeline) GetXBeforeID(amount int, beforeID string, startFromTop bool) ([]*apimodel.Status, error) {
+func (t *timeline) GetXBeforeID(ctx context.Context, amount int, beforeID string, startFromTop bool) ([]*apimodel.Status, error) {
// make a slice of statuses with the length we need to return
statuses := make([]*apimodel.Status, 0, amount)
@@ -295,7 +298,7 @@ findMarkLoop:
return statuses, nil
}
-func (t *timeline) GetXBetweenID(amount int, behindID string, beforeID string) ([]*apimodel.Status, error) {
+func (t *timeline) GetXBetweenID(ctx context.Context, amount int, behindID string, beforeID string) ([]*apimodel.Status, error) {
// make a slice of statuses with the length we need to return
statuses := make([]*apimodel.Status, 0, amount)
@@ -327,7 +330,7 @@ findMarkLoop:
// make sure we have enough posts prepared behind it to return what we're being asked for
if t.preparedPosts.data.Len() < amount+position {
- if err := t.PrepareBehind(behindID, amount); err != nil {
+ if err := t.PrepareBehind(ctx, behindID, amount); err != nil {
return nil, err
}
}
diff --git a/internal/timeline/get_test.go b/internal/timeline/get_test.go
index 0866f3bdd..96c333c5f 100644
--- a/internal/timeline/get_test.go
+++ b/internal/timeline/get_test.go
@@ -19,6 +19,7 @@
package timeline_test
import (
+ "context"
"testing"
"time"
@@ -45,14 +46,14 @@ func (suite *GetTestSuite) SetupTest() {
testrig.StandardDBSetup(suite.db, nil)
// let's take local_account_1 as the timeline owner
- tl, err := timeline.NewTimeline(suite.testAccounts["local_account_1"].ID, suite.db, suite.tc, suite.log)
+ tl, err := timeline.NewTimeline(context.Background(), suite.testAccounts["local_account_1"].ID, suite.db, suite.tc, suite.log)
if err != nil {
suite.FailNow(err.Error())
}
// prepare the timeline by just shoving all test statuses in it -- let's not be fussy about who sees what
for _, s := range suite.testStatuses {
- _, err := tl.IndexAndPrepareOne(s.CreatedAt, s.ID, s.BoostOfID, s.AccountID, s.BoostOfAccountID)
+ _, err := tl.IndexAndPrepareOne(context.Background(), s.CreatedAt, s.ID, s.BoostOfID, s.AccountID, s.BoostOfAccountID)
if err != nil {
suite.FailNow(err.Error())
}
@@ -67,7 +68,7 @@ func (suite *GetTestSuite) TearDownTest() {
func (suite *GetTestSuite) TestGetDefault() {
// get 10 20 the top and don't prepare the next query
- statuses, err := suite.timeline.Get(20, "", "", "", false)
+ statuses, err := suite.timeline.Get(context.Background(), 20, "", "", "", false)
if err != nil {
suite.FailNow(err.Error())
}
@@ -89,7 +90,7 @@ func (suite *GetTestSuite) TestGetDefault() {
func (suite *GetTestSuite) TestGetDefaultPrepareNext() {
// get 10 from the top and prepare the next query
- statuses, err := suite.timeline.Get(10, "", "", "", true)
+ statuses, err := suite.timeline.Get(context.Background(), 10, "", "", "", true)
if err != nil {
suite.FailNow(err.Error())
}
@@ -113,7 +114,7 @@ func (suite *GetTestSuite) TestGetDefaultPrepareNext() {
func (suite *GetTestSuite) TestGetMaxID() {
// ask for 10 with a max ID somewhere in the middle of the stack
- statuses, err := suite.timeline.Get(10, "01F8MHBQCBTDKN6X5VHGMMN4MA", "", "", false)
+ statuses, err := suite.timeline.Get(context.Background(), 10, "01F8MHBQCBTDKN6X5VHGMMN4MA", "", "", false)
if err != nil {
suite.FailNow(err.Error())
}
@@ -135,7 +136,7 @@ func (suite *GetTestSuite) TestGetMaxID() {
func (suite *GetTestSuite) TestGetMaxIDPrepareNext() {
// ask for 10 with a max ID somewhere in the middle of the stack
- statuses, err := suite.timeline.Get(10, "01F8MHBQCBTDKN6X5VHGMMN4MA", "", "", true)
+ statuses, err := suite.timeline.Get(context.Background(), 10, "01F8MHBQCBTDKN6X5VHGMMN4MA", "", "", true)
if err != nil {
suite.FailNow(err.Error())
}
@@ -160,7 +161,7 @@ func (suite *GetTestSuite) TestGetMaxIDPrepareNext() {
func (suite *GetTestSuite) TestGetMinID() {
// ask for 10 with a min ID somewhere in the middle of the stack
- statuses, err := suite.timeline.Get(10, "", "01F8MHBQCBTDKN6X5VHGMMN4MA", "", false)
+ statuses, err := suite.timeline.Get(context.Background(), 10, "", "01F8MHBQCBTDKN6X5VHGMMN4MA", "", false)
if err != nil {
suite.FailNow(err.Error())
}
@@ -182,7 +183,7 @@ func (suite *GetTestSuite) TestGetMinID() {
func (suite *GetTestSuite) TestGetSinceID() {
// ask for 10 with a since ID somewhere in the middle of the stack
- statuses, err := suite.timeline.Get(10, "", "", "01F8MHBQCBTDKN6X5VHGMMN4MA", false)
+ statuses, err := suite.timeline.Get(context.Background(), 10, "", "", "01F8MHBQCBTDKN6X5VHGMMN4MA", false)
if err != nil {
suite.FailNow(err.Error())
}
@@ -204,7 +205,7 @@ func (suite *GetTestSuite) TestGetSinceID() {
func (suite *GetTestSuite) TestGetSinceIDPrepareNext() {
// ask for 10 with a since ID somewhere in the middle of the stack
- statuses, err := suite.timeline.Get(10, "", "", "01F8MHBQCBTDKN6X5VHGMMN4MA", true)
+ statuses, err := suite.timeline.Get(context.Background(), 10, "", "", "01F8MHBQCBTDKN6X5VHGMMN4MA", true)
if err != nil {
suite.FailNow(err.Error())
}
@@ -229,7 +230,7 @@ func (suite *GetTestSuite) TestGetSinceIDPrepareNext() {
func (suite *GetTestSuite) TestGetBetweenID() {
// ask for 10 between these two IDs
- statuses, err := suite.timeline.Get(10, "01F8MHCP5P2NWYQ416SBA0XSEV", "", "01F8MHBQCBTDKN6X5VHGMMN4MA", false)
+ statuses, err := suite.timeline.Get(context.Background(), 10, "01F8MHCP5P2NWYQ416SBA0XSEV", "", "01F8MHBQCBTDKN6X5VHGMMN4MA", false)
if err != nil {
suite.FailNow(err.Error())
}
@@ -251,7 +252,7 @@ func (suite *GetTestSuite) TestGetBetweenID() {
func (suite *GetTestSuite) TestGetBetweenIDPrepareNext() {
// ask for 10 between these two IDs
- statuses, err := suite.timeline.Get(10, "01F8MHCP5P2NWYQ416SBA0XSEV", "", "01F8MHBQCBTDKN6X5VHGMMN4MA", true)
+ statuses, err := suite.timeline.Get(context.Background(), 10, "01F8MHCP5P2NWYQ416SBA0XSEV", "", "01F8MHBQCBTDKN6X5VHGMMN4MA", true)
if err != nil {
suite.FailNow(err.Error())
}
@@ -276,7 +277,7 @@ func (suite *GetTestSuite) TestGetBetweenIDPrepareNext() {
func (suite *GetTestSuite) TestGetXFromTop() {
// get 5 from the top
- statuses, err := suite.timeline.GetXFromTop(5)
+ statuses, err := suite.timeline.GetXFromTop(context.Background(), 5)
if err != nil {
suite.FailNow(err.Error())
}
@@ -300,7 +301,7 @@ func (suite *GetTestSuite) TestGetXBehindID() {
var attempts *int
a := 0
attempts = &a
- statuses, err := suite.timeline.GetXBehindID(3, "01F8MHBQCBTDKN6X5VHGMMN4MA", attempts)
+ statuses, err := suite.timeline.GetXBehindID(context.Background(), 3, "01F8MHBQCBTDKN6X5VHGMMN4MA", attempts)
if err != nil {
suite.FailNow(err.Error())
}
@@ -326,7 +327,7 @@ func (suite *GetTestSuite) TestGetXBehindID0() {
var attempts *int
a := 0
attempts = &a
- statuses, err := suite.timeline.GetXBehindID(3, "0", attempts)
+ statuses, err := suite.timeline.GetXBehindID(context.Background(), 3, "0", attempts)
if err != nil {
suite.FailNow(err.Error())
}
@@ -340,7 +341,7 @@ func (suite *GetTestSuite) TestGetXBehindNonexistentReasonableID() {
var attempts *int
a := 0
attempts = &a
- statuses, err := suite.timeline.GetXBehindID(3, "01F8MHBQCBTDKN6X5VHGMMN4MB", attempts) // change the last A to a B
+ statuses, err := suite.timeline.GetXBehindID(context.Background(), 3, "01F8MHBQCBTDKN6X5VHGMMN4MB", attempts) // change the last A to a B
if err != nil {
suite.FailNow(err.Error())
}
@@ -365,7 +366,7 @@ func (suite *GetTestSuite) TestGetXBehindVeryHighID() {
var attempts *int
a := 0
attempts = &a
- statuses, err := suite.timeline.GetXBehindID(7, "9998MHBQCBTDKN6X5VHGMMN4MA", attempts)
+ statuses, err := suite.timeline.GetXBehindID(context.Background(), 7, "9998MHBQCBTDKN6X5VHGMMN4MA", attempts)
if err != nil {
suite.FailNow(err.Error())
}
@@ -389,7 +390,7 @@ func (suite *GetTestSuite) TestGetXBehindVeryHighID() {
func (suite *GetTestSuite) TestGetXBeforeID() {
// get 3 before the 'middle' id
- statuses, err := suite.timeline.GetXBeforeID(3, "01F8MHBQCBTDKN6X5VHGMMN4MA", true)
+ statuses, err := suite.timeline.GetXBeforeID(context.Background(), 3, "01F8MHBQCBTDKN6X5VHGMMN4MA", true)
if err != nil {
suite.FailNow(err.Error())
}
@@ -412,7 +413,7 @@ func (suite *GetTestSuite) TestGetXBeforeID() {
func (suite *GetTestSuite) TestGetXBeforeIDNoStartFromTop() {
// get 3 before the 'middle' id
- statuses, err := suite.timeline.GetXBeforeID(3, "01F8MHBQCBTDKN6X5VHGMMN4MA", false)
+ statuses, err := suite.timeline.GetXBeforeID(context.Background(), 3, "01F8MHBQCBTDKN6X5VHGMMN4MA", false)
if err != nil {
suite.FailNow(err.Error())
}
diff --git a/internal/timeline/index.go b/internal/timeline/index.go
index 7cffe7ab9..7d7dc8873 100644
--- a/internal/timeline/index.go
+++ b/internal/timeline/index.go
@@ -20,6 +20,7 @@ package timeline
import (
"container/list"
+ "context"
"errors"
"fmt"
"time"
@@ -29,7 +30,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
)
-func (t *timeline) IndexBefore(statusID string, include bool, amount int) error {
+func (t *timeline) IndexBefore(ctx context.Context, statusID string, include bool, amount int) error {
// lazily initialize index if it hasn't been done already
if t.postIndex.data == nil {
t.postIndex.data = &list.List{}
@@ -42,7 +43,7 @@ func (t *timeline) IndexBefore(statusID string, include bool, amount int) error
if include {
// if we have the status with given statusID in the database, include it in the results set as well
s := &gtsmodel.Status{}
- if err := t.db.GetByID(statusID, s); err == nil {
+ if err := t.db.GetByID(ctx, statusID, s); err == nil {
filtered = append(filtered, s)
}
}
@@ -50,7 +51,7 @@ func (t *timeline) IndexBefore(statusID string, include bool, amount int) error
i := 0
grabloop:
for ; len(filtered) < amount && i < 5; i = i + 1 { // try the grabloop 5 times only
- statuses, err := t.db.GetHomeTimeline(t.accountID, "", "", offsetStatus, amount, false)
+ statuses, err := t.db.GetHomeTimeline(ctx, t.accountID, "", "", offsetStatus, amount, false)
if err != nil {
if err == db.ErrNoEntries {
break grabloop // we just don't have enough statuses left in the db so index what we've got and then bail
@@ -59,7 +60,7 @@ grabloop:
}
for _, s := range statuses {
- timelineable, err := t.filter.StatusHometimelineable(s, t.account)
+ timelineable, err := t.filter.StatusHometimelineable(ctx, s, t.account)
if err != nil {
continue
}
@@ -71,7 +72,7 @@ grabloop:
}
for _, s := range filtered {
- if _, err := t.IndexOne(s.CreatedAt, s.ID, s.BoostOfID, s.AccountID, s.BoostOfAccountID); err != nil {
+ if _, err := t.IndexOne(ctx, s.CreatedAt, s.ID, s.BoostOfID, s.AccountID, s.BoostOfAccountID); err != nil {
return fmt.Errorf("IndexBefore: error indexing status with id %s: %s", s.ID, err)
}
}
@@ -79,7 +80,7 @@ grabloop:
return nil
}
-func (t *timeline) IndexBehind(statusID string, include bool, amount int) error {
+func (t *timeline) IndexBehind(ctx context.Context, statusID string, include bool, amount int) error {
l := t.log.WithFields(logrus.Fields{
"func": "IndexBehind",
"include": include,
@@ -121,7 +122,7 @@ positionLoop:
if include {
// if we have the status with given statusID in the database, include it in the results set as well
s := &gtsmodel.Status{}
- if err := t.db.GetByID(statusID, s); err == nil {
+ if err := t.db.GetByID(ctx, statusID, s); err == nil {
filtered = append(filtered, s)
}
}
@@ -130,7 +131,7 @@ positionLoop:
grabloop:
for ; len(filtered) < amount && i < 5; i = i + 1 { // try the grabloop 5 times only
l.Tracef("entering grabloop; i is %d; len(filtered) is %d", i, len(filtered))
- statuses, err := t.db.GetHomeTimeline(t.accountID, offsetStatus, "", "", amount, false)
+ statuses, err := t.db.GetHomeTimeline(ctx, t.accountID, offsetStatus, "", "", amount, false)
if err != nil {
if err == db.ErrNoEntries {
break grabloop // we just don't have enough statuses left in the db so index what we've got and then bail
@@ -140,7 +141,7 @@ grabloop:
l.Tracef("got %d statuses", len(statuses))
for _, s := range statuses {
- timelineable, err := t.filter.StatusHometimelineable(s, t.account)
+ timelineable, err := t.filter.StatusHometimelineable(ctx, s, t.account)
if err != nil {
l.Tracef("status was not hometimelineable: %s", err)
continue
@@ -154,7 +155,7 @@ grabloop:
l.Trace("left grabloop")
for _, s := range filtered {
- if _, err := t.IndexOne(s.CreatedAt, s.ID, s.BoostOfID, s.AccountID, s.BoostOfAccountID); err != nil {
+ if _, err := t.IndexOne(ctx, s.CreatedAt, s.ID, s.BoostOfID, s.AccountID, s.BoostOfAccountID); err != nil {
return fmt.Errorf("IndexBehind: error indexing status with id %s: %s", s.ID, err)
}
}
@@ -163,7 +164,7 @@ grabloop:
return nil
}
-func (t *timeline) IndexOne(statusCreatedAt time.Time, statusID string, boostOfID string, accountID string, boostOfAccountID string) (bool, error) {
+func (t *timeline) IndexOne(ctx context.Context, statusCreatedAt time.Time, statusID string, boostOfID string, accountID string, boostOfAccountID string) (bool, error) {
t.Lock()
defer t.Unlock()
@@ -177,7 +178,7 @@ func (t *timeline) IndexOne(statusCreatedAt time.Time, statusID string, boostOfI
return t.postIndex.insertIndexed(postIndexEntry)
}
-func (t *timeline) IndexAndPrepareOne(statusCreatedAt time.Time, statusID string, boostOfID string, accountID string, boostOfAccountID string) (bool, error) {
+func (t *timeline) IndexAndPrepareOne(ctx context.Context, statusCreatedAt time.Time, statusID string, boostOfID string, accountID string, boostOfAccountID string) (bool, error) {
t.Lock()
defer t.Unlock()
@@ -194,7 +195,7 @@ func (t *timeline) IndexAndPrepareOne(statusCreatedAt time.Time, statusID string
}
if inserted {
- if err := t.prepare(statusID); err != nil {
+ if err := t.prepare(ctx, statusID); err != nil {
return inserted, fmt.Errorf("IndexAndPrepareOne: error preparing: %s", err)
}
}
@@ -202,7 +203,7 @@ func (t *timeline) IndexAndPrepareOne(statusCreatedAt time.Time, statusID string
return inserted, nil
}
-func (t *timeline) OldestIndexedPostID() (string, error) {
+func (t *timeline) OldestIndexedPostID(ctx context.Context) (string, error) {
var id string
if t.postIndex == nil || t.postIndex.data == nil || t.postIndex.data.Back() == nil {
// return an empty string if postindex hasn't been initialized yet
@@ -217,7 +218,7 @@ func (t *timeline) OldestIndexedPostID() (string, error) {
return entry.statusID, nil
}
-func (t *timeline) NewestIndexedPostID() (string, error) {
+func (t *timeline) NewestIndexedPostID(ctx context.Context) (string, error) {
var id string
if t.postIndex == nil || t.postIndex.data == nil || t.postIndex.data.Front() == nil {
// return an empty string if postindex hasn't been initialized yet
diff --git a/internal/timeline/index_test.go b/internal/timeline/index_test.go
index 4201a27dd..25565a1de 100644
--- a/internal/timeline/index_test.go
+++ b/internal/timeline/index_test.go
@@ -19,6 +19,7 @@
package timeline_test
import (
+ "context"
"testing"
"time"
@@ -46,7 +47,7 @@ func (suite *IndexTestSuite) SetupTest() {
testrig.StandardDBSetup(suite.db, nil)
// let's take local_account_1 as the timeline owner, and start with an empty timeline
- tl, err := timeline.NewTimeline(suite.testAccounts["local_account_1"].ID, suite.db, suite.tc, suite.log)
+ tl, err := timeline.NewTimeline(context.Background(), suite.testAccounts["local_account_1"].ID, suite.db, suite.tc, suite.log)
if err != nil {
suite.FailNow(err.Error())
}
@@ -59,82 +60,82 @@ func (suite *IndexTestSuite) TearDownTest() {
func (suite *IndexTestSuite) TestIndexBeforeLowID() {
// index 10 before the lowest status ID possible
- err := suite.timeline.IndexBefore("00000000000000000000000000", true, 10)
+ err := suite.timeline.IndexBefore(context.Background(), "00000000000000000000000000", true, 10)
suite.NoError(err)
// the oldest indexed post should be the lowest one we have in our testrig
- postID, err := suite.timeline.OldestIndexedPostID()
+ postID, err := suite.timeline.OldestIndexedPostID(context.Background())
suite.NoError(err)
suite.Equal("01F8MHAAY43M6RJ473VQFCVH37", postID)
- indexLength := suite.timeline.PostIndexLength()
+ indexLength := suite.timeline.PostIndexLength(context.Background())
suite.Equal(10, indexLength)
}
func (suite *IndexTestSuite) TestIndexBeforeHighID() {
// index 10 before the highest status ID possible
- err := suite.timeline.IndexBefore("ZZZZZZZZZZZZZZZZZZZZZZZZZZ", true, 10)
+ err := suite.timeline.IndexBefore(context.Background(), "ZZZZZZZZZZZZZZZZZZZZZZZZZZ", true, 10)
suite.NoError(err)
// the oldest indexed post should be empty
- postID, err := suite.timeline.OldestIndexedPostID()
+ postID, err := suite.timeline.OldestIndexedPostID(context.Background())
suite.NoError(err)
suite.Empty(postID)
// indexLength should be 0
- indexLength := suite.timeline.PostIndexLength()
+ indexLength := suite.timeline.PostIndexLength(context.Background())
suite.Equal(0, indexLength)
}
func (suite *IndexTestSuite) TestIndexBehindHighID() {
// index 10 behind the highest status ID possible
- err := suite.timeline.IndexBehind("ZZZZZZZZZZZZZZZZZZZZZZZZZZ", true, 10)
+ err := suite.timeline.IndexBehind(context.Background(), "ZZZZZZZZZZZZZZZZZZZZZZZZZZ", true, 10)
suite.NoError(err)
// the newest indexed post should be the highest one we have in our testrig
- postID, err := suite.timeline.NewestIndexedPostID()
+ postID, err := suite.timeline.NewestIndexedPostID(context.Background())
suite.NoError(err)
suite.Equal("01FCTA44PW9H1TB328S9AQXKDS", postID)
// indexLength should be 10 because that's all this user has hometimelineable
- indexLength := suite.timeline.PostIndexLength()
+ indexLength := suite.timeline.PostIndexLength(context.Background())
suite.Equal(10, indexLength)
}
func (suite *IndexTestSuite) TestIndexBehindLowID() {
// index 10 behind the lowest status ID possible
- err := suite.timeline.IndexBehind("00000000000000000000000000", true, 10)
+ err := suite.timeline.IndexBehind(context.Background(), "00000000000000000000000000", true, 10)
suite.NoError(err)
// the newest indexed post should be empty
- postID, err := suite.timeline.NewestIndexedPostID()
+ postID, err := suite.timeline.NewestIndexedPostID(context.Background())
suite.NoError(err)
suite.Empty(postID)
// indexLength should be 0
- indexLength := suite.timeline.PostIndexLength()
+ indexLength := suite.timeline.PostIndexLength(context.Background())
suite.Equal(0, indexLength)
}
func (suite *IndexTestSuite) TestOldestIndexedPostIDEmpty() {
// the oldest indexed post should be an empty string since there's nothing indexed yet
- postID, err := suite.timeline.OldestIndexedPostID()
+ postID, err := suite.timeline.OldestIndexedPostID(context.Background())
suite.NoError(err)
suite.Empty(postID)
// indexLength should be 0
- indexLength := suite.timeline.PostIndexLength()
+ indexLength := suite.timeline.PostIndexLength(context.Background())
suite.Equal(0, indexLength)
}
func (suite *IndexTestSuite) TestNewestIndexedPostIDEmpty() {
// the newest indexed post should be an empty string since there's nothing indexed yet
- postID, err := suite.timeline.NewestIndexedPostID()
+ postID, err := suite.timeline.NewestIndexedPostID(context.Background())
suite.NoError(err)
suite.Empty(postID)
// indexLength should be 0
- indexLength := suite.timeline.PostIndexLength()
+ indexLength := suite.timeline.PostIndexLength(context.Background())
suite.Equal(0, indexLength)
}
@@ -142,12 +143,12 @@ func (suite *IndexTestSuite) TestIndexAlreadyIndexed() {
testStatus := suite.testStatuses["local_account_1_status_1"]
// index one post -- it should be indexed
- indexed, err := suite.timeline.IndexOne(testStatus.CreatedAt, testStatus.ID, testStatus.BoostOfID, testStatus.AccountID, testStatus.BoostOfAccountID)
+ indexed, err := suite.timeline.IndexOne(context.Background(), testStatus.CreatedAt, testStatus.ID, testStatus.BoostOfID, testStatus.AccountID, testStatus.BoostOfAccountID)
suite.NoError(err)
suite.True(indexed)
// try to index the same post again -- it should not be indexed
- indexed, err = suite.timeline.IndexOne(testStatus.CreatedAt, testStatus.ID, testStatus.BoostOfID, testStatus.AccountID, testStatus.BoostOfAccountID)
+ indexed, err = suite.timeline.IndexOne(context.Background(), testStatus.CreatedAt, testStatus.ID, testStatus.BoostOfID, testStatus.AccountID, testStatus.BoostOfAccountID)
suite.NoError(err)
suite.False(indexed)
}
@@ -156,12 +157,12 @@ func (suite *IndexTestSuite) TestIndexAndPrepareAlreadyIndexedAndPrepared() {
testStatus := suite.testStatuses["local_account_1_status_1"]
// index and prepare one post -- it should be indexed
- indexed, err := suite.timeline.IndexAndPrepareOne(testStatus.CreatedAt, testStatus.ID, testStatus.BoostOfID, testStatus.AccountID, testStatus.BoostOfAccountID)
+ indexed, err := suite.timeline.IndexAndPrepareOne(context.Background(), testStatus.CreatedAt, testStatus.ID, testStatus.BoostOfID, testStatus.AccountID, testStatus.BoostOfAccountID)
suite.NoError(err)
suite.True(indexed)
// try to index and prepare the same post again -- it should not be indexed
- indexed, err = suite.timeline.IndexAndPrepareOne(testStatus.CreatedAt, testStatus.ID, testStatus.BoostOfID, testStatus.AccountID, testStatus.BoostOfAccountID)
+ indexed, err = suite.timeline.IndexAndPrepareOne(context.Background(), testStatus.CreatedAt, testStatus.ID, testStatus.BoostOfID, testStatus.AccountID, testStatus.BoostOfAccountID)
suite.NoError(err)
suite.False(indexed)
}
@@ -177,12 +178,12 @@ func (suite *IndexTestSuite) TestIndexBoostOfAlreadyIndexed() {
}
// index one post -- it should be indexed
- indexed, err := suite.timeline.IndexOne(testStatus.CreatedAt, testStatus.ID, testStatus.BoostOfID, testStatus.AccountID, testStatus.BoostOfAccountID)
+ indexed, err := suite.timeline.IndexOne(context.Background(), testStatus.CreatedAt, testStatus.ID, testStatus.BoostOfID, testStatus.AccountID, testStatus.BoostOfAccountID)
suite.NoError(err)
suite.True(indexed)
// try to index the a boost of that post -- it should not be indexed
- indexed, err = suite.timeline.IndexOne(boostOfTestStatus.CreatedAt, boostOfTestStatus.ID, boostOfTestStatus.BoostOfID, boostOfTestStatus.AccountID, boostOfTestStatus.BoostOfAccountID)
+ indexed, err = suite.timeline.IndexOne(context.Background(), boostOfTestStatus.CreatedAt, boostOfTestStatus.ID, boostOfTestStatus.BoostOfID, boostOfTestStatus.AccountID, boostOfTestStatus.BoostOfAccountID)
suite.NoError(err)
suite.False(indexed)
}
diff --git a/internal/timeline/manager.go b/internal/timeline/manager.go
index a592670a8..7f42e2f51 100644
--- a/internal/timeline/manager.go
+++ b/internal/timeline/manager.go
@@ -19,6 +19,7 @@
package timeline
import (
+ "context"
"fmt"
"strings"
"sync"
@@ -54,7 +55,7 @@ type Manager interface {
//
// The returned bool indicates whether the status was actually put in the timeline. This could be false in cases where
// the status is a boost, but a boost of the original post or the post itself already exists recently in the timeline.
- Ingest(status *gtsmodel.Status, timelineAccountID string) (bool, error)
+ Ingest(ctx context.Context, status *gtsmodel.Status, timelineAccountID string) (bool, error)
// IngestAndPrepare takes one status and indexes it into the timeline for the given account ID, and then immediately prepares it for serving.
// This is useful in cases where we know the status will need to be shown at the top of a user's timeline immediately (eg., a new status is created).
//
@@ -62,24 +63,24 @@ type Manager interface {
//
// The returned bool indicates whether the status was actually put in the timeline. This could be false in cases where
// the status is a boost, but a boost of the original post or the post itself already exists recently in the timeline.
- IngestAndPrepare(status *gtsmodel.Status, timelineAccountID string) (bool, error)
+ IngestAndPrepare(ctx context.Context, status *gtsmodel.Status, timelineAccountID string) (bool, error)
// HomeTimeline returns limit n amount of entries from the home timeline of the given account ID, in descending chronological order.
// If maxID is provided, it will return entries from that maxID onwards, inclusive.
- HomeTimeline(accountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]*apimodel.Status, error)
+ HomeTimeline(ctx context.Context, accountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]*apimodel.Status, error)
// GetIndexedLength returns the amount of posts/statuses that have been *indexed* for the given account ID.
- GetIndexedLength(timelineAccountID string) int
+ GetIndexedLength(ctx context.Context, timelineAccountID string) int
// GetDesiredIndexLength returns the amount of posts that we, ideally, index for each user.
- GetDesiredIndexLength() int
+ GetDesiredIndexLength(ctx context.Context) int
// GetOldestIndexedID returns the status ID for the oldest post that we have indexed for the given account.
- GetOldestIndexedID(timelineAccountID string) (string, error)
+ GetOldestIndexedID(ctx context.Context, timelineAccountID string) (string, error)
// PrepareXFromTop prepares limit n amount of posts, based on their indexed representations, from the top of the index.
- PrepareXFromTop(timelineAccountID string, limit int) error
+ PrepareXFromTop(ctx context.Context, timelineAccountID string, limit int) error
// Remove removes one status from the timeline of the given timelineAccountID
- Remove(timelineAccountID string, statusID string) (int, error)
+ Remove(ctx context.Context, timelineAccountID string, statusID string) (int, error)
// WipeStatusFromAllTimelines removes one status from the index and prepared posts of all timelines
- WipeStatusFromAllTimelines(statusID string) error
+ WipeStatusFromAllTimelines(ctx context.Context, statusID string) error
// WipeStatusesFromAccountID removes all statuses by the given accountID from the timelineAccountID's timelines.
- WipeStatusesFromAccountID(timelineAccountID string, accountID string) error
+ WipeStatusesFromAccountID(ctx context.Context, timelineAccountID string, accountID string) error
}
// NewManager returns a new timeline manager with the given database, typeconverter, config, and log.
@@ -101,104 +102,104 @@ type manager struct {
log *logrus.Logger
}
-func (m *manager) Ingest(status *gtsmodel.Status, timelineAccountID string) (bool, error) {
+func (m *manager) Ingest(ctx context.Context, status *gtsmodel.Status, timelineAccountID string) (bool, error) {
l := m.log.WithFields(logrus.Fields{
"func": "Ingest",
"timelineAccountID": timelineAccountID,
"statusID": status.ID,
})
- t, err := m.getOrCreateTimeline(timelineAccountID)
+ t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
if err != nil {
return false, err
}
l.Trace("ingesting status")
- return t.IndexOne(status.CreatedAt, status.ID, status.BoostOfID, status.AccountID, status.BoostOfAccountID)
+ return t.IndexOne(ctx, status.CreatedAt, status.ID, status.BoostOfID, status.AccountID, status.BoostOfAccountID)
}
-func (m *manager) IngestAndPrepare(status *gtsmodel.Status, timelineAccountID string) (bool, error) {
+func (m *manager) IngestAndPrepare(ctx context.Context, status *gtsmodel.Status, timelineAccountID string) (bool, error) {
l := m.log.WithFields(logrus.Fields{
"func": "IngestAndPrepare",
"timelineAccountID": timelineAccountID,
"statusID": status.ID,
})
- t, err := m.getOrCreateTimeline(timelineAccountID)
+ t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
if err != nil {
return false, err
}
l.Trace("ingesting status")
- return t.IndexAndPrepareOne(status.CreatedAt, status.ID, status.BoostOfID, status.AccountID, status.BoostOfAccountID)
+ return t.IndexAndPrepareOne(ctx, status.CreatedAt, status.ID, status.BoostOfID, status.AccountID, status.BoostOfAccountID)
}
-func (m *manager) Remove(timelineAccountID string, statusID string) (int, error) {
+func (m *manager) Remove(ctx context.Context, timelineAccountID string, statusID string) (int, error) {
l := m.log.WithFields(logrus.Fields{
"func": "Remove",
"timelineAccountID": timelineAccountID,
"statusID": statusID,
})
- t, err := m.getOrCreateTimeline(timelineAccountID)
+ t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
if err != nil {
return 0, err
}
l.Trace("removing status")
- return t.Remove(statusID)
+ return t.Remove(ctx, statusID)
}
-func (m *manager) HomeTimeline(timelineAccountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]*apimodel.Status, error) {
+func (m *manager) HomeTimeline(ctx context.Context, timelineAccountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]*apimodel.Status, error) {
l := m.log.WithFields(logrus.Fields{
"func": "HomeTimelineGet",
"timelineAccountID": timelineAccountID,
})
- t, err := m.getOrCreateTimeline(timelineAccountID)
+ t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
if err != nil {
return nil, err
}
- statuses, err := t.Get(limit, maxID, sinceID, minID, true)
+ statuses, err := t.Get(ctx, limit, maxID, sinceID, minID, true)
if err != nil {
l.Errorf("error getting statuses: %s", err)
}
return statuses, nil
}
-func (m *manager) GetIndexedLength(timelineAccountID string) int {
- t, err := m.getOrCreateTimeline(timelineAccountID)
+func (m *manager) GetIndexedLength(ctx context.Context, timelineAccountID string) int {
+ t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
if err != nil {
return 0
}
- return t.PostIndexLength()
+ return t.PostIndexLength(ctx)
}
-func (m *manager) GetDesiredIndexLength() int {
+func (m *manager) GetDesiredIndexLength(ctx context.Context) int {
return desiredPostIndexLength
}
-func (m *manager) GetOldestIndexedID(timelineAccountID string) (string, error) {
- t, err := m.getOrCreateTimeline(timelineAccountID)
+func (m *manager) GetOldestIndexedID(ctx context.Context, timelineAccountID string) (string, error) {
+ t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
if err != nil {
return "", err
}
- return t.OldestIndexedPostID()
+ return t.OldestIndexedPostID(ctx)
}
-func (m *manager) PrepareXFromTop(timelineAccountID string, limit int) error {
- t, err := m.getOrCreateTimeline(timelineAccountID)
+func (m *manager) PrepareXFromTop(ctx context.Context, timelineAccountID string, limit int) error {
+ t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
if err != nil {
return err
}
- return t.PrepareFromTop(limit)
+ return t.PrepareFromTop(ctx, limit)
}
-func (m *manager) WipeStatusFromAllTimelines(statusID string) error {
+func (m *manager) WipeStatusFromAllTimelines(ctx context.Context, statusID string) error {
errors := []string{}
m.accountTimelines.Range(func(k interface{}, i interface{}) bool {
t, ok := i.(Timeline)
@@ -206,7 +207,7 @@ func (m *manager) WipeStatusFromAllTimelines(statusID string) error {
panic("couldn't parse entry as Timeline, this should never happen so panic")
}
- if _, err := t.Remove(statusID); err != nil {
+ if _, err := t.Remove(ctx, statusID); err != nil {
errors = append(errors, err.Error())
}
@@ -221,22 +222,22 @@ func (m *manager) WipeStatusFromAllTimelines(statusID string) error {
return err
}
-func (m *manager) WipeStatusesFromAccountID(timelineAccountID string, accountID string) error {
- t, err := m.getOrCreateTimeline(timelineAccountID)
+func (m *manager) WipeStatusesFromAccountID(ctx context.Context, timelineAccountID string, accountID string) error {
+ t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
if err != nil {
return err
}
- _, err = t.RemoveAllBy(accountID)
+ _, err = t.RemoveAllBy(ctx, accountID)
return err
}
-func (m *manager) getOrCreateTimeline(timelineAccountID string) (Timeline, error) {
+func (m *manager) getOrCreateTimeline(ctx context.Context, timelineAccountID string) (Timeline, error) {
var t Timeline
i, ok := m.accountTimelines.Load(timelineAccountID)
if !ok {
var err error
- t, err = NewTimeline(timelineAccountID, m.db, m.tc, m.log)
+ t, err = NewTimeline(ctx, timelineAccountID, m.db, m.tc, m.log)
if err != nil {
return nil, err
}
diff --git a/internal/timeline/manager_test.go b/internal/timeline/manager_test.go
index 00c6dcb4a..ea4dc4c12 100644
--- a/internal/timeline/manager_test.go
+++ b/internal/timeline/manager_test.go
@@ -19,6 +19,7 @@
package timeline_test
import (
+ "context"
"testing"
"github.com/stretchr/testify/suite"
@@ -54,85 +55,85 @@ func (suite *ManagerTestSuite) TestManagerIntegration() {
testAccount := suite.testAccounts["local_account_1"]
// should start at 0
- indexedLen := suite.manager.GetIndexedLength(testAccount.ID)
+ indexedLen := suite.manager.GetIndexedLength(context.Background(), testAccount.ID)
suite.Equal(0, indexedLen)
// oldestIndexed should be empty string since there's nothing indexed
- oldestIndexed, err := suite.manager.GetOldestIndexedID(testAccount.ID)
+ oldestIndexed, err := suite.manager.GetOldestIndexedID(context.Background(), testAccount.ID)
suite.NoError(err)
suite.Empty(oldestIndexed)
// trigger status preparation
- err = suite.manager.PrepareXFromTop(testAccount.ID, 20)
+ err = suite.manager.PrepareXFromTop(context.Background(), testAccount.ID, 20)
suite.NoError(err)
// local_account_1 can see 12 statuses out of the testrig statuses in its home timeline
- indexedLen = suite.manager.GetIndexedLength(testAccount.ID)
+ indexedLen = suite.manager.GetIndexedLength(context.Background(), testAccount.ID)
suite.Equal(12, indexedLen)
// oldest should now be set
- oldestIndexed, err = suite.manager.GetOldestIndexedID(testAccount.ID)
+ oldestIndexed, err = suite.manager.GetOldestIndexedID(context.Background(), testAccount.ID)
suite.NoError(err)
suite.Equal("01F8MH75CBF9JFX4ZAD54N0W0R", oldestIndexed)
// get hometimeline
- statuses, err := suite.manager.HomeTimeline(testAccount.ID, "", "", "", 20, false)
+ statuses, err := suite.manager.HomeTimeline(context.Background(), testAccount.ID, "", "", "", 20, false)
suite.NoError(err)
suite.Len(statuses, 12)
// now wipe the last status from all timelines, as though it had been deleted by the owner
- err = suite.manager.WipeStatusFromAllTimelines("01F8MH75CBF9JFX4ZAD54N0W0R")
+ err = suite.manager.WipeStatusFromAllTimelines(context.Background(), "01F8MH75CBF9JFX4ZAD54N0W0R")
suite.NoError(err)
// timeline should be shorter
- indexedLen = suite.manager.GetIndexedLength(testAccount.ID)
+ indexedLen = suite.manager.GetIndexedLength(context.Background(), testAccount.ID)
suite.Equal(11, indexedLen)
// oldest should now be different
- oldestIndexed, err = suite.manager.GetOldestIndexedID(testAccount.ID)
+ oldestIndexed, err = suite.manager.GetOldestIndexedID(context.Background(), testAccount.ID)
suite.NoError(err)
suite.Equal("01F8MH82FYRXD2RC6108DAJ5HB", oldestIndexed)
// delete the new oldest status specifically from this timeline, as though local_account_1 had muted or blocked it
- removed, err := suite.manager.Remove(testAccount.ID, "01F8MH82FYRXD2RC6108DAJ5HB")
+ removed, err := suite.manager.Remove(context.Background(), testAccount.ID, "01F8MH82FYRXD2RC6108DAJ5HB")
suite.NoError(err)
suite.Equal(2, removed) // 1 status should be removed, but from both indexed and prepared, so 2 removals total
// timeline should be shorter
- indexedLen = suite.manager.GetIndexedLength(testAccount.ID)
+ indexedLen = suite.manager.GetIndexedLength(context.Background(), testAccount.ID)
suite.Equal(10, indexedLen)
// oldest should now be different
- oldestIndexed, err = suite.manager.GetOldestIndexedID(testAccount.ID)
+ oldestIndexed, err = suite.manager.GetOldestIndexedID(context.Background(), testAccount.ID)
suite.NoError(err)
suite.Equal("01F8MHAAY43M6RJ473VQFCVH37", oldestIndexed)
// now remove all entries by local_account_2 from the timeline
- err = suite.manager.WipeStatusesFromAccountID(testAccount.ID, suite.testAccounts["local_account_2"].ID)
+ err = suite.manager.WipeStatusesFromAccountID(context.Background(), testAccount.ID, suite.testAccounts["local_account_2"].ID)
suite.NoError(err)
// timeline should be empty now
- indexedLen = suite.manager.GetIndexedLength(testAccount.ID)
+ indexedLen = suite.manager.GetIndexedLength(context.Background(), testAccount.ID)
suite.Equal(5, indexedLen)
// ingest 1 into the timeline
status1 := suite.testStatuses["admin_account_status_1"]
- ingested, err := suite.manager.Ingest(status1, testAccount.ID)
+ ingested, err := suite.manager.Ingest(context.Background(), status1, testAccount.ID)
suite.NoError(err)
suite.True(ingested)
// ingest and prepare another one into the timeline
status2 := suite.testStatuses["local_account_2_status_1"]
- ingested, err = suite.manager.IngestAndPrepare(status2, testAccount.ID)
+ ingested, err = suite.manager.IngestAndPrepare(context.Background(), status2, testAccount.ID)
suite.NoError(err)
suite.True(ingested)
// timeline should be longer now
- indexedLen = suite.manager.GetIndexedLength(testAccount.ID)
+ indexedLen = suite.manager.GetIndexedLength(context.Background(), testAccount.ID)
suite.Equal(7, indexedLen)
// try to ingest status 2 again
- ingested, err = suite.manager.IngestAndPrepare(status2, testAccount.ID)
+ ingested, err = suite.manager.IngestAndPrepare(context.Background(), status2, testAccount.ID)
suite.NoError(err)
suite.False(ingested) // should be false since it's a duplicate
}
diff --git a/internal/timeline/prepare.go b/internal/timeline/prepare.go
index 20000b4e9..d57222ee8 100644
--- a/internal/timeline/prepare.go
+++ b/internal/timeline/prepare.go
@@ -20,6 +20,7 @@ package timeline
import (
"container/list"
+ "context"
"errors"
"fmt"
@@ -28,7 +29,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
)
-func (t *timeline) prepareNextQuery(amount int, maxID string, sinceID string, minID string) error {
+func (t *timeline) prepareNextQuery(ctx context.Context, amount int, maxID string, sinceID string, minID string) error {
l := t.log.WithFields(logrus.Fields{
"func": "prepareNextQuery",
"amount": amount,
@@ -42,30 +43,30 @@ func (t *timeline) prepareNextQuery(amount int, maxID string, sinceID string, mi
// maxID is defined but sinceID isn't so take from behind
if maxID != "" && sinceID == "" {
l.Debug("preparing behind maxID")
- err = t.PrepareBehind(maxID, amount)
+ err = t.PrepareBehind(ctx, maxID, amount)
}
// maxID isn't defined, but sinceID || minID are, so take x before
if maxID == "" && sinceID != "" {
l.Debug("preparing before sinceID")
- err = t.PrepareBefore(sinceID, false, amount)
+ err = t.PrepareBefore(ctx, sinceID, false, amount)
}
if maxID == "" && minID != "" {
l.Debug("preparing before minID")
- err = t.PrepareBefore(minID, false, amount)
+ err = t.PrepareBefore(ctx, minID, false, amount)
}
return err
}
-func (t *timeline) PrepareBehind(statusID string, amount int) error {
+func (t *timeline) PrepareBehind(ctx context.Context, statusID string, amount int) error {
// lazily initialize prepared posts if it hasn't been done already
if t.preparedPosts.data == nil {
t.preparedPosts.data = &list.List{}
t.preparedPosts.data.Init()
}
- if err := t.IndexBehind(statusID, true, amount); err != nil {
+ if err := t.IndexBehind(ctx, statusID, true, amount); err != nil {
return fmt.Errorf("PrepareBehind: error indexing behind id %s: %s", statusID, err)
}
@@ -93,7 +94,7 @@ prepareloop:
}
if preparing {
- if err := t.prepare(entry.statusID); err != nil {
+ if err := t.prepare(ctx, entry.statusID); err != nil {
// there's been an error
if err != db.ErrNoEntries {
// it's a real error
@@ -113,7 +114,7 @@ prepareloop:
return nil
}
-func (t *timeline) PrepareBefore(statusID string, include bool, amount int) error {
+func (t *timeline) PrepareBefore(ctx context.Context, statusID string, include bool, amount int) error {
t.Lock()
defer t.Unlock()
@@ -148,7 +149,7 @@ prepareloop:
}
if preparing {
- if err := t.prepare(entry.statusID); err != nil {
+ if err := t.prepare(ctx, entry.statusID); err != nil {
// there's been an error
if err != db.ErrNoEntries {
// it's a real error
@@ -168,7 +169,7 @@ prepareloop:
return nil
}
-func (t *timeline) PrepareFromTop(amount int) error {
+func (t *timeline) PrepareFromTop(ctx context.Context, amount int) error {
l := t.log.WithFields(logrus.Fields{
"func": "PrepareFromTop",
"amount": amount,
@@ -183,7 +184,7 @@ func (t *timeline) PrepareFromTop(amount int) error {
// if the postindex is nil, nothing has been indexed yet so index from the highest ID possible
if t.postIndex.data == nil {
l.Debug("postindex.data was nil, indexing behind highest possible ID")
- if err := t.IndexBehind("ZZZZZZZZZZZZZZZZZZZZZZZZZZ", false, amount); err != nil {
+ if err := t.IndexBehind(ctx, "ZZZZZZZZZZZZZZZZZZZZZZZZZZ", false, amount); err != nil {
return fmt.Errorf("PrepareFromTop: error indexing behind id %s: %s", "ZZZZZZZZZZZZZZZZZZZZZZZZZZ", err)
}
}
@@ -203,7 +204,7 @@ prepareloop:
return errors.New("PrepareFromTop: could not parse e as a postIndexEntry")
}
- if err := t.prepare(entry.statusID); err != nil {
+ if err := t.prepare(ctx, entry.statusID); err != nil {
// there's been an error
if err != db.ErrNoEntries {
// it's a real error
@@ -225,25 +226,25 @@ prepareloop:
return nil
}
-func (t *timeline) prepare(statusID string) error {
+func (t *timeline) prepare(ctx context.Context, statusID string) error {
// start by getting the status out of the database according to its indexed ID
gtsStatus := &gtsmodel.Status{}
- if err := t.db.GetByID(statusID, gtsStatus); err != nil {
+ if err := t.db.GetByID(ctx, statusID, gtsStatus); err != nil {
return err
}
// if the account pointer hasn't been set on this timeline already, set it lazily here
if t.account == nil {
timelineOwnerAccount := &gtsmodel.Account{}
- if err := t.db.GetByID(t.accountID, timelineOwnerAccount); err != nil {
+ if err := t.db.GetByID(ctx, t.accountID, timelineOwnerAccount); err != nil {
return err
}
t.account = timelineOwnerAccount
}
// serialize the status (or, at least, convert it to a form that's ready to be serialized)
- apiModelStatus, err := t.tc.StatusToMasto(gtsStatus, t.account)
+ apiModelStatus, err := t.tc.StatusToMasto(ctx, gtsStatus, t.account)
if err != nil {
return err
}
@@ -260,7 +261,7 @@ func (t *timeline) prepare(statusID string) error {
return t.preparedPosts.insertPrepared(preparedPostsEntry)
}
-func (t *timeline) OldestPreparedPostID() (string, error) {
+func (t *timeline) OldestPreparedPostID(ctx context.Context) (string, error) {
var id string
if t.preparedPosts == nil || t.preparedPosts.data == nil {
// return an empty string if prepared posts hasn't been initialized yet
diff --git a/internal/timeline/remove.go b/internal/timeline/remove.go
index cf0b0b617..031dace1f 100644
--- a/internal/timeline/remove.go
+++ b/internal/timeline/remove.go
@@ -20,12 +20,13 @@ package timeline
import (
"container/list"
+ "context"
"errors"
"github.com/sirupsen/logrus"
)
-func (t *timeline) Remove(statusID string) (int, error) {
+func (t *timeline) Remove(ctx context.Context, statusID string) (int, error) {
l := t.log.WithFields(logrus.Fields{
"func": "Remove",
"accountTimeline": t.accountID,
@@ -77,7 +78,7 @@ func (t *timeline) Remove(statusID string) (int, error) {
return removed, nil
}
-func (t *timeline) RemoveAllBy(accountID string) (int, error) {
+func (t *timeline) RemoveAllBy(ctx context.Context, accountID string) (int, error) {
l := t.log.WithFields(logrus.Fields{
"func": "RemoveAllBy",
"accountTimeline": t.accountID,
diff --git a/internal/timeline/timeline.go b/internal/timeline/timeline.go
index 6274a86ac..5f5fa1b4f 100644
--- a/internal/timeline/timeline.go
+++ b/internal/timeline/timeline.go
@@ -19,6 +19,7 @@
package timeline
import (
+ "context"
"sync"
"time"
@@ -41,24 +42,24 @@ type Timeline interface {
// Get returns an amount of statuses with the given parameters.
// If prepareNext is true, then the next predicted query will be prepared already in a goroutine,
// to make the next call to Get faster.
- Get(amount int, maxID string, sinceID string, minID string, prepareNext bool) ([]*apimodel.Status, error)
+ Get(ctx context.Context, amount int, maxID string, sinceID string, minID string, prepareNext bool) ([]*apimodel.Status, error)
// GetXFromTop returns x amount of posts from the top of the timeline, from newest to oldest.
- GetXFromTop(amount int) ([]*apimodel.Status, error)
+ GetXFromTop(ctx context.Context, amount int) ([]*apimodel.Status, error)
// GetXBehindID returns x amount of posts from the given id onwards, from newest to oldest.
// This will NOT include the status with the given ID.
//
// This corresponds to an api call to /timelines/home?max_id=WHATEVER
- GetXBehindID(amount int, fromID string, attempts *int) ([]*apimodel.Status, error)
+ GetXBehindID(ctx context.Context, amount int, fromID string, attempts *int) ([]*apimodel.Status, error)
// GetXBeforeID returns x amount of posts up to the given id, from newest to oldest.
// This will NOT include the status with the given ID.
//
// This corresponds to an api call to /timelines/home?since_id=WHATEVER
- GetXBeforeID(amount int, sinceID string, startFromTop bool) ([]*apimodel.Status, error)
+ GetXBeforeID(ctx context.Context, amount int, sinceID string, startFromTop bool) ([]*apimodel.Status, error)
// GetXBetweenID returns x amount of posts from the given maxID, up to the given id, from newest to oldest.
// This will NOT include the status with the given IDs.
//
// This corresponds to an api call to /timelines/home?since_id=WHATEVER&max_id=WHATEVER_ELSE
- GetXBetweenID(amount int, maxID string, sinceID string) ([]*apimodel.Status, error)
+ GetXBetweenID(ctx context.Context, amount int, maxID string, sinceID string) ([]*apimodel.Status, error)
/*
INDEXING FUNCTIONS
@@ -68,43 +69,43 @@ type Timeline interface {
//
// The returned bool indicates whether or not the status was actually inserted into the timeline. This will be false
// if the status is a boost and the original post or another boost of it already exists < boostReinsertionDepth back in the timeline.
- IndexOne(statusCreatedAt time.Time, statusID string, boostOfID string, accountID string, boostOfAccountID string) (bool, error)
+ IndexOne(ctx context.Context, statusCreatedAt time.Time, statusID string, boostOfID string, accountID string, boostOfAccountID string) (bool, 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.
- OldestIndexedPostID() (string, error)
+ OldestIndexedPostID(ctx context.Context) (string, error)
// NewestIndexedPostID returns the id of the frontmost (ie., the newest) indexed post, or an error if something goes wrong.
// If nothing goes wrong but there's no newest post, an empty string will be returned so make sure to check for this.
- NewestIndexedPostID() (string, error)
+ NewestIndexedPostID(ctx context.Context) (string, error)
- IndexBefore(statusID string, include bool, amount int) error
- IndexBehind(statusID string, include bool, amount int) error
+ IndexBefore(ctx context.Context, statusID string, include bool, amount int) error
+ IndexBehind(ctx context.Context, statusID string, include bool, amount int) error
/*
PREPARATION FUNCTIONS
*/
// PrepareXFromTop instructs the timeline to prepare x amount of posts from the top of the timeline.
- PrepareFromTop(amount int) error
+ PrepareFromTop(ctx context.Context, amount int) error
// PrepareBehind instructs the timeline to prepare the next amount of entries for serialization, from position onwards.
// If include is true, then the given status ID will also be prepared, otherwise only entries behind it will be prepared.
- PrepareBehind(statusID string, amount int) error
+ PrepareBehind(ctx context.Context, statusID string, amount int) error
// IndexOne puts a status into the timeline at the appropriate place according to its 'createdAt' property,
// and then immediately prepares it.
//
// The returned bool indicates whether or not the status was actually inserted into the timeline. This will be false
// if the status is a boost and the original post or another boost of it already exists < boostReinsertionDepth back in the timeline.
- IndexAndPrepareOne(statusCreatedAt time.Time, statusID string, boostOfID string, accountID string, boostOfAccountID string) (bool, error)
+ IndexAndPrepareOne(ctx context.Context, statusCreatedAt time.Time, statusID string, boostOfID string, accountID string, boostOfAccountID string) (bool, error)
// OldestPreparedPostID returns the id of the rearmost (ie., the oldest) prepared 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.
- OldestPreparedPostID() (string, error)
+ OldestPreparedPostID(ctx context.Context) (string, error)
/*
INFO FUNCTIONS
*/
// ActualPostIndexLength returns the actual length of the post index at this point in time.
- PostIndexLength() int
+ PostIndexLength(ctx context.Context) int
/*
UTILITY FUNCTIONS
@@ -117,11 +118,11 @@ type Timeline interface {
// If a status has multiple entries in a timeline, they will all be removed.
//
// The returned int indicates the amount of entries that were removed.
- Remove(statusID string) (int, error)
+ Remove(ctx context.Context, statusID string) (int, error)
// RemoveAllBy removes all statuses by the given accountID, from both the index and prepared posts.
//
// The returned int indicates the amount of entries that were removed.
- RemoveAllBy(accountID string) (int, error)
+ RemoveAllBy(ctx context.Context, accountID string) (int, error)
}
// timeline fulfils the Timeline interface
@@ -138,9 +139,9 @@ type timeline struct {
}
// NewTimeline returns a new Timeline for the given account ID
-func NewTimeline(accountID string, db db.DB, typeConverter typeutils.TypeConverter, log *logrus.Logger) (Timeline, error) {
+func NewTimeline(ctx context.Context, accountID string, db db.DB, typeConverter typeutils.TypeConverter, log *logrus.Logger) (Timeline, error) {
timelineOwnerAccount := &gtsmodel.Account{}
- if err := db.GetByID(accountID, timelineOwnerAccount); err != nil {
+ if err := db.GetByID(ctx, accountID, timelineOwnerAccount); err != nil {
return nil, err
}
@@ -160,7 +161,7 @@ func (t *timeline) Reset() error {
return nil
}
-func (t *timeline) PostIndexLength() int {
+func (t *timeline) PostIndexLength(ctx context.Context) int {
if t.postIndex == nil || t.postIndex.data == nil {
return 0
}