From c277a20c40e3d955f8bc63c559c3b9582f8b34ae Mon Sep 17 00:00:00 2001 From: Robin Richtsfeld Date: Fri, 16 Dec 2022 01:37:22 +0100 Subject: [PATCH] Require Topic for TopicPeriodicTimer::addPeriodicTimer --- src/Server/App/Dispatcher/TopicDispatcher.php | 4 +- src/Topic/TopicPeriodicTimer.php | 60 +++++++++++-------- .../App/Dispatcher/TopicDispatcherTest.php | 2 +- tests/Topic/TopicPeriodicTimerTest.php | 56 ++++++++++------- 4 files changed, 74 insertions(+), 48 deletions(-) diff --git a/src/Server/App/Dispatcher/TopicDispatcher.php b/src/Server/App/Dispatcher/TopicDispatcher.php index 0b8397b..e621323 100644 --- a/src/Server/App/Dispatcher/TopicDispatcher.php +++ b/src/Server/App/Dispatcher/TopicDispatcher.php @@ -135,7 +135,7 @@ private function dispatch( if ($appTopic instanceof TopicPeriodicTimerInterface) { $appTopic->setPeriodicTimer($this->topicPeriodicTimer); - if (!$this->topicPeriodicTimer->isRegistered($appTopic) && 0 !== \count($topic)) { + if (!$this->topicPeriodicTimer->isRegistered($appTopic, $topic) && 0 !== \count($topic)) { try { $appTopic->registerPeriodicTimer($topic); } catch (\Throwable $e) { @@ -178,7 +178,7 @@ private function dispatch( $appTopic->onUnSubscribe($conn, $topic, $request); if (0 === \count($topic)) { - $this->topicPeriodicTimer->clearPeriodicTimer($appTopic); + $this->topicPeriodicTimer->clearPeriodicTimer($appTopic, $topic); } break; diff --git a/src/Topic/TopicPeriodicTimer.php b/src/Topic/TopicPeriodicTimer.php index e3ece85..eacd3c2 100644 --- a/src/Topic/TopicPeriodicTimer.php +++ b/src/Topic/TopicPeriodicTimer.php @@ -2,6 +2,7 @@ namespace Gos\Bundle\WebSocketBundle\Topic; +use Ratchet\Wamp\Topic; use React\EventLoop\LoopInterface; use React\EventLoop\TimerInterface; @@ -11,7 +12,7 @@ class TopicPeriodicTimer implements \IteratorAggregate { /** - * @var array> + * @var array>> */ protected array $registry = []; protected LoopInterface $loop; @@ -21,69 +22,78 @@ public function __construct(LoopInterface $loop) $this->loop = $loop; } - public function getAllPeriodicTimers(TopicInterface $topic, string $name): TimerInterface|bool + public function getPeriodicTimer(TopicInterface $appTopic, Topic $topic, string $name): TimerInterface|bool { - if (!$this->isPeriodicTimerActive($topic, $name)) { + if (!$this->isPeriodicTimerActive($appTopic, $topic, $name)) { return false; } - $namespace = $this->getTopicNamespace($topic); + $namespace = $this->getTopicNamespace($appTopic); - return $this->registry[$namespace][$name]; + return $this->registry[$namespace][$topic->getId()][$name]; } /** * @return array */ - public function getPeriodicTimers(TopicInterface $topic): array + public function getPeriodicTimers(TopicInterface $appTopic, Topic $topic): array { - $namespace = $this->getTopicNamespace($topic); + $namespace = $this->getTopicNamespace($appTopic); - return $this->registry[$namespace] ?? []; + return $this->registry[$namespace][$topic->getId()] ?? []; } - public function addPeriodicTimer(TopicInterface $topic, string $name, int|float $timeout, callable $callback): void + public function addPeriodicTimer(TopicInterface $appTopic, Topic $topic, string $name, int|float $timeout, callable $callback): void { - $namespace = $this->getTopicNamespace($topic); + $namespace = $this->getTopicNamespace($appTopic); if (!isset($this->registry[$namespace])) { $this->registry[$namespace] = []; } - $this->registry[$namespace][$name] = $this->loop->addPeriodicTimer($timeout, $callback); + if (!isset($this->registry[$namespace][$topic->getId()])) { + $this->registry[$namespace][$topic->getId()] = []; + } + + $this->registry[$namespace][$topic->getId()][$name] = $this->loop->addPeriodicTimer($timeout, $callback); } - public function isRegistered(TopicInterface $topic): bool + public function isRegistered(TopicInterface $appTopic, Topic $topic): bool { - $namespace = $this->getTopicNamespace($topic); + $namespace = $this->getTopicNamespace($appTopic); - return isset($this->registry[$namespace]); + return isset($this->registry[$namespace][$topic->getId()]); } - public function isPeriodicTimerActive(TopicInterface $topic, string $name): bool + public function isPeriodicTimerActive(TopicInterface $appTopic, Topic $topic, string $name): bool { - $namespace = $this->getTopicNamespace($topic); + $namespace = $this->getTopicNamespace($appTopic); - return isset($this->registry[$namespace][$name]); + return isset($this->registry[$namespace][$topic->getId()][$name]); } - public function cancelPeriodicTimer(TopicInterface $topic, string $name): void + public function cancelPeriodicTimer(TopicInterface $appTopic, Topic $topic, string $name): void { - $namespace = $this->getTopicNamespace($topic); + $namespace = $this->getTopicNamespace($appTopic); - if (!isset($this->registry[$namespace][$name])) { + if (!isset($this->registry[$namespace][$topic->getId()][$name])) { return; } - $timer = $this->registry[$namespace][$name]; + $timer = $this->registry[$namespace][$topic->getId()][$name]; $this->loop->cancelTimer($timer); - unset($this->registry[$namespace][$name]); + unset($this->registry[$namespace][$topic->getId()][$name]); } - public function clearPeriodicTimer(TopicInterface $topic): void + public function clearPeriodicTimer(TopicInterface $appTopic, Topic $topic): void { - $namespace = $this->getTopicNamespace($topic); - unset($this->registry[$namespace]); + $namespace = $this->getTopicNamespace($appTopic); + + foreach ($this->registry[$namespace][$topic->getId()] as $timer) { + $this->loop->cancelTimer($timer); + } + + unset($this->registry[$namespace][$topic->getId()]); } /** diff --git a/tests/Server/App/Dispatcher/TopicDispatcherTest.php b/tests/Server/App/Dispatcher/TopicDispatcherTest.php index 60e07ea..41684de 100644 --- a/tests/Server/App/Dispatcher/TopicDispatcherTest.php +++ b/tests/Server/App/Dispatcher/TopicDispatcherTest.php @@ -366,7 +366,7 @@ public function wasRegistered(): bool $this->topicPeriodicTimer->expects(self::once()) ->method('isRegistered') - ->with($handler) + ->with($handler, $topic) ->willReturn(false); $this->dispatcher->onPublish($connection, $topic, $request, 'test', [], []); diff --git a/tests/Topic/TopicPeriodicTimerTest.php b/tests/Topic/TopicPeriodicTimerTest.php index 1b2f75f..136fe6c 100644 --- a/tests/Topic/TopicPeriodicTimerTest.php +++ b/tests/Topic/TopicPeriodicTimerTest.php @@ -6,6 +6,7 @@ use Gos\Bundle\WebSocketBundle\Topic\TopicPeriodicTimer; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Ratchet\Wamp\Topic; use React\EventLoop\LoopInterface; use React\EventLoop\TimerInterface; @@ -35,8 +36,11 @@ public function testRetrieveTheNamedPeriodicTimerWhenActive(): void $callback = static function (): void {}; $timeout = 10; - /** @var MockObject&TopicInterface $topic */ - $topic = $this->createMock(TopicInterface::class); + /** @var MockObject&TopicInterface $appTopic */ + $appTopic = $this->createMock(TopicInterface::class); + + /** @var MockObject&Topic $topic */ + $topic = $this->createMock(Topic::class); /** @var MockObject&TimerInterface $timer */ $timer = $this->createMock(TimerInterface::class); @@ -46,17 +50,20 @@ public function testRetrieveTheNamedPeriodicTimerWhenActive(): void ->with($timeout, $callback) ->willReturn($timer); - $this->topicPeriodicTimer->addPeriodicTimer($topic, 'test', $timeout, $callback); + $this->topicPeriodicTimer->addPeriodicTimer($appTopic, $topic, 'test', $timeout, $callback); - self::assertSame($timer, $this->topicPeriodicTimer->getAllPeriodicTimers($topic, 'test')); + self::assertSame($timer, $this->topicPeriodicTimer->getPeriodicTimer($appTopic, $topic, 'test')); } public function testNoTimerIsReturnedWhenNotRegisteredAndActive(): void { - /** @var MockObject&TopicInterface $topic */ - $topic = $this->createMock(TopicInterface::class); + /** @var MockObject&TopicInterface $appTopic */ + $appTopic = $this->createMock(TopicInterface::class); + + /** @var MockObject&Topic $topic */ + $topic = $this->createMock(Topic::class); - self::assertFalse($this->topicPeriodicTimer->getAllPeriodicTimers($topic, 'test')); + self::assertFalse($this->topicPeriodicTimer->getPeriodicTimer($appTopic, $topic, 'test')); } public function testRetrieveThePeriodicTimersForATopic(): void @@ -64,8 +71,11 @@ public function testRetrieveThePeriodicTimersForATopic(): void $callback = static function (): void {}; $timeout = 10; - /** @var MockObject&TopicInterface $topic */ - $topic = $this->createMock(TopicInterface::class); + /** @var MockObject&TopicInterface $appTopic */ + $appTopic = $this->createMock(TopicInterface::class); + + /** @var MockObject&Topic $topic */ + $topic = $this->createMock(Topic::class); /** @var MockObject&TimerInterface $timer */ $timer = $this->createMock(TimerInterface::class); @@ -75,17 +85,20 @@ public function testRetrieveThePeriodicTimersForATopic(): void ->with($timeout, $callback) ->willReturn($timer); - $this->topicPeriodicTimer->addPeriodicTimer($topic, 'test', $timeout, $callback); + $this->topicPeriodicTimer->addPeriodicTimer($appTopic, $topic, 'test', $timeout, $callback); - self::assertSame(['test' => $timer], $this->topicPeriodicTimer->getPeriodicTimers($topic)); + self::assertSame(['test' => $timer], $this->topicPeriodicTimer->getPeriodicTimers($appTopic, $topic)); } public function testDetermineWhetherATopicHasBeenRegistered(): void { - /** @var MockObject&TopicInterface $topic */ - $topic = $this->createMock(TopicInterface::class); + /** @var MockObject&TopicInterface $appTopic */ + $appTopic = $this->createMock(TopicInterface::class); - self::assertFalse($this->topicPeriodicTimer->isRegistered($topic)); + /** @var MockObject&Topic $topic */ + $topic = $this->createMock(Topic::class); + + self::assertFalse($this->topicPeriodicTimer->isRegistered($appTopic, $topic)); $callback = static function (): void {}; $timeout = 10; @@ -98,9 +111,9 @@ public function testDetermineWhetherATopicHasBeenRegistered(): void ->with($timeout, $callback) ->willReturn($timer); - $this->topicPeriodicTimer->addPeriodicTimer($topic, 'test', $timeout, $callback); + $this->topicPeriodicTimer->addPeriodicTimer($appTopic, $topic, 'test', $timeout, $callback); - self::assertTrue($this->topicPeriodicTimer->isRegistered($topic)); + self::assertTrue($this->topicPeriodicTimer->isRegistered($appTopic, $topic)); } public function testCancelTheNamedPeriodicTimerWhenActive(): void @@ -108,8 +121,11 @@ public function testCancelTheNamedPeriodicTimerWhenActive(): void $callback = static function (): void {}; $timeout = 10; - /** @var MockObject&TopicInterface $topic */ - $topic = $this->createMock(TopicInterface::class); + /** @var MockObject&TopicInterface $appTopic */ + $appTopic = $this->createMock(TopicInterface::class); + + /** @var MockObject&Topic $topic */ + $topic = $this->createMock(Topic::class); /** @var MockObject&TimerInterface $timer */ $timer = $this->createMock(TimerInterface::class); @@ -123,7 +139,7 @@ public function testCancelTheNamedPeriodicTimerWhenActive(): void ->method('cancelTimer') ->with($timer); - $this->topicPeriodicTimer->addPeriodicTimer($topic, 'test', $timeout, $callback); - $this->topicPeriodicTimer->cancelPeriodicTimer($topic, 'test'); + $this->topicPeriodicTimer->addPeriodicTimer($appTopic, $topic, 'test', $timeout, $callback); + $this->topicPeriodicTimer->cancelPeriodicTimer($appTopic, $topic, 'test'); } }