| 
									
										
										
										
											2023-03-12 16:00:57 +01:00
										 |  |  | // GoToSocial | 
					
						
							|  |  |  | // Copyright (C) GoToSocial Authors admin@gotosocial.org | 
					
						
							|  |  |  | // SPDX-License-Identifier: AGPL-3.0-or-later | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // 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/>. | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | package timeline | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-08-25 15:34:33 +02:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2022-11-22 19:38:10 +01:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-05 12:47:38 +01:00
										 |  |  | // GrabFunction is used by a Timeline to grab more items to index. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // It should be provided to NewTimeline when the caller is creating a timeline | 
					
						
							|  |  |  | // (of statuses, notifications, etc). | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2023-05-25 10:37:38 +02:00
										 |  |  | //   - timelineID: ID of the timeline. | 
					
						
							|  |  |  | //   - maxID: the maximum item ID desired. | 
					
						
							|  |  |  | //   - sinceID: the minimum item ID desired. | 
					
						
							|  |  |  | //   - minID: see sinceID | 
					
						
							|  |  |  | //   - limit: the maximum amount of items to be returned | 
					
						
							| 
									
										
										
										
											2022-02-05 12:47:38 +01:00
										 |  |  | // | 
					
						
							|  |  |  | // If an error is returned, the timeline will stop processing whatever request called GrabFunction, | 
					
						
							|  |  |  | // and return the error. If no error is returned, but stop = true, this indicates to the caller of GrabFunction | 
					
						
							|  |  |  | // that there are no more items to return, and processing should continue with the items already grabbed. | 
					
						
							| 
									
										
										
										
											2023-05-25 10:37:38 +02:00
										 |  |  | type GrabFunction func(ctx context.Context, timelineID string, maxID string, sinceID string, minID string, limit int) (items []Timelineable, stop bool, err error) | 
					
						
							| 
									
										
										
										
											2022-02-05 12:47:38 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // FilterFunction is used by a Timeline to filter whether or not a grabbed item should be indexed. | 
					
						
							| 
									
										
										
										
											2023-05-25 10:37:38 +02:00
										 |  |  | type FilterFunction func(ctx context.Context, timelineID string, item Timelineable) (shouldIndex bool, err error) | 
					
						
							| 
									
										
										
										
											2022-02-05 12:47:38 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // PrepareFunction converts a Timelineable into a Preparable. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // For example, this might result in the converstion of a *gtsmodel.Status with the given itemID into a serializable *apimodel.Status. | 
					
						
							| 
									
										
										
										
											2023-05-25 10:37:38 +02:00
										 |  |  | type PrepareFunction func(ctx context.Context, timelineID string, itemID string) (Preparable, error) | 
					
						
							| 
									
										
										
										
											2022-02-05 12:47:38 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // SkipInsertFunction indicates whether a new item about to be inserted in the prepared list should be skipped, | 
					
						
							|  |  |  | // based on the item itself, the next item in the timeline, and the depth at which nextItem has been found in the list. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // This will be called for every item found while iterating through a timeline, so callers should be very careful | 
					
						
							|  |  |  | // not to do anything expensive here. | 
					
						
							|  |  |  | type SkipInsertFunction func(ctx context.Context, | 
					
						
							|  |  |  | 	newItemID string, | 
					
						
							|  |  |  | 	newItemAccountID string, | 
					
						
							|  |  |  | 	newItemBoostOfID string, | 
					
						
							|  |  |  | 	newItemBoostOfAccountID string, | 
					
						
							|  |  |  | 	nextItemID string, | 
					
						
							|  |  |  | 	nextItemAccountID string, | 
					
						
							|  |  |  | 	nextItemBoostOfID string, | 
					
						
							|  |  |  | 	nextItemBoostOfAccountID string, | 
					
						
							|  |  |  | 	depth int) (bool, error) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Timeline represents a timeline for one account, and contains indexed and prepared items. | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | type Timeline interface { | 
					
						
							|  |  |  | 	/* | 
					
						
							|  |  |  | 		RETRIEVAL FUNCTIONS | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-05 12:47:38 +01:00
										 |  |  | 	// Get returns an amount of prepared items with the given parameters. | 
					
						
							| 
									
										
										
										
											2021-08-15 18:43:08 +02:00
										 |  |  | 	// If prepareNext is true, then the next predicted query will be prepared already in a goroutine, | 
					
						
							|  |  |  | 	// to make the next call to Get faster. | 
					
						
							| 
									
										
										
										
											2022-02-05 12:47:38 +01:00
										 |  |  | 	Get(ctx context.Context, amount int, maxID string, sinceID string, minID string, prepareNext bool) ([]Preparable, error) | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* | 
					
						
							| 
									
										
										
										
											2022-11-22 19:38:10 +01:00
										 |  |  | 		INDEXING + PREPARATION FUNCTIONS | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 	*/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	// IndexAndPrepareOne puts a item into the timeline at the appropriate place | 
					
						
							|  |  |  | 	// according to its id, and then immediately prepares it. | 
					
						
							| 
									
										
										
										
											2021-06-19 11:18:55 +02:00
										 |  |  | 	// | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	// The returned bool indicates whether or not the item was actually inserted | 
					
						
							|  |  |  | 	// into the timeline. This will be false if the item is a boost and the original | 
					
						
							|  |  |  | 	// item, or a boost of it, already exists recently in the timeline. | 
					
						
							| 
									
										
										
										
											2022-02-05 12:47:38 +01:00
										 |  |  | 	IndexAndPrepareOne(ctx context.Context, itemID string, boostOfID string, accountID string, boostOfAccountID string) (bool, error) | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	// Unprepare clears the prepared version of the given item (and any boosts | 
					
						
							|  |  |  | 	// thereof) from the timeline, but leaves the indexed version in place. | 
					
						
							|  |  |  | 	// | 
					
						
							|  |  |  | 	// This is useful for cache invalidation when the prepared version of the | 
					
						
							|  |  |  | 	// item has changed for some reason (edits, updates, etc), but the item does | 
					
						
							|  |  |  | 	// not need to be removed: it will be prepared again next time Get is called. | 
					
						
							|  |  |  | 	Unprepare(ctx context.Context, itemID string) error | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 	/* | 
					
						
							|  |  |  | 		INFO FUNCTIONS | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-25 10:37:38 +02:00
										 |  |  | 	// TimelineID returns the id of this timeline. | 
					
						
							|  |  |  | 	TimelineID() string | 
					
						
							| 
									
										
										
										
											2023-04-06 13:43:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Len returns the length of the item index at this point in time. | 
					
						
							|  |  |  | 	Len() int | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// OldestIndexedItemID returns the id of the rearmost (ie., the oldest) indexed item. | 
					
						
							|  |  |  | 	// If there's no oldest item, an empty string will be returned so make sure to check for this. | 
					
						
							|  |  |  | 	OldestIndexedItemID() string | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* | 
					
						
							|  |  |  | 		UTILITY FUNCTIONS | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-22 19:38:10 +01:00
										 |  |  | 	// LastGot returns the time that Get was last called. | 
					
						
							|  |  |  | 	LastGot() time.Time | 
					
						
							| 
									
										
										
										
											2023-04-06 13:43:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Prune prunes prepared and indexed items in this timeline to the desired lengths. | 
					
						
							| 
									
										
										
										
											2022-11-22 19:38:10 +01:00
										 |  |  | 	// This will be a no-op if the lengths are already < the desired values. | 
					
						
							| 
									
										
										
										
											2023-04-06 13:43:13 +02:00
										 |  |  | 	// | 
					
						
							|  |  |  | 	// The returned int indicates the amount of entries that were removed or unprepared. | 
					
						
							| 
									
										
										
										
											2022-11-22 19:38:10 +01:00
										 |  |  | 	Prune(desiredPreparedItemsLength int, desiredIndexedItemsLength int) int | 
					
						
							| 
									
										
										
										
											2023-04-06 13:43:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Remove removes an item with the given ID. | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 	// | 
					
						
							| 
									
										
										
										
											2022-02-05 12:47:38 +01:00
										 |  |  | 	// If a item has multiple entries in a timeline, they will all be removed. | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 	// | 
					
						
							|  |  |  | 	// The returned int indicates the amount of entries that were removed. | 
					
						
							| 
									
										
										
										
											2022-02-05 12:47:38 +01:00
										 |  |  | 	Remove(ctx context.Context, itemID string) (int, error) | 
					
						
							| 
									
										
										
										
											2023-04-06 13:43:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// RemoveAllByOrBoosting removes all items created by or boosting the given accountID. | 
					
						
							| 
									
										
										
										
											2021-07-11 16:22:21 +02:00
										 |  |  | 	// | 
					
						
							|  |  |  | 	// The returned int indicates the amount of entries that were removed. | 
					
						
							| 
									
										
										
										
											2023-04-06 13:43:13 +02:00
										 |  |  | 	RemoveAllByOrBoosting(ctx context.Context, accountID string) (int, error) | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // timeline fulfils the Timeline interface | 
					
						
							|  |  |  | type timeline struct { | 
					
						
							| 
									
										
										
										
											2023-04-06 13:43:13 +02:00
										 |  |  | 	items           *indexedItems | 
					
						
							| 
									
										
										
										
											2022-02-05 12:47:38 +01:00
										 |  |  | 	grabFunction    GrabFunction | 
					
						
							|  |  |  | 	filterFunction  FilterFunction | 
					
						
							|  |  |  | 	prepareFunction PrepareFunction | 
					
						
							| 
									
										
										
										
											2023-05-25 10:37:38 +02:00
										 |  |  | 	timelineID      string | 
					
						
							| 
									
										
										
										
											2022-11-22 19:38:10 +01:00
										 |  |  | 	lastGot         time.Time | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 	sync.Mutex | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-25 10:37:38 +02:00
										 |  |  | func (t *timeline) TimelineID() string { | 
					
						
							|  |  |  | 	return t.timelineID | 
					
						
							| 
									
										
										
										
											2023-04-06 13:43:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-25 10:37:38 +02:00
										 |  |  | // NewTimeline returns a new Timeline with | 
					
						
							|  |  |  | // the given ID, using the given functions. | 
					
						
							| 
									
										
										
										
											2022-02-05 12:47:38 +01:00
										 |  |  | func NewTimeline( | 
					
						
							|  |  |  | 	ctx context.Context, | 
					
						
							| 
									
										
										
										
											2023-05-25 10:37:38 +02:00
										 |  |  | 	timelineID string, | 
					
						
							| 
									
										
										
										
											2022-02-05 12:47:38 +01:00
										 |  |  | 	grabFunction GrabFunction, | 
					
						
							|  |  |  | 	filterFunction FilterFunction, | 
					
						
							|  |  |  | 	prepareFunction PrepareFunction, | 
					
						
							| 
									
										
										
										
											2022-12-08 17:35:14 +00:00
										 |  |  | 	skipInsertFunction SkipInsertFunction, | 
					
						
							| 
									
										
										
										
											2023-04-06 13:43:13 +02:00
										 |  |  | ) Timeline { | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 	return &timeline{ | 
					
						
							| 
									
										
										
										
											2023-04-06 13:43:13 +02:00
										 |  |  | 		items: &indexedItems{ | 
					
						
							| 
									
										
										
										
											2022-02-05 12:47:38 +01:00
										 |  |  | 			skipInsert: skipInsertFunction, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		grabFunction:    grabFunction, | 
					
						
							|  |  |  | 		filterFunction:  filterFunction, | 
					
						
							|  |  |  | 		prepareFunction: prepareFunction, | 
					
						
							| 
									
										
										
										
											2023-05-25 10:37:38 +02:00
										 |  |  | 		timelineID:      timelineID, | 
					
						
							| 
									
										
										
										
											2022-11-22 19:38:10 +01:00
										 |  |  | 		lastGot:         time.Time{}, | 
					
						
							| 
									
										
										
										
											2023-04-06 13:43:13 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | } |