diff --git a/app/realtime.php b/app/realtime.php index 2fa34fec71..e5308a6a62 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -294,32 +294,7 @@ $server->on('message', function (Server $server, Frame $frame) { }); $server->on('close', function (Server $server, int $fd) use (&$connections, &$subscriptions) { - /** - * TODO: Move into Realtime Class for tests - */ - $projectId = $connections[$fd]['projectId'] ?? ''; - $roles = $connections[$fd]['roles'] ?? []; - - foreach ($roles as $key => $role) { - foreach ($subscriptions[$projectId][$role] as $channel => $list) { - unset($subscriptions[$projectId][$role][$channel][$fd]); // Remove connection - - if (empty($subscriptions[$projectId][$role][$channel])) { - unset($subscriptions[$projectId][$role][$channel]); // Remove channel when no connections - } - } - - if (empty($subscriptions[$projectId][$role])) { - unset($subscriptions[$projectId][$role]); // Remove role when no channels - } - } - - if (empty($subscriptions[$projectId])) { // Remove project when no roles - unset($subscriptions[$projectId]); - } - - unset($connections[$fd]); - + Realtime::removeSubscription($fd, $subscriptions, $connections); Console::info('Connection close: ' . $fd); }); diff --git a/src/Appwrite/Realtime/Realtime.php b/src/Appwrite/Realtime/Realtime.php index b6028baf4d..2dd185f933 100644 --- a/src/Appwrite/Realtime/Realtime.php +++ b/src/Appwrite/Realtime/Realtime.php @@ -110,7 +110,7 @@ class Realtime * @param array $roles * @param array $channels */ - static function addSubscription($projectId, $connection, &$subscriptions, &$connections, &$roles, &$channels) + static function addSubscription($projectId, $connection, $roles, &$subscriptions, &$connections, &$channels) { /** * Build Subscriptions Tree @@ -145,4 +145,37 @@ class Realtime 'roles' => $roles, ]; } + + /** + * Remove Subscription. + * + * @param mixed $connection + * @param array $subscriptions + * @param array $connections + */ + static function removeSubscription($connection, &$subscriptions, &$connections) + { + $projectId = $connections[$connection]['projectId'] ?? ''; + $roles = $connections[$connection]['roles'] ?? []; + + foreach ($roles as $key => $role) { + foreach ($subscriptions[$projectId][$role] as $channel => $list) { + unset($subscriptions[$projectId][$role][$channel][$connection]); // Remove connection + + if (empty($subscriptions[$projectId][$role][$channel])) { + unset($subscriptions[$projectId][$role][$channel]); // Remove channel when no connections + } + } + + if (empty($subscriptions[$projectId][$role])) { + unset($subscriptions[$projectId][$role]); // Remove role when no channels + } + } + + if (empty($subscriptions[$projectId])) { // Remove project when no roles + unset($subscriptions[$projectId]); + } + + unset($connections[$connection]); + } } diff --git a/tests/unit/Realtime/RealtimeChannelsTest.php b/tests/unit/Realtime/RealtimeChannelsTest.php index cd993c6719..d10a7aa7d2 100644 --- a/tests/unit/Realtime/RealtimeChannelsTest.php +++ b/tests/unit/Realtime/RealtimeChannelsTest.php @@ -63,9 +63,9 @@ class RealtimeChannelsTest extends TestCase Realtime::addSubscription( '1', $this->connectionsCount, + Realtime::getRoles(), $this->subscriptions, $this->connections, - Realtime::getRoles(), Realtime::parseChannels([0 => $channel]) ); @@ -85,9 +85,9 @@ class RealtimeChannelsTest extends TestCase Realtime::addSubscription( '1', $this->connectionsCount, + Realtime::getRoles(), $this->subscriptions, $this->connections, - Realtime::getRoles(), Realtime::parseChannels([0 => $channel]) ); @@ -127,6 +127,20 @@ class RealtimeChannelsTest extends TestCase * - Guests */ $this->assertCount($this->connectionsTotal, $this->connections); + + Realtime::removeSubscription(-1, $this->subscriptions, $this->connections); + + $this->assertCount($this->connectionsTotal, $this->connections); + $this->assertCount(($this->connectionsAuthenticated + (3 * $this->connectionsPerChannel) + 3), $this->subscriptions['1']); + + for ($i=0; $i < $this->connectionsCount; $i++) { + Realtime::removeSubscription($i, $this->subscriptions, $this->connections); + + $this->assertCount(($this->connectionsCount - $i - 1), $this->connections); + } + + $this->assertEmpty($this->connections); + $this->assertEmpty($this->subscriptions); } /** diff --git a/tests/unit/Realtime/RealtimeGuestTest.php b/tests/unit/Realtime/RealtimeGuestTest.php index 35507a0d50..217ea77fb1 100644 --- a/tests/unit/Realtime/RealtimeGuestTest.php +++ b/tests/unit/Realtime/RealtimeGuestTest.php @@ -46,7 +46,7 @@ class RealtimeGuestTest extends TestCase $this->assertArrayNotHasKey('account', $channels); $this->assertArrayNotHasKey('account.456', $channels); - Realtime::addSubscription('1', 1, $this->subscriptions, $this->connections, $roles, $channels); + Realtime::addSubscription('1', 1, $roles, $this->subscriptions, $this->connections, $channels); $event = [ @@ -201,5 +201,16 @@ class RealtimeGuestTest extends TestCase ); $this->assertEmpty($receivers); + + Realtime::removeSubscription(2, $this->subscriptions, $this->connections); + + $this->assertCount(1, $this->connections); + $this->assertCount(2, $this->subscriptions['1']); + + + Realtime::removeSubscription(1, $this->subscriptions, $this->connections); + + $this->assertEmpty($this->connections); + $this->assertEmpty($this->subscriptions); } } diff --git a/tests/unit/Realtime/RealtimeTest.php b/tests/unit/Realtime/RealtimeTest.php index ea97d2c5c9..19fd1e74c4 100644 --- a/tests/unit/Realtime/RealtimeTest.php +++ b/tests/unit/Realtime/RealtimeTest.php @@ -70,7 +70,7 @@ class RealtimeTest extends TestCase $this->assertArrayNotHasKey('account', $channels); $this->assertArrayNotHasKey('account.456', $channels); - Realtime::addSubscription('1', 1, $this->subscriptions, $this->connections, $roles, $channels); + Realtime::addSubscription('1', 1, $roles, $this->subscriptions, $this->connections, $channels); $event = [ 'project' => '1', @@ -219,5 +219,16 @@ class RealtimeTest extends TestCase ); $this->assertEmpty($receivers); + + Realtime::removeSubscription(2, $this->subscriptions, $this->connections); + + $this->assertCount(1, $this->connections); + $this->assertCount(8, $this->subscriptions['1']); + + + Realtime::removeSubscription(1, $this->subscriptions, $this->connections); + + $this->assertEmpty($this->connections); + $this->assertEmpty($this->subscriptions); } }