From 16303866fb5363ebe3fa8a74189625e7d5bf5f6a Mon Sep 17 00:00:00 2001 From: Roardom Date: Thu, 27 Nov 2025 08:52:18 +0000 Subject: [PATCH] refactor: user audible and echo cache Every time a user switches rooms or sends a pm, we need to ensure the sender and recipient have an echo and an audible. Previously, every user's echoes and audibles were cached, and we checked to see if the cached value contained the appropriate recipient, and if not, created the echo/audible and sent the user a new list. Now, we try to create it by default, and if it was created, send the user the new list. A simple keyed insert doesn't take a lot of compute so it doesn't need to be cached. --- app/Bots/NerdBot.php | 56 ++++---- app/Bots/SystemBot.php | 56 ++++---- app/Http/Controllers/API/ChatController.php | 151 ++++++++------------ 3 files changed, 112 insertions(+), 151 deletions(-) diff --git a/app/Bots/NerdBot.php b/app/Bots/NerdBot.php index d20717d694..cc732527bb 100644 --- a/app/Bots/NerdBot.php +++ b/app/Bots/NerdBot.php @@ -279,40 +279,34 @@ public function pm(): true|\Illuminate\Http\Response if ($type === 'message' || $type === 'private') { // Create echo for user if missing - $echoes = cache()->remember( - 'user-echoes'.$target->id, - 3600, - fn () => UserEcho::with(['user', 'room', 'target', 'bot'])->where('user_id', '=', $target->id)->get() - ); - - if ($echoes->doesntContain(fn ($echo) => $echo->bot_id == $this->bot->id)) { - $echoes->push(UserEcho::create([ - 'user_id' => $target->id, - 'bot_id' => $this->bot->id, - ])); - - cache()->put('user-echoes'.$target->id, $echoes, 3600); - - Chatter::dispatch('echo', $target->id, UserEchoResource::collection($echoes)); + $affected = UserEcho::query()->upsert([[ + 'user_id' => $target->id, + 'bot_id' => $this->bot->id, + ]], ['user_id', 'bot_id']); + + if ($affected === 1) { + Chatter::dispatch('echo', $target->id, UserEchoResource::collection( + UserEcho::query() + ->with(['user', 'room', 'target', 'bot']) + ->where('user_id', '=', $target->id) + ->get() + )); } // Create audible for user if missing - $audibles = cache()->remember( - 'user-audibles'.$target->id, - 3600, - fn () => UserAudible::with(['user', 'room', 'target', 'bot'])->where('user_id', '=', $target->id)->get() - ); - - if ($audibles->doesntContain(fn ($audible) => $audible->bot_id == $this->bot->id)) { - $audibles->push(UserAudible::create([ - 'user_id' => $target->id, - 'bot_id' => $this->bot->id, - 'status' => false, - ])); - - cache()->put('user-audibles'.$target->id, $audibles, 3600); - - Chatter::dispatch('audible', $target->id, UserAudibleResource::collection($audibles)); + $affected = UserAudible::query()->upsert([[ + 'user_id' => $target->id, + 'bot_id' => $this->bot->id, + 'status' => false, + ]], ['user_id', 'bot_id']); + + if ($affected === 1) { + Chatter::dispatch('audible', $target->id, UserAudibleResource::collection( + UserAudible::query() + ->with(['user', 'room', 'target', 'bot']) + ->where('user_id', '=', $target->id) + ->get() + )); } // Create message diff --git a/app/Bots/SystemBot.php b/app/Bots/SystemBot.php index 5de11035cc..4990de1683 100644 --- a/app/Bots/SystemBot.php +++ b/app/Bots/SystemBot.php @@ -165,40 +165,34 @@ public function pm(): \Illuminate\Http\Response|true if ($type === 'message' || $type === 'private') { // Create echo for user if missing - $echoes = cache()->remember( - 'user-echoes'.$target->id, - 3600, - fn () => UserEcho::with(['user', 'room', 'target', 'bot'])->where('user_id', '=', $target->id)->get() - ); - - if ($echoes->doesntContain(fn ($echo) => $echo->bot_id == $this->bot->id)) { - $echoes->push(UserEcho::create([ - 'user_id' => $target->id, - 'bot_id' => $this->bot->id, - ])); - - cache()->put('user-echoes'.$target->id, $echoes, 3600); - - Chatter::dispatch('echo', $target->id, UserEchoResource::collection($echoes)); + $affected = UserEcho::query()->upsert([[ + 'user_id' => $target->id, + 'bot_id' => $this->bot->id, + ]], ['user_id', 'bot_id']); + + if ($affected === 1) { + Chatter::dispatch('echo', $target->id, UserEchoResource::collection( + UserEcho::query() + ->with(['user', 'room', 'target', 'bot']) + ->where('user_id', '=', $target->id) + ->get() + )); } // Create audible for user if missing - $audibles = cache()->remember( - 'user-audibles'.$target->id, - 3600, - fn () => UserAudible::with(['user', 'room', 'target', 'bot'])->where('user_id', '=', $target->id)->get() - ); - - if ($audibles->doesntContain(fn ($audible) => $audible->bot_id == $this->bot->id)) { - $audibles->push(UserAudible::create([ - 'user_id' => $target->id, - 'bot_id' => $this->bot->id, - 'status' => false, - ])); - - cache()->put('user-audibles'.$target->id, $audibles, 3600); - - Chatter::dispatch('audible', $target->id, UserAudibleResource::collection($audibles)); + $affected = UserAudible::query()->upsert([[ + 'user_id' => $target->id, + 'bot_id' => $this->bot->id, + 'status' => false, + ]], ['user_id', 'bot_id']); + + if ($affected === 1) { + Chatter::dispatch('audible', $target->id, UserAudibleResource::collection( + UserAudible::query() + ->with(['user', 'room', 'target', 'bot']) + ->where('user_id', '=', $target->id) + ->get() + )); } // Create message diff --git a/app/Http/Controllers/API/ChatController.php b/app/Http/Controllers/API/ChatController.php index ab7443d69e..6461ba3dff 100644 --- a/app/Http/Controllers/API/ChatController.php +++ b/app/Http/Controllers/API/ChatController.php @@ -130,40 +130,34 @@ public function botMessages(Request $request, int $botId): \Illuminate\Http\Reso $user = $request->user(); // Create echo for user if missing - $echoes = cache()->remember( - 'user-echoes'.$user->id, - 3600, - fn () => UserEcho::with(['user', 'room', 'target', 'bot'])->where('user_id', '=', $user->id)->get() - ); - - if ($echoes->doesntContain(fn ($echo) => $echo->bot_id == $bot->id)) { - $echoes->push(UserEcho::create([ - 'user_id' => $user->id, - 'bot_id' => $bot->id, - ])); - - cache()->put('user-echoes'.$user->id, $echoes, 3600); - - Chatter::dispatch('echo', $user->id, UserEchoResource::collection($echoes)); + $affected = UserEcho::query()->upsert([[ + 'user_id' => $user->id, + 'bot_id' => $bot->id, + ]], ['user_id', 'bot_id']); + + if ($affected === 1) { + Chatter::dispatch('echo', $user->id, UserEchoResource::collection( + UserEcho::query() + ->with(['user', 'room', 'target', 'bot']) + ->where('user_id', '=', $user->id) + ->get() + )); } // Create audible for user if missing - $audibles = cache()->remember( - 'user-audibles'.$user->id, - 3600, - fn () => UserAudible::with(['user', 'room', 'target', 'bot'])->where('user_id', '=', $user->id)->get() - ); - - if ($audibles->doesntContain(fn ($audible) => $audible->bot_id == $bot->id)) { - $audibles->push(UserAudible::create([ - 'user_id' => $user->id, - 'bot_id' => $bot->id, - 'status' => false, - ])); - - cache()->put('user-audibles'.$user->id, $audibles, 3600); - - Chatter::dispatch('audible', $user->id, UserAudibleResource::collection($audibles)); + $affected = UserAudible::query()->upsert([[ + 'user_id' => $user->id, + 'bot_id' => $bot->id, + 'status' => false, + ]], ['user_id', 'bot_id']); + + if ($affected === 1) { + Chatter::dispatch('audible', $user->id, UserAudibleResource::collection( + UserAudible::query() + ->with(['user', 'room', 'target', 'bot']) + ->where('user_id', '=', $user->id) + ->get() + )); } return ChatMessageResource::collection($this->chatRepository->botMessages($request->user()->id, $bot->id)); @@ -222,42 +216,36 @@ public function createMessage(Request $request): \Illuminate\Contracts\Routing\R if ($receiverId && $receiverId > 0) { // Create echo for both users if missing foreach ([[$userId, $receiverId], [$receiverId, $userId]] as [$user1Id, $user2Id]) { - $echoes = cache()->remember( - 'user-echoes'.$user1Id, - 3600, - fn () => UserEcho::with(['user', 'room', 'target', 'bot'])->where('user_id', '=', $user1Id)->get() - ); - - if ($echoes->doesntContain(fn ($echo) => $echo->target_id == $user2Id)) { - $echoes->push(UserEcho::create([ - 'user_id' => $user1Id, - 'target_id' => $user2Id, - ])); - - cache()->put('user-echoes'.$user1Id, $echoes, 3600); - - Chatter::dispatch('echo', $user1Id, UserEchoResource::collection($echoes)); + $affected = UserEcho::query()->upsert([[ + 'user_id' => $user->id, + 'target_id' => $bot->id, + ]], ['user_id', 'target_id']); + + if ($affected === 1) { + Chatter::dispatch('echo', $user->id, UserEchoResource::collection( + UserEcho::query() + ->with(['user', 'room', 'target', 'bot']) + ->where('user_id', '=', $user->id) + ->get() + )); } } // Create audible for both users if missing foreach ([[$userId, $receiverId], [$receiverId, $userId]] as [$user1Id, $user2Id]) { - $audibles = cache()->remember( - 'user-audibles'.$user1Id, - 3600, - fn () => UserAudible::with(['user', 'room', 'target', 'bot'])->where('user_id', '=', $user1Id)->get() - ); - - if ($audibles->doesntContain(fn ($audible) => $audible->target_id == $user2Id)) { - $audibles->push(UserAudible::create([ - 'user_id' => $user1Id, - 'target_id' => $user2Id, - 'status' => true, - ])); - - cache()->put('user-audibles'.$user1Id, $audibles, 3600); - - Chatter::dispatch('audible', $user1Id, UserAudibleResource::collection($audibles)); + $affected = UserAudible::query()->upsert([[ + 'user_id' => $user->id, + 'target_id' => $bot->id, + 'status' => true, + ]], ['user_id', 'target_id']); + + if ($affected === 1) { + Chatter::dispatch('audible', $user->id, UserAudibleResource::collection( + UserAudible::query() + ->with(['user', 'room', 'target', 'bot']) + ->where('user_id', '=', $user->id) + ->get() + )); } } @@ -307,8 +295,6 @@ public function deleteRoomEcho(Request $request): \Illuminate\Contracts\Routing\ $senderEchoes = UserEcho::with(['room', 'target', 'bot'])->where('user_id', $user->id)->get(); - $expiresAt = Carbon::now()->addMinutes(60); - cache()->put('user-echoes'.$user->id, $senderEchoes, $expiresAt); event(new Chatter('echo', $user->id, UserEchoResource::collection($senderEchoes))); /** @@ -326,8 +312,6 @@ public function deleteTargetEcho(Request $request): \Illuminate\Contracts\Routin $user->load(['chatStatus', 'chatroom', 'group', 'echoes']); $senderEchoes = UserEcho::with(['room', 'target', 'bot'])->where('user_id', $user->id)->get(); - $expiresAt = Carbon::now()->addMinutes(60); - cache()->put('user-echoes'.$user->id, $senderEchoes, $expiresAt); event(new Chatter('echo', $user->id, UserEchoResource::collection($senderEchoes))); /** @@ -345,8 +329,6 @@ public function deleteBotEcho(Request $request): \Illuminate\Http\JsonResponse $user->load(['chatStatus', 'chatroom', 'group', 'echoes']); $senderEchoes = UserEcho::with(['room', 'target', 'bot'])->where('user_id', $user->id)->get(); - $expiresAt = Carbon::now()->addMinutes(60); - cache()->put('user-echoes'.$user->id, $senderEchoes, $expiresAt); event(new Chatter('echo', $user->id, UserEchoResource::collection($senderEchoes))); return response()->json($user); @@ -362,8 +344,6 @@ public function toggleRoomAudible(Request $request): \Illuminate\Http\JsonRespon $user->load(['chatStatus', 'chatroom', 'group', 'audibles', 'audibles']); $senderAudibles = UserAudible::with(['room', 'target', 'bot'])->where('user_id', $user->id)->get(); - $expiresAt = Carbon::now()->addMinutes(60); - cache()->put('user-audibles'.$user->id, $senderAudibles, $expiresAt); event(new Chatter('audible', $user->id, UserAudibleResource::collection($senderAudibles))); return response()->json($user); @@ -379,8 +359,6 @@ public function toggleTargetAudible(Request $request): \Illuminate\Http\JsonResp $user->load(['chatStatus', 'chatroom', 'group', 'audibles', 'audibles']); $senderAudibles = UserAudible::with(['target', 'room', 'bot'])->where('user_id', $user->id)->get(); - $expiresAt = Carbon::now()->addMinutes(60); - cache()->put('user-audibles'.$user->id, $senderAudibles, $expiresAt); event(new Chatter('audible', $user->id, UserAudibleResource::collection($senderAudibles))); return response()->json($user); @@ -396,8 +374,6 @@ public function toggleBotAudible(Request $request): \Illuminate\Http\JsonRespons $user->load(['chatStatus', 'chatroom', 'group', 'audibles', 'audibles'])->findOrFail($user->id); $senderAudibles = UserAudible::with(['bot', 'room', 'bot'])->where('user_id', $user->id)->get(); - $expiresAt = Carbon::now()->addMinutes(60); - cache()->put('user-audibles'.$user->id, $senderAudibles, $expiresAt); event(new Chatter('audible', $user->id, UserAudibleResource::collection($senderAudibles))); return response()->json($user); @@ -429,21 +405,18 @@ public function updateUserRoom(Request $request): \Illuminate\Http\JsonResponse $user->save(); // Create echo for user if missing - $echoes = cache()->remember( - 'user-echoes'.$user->id, - 3600, - fn () => UserEcho::with(['user', 'room', 'target', 'bot'])->where('user_id', '=', $user->id)->get(), - ); - - if ($echoes->doesntContain(fn ($echo) => $echo->room_id == $room->id)) { - $echoes->push(UserEcho::create([ - 'user_id' => $user->id, - 'room_id' => $room->id, - ])); - - cache()->put('user-echoes'.$user->id, $echoes, 3600); - - Chatter::dispatch('echo', $user->id, UserEchoResource::collection($echoes)); + $affected = UserEcho::query()->upsert([[ + 'user_id' => $user->id, + 'room_id' => $room->id, + ]], ['user_id', 'room_id']); + + if ($affected === 1) { + Chatter::dispatch('echo', $user->id, UserEchoResource::collection( + UserEcho::query() + ->with(['user', 'room', 'target', 'bot']) + ->where('user_id', '=', $user->id) + ->get() + )); } return response()->json($user);