diff --git a/app/Http/Controllers/DirectMessageController.php b/app/Http/Controllers/DirectMessageController.php index b6f0b8d5c..fc3f74e3d 100644 --- a/app/Http/Controllers/DirectMessageController.php +++ b/app/Http/Controllers/DirectMessageController.php @@ -385,17 +385,6 @@ class DirectMessageController extends Controller $res = FollowerService::getMutualsWithProfiles($user->profile_id, 10, $cursor); - if ($cursor && $res && isset($res['total_count']) && is_int($res['total_count']) && $res['total_count'] > 100) { - $empty = [ - 'data' => [], - 'has_more' => false, - 'next_cursor' => false, - 'total_count' => $res['total_count'], - ]; - - return response()->json($empty); - } - return response()->json($res); } diff --git a/app/Services/FollowerService.php b/app/Services/FollowerService.php index 7505fa121..9750d358c 100644 --- a/app/Services/FollowerService.php +++ b/app/Services/FollowerService.php @@ -27,6 +27,8 @@ class FollowerService const FOLLOWERS_MUTUALS_KEY = 'pf:services:follow:mutuals:v2:'; + const MUTUALS_DM_MAX_PAGES = 5; + public static function add($actor, $target, $refresh = true) { $ts = (int) microtime(true); @@ -301,29 +303,32 @@ class FollowerService } /** - * Get mutual followers for DM suggestions using Redis set intersection - * This is extremely fast as it operates entirely in Redis memory + * Get mutual followers for DM suggestions, newest mutuals first. + * Pagination is capped internally at MUTUALS_DM_MAX_PAGES pages. * * @param int $profileId * @param int $limit - * @param int|null $cursor + * @param int|null $cursor Profile id of the last item seen */ public static function getMutualsForDM($profileId, $limit = 20, $cursor = null): array { + $empty = [ + 'data' => [], + 'has_more' => false, + 'next_cursor' => null, + 'total_count' => 0, + ]; + $acct = AccountService::get($profileId, true); if (! $acct || ! isset($acct['id'])) { - return [ - 'data' => [], - 'has_more' => false, - 'next_cursor' => null, - 'total_count' => 0, - ]; + return $empty; } self::cacheSyncCheck($profileId, 'followers'); self::cacheSyncCheck($profileId, 'following'); $mutualsKey = self::warmMutuals($profileId); + $totalCount = Redis::zcard($mutualsKey); $start = 0; @@ -334,20 +339,28 @@ class FollowerService } } - $mutuals = Redis::zrevrange($mutualsKey, $start, $start + $limit); + $maxItems = self::MUTUALS_DM_MAX_PAGES * $limit; + + if ($start >= $maxItems) { + $empty['total_count'] = $totalCount; - $hasMore = count($mutuals) > $limit; - if ($hasMore) { - $mutuals = array_slice($mutuals, 0, $limit); + return $empty; } - $nextCursor = $hasMore && ! empty($mutuals) ? end($mutuals) : null; + $end = min($start + $limit, $maxItems); + + $mutuals = Redis::zrevrange($mutualsKey, $start, $end); + + $hasMore = count($mutuals) > $limit && ($start + $limit) < $maxItems; + $mutuals = array_slice($mutuals, 0, $limit); + + $nextCursor = $hasMore && ! empty($mutuals) ? (int) end($mutuals) : null; return [ 'data' => array_map('intval', $mutuals), 'has_more' => $hasMore, - 'next_cursor' => $nextCursor ? (int) $nextCursor : null, - 'total_count' => Redis::zcard($mutualsKey), + 'next_cursor' => $nextCursor, + 'total_count' => $totalCount, ]; } @@ -376,12 +389,9 @@ class FollowerService } } - return [ - 'data' => $orderedProfiles, - 'has_more' => $mutuals['has_more'], - 'next_cursor' => $mutuals['next_cursor'], - 'total_count' => $mutuals['total_count'], - ]; + $mutuals['data'] = $orderedProfiles; + + return $mutuals; } public static function getMutualCount($profileId)