diff --git a/src/Client.php b/src/Client.php index 53e86c2..981753c 100644 --- a/src/Client.php +++ b/src/Client.php @@ -20,6 +20,7 @@ class Client private string $name = ''; + /** @var array */ private array $handlers = []; private array $subscriptions = []; @@ -240,4 +241,23 @@ public function skipInvalidMessages(bool $skipInvalidMessages): self $this->skipInvalidMessages = $skipInvalidMessages; return $this; } + + public function unsubscribeAll(): self + { + foreach ($this->subscriptions as $index => $subscription) { + unset($this->subscriptions[$index]); + $this->connection->sendMessage(new Unsubscribe(['sid' => $subscription['sid']])); + unset($this->handlers[$subscription['sid']]); + } + + return $this; + } + + public function disconnect(): self + { + $this->unsubscribeAll(); + $this->connection->close(); + + return $this; + } } diff --git a/src/Connection.php b/src/Connection.php index 411e043..425d567 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -290,4 +290,12 @@ private function processException(Throwable $e) ])); } } + + public function close(): void + { + if ($this->socket) { + fclose($this->socket); + $this->socket = null; + } + } } diff --git a/tests/Functional/ClientTest.php b/tests/Functional/ClientTest.php index b82678b..c6f9eef 100644 --- a/tests/Functional/ClientTest.php +++ b/tests/Functional/ClientTest.php @@ -112,4 +112,21 @@ public function testInvalidTlsKey() ]); $client->ping(); } + + public function testCloseClosesSocket(): void + { + $client = $this->createClient([]); + self::assertTrue($client->ping()); + + $connection = $client->connection; + + // Call the close method + $connection->close(); + + $property = new ReflectionProperty(Connection::class, 'socket'); + $property->setAccessible(true); + + // Assert that the socket is closed and set to null + self::assertNull($property->getValue($connection)); + } } diff --git a/tests/Functional/SubjectTest.php b/tests/Functional/SubjectTest.php index bbc3e97..254c86d 100644 --- a/tests/Functional/SubjectTest.php +++ b/tests/Functional/SubjectTest.php @@ -5,6 +5,7 @@ namespace Tests\Functional; use Basis\Nats\Client; +use Basis\Nats\Connection; use Basis\Nats\Message\Payload; use ReflectionProperty; use Tests\FunctionalTestCase; @@ -226,4 +227,45 @@ public function greet(Payload $payload): string { return 'Hello, ' . $payload->body; } + + public function testUnsubscribeAll(): void + { + $property = new ReflectionProperty(Client::class, 'handlers'); + $property->setAccessible(true); + + $client = $this->createClient(); + + $subjects = ['hello.request1', 'hello.request2']; + foreach ($subjects as $subject) { + $client->subscribe($subject, $this->greet(...)); + } + self::assertCount(2, $property->getValue($client)); + + $client->unsubscribeAll(); + self::assertCount(0, $property->getValue($client)); + } + + public function testDisconnect(): void + { + $property = new ReflectionProperty(Client::class, 'handlers'); + $property->setAccessible(true); + + $client = $this->createClient(); + $connection = $client->connection; + + $subjects = ['hello.request1', 'hello.request2']; + foreach ($subjects as $subject) { + $client->subscribe($subject, $this->greet(...)); + } + self::assertCount(2, $property->getValue($client)); + + $client->disconnect(); + self::assertCount(0, $property->getValue($client)); + + $property = new ReflectionProperty(Connection::class, 'socket'); + $property->setAccessible(true); + + // Assert that the socket is closed and set to null + self::assertNull($property->getValue($connection)); + } }