summaryrefslogtreecommitdiff
path: root/internal/federation
diff options
context:
space:
mode:
Diffstat (limited to 'internal/federation')
-rw-r--r--internal/federation/dereferencing/account.go114
-rw-r--r--internal/federation/dereferencing/collection.go2
-rw-r--r--internal/federation/federatingdb/accept.go20
-rw-r--r--internal/federation/federatingdb/announce.go9
-rw-r--r--internal/federation/federatingdb/create.go65
-rw-r--r--internal/federation/federatingdb/delete.go9
-rw-r--r--internal/federation/federatingdb/update.go22
7 files changed, 184 insertions, 57 deletions
diff --git a/internal/federation/dereferencing/account.go b/internal/federation/dereferencing/account.go
index 305b3f05c..e8d32f58a 100644
--- a/internal/federation/dereferencing/account.go
+++ b/internal/federation/dereferencing/account.go
@@ -695,7 +695,7 @@ func (d *Dereferencer) enrichAccount(
representation of the target account, derived from
a combination of webfinger lookups and dereferencing.
Further fetching beyond this point is for peripheral
- things like account avatar, header, emojis.
+ things like account avatar, header, emojis, stats.
*/
// Ensure internal db ID is
@@ -718,6 +718,11 @@ func (d *Dereferencer) enrichAccount(
log.Errorf(ctx, "error fetching remote emojis for account %s: %v", uri, err)
}
+ // Fetch followers/following count for this account.
+ if err := d.fetchRemoteAccountStats(ctx, latestAcc, requestUser); err != nil {
+ log.Errorf(ctx, "error fetching remote stats for account %s: %v", uri, err)
+ }
+
if account.IsNew() {
// Prefer published/created time from
// apubAcc, fall back to FetchedAt value.
@@ -1036,6 +1041,113 @@ func (d *Dereferencer) fetchRemoteAccountEmojis(ctx context.Context, targetAccou
return changed, nil
}
+func (d *Dereferencer) fetchRemoteAccountStats(ctx context.Context, account *gtsmodel.Account, requestUser string) error {
+ // Ensure we have a stats model for this account.
+ if account.Stats == nil {
+ if err := d.state.DB.PopulateAccountStats(ctx, account); err != nil {
+ return gtserror.Newf("db error getting account stats: %w", err)
+ }
+ }
+
+ // We want to update stats by getting remote
+ // followers/following/statuses counts for
+ // this account.
+ //
+ // If we fail getting any particular stat,
+ // it will just fall back to counting local.
+
+ // Followers first.
+ if count, err := d.countCollection(
+ ctx,
+ account.FollowersURI,
+ requestUser,
+ ); err != nil {
+ // Log this but don't bail.
+ log.Warnf(ctx,
+ "couldn't count followers for @%s@%s: %v",
+ account.Username, account.Domain, err,
+ )
+ } else if count > 0 {
+ // Positive integer is useful!
+ account.Stats.FollowersCount = &count
+ }
+
+ // Now following.
+ if count, err := d.countCollection(
+ ctx,
+ account.FollowingURI,
+ requestUser,
+ ); err != nil {
+ // Log this but don't bail.
+ log.Warnf(ctx,
+ "couldn't count following for @%s@%s: %v",
+ account.Username, account.Domain, err,
+ )
+ } else if count > 0 {
+ // Positive integer is useful!
+ account.Stats.FollowingCount = &count
+ }
+
+ // Now statuses count.
+ if count, err := d.countCollection(
+ ctx,
+ account.OutboxURI,
+ requestUser,
+ ); err != nil {
+ // Log this but don't bail.
+ log.Warnf(ctx,
+ "couldn't count statuses for @%s@%s: %v",
+ account.Username, account.Domain, err,
+ )
+ } else if count > 0 {
+ // Positive integer is useful!
+ account.Stats.StatusesCount = &count
+ }
+
+ // Update stats now.
+ if err := d.state.DB.UpdateAccountStats(
+ ctx,
+ account.Stats,
+ "followers_count",
+ "following_count",
+ "statuses_count",
+ ); err != nil {
+ return gtserror.Newf("db error updating account stats: %w", err)
+ }
+
+ return nil
+}
+
+// countCollection parses the given uriStr,
+// dereferences the result as a collection
+// type, and returns total items as 0, or
+// a positive integer, or -1 if total items
+// cannot be counted.
+//
+// Error will be returned for invalid non-empty
+// URIs or dereferencing isses.
+func (d *Dereferencer) countCollection(
+ ctx context.Context,
+ uriStr string,
+ requestUser string,
+) (int, error) {
+ if uriStr == "" {
+ return -1, nil
+ }
+
+ uri, err := url.Parse(uriStr)
+ if err != nil {
+ return -1, err
+ }
+
+ collect, err := d.dereferenceCollection(ctx, requestUser, uri)
+ if err != nil {
+ return -1, err
+ }
+
+ return collect.TotalItems(), nil
+}
+
// dereferenceAccountFeatured dereferences an account's featuredCollectionURI (if not empty). For each discovered status, this status will
// be dereferenced (if necessary) and marked as pinned (if necessary). Then, old pins will be removed if they're not included in new pins.
func (d *Dereferencer) dereferenceAccountFeatured(ctx context.Context, requestUser string, account *gtsmodel.Account) error {
diff --git a/internal/federation/dereferencing/collection.go b/internal/federation/dereferencing/collection.go
index 07f56c952..1a9f1555b 100644
--- a/internal/federation/dereferencing/collection.go
+++ b/internal/federation/dereferencing/collection.go
@@ -40,7 +40,7 @@ func (d *Dereferencer) dereferenceCollection(ctx context.Context, username strin
rsp, err := transport.Dereference(ctx, pageIRI)
if err != nil {
- return nil, gtserror.Newf("error deferencing %s: %w", pageIRI.String(), err)
+ return nil, gtserror.Newf("error dereferencing %s: %w", pageIRI.String(), err)
}
collect, err := ap.ResolveCollection(ctx, rsp.Body)
diff --git a/internal/federation/federatingdb/accept.go b/internal/federation/federatingdb/accept.go
index 7ec9346e0..50a7c2db1 100644
--- a/internal/federation/federatingdb/accept.go
+++ b/internal/federation/federatingdb/accept.go
@@ -89,11 +89,13 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA
return err
}
+ // Process side effects asynchronously.
f.state.Workers.EnqueueFediAPI(ctx, messages.FromFediAPI{
- APObjectType: ap.ActivityFollow,
- APActivityType: ap.ActivityAccept,
- GTSModel: follow,
- ReceivingAccount: receivingAcct,
+ APObjectType: ap.ActivityFollow,
+ APActivityType: ap.ActivityAccept,
+ GTSModel: follow,
+ ReceivingAccount: receivingAcct,
+ RequestingAccount: requestingAcct,
})
}
@@ -136,11 +138,13 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA
return err
}
+ // Process side effects asynchronously.
f.state.Workers.EnqueueFediAPI(ctx, messages.FromFediAPI{
- APObjectType: ap.ActivityFollow,
- APActivityType: ap.ActivityAccept,
- GTSModel: follow,
- ReceivingAccount: receivingAcct,
+ APObjectType: ap.ActivityFollow,
+ APActivityType: ap.ActivityAccept,
+ GTSModel: follow,
+ ReceivingAccount: receivingAcct,
+ RequestingAccount: requestingAcct,
})
continue
diff --git a/internal/federation/federatingdb/announce.go b/internal/federation/federatingdb/announce.go
index e13e212da..2f5950a30 100644
--- a/internal/federation/federatingdb/announce.go
+++ b/internal/federation/federatingdb/announce.go
@@ -82,10 +82,11 @@ func (f *federatingDB) Announce(ctx context.Context, announce vocab.ActivityStre
// This is a new boost. Process side effects asynchronously.
f.state.Workers.EnqueueFediAPI(ctx, messages.FromFediAPI{
- APObjectType: ap.ActivityAnnounce,
- APActivityType: ap.ActivityCreate,
- GTSModel: boost,
- ReceivingAccount: receivingAcct,
+ APObjectType: ap.ActivityAnnounce,
+ APActivityType: ap.ActivityCreate,
+ GTSModel: boost,
+ ReceivingAccount: receivingAcct,
+ RequestingAccount: requestingAcct,
})
return nil
diff --git a/internal/federation/federatingdb/create.go b/internal/federation/federatingdb/create.go
index cacaf07cf..94261526e 100644
--- a/internal/federation/federatingdb/create.go
+++ b/internal/federation/federatingdb/create.go
@@ -131,10 +131,11 @@ func (f *federatingDB) activityBlock(ctx context.Context, asType vocab.Type, rec
}
f.state.Workers.EnqueueFediAPI(ctx, messages.FromFediAPI{
- APObjectType: ap.ActivityBlock,
- APActivityType: ap.ActivityCreate,
- GTSModel: block,
- ReceivingAccount: receiving,
+ APObjectType: ap.ActivityBlock,
+ APActivityType: ap.ActivityCreate,
+ GTSModel: block,
+ ReceivingAccount: receiving,
+ RequestingAccount: requestingAccount,
})
return nil
@@ -307,7 +308,8 @@ func (f *federatingDB) createPollOptionables(
PollID: inReplyTo.PollID,
Poll: inReplyTo.Poll,
},
- ReceivingAccount: receiver,
+ ReceivingAccount: receiver,
+ RequestingAccount: requester,
})
return nil
@@ -376,12 +378,13 @@ func (f *federatingDB) createStatusable(
// Pass the statusable URI (APIri) into the processor
// worker and do the rest of the processing asynchronously.
f.state.Workers.EnqueueFediAPI(ctx, messages.FromFediAPI{
- APObjectType: ap.ObjectNote,
- APActivityType: ap.ActivityCreate,
- APIri: ap.GetJSONLDId(statusable),
- APObjectModel: nil,
- GTSModel: nil,
- ReceivingAccount: receiver,
+ APObjectType: ap.ObjectNote,
+ APActivityType: ap.ActivityCreate,
+ APIri: ap.GetJSONLDId(statusable),
+ APObjectModel: nil,
+ GTSModel: nil,
+ ReceivingAccount: receiver,
+ RequestingAccount: requester,
})
return nil
}
@@ -389,12 +392,13 @@ func (f *federatingDB) createStatusable(
// Do the rest of the processing asynchronously. The processor
// will handle inserting/updating + further dereferencing the status.
f.state.Workers.EnqueueFediAPI(ctx, messages.FromFediAPI{
- APObjectType: ap.ObjectNote,
- APActivityType: ap.ActivityCreate,
- APIri: nil,
- GTSModel: nil,
- APObjectModel: statusable,
- ReceivingAccount: receiver,
+ APObjectType: ap.ObjectNote,
+ APActivityType: ap.ActivityCreate,
+ APIri: nil,
+ GTSModel: nil,
+ APObjectModel: statusable,
+ ReceivingAccount: receiver,
+ RequestingAccount: requester,
})
return nil
@@ -436,10 +440,11 @@ func (f *federatingDB) activityFollow(ctx context.Context, asType vocab.Type, re
}
f.state.Workers.EnqueueFediAPI(ctx, messages.FromFediAPI{
- APObjectType: ap.ActivityFollow,
- APActivityType: ap.ActivityCreate,
- GTSModel: followRequest,
- ReceivingAccount: receivingAccount,
+ APObjectType: ap.ActivityFollow,
+ APActivityType: ap.ActivityCreate,
+ GTSModel: followRequest,
+ ReceivingAccount: receivingAccount,
+ RequestingAccount: requestingAccount,
})
return nil
@@ -480,10 +485,11 @@ func (f *federatingDB) activityLike(ctx context.Context, asType vocab.Type, rece
}
f.state.Workers.EnqueueFediAPI(ctx, messages.FromFediAPI{
- APObjectType: ap.ActivityLike,
- APActivityType: ap.ActivityCreate,
- GTSModel: fave,
- ReceivingAccount: receivingAccount,
+ APObjectType: ap.ActivityLike,
+ APActivityType: ap.ActivityCreate,
+ GTSModel: fave,
+ ReceivingAccount: receivingAccount,
+ RequestingAccount: requestingAccount,
})
return nil
@@ -531,10 +537,11 @@ func (f *federatingDB) activityFlag(ctx context.Context, asType vocab.Type, rece
}
f.state.Workers.EnqueueFediAPI(ctx, messages.FromFediAPI{
- APObjectType: ap.ActivityFlag,
- APActivityType: ap.ActivityCreate,
- GTSModel: report,
- ReceivingAccount: receivingAccount,
+ APObjectType: ap.ActivityFlag,
+ APActivityType: ap.ActivityCreate,
+ GTSModel: report,
+ ReceivingAccount: receivingAccount,
+ RequestingAccount: requestingAccount,
})
return nil
diff --git a/internal/federation/federatingdb/delete.go b/internal/federation/federatingdb/delete.go
index 384291463..14bc20209 100644
--- a/internal/federation/federatingdb/delete.go
+++ b/internal/federation/federatingdb/delete.go
@@ -63,10 +63,11 @@ func (f *federatingDB) Delete(ctx context.Context, id *url.URL) error {
if a, err := f.state.DB.GetAccountByURI(ctx, id.String()); err == nil && requestingAcct.ID == a.ID {
l.Debugf("deleting account: %s", a.ID)
f.state.Workers.EnqueueFediAPI(ctx, messages.FromFediAPI{
- APObjectType: ap.ObjectProfile,
- APActivityType: ap.ActivityDelete,
- GTSModel: a,
- ReceivingAccount: receivingAcct,
+ APObjectType: ap.ObjectProfile,
+ APActivityType: ap.ActivityDelete,
+ GTSModel: a,
+ ReceivingAccount: receivingAcct,
+ RequestingAccount: requestingAcct,
})
}
diff --git a/internal/federation/federatingdb/update.go b/internal/federation/federatingdb/update.go
index bd8ad3106..733abba0d 100644
--- a/internal/federation/federatingdb/update.go
+++ b/internal/federation/federatingdb/update.go
@@ -99,11 +99,12 @@ func (f *federatingDB) updateAccountable(ctx context.Context, receivingAcct *gts
// updating of eg., avatar/header, emojis, etc. The actual db
// inserts/updates will take place there.
f.state.Workers.EnqueueFediAPI(ctx, messages.FromFediAPI{
- APObjectType: ap.ObjectProfile,
- APActivityType: ap.ActivityUpdate,
- GTSModel: requestingAcct,
- APObjectModel: accountable,
- ReceivingAccount: receivingAcct,
+ APObjectType: ap.ObjectProfile,
+ APActivityType: ap.ActivityUpdate,
+ GTSModel: requestingAcct,
+ APObjectModel: accountable,
+ ReceivingAccount: receivingAcct,
+ RequestingAccount: requestingAcct,
})
return nil
@@ -155,11 +156,12 @@ func (f *federatingDB) updateStatusable(ctx context.Context, receivingAcct *gtsm
// Queue an UPDATE NOTE activity to our fedi API worker,
// this will handle necessary database insertions, etc.
f.state.Workers.EnqueueFediAPI(ctx, messages.FromFediAPI{
- APObjectType: ap.ObjectNote,
- APActivityType: ap.ActivityUpdate,
- GTSModel: status, // original status
- APObjectModel: (ap.Statusable)(statusable),
- ReceivingAccount: receivingAcct,
+ APObjectType: ap.ObjectNote,
+ APActivityType: ap.ActivityUpdate,
+ GTSModel: status, // original status
+ APObjectModel: (ap.Statusable)(statusable),
+ ReceivingAccount: receivingAcct,
+ RequestingAccount: requestingAcct,
})
return nil