id : (int) $user; $store = $this->store(); $onlineKey = $this->onlineKey($userId); $existing = $store->get($onlineKey, []); $previousConversationId = (int) ($existing['conversation_id'] ?? 0) ?: null; $onlineTtl = max(30, (int) config('messaging.presence.ttl_seconds', 90)); $conversationTtl = max(15, (int) config('messaging.presence.conversation_ttl_seconds', 45)); if ($previousConversationId && $previousConversationId !== $conversationId) { $store->forget($this->conversationKey($previousConversationId, $userId)); } $store->put($onlineKey, [ 'conversation_id' => $conversationId, 'seen_at' => now()->toIso8601String(), ], now()->addSeconds($onlineTtl)); if ($conversationId) { $store->put($this->conversationKey($conversationId, $userId), now()->toIso8601String(), now()->addSeconds($conversationTtl)); } } public function isUserOnline(int $userId): bool { return $this->store()->has($this->onlineKey($userId)); } public function isViewingConversation(int $conversationId, int $userId): bool { return $this->store()->has($this->conversationKey($conversationId, $userId)); } private function onlineKey(int $userId): string { return 'messages:presence:user:' . $userId; } private function conversationKey(int $conversationId, int $userId): string { return 'messages:presence:conversation:' . $conversationId . ':user:' . $userId; } private function store(): Repository { $store = (string) config('messaging.presence.cache_store', 'redis'); if ($store === 'redis' && ! class_exists('Redis')) { return Cache::store(); } try { return Cache::store($store); } catch (\Throwable) { return Cache::store(); } } }