77use BeyondCode \LaravelWebSockets \WebSockets \Channels \ChannelManager ;
88use Clue \React \Redis \Client ;
99use Clue \React \Redis \Factory ;
10+ use Illuminate \Support \Facades \Cache ;
1011use Illuminate \Support \Str ;
1112use React \EventLoop \LoopInterface ;
1213use React \Promise \PromiseInterface ;
@@ -42,6 +43,13 @@ class RedisClient extends LocalClient
4243 */
4344 protected $ subscribeClient ;
4445
46+ /**
47+ * The Redis manager instance.
48+ *
49+ * @var \Illuminate\Redis\RedisManager
50+ */
51+ protected $ redis ;
52+
4553 /**
4654 * Mapping of subscribed channels, where the key is the channel name,
4755 * and the value is the amount of connections which are subscribed to
@@ -60,6 +68,7 @@ class RedisClient extends LocalClient
6068 public function __construct ()
6169 {
6270 $ this ->serverId = Str::uuid ()->toString ();
71+ $ this ->redis = Cache::getRedis ();
6372 }
6473
6574 /**
@@ -175,6 +184,36 @@ public function unsubscribe($appId, string $channel): bool
175184 return true ;
176185 }
177186
187+ /**
188+ * Subscribe to the app's pubsub keyspace.
189+ *
190+ * @param mixed $appId
191+ * @return bool
192+ */
193+ public function subscribeToApp ($ appId ): bool
194+ {
195+ $ this ->subscribeClient ->__call ('subscribe ' , [$ this ->getTopicName ($ appId )]);
196+
197+ $ this ->redis ->hincrby ($ this ->getTopicName ($ appId ), 'connections ' , 1 );
198+
199+ return true ;
200+ }
201+
202+ /**
203+ * Unsubscribe from the app's pubsub keyspace.
204+ *
205+ * @param mixed $appId
206+ * @return bool
207+ */
208+ public function unsubscribeFromApp ($ appId ): bool
209+ {
210+ $ this ->subscribeClient ->__call ('unsubscribe ' , [$ this ->getTopicName ($ appId )]);
211+
212+ $ this ->redis ->hincrby ($ this ->getTopicName ($ appId ), 'connections ' , -1 );
213+
214+ return true ;
215+ }
216+
178217 /**
179218 * Add a member to a channel. To be called when they have
180219 * subscribed to the channel.
@@ -258,6 +297,19 @@ public function channelMemberCounts($appId, array $channelNames): PromiseInterfa
258297 });
259298 }
260299
300+ /**
301+ * Get the amount of unique connections.
302+ *
303+ * @param mixed $appId
304+ * @return null|int|\React\Promise\PromiseInterface
305+ */
306+ public function appConnectionsCount ($ appId )
307+ {
308+ // Use the in-built Redis manager to avoid async run.
309+
310+ return $ this ->redis ->hget ($ this ->getTopicName ($ appId ), 'connections ' ) ?: 0 ;
311+ }
312+
261313 /**
262314 * Handle a message received from Redis on a specific channel.
263315 *
@@ -377,13 +429,19 @@ public function getServerId()
377429 * app ID and channel name.
378430 *
379431 * @param mixed $appId
380- * @param string $channel
432+ * @param string|null $channel
381433 * @return string
382434 */
383- protected function getTopicName ($ appId , string $ channel ): string
435+ protected function getTopicName ($ appId , string $ channel = null ): string
384436 {
385437 $ prefix = config ('database.redis.options.prefix ' , null );
386438
387- return "{$ prefix }{$ appId }: {$ channel }" ;
439+ $ hash = "{$ prefix }{$ appId }" ;
440+
441+ if ($ channel ) {
442+ $ hash .= ": {$ channel }" ;
443+ }
444+
445+ return $ hash ;
388446 }
389447}
0 commit comments