gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

timeline.go (6584B)


      1 // GoToSocial
      2 // Copyright (C) GoToSocial Authors admin@gotosocial.org
      3 // SPDX-License-Identifier: AGPL-3.0-or-later
      4 //
      5 // This program is free software: you can redistribute it and/or modify
      6 // it under the terms of the GNU Affero General Public License as published by
      7 // the Free Software Foundation, either version 3 of the License, or
      8 // (at your option) any later version.
      9 //
     10 // This program is distributed in the hope that it will be useful,
     11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 // GNU Affero General Public License for more details.
     14 //
     15 // You should have received a copy of the GNU Affero General Public License
     16 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 
     18 package timeline
     19 
     20 import (
     21 	"context"
     22 	"sync"
     23 	"time"
     24 )
     25 
     26 // GrabFunction is used by a Timeline to grab more items to index.
     27 //
     28 // It should be provided to NewTimeline when the caller is creating a timeline
     29 // (of statuses, notifications, etc).
     30 //
     31 //   - timelineID: ID of the timeline.
     32 //   - maxID: the maximum item ID desired.
     33 //   - sinceID: the minimum item ID desired.
     34 //   - minID: see sinceID
     35 //   - limit: the maximum amount of items to be returned
     36 //
     37 // If an error is returned, the timeline will stop processing whatever request called GrabFunction,
     38 // and return the error. If no error is returned, but stop = true, this indicates to the caller of GrabFunction
     39 // that there are no more items to return, and processing should continue with the items already grabbed.
     40 type GrabFunction func(ctx context.Context, timelineID string, maxID string, sinceID string, minID string, limit int) (items []Timelineable, stop bool, err error)
     41 
     42 // FilterFunction is used by a Timeline to filter whether or not a grabbed item should be indexed.
     43 type FilterFunction func(ctx context.Context, timelineID string, item Timelineable) (shouldIndex bool, err error)
     44 
     45 // PrepareFunction converts a Timelineable into a Preparable.
     46 //
     47 // For example, this might result in the converstion of a *gtsmodel.Status with the given itemID into a serializable *apimodel.Status.
     48 type PrepareFunction func(ctx context.Context, timelineID string, itemID string) (Preparable, error)
     49 
     50 // SkipInsertFunction indicates whether a new item about to be inserted in the prepared list should be skipped,
     51 // based on the item itself, the next item in the timeline, and the depth at which nextItem has been found in the list.
     52 //
     53 // This will be called for every item found while iterating through a timeline, so callers should be very careful
     54 // not to do anything expensive here.
     55 type SkipInsertFunction func(ctx context.Context,
     56 	newItemID string,
     57 	newItemAccountID string,
     58 	newItemBoostOfID string,
     59 	newItemBoostOfAccountID string,
     60 	nextItemID string,
     61 	nextItemAccountID string,
     62 	nextItemBoostOfID string,
     63 	nextItemBoostOfAccountID string,
     64 	depth int) (bool, error)
     65 
     66 // Timeline represents a timeline for one account, and contains indexed and prepared items.
     67 type Timeline interface {
     68 	/*
     69 		RETRIEVAL FUNCTIONS
     70 	*/
     71 
     72 	// Get returns an amount of prepared items with the given parameters.
     73 	// If prepareNext is true, then the next predicted query will be prepared already in a goroutine,
     74 	// to make the next call to Get faster.
     75 	Get(ctx context.Context, amount int, maxID string, sinceID string, minID string, prepareNext bool) ([]Preparable, error)
     76 
     77 	/*
     78 		INDEXING + PREPARATION FUNCTIONS
     79 	*/
     80 
     81 	// IndexAndPrepareOne puts a item into the timeline at the appropriate place
     82 	// according to its id, and then immediately prepares it.
     83 	//
     84 	// The returned bool indicates whether or not the item was actually inserted
     85 	// into the timeline. This will be false if the item is a boost and the original
     86 	// item, or a boost of it, already exists recently in the timeline.
     87 	IndexAndPrepareOne(ctx context.Context, itemID string, boostOfID string, accountID string, boostOfAccountID string) (bool, error)
     88 
     89 	// Unprepare clears the prepared version of the given item (and any boosts
     90 	// thereof) from the timeline, but leaves the indexed version in place.
     91 	//
     92 	// This is useful for cache invalidation when the prepared version of the
     93 	// item has changed for some reason (edits, updates, etc), but the item does
     94 	// not need to be removed: it will be prepared again next time Get is called.
     95 	Unprepare(ctx context.Context, itemID string) error
     96 
     97 	/*
     98 		INFO FUNCTIONS
     99 	*/
    100 
    101 	// TimelineID returns the id of this timeline.
    102 	TimelineID() string
    103 
    104 	// Len returns the length of the item index at this point in time.
    105 	Len() int
    106 
    107 	// OldestIndexedItemID returns the id of the rearmost (ie., the oldest) indexed item.
    108 	// If there's no oldest item, an empty string will be returned so make sure to check for this.
    109 	OldestIndexedItemID() string
    110 
    111 	/*
    112 		UTILITY FUNCTIONS
    113 	*/
    114 
    115 	// LastGot returns the time that Get was last called.
    116 	LastGot() time.Time
    117 
    118 	// Prune prunes prepared and indexed items in this timeline to the desired lengths.
    119 	// This will be a no-op if the lengths are already < the desired values.
    120 	//
    121 	// The returned int indicates the amount of entries that were removed or unprepared.
    122 	Prune(desiredPreparedItemsLength int, desiredIndexedItemsLength int) int
    123 
    124 	// Remove removes an item with the given ID.
    125 	//
    126 	// If a item has multiple entries in a timeline, they will all be removed.
    127 	//
    128 	// The returned int indicates the amount of entries that were removed.
    129 	Remove(ctx context.Context, itemID string) (int, error)
    130 
    131 	// RemoveAllByOrBoosting removes all items created by or boosting the given accountID.
    132 	//
    133 	// The returned int indicates the amount of entries that were removed.
    134 	RemoveAllByOrBoosting(ctx context.Context, accountID string) (int, error)
    135 }
    136 
    137 // timeline fulfils the Timeline interface
    138 type timeline struct {
    139 	items           *indexedItems
    140 	grabFunction    GrabFunction
    141 	filterFunction  FilterFunction
    142 	prepareFunction PrepareFunction
    143 	timelineID      string
    144 	lastGot         time.Time
    145 	sync.Mutex
    146 }
    147 
    148 func (t *timeline) TimelineID() string {
    149 	return t.timelineID
    150 }
    151 
    152 // NewTimeline returns a new Timeline with
    153 // the given ID, using the given functions.
    154 func NewTimeline(
    155 	ctx context.Context,
    156 	timelineID string,
    157 	grabFunction GrabFunction,
    158 	filterFunction FilterFunction,
    159 	prepareFunction PrepareFunction,
    160 	skipInsertFunction SkipInsertFunction,
    161 ) Timeline {
    162 	return &timeline{
    163 		items: &indexedItems{
    164 			skipInsert: skipInsertFunction,
    165 		},
    166 		grabFunction:    grabFunction,
    167 		filterFunction:  filterFunction,
    168 		prepareFunction: prepareFunction,
    169 		timelineID:      timelineID,
    170 		lastGot:         time.Time{},
    171 	}
    172 }