dereferencer.go (7381B)
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 dereferencing 19 20 import ( 21 "context" 22 "net/url" 23 "sync" 24 25 "codeberg.org/gruf/go-mutexes" 26 "github.com/superseriousbusiness/gotosocial/internal/ap" 27 "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" 28 "github.com/superseriousbusiness/gotosocial/internal/media" 29 "github.com/superseriousbusiness/gotosocial/internal/state" 30 "github.com/superseriousbusiness/gotosocial/internal/transport" 31 "github.com/superseriousbusiness/gotosocial/internal/typeutils" 32 ) 33 34 // Dereferencer wraps logic and functionality for doing dereferencing of remote accounts, statuses, etc, from federated instances. 35 type Dereferencer interface { 36 // GetAccountByURI will attempt to fetch an accounts by its URI, first checking the database. In the case of a newly-met remote model, or a remote model 37 // whose last_fetched date is beyond a certain interval, the account will be dereferenced. In the case of dereferencing, some low-priority account information 38 // may be enqueued for asynchronous fetching, e.g. featured account statuses (pins). An ActivityPub object indicates the account was dereferenced. 39 GetAccountByURI(ctx context.Context, requestUser string, uri *url.URL) (*gtsmodel.Account, ap.Accountable, error) 40 41 // GetAccountByUsernameDomain will attempt to fetch an accounts by its username@domain, first checking the database. In the case of a newly-met remote model, 42 // or a remote model whose last_fetched date is beyond a certain interval, the account will be dereferenced. In the case of dereferencing, some low-priority 43 // account information may be enqueued for asynchronous fetching, e.g. featured account statuses (pins). An ActivityPub object indicates the account was dereferenced. 44 GetAccountByUsernameDomain(ctx context.Context, requestUser string, username string, domain string) (*gtsmodel.Account, ap.Accountable, error) 45 46 // RefreshAccount updates the given account if remote and last_fetched is beyond fetch interval, or if force is set. An updated account model is returned, 47 // but in the case of dereferencing, some low-priority account information may be enqueued for asynchronous fetching, e.g. featured account statuses (pins). 48 // An ActivityPub object indicates the account was dereferenced (i.e. updated). 49 RefreshAccount(ctx context.Context, requestUser string, account *gtsmodel.Account, apubAcc ap.Accountable, force bool) (*gtsmodel.Account, ap.Accountable, error) 50 51 // RefreshAccountAsync enqueues the given account for an asychronous update fetching, if last_fetched is beyond fetch interval, or if forcc is set. 52 // This is a more optimized form of manually enqueueing .UpdateAccount() to the federation worker, since it only enqueues update if necessary. 53 RefreshAccountAsync(ctx context.Context, requestUser string, account *gtsmodel.Account, apubAcc ap.Accountable, force bool) 54 55 // GetStatusByURI will attempt to fetch a status by its URI, first checking the database. In the case of a newly-met remote model, or a remote model 56 // whose last_fetched date is beyond a certain interval, the status will be dereferenced. In the case of dereferencing, some low-priority status information 57 // may be enqueued for asynchronous fetching, e.g. dereferencing the remainder of the status thread. An ActivityPub object indicates the status was dereferenced. 58 GetStatusByURI(ctx context.Context, requestUser string, uri *url.URL) (*gtsmodel.Status, ap.Statusable, error) 59 60 // RefreshStatus updates the given status if remote and last_fetched is beyond fetch interval, or if force is set. An updated status model is returned, 61 // but in the case of dereferencing, some low-priority status information may be enqueued for asynchronous fetching, e.g. dereferencing the remainder of the 62 // status thread. An ActivityPub object indicates the status was dereferenced (i.e. updated). 63 RefreshStatus(ctx context.Context, requestUser string, status *gtsmodel.Status, apubStatus ap.Statusable, force bool) (*gtsmodel.Status, ap.Statusable, error) 64 65 // RefreshStatusAsync enqueues the given status for an asychronous update fetching, if last_fetched is beyond fetch interval, or if force is set. 66 // This is a more optimized form of manually enqueueing .UpdateStatus() to the federation worker, since it only enqueues update if necessary. 67 RefreshStatusAsync(ctx context.Context, requestUser string, status *gtsmodel.Status, apubStatus ap.Statusable, force bool) 68 69 GetRemoteInstance(ctx context.Context, username string, remoteInstanceURI *url.URL) (*gtsmodel.Instance, error) 70 71 DereferenceAnnounce(ctx context.Context, announce *gtsmodel.Status, requestingUsername string) error 72 73 GetRemoteMedia(ctx context.Context, requestingUsername string, accountID string, remoteURL string, ai *media.AdditionalMediaInfo) (*media.ProcessingMedia, error) 74 75 GetRemoteEmoji(ctx context.Context, requestingUsername string, remoteURL string, shortcode string, domain string, id string, emojiURI string, ai *media.AdditionalEmojiInfo, refresh bool) (*media.ProcessingEmoji, error) 76 77 Handshaking(username string, remoteAccountID *url.URL) bool 78 } 79 80 type deref struct { 81 state *state.State 82 typeConverter typeutils.TypeConverter 83 transportController transport.Controller 84 mediaManager *media.Manager 85 derefAvatars map[string]*media.ProcessingMedia 86 derefAvatarsMu mutexes.Mutex 87 derefHeaders map[string]*media.ProcessingMedia 88 derefHeadersMu mutexes.Mutex 89 derefEmojis map[string]*media.ProcessingEmoji 90 derefEmojisMu mutexes.Mutex 91 handshakes map[string][]*url.URL 92 handshakeSync sync.Mutex // mutex to lock/unlock when checking or updating the handshakes map 93 } 94 95 // NewDereferencer returns a Dereferencer initialized with the given parameters. 96 func NewDereferencer(state *state.State, typeConverter typeutils.TypeConverter, transportController transport.Controller, mediaManager *media.Manager) Dereferencer { 97 return &deref{ 98 state: state, 99 typeConverter: typeConverter, 100 transportController: transportController, 101 mediaManager: mediaManager, 102 derefAvatars: make(map[string]*media.ProcessingMedia), 103 derefHeaders: make(map[string]*media.ProcessingMedia), 104 derefEmojis: make(map[string]*media.ProcessingEmoji), 105 handshakes: make(map[string][]*url.URL), 106 107 // use wrapped mutexes to allow safely deferring unlock 108 // even when more granular locks are required (only unlocks once). 109 derefAvatarsMu: mutexes.WithSafety(mutexes.New()), 110 derefHeadersMu: mutexes.WithSafety(mutexes.New()), 111 derefEmojisMu: mutexes.WithSafety(mutexes.New()), 112 } 113 }