From 7a07e1f28709861745b208f9ac2addfe02668878 Mon Sep 17 00:00:00 2001 From: Savio Resende Date: Fri, 29 Sep 2023 19:04:47 -0500 Subject: [PATCH] Code Refactor: data resiliency improvements. --- src/Actions/ActionManager.php | 5 +- src/Actions/Traits/HasPersistence.php | 8 +- .../Abstractions/GenericPersistence.php | 14 -- src/Models/Sqlite/DatabaseBootstrap.php | 100 ---------- src/Models/{Sqlite => }/WsAssociation.php | 3 +- src/Models/{Sqlite => }/WsChannel.php | 3 +- src/Models/{Sqlite => }/WsListener.php | 3 +- .../Abstracts/GenericPersistence.php | 32 ++++ src/Persistence/DTO/DatabaseConnectionDTO.php | 64 +++++++ src/Persistence/DatabaseBootstrap.php | 179 ++++++++++++++++++ .../ChannelPersistenceInterface.php | 2 +- .../GenericPersistenceInterface.php | 2 +- .../ListenerPersistenceInterface.php | 2 +- .../UserAssocPersistenceInterface.php | 2 +- .../WebSockets/AssociationsPersistence.php | 18 +- .../WebSockets/ChannelsPersistence.php | 24 +-- .../WebSockets/ListenersPersistence.php | 19 +- src/SocketHandlers/SocketMessageRouter.php | 76 ++++---- tests/Assets/.gitignore | 1 + tests/Assets/SampleChannelPersistence.php | 40 ---- tests/Assets/SampleListenerPersistence.php | 55 ------ tests/Assets/SamplePersistence.php | 2 +- tests/Assets/SampleUserAssocPersistence.php | 43 ----- tests/SocketChannelPersistenceTest.php | 5 +- tests/SocketHandlerTestCase.php | 27 +-- tests/SocketListenerPersistenceTest.php | 5 +- tests/SocketListenerTest.php | 11 +- tests/SocketMessageRouterTest.php | 59 ++++-- tests/SocketUserAssocPersistenceTest.php | 5 +- tests/TestCase.php | 17 ++ 30 files changed, 458 insertions(+), 368 deletions(-) delete mode 100644 src/Models/Abstractions/GenericPersistence.php delete mode 100644 src/Models/Sqlite/DatabaseBootstrap.php rename src/Models/{Sqlite => }/WsAssociation.php (76%) rename src/Models/{Sqlite => }/WsChannel.php (77%) rename src/Models/{Sqlite => }/WsListener.php (75%) create mode 100644 src/Persistence/Abstracts/GenericPersistence.php create mode 100644 src/Persistence/DTO/DatabaseConnectionDTO.php create mode 100644 src/Persistence/DatabaseBootstrap.php rename src/{Models => Persistence}/Interfaces/ChannelPersistenceInterface.php (94%) rename src/{Models => Persistence}/Interfaces/GenericPersistenceInterface.php (83%) rename src/{Models => Persistence}/Interfaces/ListenerPersistenceInterface.php (95%) rename src/{Models => Persistence}/Interfaces/UserAssocPersistenceInterface.php (94%) rename src/{Models/Sqlite => Persistence}/WebSockets/AssociationsPersistence.php (76%) rename src/{Models/Sqlite => Persistence}/WebSockets/ChannelsPersistence.php (69%) rename src/{Models/Sqlite => Persistence}/WebSockets/ListenersPersistence.php (79%) create mode 100644 tests/Assets/.gitignore delete mode 100644 tests/Assets/SampleChannelPersistence.php delete mode 100644 tests/Assets/SampleListenerPersistence.php delete mode 100644 tests/Assets/SampleUserAssocPersistence.php create mode 100644 tests/TestCase.php diff --git a/src/Actions/ActionManager.php b/src/Actions/ActionManager.php index 2e685fb..13b1d03 100644 --- a/src/Actions/ActionManager.php +++ b/src/Actions/ActionManager.php @@ -3,8 +3,7 @@ namespace Conveyor\Actions; use Conveyor\Actions\Interfaces\ActionInterface; -use Conveyor\Models\Interfaces\GenericPersistenceInterface; -use Conveyor\SocketHandlers\SocketMessageRouter; +use Conveyor\Persistence\Interfaces\GenericPersistenceInterface; use Exception; use League\Pipeline\PipelineBuilder; use League\Pipeline\PipelineInterface; @@ -40,6 +39,8 @@ public static function make(array $actions = [], bool $fresh = false): static } /** + * This method adds default actions to the manager. + * * @param bool $fresh * * @return static diff --git a/src/Actions/Traits/HasPersistence.php b/src/Actions/Traits/HasPersistence.php index 08bd411..54df88f 100644 --- a/src/Actions/Traits/HasPersistence.php +++ b/src/Actions/Traits/HasPersistence.php @@ -2,10 +2,10 @@ namespace Conveyor\Actions\Traits; -use Conveyor\Models\Interfaces\ChannelPersistenceInterface; -use Conveyor\Models\Interfaces\GenericPersistenceInterface; -use Conveyor\Models\Interfaces\ListenerPersistenceInterface; -use Conveyor\Models\Interfaces\UserAssocPersistenceInterface; +use Conveyor\Persistence\Interfaces\ChannelPersistenceInterface; +use Conveyor\Persistence\Interfaces\GenericPersistenceInterface; +use Conveyor\Persistence\Interfaces\ListenerPersistenceInterface; +use Conveyor\Persistence\Interfaces\UserAssocPersistenceInterface; trait HasPersistence { diff --git a/src/Models/Abstractions/GenericPersistence.php b/src/Models/Abstractions/GenericPersistence.php deleted file mode 100644 index 577f6b2..0000000 --- a/src/Models/Abstractions/GenericPersistence.php +++ /dev/null @@ -1,14 +0,0 @@ -databasePath = $databasePath; - } - - if (file_exists($this->databasePath)) { - return; - } - - if (!touch($this->databasePath)) { - throw new Exception('Failed to create database file for Conveyor functionalities!'); - } - } - - private function getCapsule(): Manager - { - $capsule = new Manager; - $capsule->addConnection([ - 'driver' => 'sqlite', - 'database' => $this->databasePath, - 'prefix' => '', - ]); - $capsule->setAsGlobal(); - $capsule->bootEloquent(); - return $capsule; - } - - public function migrateChannelPersistence(bool $fresh = false): void - { - $schema = $this->getCapsule()->schema(); - - if ($fresh && $schema->hasTable(WsChannel::TABLE_NAME)) { - $schema->drop(WsChannel::TABLE_NAME); - } - - if ($schema->hasTable(WsChannel::TABLE_NAME)) { - return; - } - - $schema->create(WsChannel::TABLE_NAME, function (Blueprint $table) { - $table->id(); - $table->integer('fd'); - $table->string('channel'); - $table->timestamps(); - }); - } - - public function migrateListenerPersistence(bool $fresh = false): void - { - $schema = $this->getCapsule()->schema(); - - if ($fresh && $schema->hasTable(WsListener::TABLE_NAME)) { - $schema->drop(WsListener::TABLE_NAME); - } - - if ($schema->hasTable(WsListener::TABLE_NAME)) { - return; - } - - $schema->create(WsListener::TABLE_NAME, function (Blueprint $table) { - $table->id(); - $table->integer('fd'); - $table->string('action'); - $table->timestamps(); - }); - } - - public function migrateAssociationPersistence(bool $fresh = false): void - { - $schema = $this->getCapsule()->schema(); - - if ($fresh && $schema->hasTable(WsAssociation::TABLE_NAME)) { - $schema->drop(WsAssociation::TABLE_NAME); - } - - if ($schema->hasTable(WsAssociation::TABLE_NAME)) { - return; - } - - $schema->create(WsAssociation::TABLE_NAME, function (Blueprint $table) { - $table->id(); - $table->integer('fd'); - $table->integer('user_id'); - $table->timestamps(); - }); - } -} diff --git a/src/Models/Sqlite/WsAssociation.php b/src/Models/WsAssociation.php similarity index 76% rename from src/Models/Sqlite/WsAssociation.php rename to src/Models/WsAssociation.php index fcd8dc8..eadf110 100644 --- a/src/Models/Sqlite/WsAssociation.php +++ b/src/Models/WsAssociation.php @@ -1,6 +1,6 @@ 'sqlite', + 'database' => __DIR__ . '/../../../../../database/database.sqlite', + 'username' => null, + 'password' => null, + 'charset' => 'utf8', + 'collation' => 'utf8_unicode_ci', + 'prefix' => '', + ], + ) { + if (is_array($this->databaseOptions)) { + $this->databaseOptions = DatabaseConnectionDTO::fromArray($this->databaseOptions); + } + + $this->refresh(true); + } + + abstract public function refresh(bool $fresh = false): static; +} diff --git a/src/Persistence/DTO/DatabaseConnectionDTO.php b/src/Persistence/DTO/DatabaseConnectionDTO.php new file mode 100644 index 0000000..43c1efa --- /dev/null +++ b/src/Persistence/DTO/DatabaseConnectionDTO.php @@ -0,0 +1,64 @@ + $this->driver, + 'database' => $this->database, + 'username' => $this->username, + 'password' => $this->password, + 'charset' => $this->charset, + 'collation' => $this->collation, + 'prefix' => $this->prefix, + ]; + } + + public function offsetExists($offset): bool + { + return property_exists($this, $offset); + } + + public function offsetGet($offset): mixed + { + return $this->{$offset}; + } + + public function offsetSet($offset, $value): void + { + $this->{$offset} = $value; + } + + public function offsetUnset($offset): void + { + $this->{$offset} = null; + } +} diff --git a/src/Persistence/DatabaseBootstrap.php b/src/Persistence/DatabaseBootstrap.php new file mode 100644 index 0000000..bf3e9ff --- /dev/null +++ b/src/Persistence/DatabaseBootstrap.php @@ -0,0 +1,179 @@ +validateDatabaseOptions(); + + if (is_array($this->databaseOptions)) { + $this->databaseOptions = DatabaseConnectionDTO::fromArray($this->databaseOptions); + } + + $database = $this->databaseOptions['database']; + if (!file_exists($database) && !touch($database)) { + throw new Exception('Failed to create database file (' . $database . ') for Conveyor functionalities!'); + } + + $this->startCapsule(); + } + + private function startCapsule() + { + if (!$this->isLaravel()) { + $this->getCapsule(); + return; + } + + DB::purge('socket-conveyor'); + config([ + 'database.connections.socket-conveyor' => [ + 'driver' => 'sqlite', + 'database' => $this->databaseOptions['database'], + 'prefix' => '', + ] + ]); + } + + private function getCapsule(): Manager + { + if (null !== $this->manager) { + return $this->manager; + } + + $manager = new Manager; + $manager->addConnection($this->databaseOptions->toArray(), 'socket-conveyor'); + $manager->setAsGlobal(); + $manager->bootEloquent(); + return $manager; + } + + public function migrateChannelPersistence(bool $fresh = false): void + { + $schema = $this->getSchema(); + + if ($fresh && $schema->hasTable(WsChannel::TABLE_NAME)) { + $schema->drop(WsChannel::TABLE_NAME); + } + + if ($schema->hasTable(WsChannel::TABLE_NAME)) { + return; + } + + $schema->create(WsChannel::TABLE_NAME, function (Blueprint $table) { + $table->id(); + $table->integer('fd'); + $table->string('channel'); + $table->timestamps(); + }); + } + + public function migrateListenerPersistence(bool $fresh = false): void + { + $schema = $this->getSchema(); + + if ($fresh && $schema->hasTable(WsListener::TABLE_NAME)) { + $schema->drop(WsListener::TABLE_NAME); + } + + if ($schema->hasTable(WsListener::TABLE_NAME)) { + return; + } + + $schema->create(WsListener::TABLE_NAME, function (Blueprint $table) { + $table->id(); + $table->integer('fd'); + $table->string('action'); + $table->timestamps(); + }); + } + + public function migrateAssociationPersistence(bool $fresh = false): void + { + $schema = $this->getSchema(); + + if ($fresh && $schema->hasTable(WsAssociation::TABLE_NAME)) { + $schema->drop(WsAssociation::TABLE_NAME); + } + + if ($schema->hasTable(WsAssociation::TABLE_NAME)) { + return; + } + + $schema->create(WsAssociation::TABLE_NAME, function (Blueprint $table) { + $table->id(); + $table->integer('fd'); + $table->integer('user_id'); + $table->timestamps(); + }); + } + + private function getSchema(): Builder + { + $connection = 'socket-conveyor'; + + if ($this->isLaravel()) { + return Schema::connection($connection); + } + + return $this->getCapsule()->schema($connection); + } + + private function isLaravel(): bool + { + return function_exists('app') && app() instanceof Application; + } + + private function validateDatabaseOptions(): void + { + if (!isset($this->databaseOptions['driver'])) { + throw new Exception('Database driver not set!'); + } + + if (!isset($this->databaseOptions['database'])) { + throw new Exception('Database name not set!'); + } + + if (!isset($this->databaseOptions['username'])) { + throw new Exception('Database username not set!'); + } + + if (!isset($this->databaseOptions['password'])) { + throw new Exception('Database password not set!'); + } + + if (!isset($this->databaseOptions['charset'])) { + throw new Exception('Database charset not set!'); + } + + if (!isset($this->databaseOptions['collation'])) { + throw new Exception('Database collation not set!'); + } + + if (!isset($this->databaseOptions['prefix'])) { + throw new Exception('Database prefix not set!'); + } + } +} diff --git a/src/Models/Interfaces/ChannelPersistenceInterface.php b/src/Persistence/Interfaces/ChannelPersistenceInterface.php similarity index 94% rename from src/Models/Interfaces/ChannelPersistenceInterface.php rename to src/Persistence/Interfaces/ChannelPersistenceInterface.php index e6b710e..2629932 100644 --- a/src/Models/Interfaces/ChannelPersistenceInterface.php +++ b/src/Persistence/Interfaces/ChannelPersistenceInterface.php @@ -1,6 +1,6 @@ migrateAssociationPersistence($fresh); + (new DatabaseBootstrap($this->databaseOptions))->migrateAssociationPersistence($fresh); if (!$fresh) { return $this; diff --git a/src/Models/Sqlite/WebSockets/ChannelsPersistence.php b/src/Persistence/WebSockets/ChannelsPersistence.php similarity index 69% rename from src/Models/Sqlite/WebSockets/ChannelsPersistence.php rename to src/Persistence/WebSockets/ChannelsPersistence.php index ed00930..053bae7 100644 --- a/src/Models/Sqlite/WebSockets/ChannelsPersistence.php +++ b/src/Persistence/WebSockets/ChannelsPersistence.php @@ -1,20 +1,16 @@ refresh(true); - } - public function connect(int $fd, string $channel): void { $this->disconnect($fd); @@ -57,9 +53,13 @@ public function getAllConnections(): array return $connections; } - public function refresh(bool $fresh = false, ?string $databasePath = null): static + /** + * @throws Exception + */ + public function refresh(bool $fresh = false): static { - (new DatabaseBootstrap($databasePath))->migrateChannelPersistence($fresh); + /** @throws Exception */ + (new DatabaseBootstrap($this->databaseOptions))->migrateChannelPersistence($fresh); if (!$fresh) { return $this; diff --git a/src/Models/Sqlite/WebSockets/ListenersPersistence.php b/src/Persistence/WebSockets/ListenersPersistence.php similarity index 79% rename from src/Models/Sqlite/WebSockets/ListenersPersistence.php rename to src/Persistence/WebSockets/ListenersPersistence.php index 8da61c5..779b3bd 100644 --- a/src/Models/Sqlite/WebSockets/ListenersPersistence.php +++ b/src/Persistence/WebSockets/ListenersPersistence.php @@ -1,14 +1,15 @@ migrateListenerPersistence($fresh); + /** @throws Exception */ + (new DatabaseBootstrap($this->databaseOptions))->migrateListenerPersistence($fresh); if (!$fresh) { return $this; diff --git a/src/SocketHandlers/SocketMessageRouter.php b/src/SocketHandlers/SocketMessageRouter.php index e330156..4a3b1d8 100644 --- a/src/SocketHandlers/SocketMessageRouter.php +++ b/src/SocketHandlers/SocketMessageRouter.php @@ -8,10 +8,10 @@ use Conveyor\Actions\Traits\HasPersistence; use Conveyor\Exceptions\InvalidActionException; use Conveyor\Helpers\Arr; -use Conveyor\Models\Interfaces\GenericPersistenceInterface; -use Conveyor\Models\Sqlite\WebSockets\AssociationsPersistence; -use Conveyor\Models\Sqlite\WebSockets\ChannelsPersistence; -use Conveyor\Models\Sqlite\WebSockets\ListenersPersistence; +use Conveyor\Persistence\Interfaces\GenericPersistenceInterface; +use Conveyor\Persistence\WebSockets\AssociationsPersistence; +use Conveyor\Persistence\WebSockets\ChannelsPersistence; +use Conveyor\Persistence\WebSockets\ListenersPersistence; use Conveyor\SocketHandlers\Interfaces\ExceptionHandlerInterface; use Conveyor\SocketHandlers\Interfaces\SocketHandlerInterface; use Exception; @@ -26,7 +26,7 @@ class SocketMessageRouter implements SocketHandlerInterface protected mixed $server = null; protected ?int $fd = null; protected mixed $parsedData; - protected ActionManager $actionManager; + protected ?ActionManager $actionManager = null; /** * @param null|array|GenericPersistenceInterface $persistence @@ -34,33 +34,30 @@ class SocketMessageRouter implements SocketHandlerInterface * @throws Exception */ public function __construct( - null|array|GenericPersistenceInterface $persistence = null, - array $actions = [], protected bool $fresh = false, - ) { - $this->preparePersistence($persistence); + ) {} + + public static function init(bool $fresh = false): static + { + return new self($fresh); + } + + public function actions(array $actions = [], bool $fresh = false) + { $this->actionManager = ActionManager::make($actions, $fresh); + return $this; } /** * @param string $data * @param int $fd * @param mixed $server - * @param array $options Constructor options: $persistence, $actions, $fresh * @return mixed * @throws Exception */ - public static function run( - string $data, - int $fd, - mixed $server, - array $options = [], - ) { - return (new self( - persistence: $options['persistence'] ?? null, - actions: $options['actions'] ?? [], - fresh: $options['fresh'] ?? false, - ))( + public function run(string $data, int $fd, mixed $server): mixed + { + return $this( data: $data, fd: $fd, server: $server, @@ -79,15 +76,16 @@ public static function run( public static function refresh( null|array|GenericPersistenceInterface $persistence = null, ): static { - return new self(persistence: $persistence, fresh: true); + return self::init(true) + ->persistence($persistence); } /** * @param array|GenericPersistenceInterface|null $persistence * - * @return void + * @return self */ - private function preparePersistence(null|array|GenericPersistenceInterface $persistence) + public function persistence(null|array|GenericPersistenceInterface $persistence): self { if (null === $persistence) { $persistence = [ @@ -99,20 +97,24 @@ private function preparePersistence(null|array|GenericPersistenceInterface $pers if (!is_array($persistence)) { $this->setPersistence($persistence); - return; + return $this; } foreach ($persistence as $item) { $this->setPersistence($item); } + + return $this; } /** * @param string $data Data to be processed. * @param int $fd Sender's File descriptor (connection). * @param mixed $server Server object, e.g. Swoole\WebSocket\Frame. + * @return mixed + * @throws Exception */ - public function __invoke(string $data, int $fd, mixed $server) + public function __invoke(string $data, int $fd, mixed $server): mixed { return $this->handle($data, $fd, $server); } @@ -173,7 +175,7 @@ final public function validateData(?array $data): void throw new InvalidArgumentException('Missing action key in data!'); } - if (!$this->actionManager->hasAction($data['action'])) { + if (!$this->getActionManager()->hasAction($data['action'])) { throw new InvalidActionException( 'Invalid Action! This action (' . $data['action'] . ') is not set.' ); @@ -184,10 +186,10 @@ final public function validateData(?array $data): void * @param string $data Data to be processed. * @param int $fd Sender's File descriptor (connection). * @param mixed $server Server object, e.g. \OpenSwoole\WebSocket\Frame. - * + * @return mixed * @throws Exception */ - public function handle(string $data, int $fd, mixed $server) + public function handle(string $data, int $fd, mixed $server): mixed { $this->fd = $fd; $this->server = $server; @@ -196,11 +198,11 @@ public function handle(string $data, int $fd, mixed $server) $action = $this->parseData($data); $action->setFd($fd); $action->setServer($server); + $this->registerActionPersistence($action); /** @var Pipeline */ - $pipeline = $this->actionManager->getPipeline($action->getName()); + $pipeline = $this->getActionManager()->getPipeline($action->getName()); - $this->registerActionPersistence($action); $this->closeConnections(); try { @@ -236,7 +238,7 @@ public function parseData(string $data): ActionInterface // @throws InvalidArgumentException|InvalidActionException $this->validateData($this->parsedData); - return $this->actionManager->getAction($this->parsedData['action']); + return $this->getActionManager()->getAction($this->parsedData['action']); } /** @@ -289,15 +291,15 @@ public function getFd(): int private function registerActionPersistence(ActionInterface $action): void { if (null !== $this->channelPersistence) { - $this->actionManager->setActionPersistence($action, $this->channelPersistence); + $this->getActionManager()->setActionPersistence($action, $this->channelPersistence); } if (null !== $this->userAssocPersistence) { - $this->actionManager->setActionPersistence($action, $this->userAssocPersistence); + $this->getActionManager()->setActionPersistence($action, $this->userAssocPersistence); } if (null !== $this->listenerPersistence) { - $this->actionManager->setActionPersistence($action, $this->listenerPersistence); + $this->getActionManager()->setActionPersistence($action, $this->listenerPersistence); } } @@ -311,6 +313,10 @@ public function getServer(): mixed public function getActionManager(): ActionManager { + if (null === $this->actionManager) { + $this->actions(); + } + return $this->actionManager; } } diff --git a/tests/Assets/.gitignore b/tests/Assets/.gitignore new file mode 100644 index 0000000..13afefc --- /dev/null +++ b/tests/Assets/.gitignore @@ -0,0 +1 @@ +temp-database.sqlite diff --git a/tests/Assets/SampleChannelPersistence.php b/tests/Assets/SampleChannelPersistence.php deleted file mode 100644 index 8d9175c..0000000 --- a/tests/Assets/SampleChannelPersistence.php +++ /dev/null @@ -1,40 +0,0 @@ -data[$fd] = $channel; - } - - public function disconnect(int $fd): void - { - unset($this->data[$fd]); - } - - public function getAllConnections(): array - { - return $this->data; - } - - public function refresh(bool $fresh = false): static - { - if ($fresh) { - $this->data = []; - } - return $this; - } - - public function getChannel(int $fd): ?string - { - return $this->data[$fd] ?? null; - } -} diff --git a/tests/Assets/SampleListenerPersistence.php b/tests/Assets/SampleListenerPersistence.php deleted file mode 100644 index 1362cd1..0000000 --- a/tests/Assets/SampleListenerPersistence.php +++ /dev/null @@ -1,55 +0,0 @@ -listeners, $fd); - } - - public function listen(int $fd, string $action): void - { - if (!isset($this->listeners[$fd])) { - $this->listeners[$fd] = []; - } - - $this->listeners[$fd][] = $action; - } - - public function getAllListeners(): array - { - return $this->listeners; - } - - public function stopListener(int $fd, string $action): bool - { - $this->listeners[$fd] = array_filter($this->listeners[$fd], function($item) use ($action) { - return $item !== $action; - }); - return true; - } - - public function stopListenersForFd(int $fd): bool - { - unset($this->listeners[$fd]); - return true; - } - - public function refresh(bool $fresh = false): static - { - if ($fresh) { - $this->listeners = []; - } - - return $this; - } -} - diff --git a/tests/Assets/SamplePersistence.php b/tests/Assets/SamplePersistence.php index f4761ca..bb86e66 100644 --- a/tests/Assets/SamplePersistence.php +++ b/tests/Assets/SamplePersistence.php @@ -2,7 +2,7 @@ namespace Tests\Assets; -use Conveyor\Models\Interfaces\ChannelPersistenceInterface; +use Conveyor\Persistence\Interfaces\ChannelPersistenceInterface; class SamplePersistence implements ChannelPersistenceInterface { diff --git a/tests/Assets/SampleUserAssocPersistence.php b/tests/Assets/SampleUserAssocPersistence.php deleted file mode 100644 index 7cc85b1..0000000 --- a/tests/Assets/SampleUserAssocPersistence.php +++ /dev/null @@ -1,43 +0,0 @@ -associations[$fd] = $userId; - } - - public function disassoc(int $fd): void - { - unset($this->associations[$fd]); - } - - public function getAssoc(int $fd): ?int - { - if (!isset($this->associations[$fd])) { - return null; - } - - return $this->associations[$fd]; - } - - public function getAllAssocs(): array - { - return $this->associations; - } - - public function refresh(bool $fresh = false): static - { - if ($fresh) { - $this->associations = []; - } - - return $this; - } -} diff --git a/tests/SocketChannelPersistenceTest.php b/tests/SocketChannelPersistenceTest.php index dd3e2cf..f3eb24a 100644 --- a/tests/SocketChannelPersistenceTest.php +++ b/tests/SocketChannelPersistenceTest.php @@ -2,8 +2,7 @@ namespace Tests; -use Conveyor\Models\Sqlite\WebSockets\ChannelsPersistence; -use PHPUnit\Framework\TestCase; +use Conveyor\Persistence\WebSockets\ChannelsPersistence; class SocketChannelPersistenceTest extends TestCase { @@ -14,7 +13,7 @@ class SocketChannelPersistenceTest extends TestCase */ public function freeMemory() { - $this->data = new ChannelsPersistence; + $this->data = new ChannelsPersistence($this->getDatabaseOptions()); } private function connectToChannel(int $fd, string $channel) diff --git a/tests/SocketHandlerTestCase.php b/tests/SocketHandlerTestCase.php index ad7750d..a847dad 100644 --- a/tests/SocketHandlerTestCase.php +++ b/tests/SocketHandlerTestCase.php @@ -5,9 +5,11 @@ use Conveyor\Actions\ActionManager; use Conveyor\Actions\AddListenerAction; use Conveyor\Actions\ChannelConnectAction; -use Conveyor\Models\Interfaces\GenericPersistenceInterface; +use Conveyor\Persistence\Interfaces\GenericPersistenceInterface; +use Conveyor\Persistence\WebSockets\AssociationsPersistence; +use Conveyor\Persistence\WebSockets\ChannelsPersistence; +use Conveyor\Persistence\WebSockets\ListenersPersistence; use Conveyor\SocketHandlers\SocketMessageRouter; -use PHPUnit\Framework\TestCase; use Tests\Assets\SampleChannelPersistence; use Tests\Assets\SampleListenerPersistence; use Tests\Assets\SampleReturnAction; @@ -20,9 +22,9 @@ class SocketHandlerTestCase extends TestCase { public array $userKeys = []; - public SampleChannelPersistence $channelPersistence; - public SampleListenerPersistence $listenerPersistence; - public SampleUserAssocPersistence $userAssocPersistence; + public ChannelsPersistence $channelPersistence; + public ListenersPersistence $listenerPersistence; + public AssociationsPersistence $userAssocPersistence; public SocketMessageRouter $router; public SampleSocketServer $server; @@ -34,14 +36,14 @@ class SocketHandlerTestCase extends TestCase */ public function setUpRouter() { - $this->channelPersistence = new SampleChannelPersistence; - $this->listenerPersistence = new SampleListenerPersistence; - $this->userAssocPersistence = new SampleUserAssocPersistence; + $this->channelPersistence = new ChannelsPersistence($this->getDatabaseOptions()); + $this->listenerPersistence = new ListenersPersistence($this->getDatabaseOptions()); + $this->userAssocPersistence = new AssociationsPersistence($this->getDatabaseOptions()); $this->router = $this->prepareSocketMessageRouter([ - 'channel' => $this->channelPersistence, - 'listen' => $this->listenerPersistence, - 'userAssoc' => $this->userAssocPersistence, + $this->channelPersistence, + $this->listenerPersistence, + $this->userAssocPersistence, ]); } @@ -56,7 +58,8 @@ public function setUpServer() protected function prepareSocketMessageRouter(null|array|GenericPersistenceInterface $persistence = null): SocketMessageRouter { - $socketRouter = new SocketMessageRouter($persistence); + $socketRouter = new SocketMessageRouter(); + $socketRouter->persistence($persistence); $actionManager = $socketRouter->getActionManager(); $resultOfAddMethod = $actionManager->add(new ChannelConnectAction); diff --git a/tests/SocketListenerPersistenceTest.php b/tests/SocketListenerPersistenceTest.php index c84ecfe..613d1db 100644 --- a/tests/SocketListenerPersistenceTest.php +++ b/tests/SocketListenerPersistenceTest.php @@ -2,8 +2,7 @@ namespace Tests; -use Conveyor\Models\Sqlite\WebSockets\ListenersPersistence; -use PHPUnit\Framework\TestCase; +use Conveyor\Persistence\WebSockets\ListenersPersistence; use Tests\Assets\SampleAction; class SocketListenerPersistenceTest extends TestCase @@ -15,7 +14,7 @@ class SocketListenerPersistenceTest extends TestCase */ public function freeMemory() { - $this->data = new ListenersPersistence; + $this->data = new ListenersPersistence($this->getDatabaseOptions()); $this->data->refresh(true); } diff --git a/tests/SocketListenerTest.php b/tests/SocketListenerTest.php index 0a654ab..bc66c52 100644 --- a/tests/SocketListenerTest.php +++ b/tests/SocketListenerTest.php @@ -4,6 +4,9 @@ use Conveyor\Actions\BroadcastAction; use Conveyor\Actions\FanoutAction; +use Conveyor\Persistence\WebSockets\AssociationsPersistence; +use Conveyor\Persistence\WebSockets\ChannelsPersistence; +use Conveyor\Persistence\WebSockets\ListenersPersistence; use Tests\Assets\SecondaryBroadcastAction; use Tests\Assets\SecondaryFanoutAction; @@ -81,9 +84,9 @@ public function testCanFanoutToListenersCrossRequests() $this->assertCount(2, $this->userKeys); $this->router = $this->prepareSocketMessageRouter([ - 'channel' => $this->channelPersistence, - 'listen' => $this->listenerPersistence, - 'userAssoc' => $this->userAssocPersistence, + new ChannelsPersistence($this->getDatabaseOptions()), + new ListenersPersistence($this->getDatabaseOptions()), + new AssociationsPersistence($this->getDatabaseOptions()), ]); $this->userKeys = []; @@ -94,6 +97,6 @@ public function testCanFanoutToListenersCrossRequests() 'data' => $message, ])); - $this->assertCount(1, $this->userKeys); + $this->assertCount(3, $this->userKeys); } } diff --git a/tests/SocketMessageRouterTest.php b/tests/SocketMessageRouterTest.php index 01c3573..0bf2e67 100644 --- a/tests/SocketMessageRouterTest.php +++ b/tests/SocketMessageRouterTest.php @@ -4,7 +4,9 @@ use Conveyor\Actions\BroadcastAction; use Conveyor\Actions\ChannelConnectAction; -use Conveyor\Models\Sqlite\WebSockets\ChannelsPersistence; +use Conveyor\Persistence\WebSockets\AssociationsPersistence; +use Conveyor\Persistence\WebSockets\ChannelsPersistence; +use Conveyor\Persistence\WebSockets\ListenersPersistence; use Conveyor\SocketHandlers\SocketMessageRouter; use Exception; use Tests\Assets\NotValidMiddleware; @@ -128,11 +130,15 @@ public function testCanAddMiddlewareToPipelineOfHandlerAndExecute() $this->assertCount(1, $this->userKeys); } - public function testCantAddActionAlreadyAddedThroughConstructor() + public function testCantAddActionAlreadyAdded() { $this->expectException(Exception::class); - new SocketMessageRouter(null, [ + (new SocketMessageRouter)->persistence([ + new ChannelsPersistence($this->getDatabaseOptions()), + new ListenersPersistence($this->getDatabaseOptions()), + new AssociationsPersistence($this->getDatabaseOptions()), + ])->actions([ [SampleAction::class, new SampleMiddleware], [SampleAction::class, function(){}], ]); @@ -140,15 +146,21 @@ public function testCantAddActionAlreadyAddedThroughConstructor() public function testCanAddMiddlewareThroughConstructor() { - $socketRouter = new SocketMessageRouter(null, [ - [ - SampleAction::class, - function ($p) { - $this->userKeys[$p->getFd()] = $p->getParsedData('action'); - return $p; - }, - ], - ]); + $socketRouter = (new SocketMessageRouter) + ->persistence([ + new ChannelsPersistence($this->getDatabaseOptions()), + new ListenersPersistence($this->getDatabaseOptions()), + new AssociationsPersistence($this->getDatabaseOptions()), + ]) + ->actions([ + [ + SampleAction::class, + function ($p) { + $this->userKeys[$p->getFd()] = $p->getParsedData('action'); + return $p; + }, + ], + ]); $data = json_encode([ 'action' => SampleAction::ACTION_NAME, @@ -163,7 +175,11 @@ public function testCantAddInvalidMiddlewareThroughConstructor() { $this->expectException(TypeError::class); - new SocketMessageRouter(null, [ + new SocketMessageRouter([ + new ChannelsPersistence($this->getDatabaseOptions()), + new ListenersPersistence($this->getDatabaseOptions()), + new AssociationsPersistence($this->getDatabaseOptions()), + ], [ [SampleAction::class, new NotValidMiddleware] ]); } @@ -266,14 +282,25 @@ public function testCantSendPlainText() public function testCanCallStaticMethod() { - SocketMessageRouter::run('some message', 1, $this->server); + SocketMessageRouter::init() + ->persistence([ + new ChannelsPersistence($this->getDatabaseOptions()), + new ListenersPersistence($this->getDatabaseOptions()), + new AssociationsPersistence($this->getDatabaseOptions()), + ]) + ->run( + data: 'some message', + fd: 1, + server: $this->server, + ); $this->assertCount(1, $this->userKeys); } public function testCanCallRefreshPersistence() { - $channelPersistence = new ChannelsPersistence; - $conveyor = new SocketMessageRouter($channelPersistence); + $channelPersistence = new ChannelsPersistence($this->getDatabaseOptions()); + $conveyor = new SocketMessageRouter(); + $conveyor->persistence($channelPersistence); ($conveyor)(json_encode([ 'action' => ChannelConnectAction::ACTION_NAME, diff --git a/tests/SocketUserAssocPersistenceTest.php b/tests/SocketUserAssocPersistenceTest.php index 3e716d4..897cc16 100644 --- a/tests/SocketUserAssocPersistenceTest.php +++ b/tests/SocketUserAssocPersistenceTest.php @@ -2,8 +2,7 @@ namespace Tests; -use Conveyor\Models\Sqlite\WebSockets\AssociationsPersistence; -use PHPUnit\Framework\TestCase; +use Conveyor\Persistence\WebSockets\AssociationsPersistence; class SocketUserAssocPersistenceTest extends TestCase { @@ -14,7 +13,7 @@ class SocketUserAssocPersistenceTest extends TestCase */ public function freeMemory() { - $this->data = new AssociationsPersistence; + $this->data = new AssociationsPersistence($this->getDatabaseOptions()); $this->data->refresh(true); } diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..a151a62 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,17 @@ + 'sqlite', + 'database' => __DIR__ . '/Assets/temp-database.sqlite', + ]); + } +}