Skip to content

Commit 696640a

Browse files
shleeableYour Name
andauthored
Investigate Mastodon Quotes failures (#432)
* Update ActivityPubService.php * Update QuoteRequestHandler.php * Update QuoteRequestHandler.php * Update QuoteRequestHandler.php * Update QuoteRequestHandler.php * pint --------- Co-authored-by: Your Name <you@example.com>
1 parent 1fd6398 commit 696640a

2 files changed

Lines changed: 69 additions & 10 deletions

File tree

app/Federation/Handlers/QuoteRequestHandler.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace App\Federation\Handlers;
44

55
use App\Federation\ActivityBuilders\QuoteRequestActivityBuilder;
6+
use App\Jobs\Federation\DiscoverInstance;
67
use App\Models\Comment;
78
use App\Models\CommentReply;
89
use App\Models\Profile;
@@ -25,6 +26,11 @@ class QuoteRequestHandler
2526
*/
2627
public function handle(array $activity, Profile $actor, ?Profile $target = null): void
2728
{
29+
// Ensure we discover the instance if this is a new remote actor
30+
if (! $actor->local && $actor->uri) {
31+
DiscoverInstance::dispatch($actor->uri)->onQueue('activitypub-in');
32+
}
33+
2834
$quotedObjectUrl = $activity['object'];
2935
$quotePostUrl = is_array($activity['instrument'])
3036
? ($activity['instrument']['id'] ?? null)
@@ -160,6 +166,31 @@ protected function approveQuoteRequest(
160166
string $quotePostUrl,
161167
Profile $quoterProfile
162168
): void {
169+
// Ensure the quoter profile has an inbox URL for delivery
170+
if (! $quoterProfile->inbox_url) {
171+
// Try to re-fetch the actor data to get the inbox URL (bypass cache)
172+
$actorData = app(\App\Services\ActivityPubService::class)->get($quoterProfile->uri, [], true, true, true, true);
173+
174+
if ($actorData && isset($actorData['inbox'])) {
175+
$quoterProfile->inbox_url = $actorData['inbox'];
176+
$quoterProfile->shared_inbox_url = data_get($actorData, 'endpoints.sharedInbox');
177+
$quoterProfile->save();
178+
179+
// Discover the instance since we're seeing it for the first time
180+
DiscoverInstance::dispatch($quoterProfile->uri)->onQueue('activitypub-in');
181+
182+
} else {
183+
if (config('logging.dev_log')) {
184+
Log::error('QuoteRequest handler: Failed to fetch inbox_url for quoter', [
185+
'quoter_id' => $quoterProfile->id,
186+
'quoter_uri' => $quoterProfile->uri,
187+
]);
188+
}
189+
190+
return;
191+
}
192+
}
193+
163194
$existing = QuoteAuthorization::where('quote_post_url', $quotePostUrl)
164195
->where('quotable_type', get_class($quotable))
165196
->where('quotable_id', $quotable->id)
@@ -212,6 +243,30 @@ protected function approveQuoteRequest(
212243
*/
213244
protected function rejectQuoteRequest(array $activity, $quotable, Profile $quoterProfile): void
214245
{
246+
// Ensure the quoter profile has an inbox URL for delivery
247+
if (! $quoterProfile->inbox_url) {
248+
// Try to re-fetch the actor data to get the inbox URL (bypass cache)
249+
$actorData = app(\App\Services\ActivityPubService::class)->get($quoterProfile->uri, [], true, true, true, true);
250+
if ($actorData && isset($actorData['inbox'])) {
251+
$quoterProfile->inbox_url = $actorData['inbox'];
252+
$quoterProfile->shared_inbox_url = data_get($actorData, 'endpoints.sharedInbox');
253+
$quoterProfile->save();
254+
255+
// Discover the instance since we're seeing it for the first time
256+
DiscoverInstance::dispatch($quoterProfile->uri)->onQueue('activitypub-in');
257+
258+
} else {
259+
if (config('logging.dev_log')) {
260+
Log::error('QuoteRequest handler: Failed to fetch inbox_url for quoter (reject)', [
261+
'quoter_id' => $quoterProfile->id,
262+
'quoter_uri' => $quoterProfile->uri,
263+
]);
264+
}
265+
266+
return;
267+
}
268+
}
269+
215270
$reject = QuoteRequestActivityBuilder::buildReject(
216271
$activity,
217272
$quotable->profile

app/Services/ActivityPubService.php

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
class ActivityPubService
1212
{
13-
public function get($url, $params = [], $signed = true, $validateUrl = true, $validateContentType = true)
13+
public function get($url, $params = [], $signed = true, $validateUrl = true, $validateContentType = true, $bypassCache = false)
1414
{
1515
if ($validateUrl) {
1616
$valid = app(SanitizeService::class)->url($url, true);
@@ -21,27 +21,31 @@ public function get($url, $params = [], $signed = true, $validateUrl = true, $va
2121

2222
$cacheKey = 'activitypub-fetch:'.sha1($url.json_encode($params));
2323

24-
$cached = Cache::get($cacheKey);
25-
if ($cached !== null) {
26-
return $cached;
24+
if (! $bypassCache) {
25+
$cached = Cache::get($cacheKey);
26+
if ($cached !== null) {
27+
return $cached;
28+
}
2729
}
2830

2931
$lock = Cache::lock('activitypub-fetch_lock:'.sha1($url.json_encode($params)), 10);
3032

3133
try {
3234
$lock->block(10);
3335

34-
$cached = Cache::get($cacheKey);
35-
if ($cached !== null) {
36-
return $cached;
36+
if (! $bypassCache) {
37+
$cached = Cache::get($cacheKey);
38+
if ($cached !== null) {
39+
return $cached;
40+
}
3741
}
3842

3943
$result = $this->fetchActivityPub($url, $params, $signed, $validateContentType);
4044

41-
if ($result !== false) {
42-
Cache::put($cacheKey, $result, 14400);
45+
if ($result !== false && $result !== null) {
46+
Cache::put($cacheKey, $result, 14400); // Cache successful results for 4 hours
4347
} else {
44-
Cache::put($cacheKey, null, 14400);
48+
Cache::put($cacheKey, null, 300); // Cache failures for only 5 minutes
4549
}
4650

4751
return $result;

0 commit comments

Comments
 (0)