diff options
author | 2023-02-10 20:15:23 +0000 | |
---|---|---|
committer | 2023-02-10 20:15:23 +0000 | |
commit | 6ac1dda96f2e0230159fdfcc05195a94bda36d21 (patch) | |
tree | 9a179d5fd0211f2e7578e9f6b4b927efc11e6b00 /internal/federation/dereferencing/account.go | |
parent | [bugfix] Fix error on searching for account w/accountDomain by host (#1465) (diff) | |
download | gotosocial-6ac1dda96f2e0230159fdfcc05195a94bda36d21.tar.xz |
[chore] small changes missed in previous dereferencer.GetAccount() PRs (#1467)
* small formatting changes, rewrite fetchRemoteMedia to use separate funcs + use mutex lock correctly
* move url parsing before acquiring mutex locks
* use wrapped mutexes to allow safe unlocking. (previously i did a fucky and passed mutex by value...)
* remove unused code
* use consistent map keying for dereferencing headers/avatars
---------
Signed-off-by: kim <grufwub@gmail.com>
Diffstat (limited to 'internal/federation/dereferencing/account.go')
-rw-r--r-- | internal/federation/dereferencing/account.go | 165 |
1 files changed, 110 insertions, 55 deletions
diff --git a/internal/federation/dereferencing/account.go b/internal/federation/dereferencing/account.go index 14864c1b5..82b69c7a1 100644 --- a/internal/federation/dereferencing/account.go +++ b/internal/federation/dereferencing/account.go @@ -146,6 +146,7 @@ func (d *deref) enrichAccount(ctx context.Context, requestUser string, uri *url. } } + // Pre-fetch a transport for requesting username, used by later deref procedures. transport, err := d.transportController.NewTransportForUsername(ctx, requestUser) if err != nil { return nil, fmt.Errorf("enrichAccount: couldn't create transport: %w", err) @@ -163,19 +164,14 @@ func (d *deref) enrichAccount(ctx context.Context, requestUser string, uri *url. if err == nil { if account.Domain != accDomain { - // We have the correct accountDomain now; if it was different from - // the account domain we were provided, do another db lookup to check - // if we already had the account in the db under the account domain we - // just discovered, otherwise we risk thinking this is a new account - // and trying to put it into the database again (which will cause issues). + // After webfinger, we now have correct account domain from which we can do a final DB check. alreadyAccount, err := d.db.GetAccountByUsernameDomain(ctx, account.Username, accDomain) if err != nil && !errors.Is(err, db.ErrNoEntries) { return nil, fmt.Errorf("enrichAccount: db err looking for account again after webfinger: %w", err) } if err == nil { - // We already had the account in the database; - // continue by enriching that one instead. + // Enrich existing account. account = alreadyAccount } } @@ -197,14 +193,14 @@ func (d *deref) enrichAccount(ctx context.Context, requestUser string, uri *url. } } - // Check whether this account URI is a blocked domain / subdomain + // Check whether this account URI is a blocked domain / subdomain. if blocked, err := d.db.IsDomainBlocked(ctx, uri.Host); err != nil { return nil, newErrDB(fmt.Errorf("enrichAccount: error checking blocked domain: %w", err)) } else if blocked { return nil, fmt.Errorf("enrichAccount: %s is blocked", uri.Host) } - // Mark deref+update handshake start + // Mark deref+update handshake start. d.startHandshake(requestUser, uri) defer d.stopHandshake(requestUser, uri) @@ -225,7 +221,7 @@ func (d *deref) enrichAccount(ctx context.Context, requestUser string, uri *url. if account.Username == "" { // No username was provided, so no webfinger was attempted earlier. // - // Now we have a username we can attempt it now, this ensures up-to-date accountdomain info. + // Now we have a username we can attempt it, this ensures up-to-date accountdomain info. accDomain, _, err := d.fingerRemoteAccount(ctx, transport, latestAcc.Username, uri.Host) if err == nil { @@ -238,32 +234,32 @@ func (d *deref) enrichAccount(ctx context.Context, requestUser string, uri *url. latestAcc.ID = account.ID latestAcc.FetchedAt = time.Now() - // Fetch latest account avatar only if remote URI has changed - if latestAcc.AvatarRemoteURL != "" && latestAcc.AvatarRemoteURL != account.AvatarRemoteURL { - d.dereferencingAvatarsLock.Lock() - newAvatarID, err := d.fetchRemoteAccountMedia(ctx, transport, latestAcc.AvatarRemoteURL, latestAcc.ID, d.dereferencingAvatars, true, false) - d.dereferencingAvatarsLock.Unlock() + // Use the existing account media attachments by default. + latestAcc.AvatarMediaAttachmentID = account.AvatarMediaAttachmentID + latestAcc.HeaderMediaAttachmentID = account.HeaderMediaAttachmentID + + if latestAcc.AvatarRemoteURL != account.AvatarRemoteURL && latestAcc.AvatarRemoteURL != "" { + // Account avatar URL has changed; fetch up-to-date copy and use new media ID. + latestAcc.AvatarMediaAttachmentID, err = d.fetchRemoteAccountAvatar(ctx, + transport, + latestAcc.AvatarRemoteURL, + latestAcc.ID, + ) if err != nil { log.Errorf("error fetching remote avatar for account %s: %v", uri, err) - } else { - latestAcc.AvatarMediaAttachmentID = newAvatarID } - } else { - latestAcc.AvatarMediaAttachmentID = account.AvatarMediaAttachmentID // no change / empty url } - // Fetch latest account header only if remote URI has changed - if latestAcc.AvatarRemoteURL != "" && latestAcc.AvatarRemoteURL != account.AvatarRemoteURL { - d.dereferencingHeadersLock.Lock() - newHeaderID, err := d.fetchRemoteAccountMedia(ctx, transport, latestAcc.HeaderRemoteURL, latestAcc.ID, d.dereferencingHeaders, false, true) - d.dereferencingHeadersLock.Unlock() + if latestAcc.HeaderRemoteURL != account.HeaderRemoteURL && latestAcc.HeaderRemoteURL != "" { + // Account header URL has changed; fetch up-to-date copy and use new media ID. + latestAcc.HeaderMediaAttachmentID, err = d.fetchRemoteAccountHeader(ctx, + transport, + latestAcc.HeaderRemoteURL, + latestAcc.ID, + ) if err != nil { log.Errorf("error fetching remote header for account %s: %v", uri, err) - } else { - latestAcc.HeaderMediaAttachmentID = newHeaderID } - } else { - latestAcc.HeaderMediaAttachmentID = account.HeaderMediaAttachmentID // no change / empty url } // Fetch the latest remote account emoji IDs used in account display name/bio. @@ -338,47 +334,106 @@ func (d *deref) dereferenceAccountable(ctx context.Context, transport transport. return nil, newErrWrongType(fmt.Errorf("DereferenceAccountable: type name %s not supported as Accountable", t.GetTypeName())) } -func (d *deref) fetchRemoteAccountMedia( - ctx context.Context, - transport transport.Transport, - mediaRemoteURL string, - targetAccountID string, - dereferencingMap map[string]*media.ProcessingMedia, - avatar bool, - header bool, -) (string, error) { - // first check if we're already processing this media - if alreadyProcessing, ok := dereferencingMap[targetAccountID]; ok { - // we're already on it, nothing else to do - return alreadyProcessing.AttachmentID(), nil - } - - avatarIRI, err := url.Parse(mediaRemoteURL) +func (d *deref) fetchRemoteAccountAvatar(ctx context.Context, tsport transport.Transport, avatarURL string, accountID string) (string, error) { + // Parse and validate provided media URL. + avatarURI, err := url.Parse(avatarURL) + if err != nil { + return "", err + } + + // Acquire lock for derefs map. + unlock := d.derefAvatarsMu.Lock() + defer unlock() + + if processing, ok := d.derefAvatars[avatarURL]; ok { + // we're already dereferencing it, nothing to do. + return processing.AttachmentID(), nil + } + + // Set the media data function to dereference avatar from URI. + data := func(ctx context.Context) (io.ReadCloser, int64, error) { + return tsport.DereferenceMedia(ctx, avatarURI) + } + + // Create new media processing request from the media manager instance. + processing, err := d.mediaManager.ProcessMedia(ctx, data, nil, accountID, &media.AdditionalMediaInfo{ + Avatar: func() *bool { v := false; return &v }(), + RemoteURL: &avatarURL, + }) + if err != nil { + return "", err + } + + // Store media in map to mark as processing. + d.derefAvatars[avatarURL] = processing + + // Unlock map. + unlock() + + defer func() { + // On exit safely remove media from map. + unlock := d.derefAvatarsMu.Lock() + delete(d.derefAvatars, avatarURL) + unlock() + }() + + // Start media attachment loading (blocking call). + if _, err := processing.LoadAttachment(ctx); err != nil { + return "", err + } + + return processing.AttachmentID(), nil +} + +func (d *deref) fetchRemoteAccountHeader(ctx context.Context, tsport transport.Transport, headerURL string, accountID string) (string, error) { + // Parse and validate provided media URL. + headerURI, err := url.Parse(headerURL) if err != nil { return "", err } - data := func(innerCtx context.Context) (io.ReadCloser, int64, error) { - return transport.DereferenceMedia(innerCtx, avatarIRI) + // Acquire lock for derefs map. + unlock := d.derefHeadersMu.Lock() + defer unlock() + + if processing, ok := d.derefHeaders[headerURL]; ok { + // we're already dereferencing it, nothing to do. + return processing.AttachmentID(), nil + } + + // Set the media data function to dereference header from URI. + data := func(ctx context.Context) (io.ReadCloser, int64, error) { + return tsport.DereferenceMedia(ctx, headerURI) } - processingMedia, err := d.mediaManager.ProcessMedia(ctx, data, nil, targetAccountID, &media.AdditionalMediaInfo{ - RemoteURL: &mediaRemoteURL, - Avatar: &avatar, - Header: &header, + // Create new media processing request from the media manager instance. + processing, err := d.mediaManager.ProcessMedia(ctx, data, nil, accountID, &media.AdditionalMediaInfo{ + Header: func() *bool { v := true; return &v }(), + RemoteURL: &headerURL, }) if err != nil { return "", err } - // store it in our map to indicate it's in process - dereferencingMap[targetAccountID] = processingMedia - defer delete(dereferencingMap, targetAccountID) - if _, err := processingMedia.LoadAttachment(ctx); err != nil { + // Store media in map to mark as processing. + d.derefHeaders[headerURL] = processing + + // Unlock map. + unlock() + + defer func() { + // On exit safely remove media from map. + unlock := d.derefHeadersMu.Lock() + delete(d.derefHeaders, headerURL) + unlock() + }() + + // Start media attachment loading (blocking call). + if _, err := processing.LoadAttachment(ctx); err != nil { return "", err } - return processingMedia.AttachmentID(), nil + return processing.AttachmentID(), nil } func (d *deref) fetchRemoteAccountEmojis(ctx context.Context, targetAccount *gtsmodel.Account, requestingUsername string) (bool, error) { |