diff options
Diffstat (limited to 'internal/timeline/timeline.go')
-rw-r--r-- | internal/timeline/timeline.go | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/internal/timeline/timeline.go b/internal/timeline/timeline.go new file mode 100644 index 000000000..7408436dc --- /dev/null +++ b/internal/timeline/timeline.go @@ -0,0 +1,139 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package timeline + +import ( + "sync" + "time" + + "github.com/sirupsen/logrus" + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" + "github.com/superseriousbusiness/gotosocial/internal/db" + "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" + "github.com/superseriousbusiness/gotosocial/internal/typeutils" +) + +// Timeline represents a timeline for one account, and contains indexed and prepared posts. +type Timeline interface { + /* + RETRIEVAL FUNCTIONS + */ + + Get(amount int, maxID string, sinceID string, minID string) ([]*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) + // 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) ([]*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) + // 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) + + /* + INDEXING FUNCTIONS + */ + + // IndexOne puts a status into the timeline at the appropriate place according to its 'createdAt' property. + IndexOne(statusCreatedAt time.Time, statusID 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. + OldestIndexedPostID() (string, error) + + /* + PREPARATION FUNCTIONS + */ + + // PrepareXFromTop instructs the timeline to prepare x amount of posts from the top of the timeline. + PrepareFromTop(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 + // IndexOne puts a status into the timeline at the appropriate place according to its 'createdAt' property, + // and then immediately prepares it. + IndexAndPrepareOne(statusCreatedAt time.Time, statusID string) 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) + + /* + INFO FUNCTIONS + */ + + // ActualPostIndexLength returns the actual length of the post index at this point in time. + PostIndexLength() int + + /* + UTILITY FUNCTIONS + */ + + // Reset instructs the timeline to reset to its base state -- cache only the minimum amount of posts. + Reset() error + // Remove removes a status from both the index and prepared posts. + // + // 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) +} + +// timeline fulfils the Timeline interface +type timeline struct { + postIndex *postIndex + preparedPosts *preparedPosts + accountID string + account *gtsmodel.Account + db db.DB + tc typeutils.TypeConverter + log *logrus.Logger + sync.Mutex +} + +// NewTimeline returns a new Timeline for the given account ID +func NewTimeline(accountID string, db db.DB, typeConverter typeutils.TypeConverter, log *logrus.Logger) Timeline { + return &timeline{ + postIndex: &postIndex{}, + preparedPosts: &preparedPosts{}, + accountID: accountID, + db: db, + tc: typeConverter, + log: log, + } +} + +func (t *timeline) Reset() error { + return nil +} + +func (t *timeline) PostIndexLength() int { + if t.postIndex == nil || t.postIndex.data == nil { + return 0 + } + + return t.postIndex.data.Len() +} |