浏览代码

Add optional home feed caching

Daniel Supernault 2 年之前
父节点
当前提交
3328b367fd

+ 75 - 1
app/Http/Controllers/Api/ApiV1Controller.php

@@ -61,6 +61,7 @@ use App\Jobs\VideoPipeline\{
 
 
 use App\Services\{
 use App\Services\{
 	AccountService,
 	AccountService,
+	BookmarkService,
 	CollectionService,
 	CollectionService,
 	FollowerService,
 	FollowerService,
 	InstanceService,
 	InstanceService,
@@ -768,6 +769,10 @@ class ApiV1Controller extends Controller
 			->whereFollowingId($target->id)
 			->whereFollowingId($target->id)
 			->delete();
 			->delete();
 
 
+		if(config('instance.timeline.home.cached')) {
+            Cache::forget('pf:timelines:home:' . $user->profile_id);
+        }
+
 		FollowerService::remove($user->profile_id, $target->id);
 		FollowerService::remove($user->profile_id, $target->id);
 
 
 		$target->decrement('followers_count');
 		$target->decrement('followers_count');
@@ -1935,11 +1940,80 @@ class ApiV1Controller extends Controller
 		$limit = $request->input('limit') ?? 20;
 		$limit = $request->input('limit') ?? 20;
 		$pid = $request->user()->profile_id;
 		$pid = $request->user()->profile_id;
 
 
-		$following = Cache::remember('profile:following:'.$pid, now()->addMinutes(1440), function() use($pid) {
+		$following = Cache::remember('profile:following:'.$pid, 1209600, function() use($pid) {
 			$following = Follower::whereProfileId($pid)->pluck('following_id');
 			$following = Follower::whereProfileId($pid)->pluck('following_id');
 			return $following->push($pid)->toArray();
 			return $following->push($pid)->toArray();
 		});
 		});
 
 
+		if(config('instance.timeline.home.cached') && (!$min && !$max)) {
+            $ttl = config('instance.timeline.home.cache_ttl');
+            $res = Cache::remember(
+                'pf:timelines:home:' . $pid,
+                $ttl,
+                function() use(
+                $following,
+                $limit,
+                $pid
+                ) {
+                return Status::select(
+                    'id',
+                    'uri',
+                    'caption',
+                    'rendered',
+                    'profile_id',
+                    'type',
+                    'in_reply_to_id',
+                    'reblog_of_id',
+                    'is_nsfw',
+                    'scope',
+                    'local',
+                    'reply_count',
+                    'comments_disabled',
+                    'place_id',
+                    'likes_count',
+                    'reblogs_count',
+                    'created_at',
+                    'updated_at'
+                  )
+                  ->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
+                  ->whereIn('profile_id', $following)
+                  ->whereIn('visibility',['public', 'unlisted', 'private'])
+                  ->orderBy('created_at', 'desc')
+                  ->limit($limit)
+                  ->get()
+                  ->map(function($s) {
+                       $status = StatusService::get($s->id, false);
+                       if(!$status) {
+                            return false;
+                       }
+                       return $status;
+                  })
+                  ->filter(function($s) {
+                        return $s && isset($s['account']['id']);
+                  })
+                  ->values()
+                  ->toArray();
+            });
+
+            $res = collect($res)
+                ->map(function($s) use ($pid) {
+                    $status = StatusService::get($s['id'], false);
+                    if(!$status) {
+                        return false;
+                    }
+                    $status['favourited'] = (bool) LikeService::liked($pid, $s['id']);
+                    $status['bookmarked'] = (bool) BookmarkService::get($pid, $s['id']);
+                    $status['reblogged'] = (bool) ReblogService::get($pid, $s['id']);
+                    return $status;
+                })
+                ->filter(function($s) {
+                    return $s && isset($s['account']['id']);
+                })
+                ->values()
+                ->take($limit)
+                ->toArray();
+		}
+
 		if($min || $max) {
 		if($min || $max) {
 			$dir = $min ? '>' : '<';
 			$dir = $min ? '>' : '<';
 			$id = $min ?? $max;
 			$id = $min ?? $max;

+ 81 - 14
app/Http/Controllers/PublicApiController.php

@@ -454,29 +454,19 @@ class PublicApiController extends Controller
         $user = $request->user();
         $user = $request->user();
 
 
         $key = 'user:last_active_at:id:'.$user->id;
         $key = 'user:last_active_at:id:'.$user->id;
-        $ttl = now()->addMinutes(20);
-        Cache::remember($key, $ttl, function() use($user) {
+        if(Cache::get($key) == null) {
             $user->last_active_at = now();
             $user->last_active_at = now();
             $user->save();
             $user->save();
-            return;
-        });
+            Cache::put($key, true, 43200);
+        }
 
 
         $pid = $user->profile_id;
         $pid = $user->profile_id;
 
 
-        $following = Cache::remember('profile:following:'.$pid, now()->addMinutes(1440), function() use($pid) {
+        $following = Cache::remember('profile:following:'.$pid, 1209600, function() use($pid) {
             $following = Follower::whereProfileId($pid)->pluck('following_id');
             $following = Follower::whereProfileId($pid)->pluck('following_id');
             return $following->push($pid)->toArray();
             return $following->push($pid)->toArray();
         });
         });
 
 
-        if($recentFeed == true) {
-            $key = 'profile:home-timeline-cursor:'.$user->id;
-            $ttl = now()->addMinutes(30);
-            $min = Cache::remember($key, $ttl, function() use($pid) {
-                $res = StatusView::whereProfileId($pid)->orderByDesc('status_id')->first();
-                return $res ? $res->status_id : null;
-            });
-        }
-
         $filtered = $user ? UserFilterService::filters($user->profile_id) : [];
         $filtered = $user ? UserFilterService::filters($user->profile_id) : [];
         $types = ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'];
         $types = ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'];
         // $types = ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album', 'text'];
         // $types = ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album', 'text'];
@@ -496,6 +486,83 @@ class PublicApiController extends Controller
             array_push($types, 'poll');
             array_push($types, 'poll');
         }
         }
 
 
+        if(config('instance.timeline.home.cached') && $limit == 6 && (!$min && !$max)) {
+            $ttl = config('instance.timeline.home.cache_ttl');
+            $res = Cache::remember(
+                'pf:timelines:home:' . $pid,
+                $ttl,
+                function() use(
+                $types,
+                $textOnlyReplies,
+                $following,
+                $limit,
+                $filtered,
+                $user
+                ) {
+                return Status::select(
+                    'id',
+                    'uri',
+                    'caption',
+                    'rendered',
+                    'profile_id',
+                    'type',
+                    'in_reply_to_id',
+                    'reblog_of_id',
+                    'is_nsfw',
+                    'scope',
+                    'local',
+                    'reply_count',
+                    'comments_disabled',
+                    'place_id',
+                    'likes_count',
+                    'reblogs_count',
+                    'created_at',
+                    'updated_at'
+                  )
+                  ->whereIn('type', $types)
+                  ->when(!$textOnlyReplies, function($q, $textOnlyReplies) {
+                    return $q->whereNull('in_reply_to_id');
+                  })
+                  ->whereIn('profile_id', $following)
+                  ->whereIn('visibility',['public', 'unlisted', 'private'])
+                  ->orderBy('created_at', 'desc')
+                  ->limit($limit)
+                  ->get()
+                  ->map(function($s) use ($user) {
+                       $status = StatusService::get($s->id, false);
+                       if(!$status) {
+                            return false;
+                       }
+                       return $status;
+                  })
+                  ->filter(function($s) use($filtered) {
+                        return $s && in_array($s['account']['id'], $filtered) == false;
+                  })
+                  ->values()
+                  ->toArray();
+            });
+
+            $res = collect($res)
+                ->map(function($s) use ($user) {
+                    $status = StatusService::get($s['id'], false);
+                    if(!$status) {
+                        return false;
+                    }
+                    $status['favourited'] = (bool) LikeService::liked($user->profile_id, $s['id']);
+                    $status['bookmarked'] = (bool) BookmarkService::get($user->profile_id, $s['id']);
+                    $status['reblogged'] = (bool) ReblogService::get($user->profile_id, $s['id']);
+                    return $status;
+                })
+                ->filter(function($s) use($filtered) {
+                    return $s && in_array($s['account']['id'], $filtered) == false;
+                })
+                ->values()
+                ->take($limit)
+                ->toArray();
+
+            return $res;
+        }
+
         if($min || $max) {
         if($min || $max) {
             $dir = $min ? '>' : '<';
             $dir = $min ? '>' : '<';
             $id = $min ?? $max;
             $id = $min ?? $max;

+ 5 - 0
app/Observers/FollowerObserver.php

@@ -4,6 +4,7 @@ namespace App\Observers;
 
 
 use App\Follower;
 use App\Follower;
 use App\Services\FollowerService;
 use App\Services\FollowerService;
+use Cache;
 
 
 class FollowerObserver
 class FollowerObserver
 {
 {
@@ -15,6 +16,10 @@ class FollowerObserver
      */
      */
     public function created(Follower $follower)
     public function created(Follower $follower)
     {
     {
+        if(config('instance.timeline.home.cached')) {
+            Cache::forget('pf:timelines:home:' . $follower->profile_id);
+        }
+
         FollowerService::add($follower->profile_id, $follower->following_id);
         FollowerService::add($follower->profile_id, $follower->following_id);
     }
     }
 
 

+ 9 - 0
app/Observers/StatusObserver.php

@@ -4,6 +4,7 @@ namespace App\Observers;
 
 
 use App\Status;
 use App\Status;
 use App\Services\ProfileStatusService;
 use App\Services\ProfileStatusService;
+use Cache;
 
 
 class StatusObserver
 class StatusObserver
 {
 {
@@ -33,6 +34,10 @@ class StatusObserver
      */
      */
     public function updated(Status $status)
     public function updated(Status $status)
     {
     {
+        if(config('instance.timeline.home.cached')) {
+            Cache::forget('pf:timelines:home:' . $status->profile_id);
+        }
+
         if(in_array($status->scope, ['public', 'unlisted']) && in_array($status->type, ['photo', 'photo:album', 'video'])) {
         if(in_array($status->scope, ['public', 'unlisted']) && in_array($status->type, ['photo', 'photo:album', 'video'])) {
             ProfileStatusService::add($status->profile_id, $status->id);
             ProfileStatusService::add($status->profile_id, $status->id);
         }
         }
@@ -46,6 +51,10 @@ class StatusObserver
      */
      */
     public function deleted(Status $status)
     public function deleted(Status $status)
     {
     {
+        if(config('instance.timeline.home.cached')) {
+            Cache::forget('pf:timelines:home:' . $status->profile_id);
+        }
+
         ProfileStatusService::delete($status->profile_id, $status->id);
         ProfileStatusService::delete($status->profile_id, $status->id);
     }
     }
 
 

+ 2 - 0
app/Services/FollowerService.php

@@ -27,6 +27,7 @@ class FollowerService
 		RelationshipService::refresh($actor, $target);
 		RelationshipService::refresh($actor, $target);
 		Redis::zadd(self::FOLLOWING_KEY . $actor, $ts, $target);
 		Redis::zadd(self::FOLLOWING_KEY . $actor, $ts, $target);
 		Redis::zadd(self::FOLLOWERS_KEY . $target, $ts, $actor);
 		Redis::zadd(self::FOLLOWERS_KEY . $target, $ts, $actor);
+		Cache::forget('profile:following:' . $actor);
 	}
 	}
 
 
 	public static function remove($actor, $target)
 	public static function remove($actor, $target)
@@ -38,6 +39,7 @@ class FollowerService
 		AccountService::del($actor);
 		AccountService::del($actor);
 		AccountService::del($target);
 		AccountService::del($target);
 		RelationshipService::refresh($actor, $target);
 		RelationshipService::refresh($actor, $target);
+		Cache::forget('profile:following:' . $actor);
 	}
 	}
 
 
 	public static function followers($id, $start = 0, $stop = 10)
 	public static function followers($id, $start = 0, $stop = 10)

+ 5 - 0
config/instance.php

@@ -23,6 +23,11 @@ return [
 	'email' => env('INSTANCE_CONTACT_EMAIL'),
 	'email' => env('INSTANCE_CONTACT_EMAIL'),
 
 
 	'timeline' => [
 	'timeline' => [
+		'home' => [
+			'cached' => env('PF_HOME_TIMELINE_CACHE', false),
+			'cache_ttl' => env('PF_HOME_TIMELINE_CACHE_TTL', 900)
+		],
+
 		'local' => [
 		'local' => [
 			'is_public' => env('INSTANCE_PUBLIC_LOCAL_TIMELINE', false)
 			'is_public' => env('INSTANCE_PUBLIC_LOCAL_TIMELINE', false)
 		],
 		],