From 3ef6c9fe8190b361318938c1e14749646926dc72 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Thu, 10 Mar 2022 23:34:34 -0700 Subject: [PATCH 1/3] Improve reblog api performance --- app/Http/Controllers/Api/ApiV1Controller.php | 40 ++++++++++---------- app/Jobs/SharePipeline/SharePipeline.php | 3 ++ app/Jobs/SharePipeline/UndoSharePipeline.php | 3 ++ app/Services/ReblogService.php | 31 +++++++++++++++ 4 files changed, 57 insertions(+), 20 deletions(-) diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index f01bb1a7c..d2abdbeff 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -1879,7 +1879,7 @@ class ApiV1Controller extends Controller if($status->profile_id !== $user->profile_id) { if($status->scope == 'private') { - abort_if(!$status->profile->followedBy($user->profile), 403); + abort_if(!FollowerService::follows($user->profile_id, $status->profile_id), 403); } else { abort_if(!in_array($status->scope, ['public','unlisted']), 403); } @@ -1922,22 +1922,7 @@ class ApiV1Controller extends Controller public function statusCard(Request $request, $id) { abort_if(!$request->user(), 403); - - $user = $request->user(); - - $status = Status::findOrFail($id); - - if($status->profile_id !== $user->profile_id) { - if($status->scope == 'private') { - abort_if(!$status->profile->followedBy($user->profile), 403); - } else { - abort_if(!in_array($status->scope, ['public','unlisted']), 403); - } - } - - // Return empty response since we don't handle support cards $res = []; - return response()->json($res); } @@ -1963,15 +1948,30 @@ class ApiV1Controller extends Controller if($status->profile_id !== $user->profile_id) { if($status->scope == 'private') { - abort_if(!$status->profile->followedBy($user->profile), 403); + abort_if(!FollowerService::follows($user->profile_id, $status->profile_id), 403); } else { abort_if(!in_array($status->scope, ['public','unlisted']), 403); } } - $shared = $status->sharedBy()->latest()->simplePaginate($limit); - $resource = new Fractal\Resource\Collection($shared, new AccountTransformer()); - $res = $this->fractal->createData($resource)->toArray(); + $page = $request->input('page', 1); + $start = $page == 1 ? 0 : (($page * $limit) - $limit); + $end = $start + $limit - 1; + + $ids = ReblogService::getPostReblogs($id, $start, $end); + if(empty($ids)) { + return []; + } + + $res = collect($ids) + ->map(function($id) { + $status = StatusService::get($id); + return AccountService::get($status['account']['id']); + }) + ->filter(function($account) { + return $account && isset($account['id']); + }) + ->values(); $url = $request->url(); $page = $request->input('page', 1); diff --git a/app/Jobs/SharePipeline/SharePipeline.php b/app/Jobs/SharePipeline/SharePipeline.php index 9f20bb3e9..5425ce972 100644 --- a/app/Jobs/SharePipeline/SharePipeline.php +++ b/app/Jobs/SharePipeline/SharePipeline.php @@ -15,6 +15,7 @@ use League\Fractal\Serializer\ArraySerializer; use App\Transformer\ActivityPub\Verb\Announce; use GuzzleHttp\{Pool, Client, Promise}; use App\Util\ActivityPub\HttpSignature; +use App\Services\ReblogService; use App\Services\StatusService; class SharePipeline implements ShouldQueue @@ -75,6 +76,8 @@ class SharePipeline implements ShouldQueue $this->remoteAnnounceDeliver(); + ReblogService::addPostReblog($parent->id, $status->id); + $parent->reblogs_count = $parent->shares()->count(); $parent->save(); StatusService::del($parent->id); diff --git a/app/Jobs/SharePipeline/UndoSharePipeline.php b/app/Jobs/SharePipeline/UndoSharePipeline.php index ba3a2791b..04b2ede26 100644 --- a/app/Jobs/SharePipeline/UndoSharePipeline.php +++ b/app/Jobs/SharePipeline/UndoSharePipeline.php @@ -15,6 +15,7 @@ use League\Fractal\Serializer\ArraySerializer; use App\Transformer\ActivityPub\Verb\UndoAnnounce; use GuzzleHttp\{Pool, Client, Promise}; use App\Util\ActivityPub\HttpSignature; +use App\Services\ReblogService; use App\Services\StatusService; class UndoSharePipeline implements ShouldQueue @@ -35,6 +36,8 @@ class UndoSharePipeline implements ShouldQueue $parent = $status->parent(); $target = $status->parent()->profile; + ReblogService::removePostReblog($parent->id, $status->id); + if ($status->uri !== null) { return; } diff --git a/app/Services/ReblogService.php b/app/Services/ReblogService.php index f6655c8f6..ff70de378 100644 --- a/app/Services/ReblogService.php +++ b/app/Services/ReblogService.php @@ -2,11 +2,15 @@ namespace App\Services; +use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Redis; +use App\Status; class ReblogService { const CACHE_KEY = 'pf:services:reblogs:'; + const REBLOGS_KEY = 'pf:services:reblogs:post:'; + const COLDBOOT_KEY = 'pf:services:reblogs:post_:'; public static function get($profileId, $statusId) { @@ -26,4 +30,31 @@ class ReblogService { return Redis::zrem(self::CACHE_KEY . $profileId, $statusId); } + + public static function getPostReblogs($id, $start = 0, $stop = 10) + { + if(!Redis::zcard(self::REBLOGS_KEY . $id)) { + return Cache::remember(self::COLDBOOT_KEY . $id, 86400, function() use($id) { + return Status::whereReblogOfId($id) + ->pluck('id') + ->each(function($reblog) use($id) { + self::addPostReblog($id, $reblog); + }) + ->map(function($reblog) { + return (string) $reblog; + }); + }); + } + return Redis::zrange(self::REBLOGS_KEY . $id, $start, $stop); + } + + public static function addPostReblog($parentId, $reblogId) + { + return Redis::zadd(self::REBLOGS_KEY . $parentId, $reblogId); + } + + public static function removePostReblog($parentId, $reblogId) + { + return Redis::zrem(self::REBLOGS_KEY . $parentId, $reblogId); + } } From b3ef2b2902d98f8920c907778bfba0e2ba2985f9 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Thu, 10 Mar 2022 23:38:10 -0700 Subject: [PATCH 2/3] Improve reblog api performance --- app/Http/Controllers/Api/ApiV1Controller.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index d2abdbeff..da6418aa4 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -2238,7 +2238,7 @@ class ApiV1Controller extends Controller if($status->profile_id !== $user->profile_id) { if($status->scope == 'private') { - abort_if(!$status->profile->followedBy($user->profile), 403); + abort_if(!FollowerService::follows($user->profile_id, $status->profile_id), 403); } else { abort_if(!in_array($status->scope, ['public','unlisted']), 403); } @@ -2281,7 +2281,7 @@ class ApiV1Controller extends Controller if($status->profile_id !== $user->profile_id) { if($status->scope == 'private') { - abort_if(!$status->profile->followedBy($user->profile), 403); + abort_if(!FollowerService::follows($user->profile_id, $status->profile_id), 403); } else { abort_if(!in_array($status->scope, ['public','unlisted']), 403); } From aef373a91c8c33c5b957af71322bc2cba9e5644e Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Thu, 10 Mar 2022 23:38:15 -0700 Subject: [PATCH 3/3] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d5a6abcc..50fabd804 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,7 @@ - Updated CollectionController, fixes #3289. ([c7e1e473](https://github.com/pixelfed/pixelfed/commit/c7e1e473)) - Updated SpaController, handle web redirects. ([b6c6c85b](https://github.com/pixelfed/pixelfed/commit/b6c6c85b)) - Updated presenter components, remove video poster attribute. ([4d612dfa](https://github.com/pixelfed/pixelfed/commit/4d612dfa)) +- Improved reblog api performance ([3ef6c9fe](https://github.com/pixelfed/pixelfed/commit/3ef6c9fe)) - ([](https://github.com/pixelfed/pixelfed/commit/)) ## [v0.11.2 (2022-01-09)](https://github.com/pixelfed/pixelfed/compare/v0.11.1...v0.11.2)