22
33namespace  BeyondCode \LaravelWebSockets \ChannelManagers ;
44
5- use  BeyondCode \LaravelWebSockets \Channels \Channel ;
65use  BeyondCode \LaravelWebSockets \DashboardLogger ;
76use  BeyondCode \LaravelWebSockets \Helpers ;
87use  BeyondCode \LaravelWebSockets \Server \MockableConnection ;
@@ -145,31 +144,18 @@ public function subscribeToChannel(ConnectionInterface $connection, string $chan
145144     */ 
146145    public  function  unsubscribeFromChannel (ConnectionInterface $ connectionstring  $ channelNamestdClass $ payloadPromiseInterface 
147146    {
148-         return  $ this getGlobalConnectionsCount ($ connectionapp ->id , $ channelName
147+         return  parent ::unsubscribeFromChannel ($ connection$ channelName$ payload
148+             ->then (function  () use  ($ connection$ channelName
149+                 return  $ this decrementSubscriptionsCount ($ connectionapp ->id , $ channelName
150+             })
149151            ->then (function  ($ countuse  ($ connection$ channelName
150-                 if  ($ count0 ) {
151-                     // Make sure to not stay subscribed to the PubSub topic 
152-                     // if there are no connections. 
152+                 $ this removeConnectionFromSet ($ connection
153+                 // If the total connections count gets to 0 after unsubscribe, 
154+                 // try again to check & unsubscribe from the PubSub topic if needed. 
155+                 if  ($ count1 ) {
156+                     $ this removeChannelFromSet ($ connectionapp ->id , $ channelName
153157                    $ this unsubscribeFromTopic ($ connectionapp ->id , $ channelName
154158                }
155- 
156-                 $ this decrementSubscriptionsCount ($ connectionapp ->id , $ channelName
157-                     ->then (function  ($ countuse  ($ connection$ channelName
158-                         // If the total connections count gets to 0 after unsubscribe, 
159-                         // try again to check & unsubscribe from the PubSub topic if needed. 
160-                         if  ($ count1 ) {
161-                             $ this unsubscribeFromTopic ($ connectionapp ->id , $ channelName
162-                         }
163-                     });
164-             })
165-             ->then (function  () use  ($ connection$ channelName
166-                 return  $ this removeChannelFromSet ($ connectionapp ->id , $ channelName
167-             })
168-             ->then (function  () use  ($ connection
169-                 return  $ this removeConnectionFromSet ($ connection
170-             })
171-             ->then (function  () use  ($ connection$ channelName$ payload
172-                 return  parent ::unsubscribeFromChannel ($ connection$ channelName$ payload
173159            });
174160    }
175161
@@ -363,6 +349,16 @@ public function connectionPonged(ConnectionInterface $connection): PromiseInterf
363349    {
364350        // This will update the score with the current timestamp. 
365351        return  $ this addConnectionToSet ($ connectionnow ())
352+             ->then (function  () use  ($ connection
353+                 $ payload
354+                     'socketId '  => $ connectionsocketId ,
355+                     'appId '  => $ connectionapp ->id ,
356+                     'serverId '  => $ this getServerId (),
357+                 ];
358+ 
359+                 return  $ this publishClient 
360+                     ->publish ($ this getPongRedisHash ($ connectionapp ->id ), json_encode ($ payload
361+             })
366362            ->then (function  () use  ($ connection
367363                return  parent ::connectionPonged ($ connection
368364            });
@@ -375,18 +371,23 @@ public function connectionPonged(ConnectionInterface $connection): PromiseInterf
375371     */ 
376372    public  function  removeObsoleteConnections (): PromiseInterface 
377373    {
378-         $ this lock ()->get (function  () {
379-             $ this getConnectionsFromSet (0 , now ()->subMinutes (2 )->format ('U ' ))
380-                 ->then (function  ($ connections
381-                     foreach  ($ connectionsas  $ socketId$ appId
382-                         $ connection$ this fakeConnectionForApp ($ appId$ socketId
374+         $ lock$ this lock ();
375+         try  {
376+             $ lockget (function  () {
377+                 $ this getConnectionsFromSet (0 , now ()->subMinutes (2 )->format ('U ' ))
378+                     ->then (function  ($ connections
379+                         foreach  ($ connectionsas  $ socketId$ appId
380+                             $ connection$ this fakeConnectionForApp ($ appId$ socketId
383381
384-                         $ this unsubscribeFromAllChannels ($ connection
385-                     }
386-                 });
387-         });
382+                              $ this unsubscribeFromAllChannels ($ connection
383+                          }
384+                      });
385+              });
388386
389-         return  parent ::removeObsoleteConnections ();
387+             return  parent ::removeObsoleteConnections ();
388+         } finally  {
389+             optional ($ lockforceRelease ();
390+         }
390391    }
391392
392393    /** 
@@ -404,6 +405,12 @@ public function onMessage(string $redisChannel, string $payload)
404405            return ;
405406        }
406407
408+         if  ($ redisChannel$ this getPongRedisHash ($ payloadappId )) {
409+             $ connection$ this fakeConnectionForApp ($ payloadappId , $ payloadsocketId );
410+ 
411+             return  parent ::connectionPonged ($ connection
412+         }
413+ 
407414        $ payloadchannel  = Str::after ($ redisChannel"{$ payloadappId }: " );
408415
409416        if  (! $ channel$ this find ($ payloadappId , $ payloadchannel )) {
@@ -429,6 +436,16 @@ public function onMessage(string $redisChannel, string $payload)
429436        $ channelbroadcastLocallyToEveryoneExcept ($ payload$ socketId$ appId
430437    }
431438
439+     public  function  find ($ appIdstring  $ channel
440+     {
441+         if  (! $ channelInstanceparent ::find ($ appId$ channel
442+             $ class$ this getChannelClassName ($ channel
443+             $ this channels [$ appId$ channelnew  $ class$ channel
444+         }
445+ 
446+         return  parent ::find ($ appId$ channel
447+     }
448+ 
432449    /** 
433450     * Build the Redis connection URL from Laravel database config. 
434451     * 
@@ -601,6 +618,20 @@ public function removeChannelFromSet($appId, string $channel): PromiseInterface
601618        );
602619    }
603620
621+     /** 
622+      * Check if channel is on the list. 
623+      * 
624+      * @param  string|int  $appId 
625+      * @param  string  $channel 
626+      * @return PromiseInterface 
627+      */ 
628+     public  function  isChannelInSet ($ appIdstring  $ channelPromiseInterface 
629+     {
630+         return  $ this publishClient ->sismember (
631+             $ this getChannelsRedisHash ($ appId$ channel
632+         );
633+     }
634+ 
604635    /** 
605636     * Set data for a topic. Might be used for the presence channels. 
606637     * 
@@ -729,6 +760,16 @@ public function getRedisKey($appId = null, string $channel = null, array $suffix
729760        return  $ hash
730761    }
731762
763+     /** 
764+      * Get the pong Redis hash. 
765+      * 
766+      * @param  string|int  $appId 
767+      */ 
768+     public  function  getPongRedisHash ($ appIdstring 
769+     {
770+         return  $ this getRedisKey ($ appIdnull , ['pong ' ]);
771+     }
772+ 
732773    /** 
733774     * Get the statistics Redis hash. 
734775     * 
0 commit comments