From 264ea3de74bbe3faec3361c58d446e462360a922 Mon Sep 17 00:00:00 2001 From: GitHub Date: Thu, 29 Aug 2024 08:18:44 +0000 Subject: [PATCH] Refactored async await in discovery (#309) --- src/Clients/Discovery.php | 68 +++++++++++++++++--- src/Translations/viera-connector.en_us.neon | 2 + src/ValueObjects/LocalDevice.php | 70 +++++++++++++++++++++ 3 files changed, 131 insertions(+), 9 deletions(-) create mode 100644 src/ValueObjects/LocalDevice.php diff --git a/src/Clients/Discovery.php b/src/Clients/Discovery.php index f81cdb5..5a53442 100644 --- a/src/Clients/Discovery.php +++ b/src/Clients/Discovery.php @@ -23,10 +23,12 @@ use FastyBird\Connector\Viera\Helpers; use FastyBird\Connector\Viera\Queue; use FastyBird\Connector\Viera\Services; +use FastyBird\Connector\Viera\ValueObjects; use FastyBird\Library\Application\Helpers as ApplicationHelpers; use FastyBird\Library\Metadata\Types as MetadataTypes; use FastyBird\Module\Devices\Events as DevicesEvents; use Nette; +use Orisai\ObjectMapper; use Psr\EventDispatcher as PsrEventDispatcher; use React\Datagram; use React\EventLoop; @@ -39,6 +41,7 @@ use function preg_match; use function React\Async\async; use function React\Async\await; +use function serialize; use function sprintf; use function strval; use function trim; @@ -62,10 +65,18 @@ final class Discovery private const SEARCH_TIMEOUT = 5; + private const PROCESS_RESULTS_TIMER = 0.1; + private const MATCH_DEVICE_LOCATION = '/LOCATION:\s(?[\da-zA-Z:\/.]+)/'; private const MATCH_DEVICE_ID = '/USN:\suuid:(?[\da-zA-Z-]+)::urn/'; + /** @var array */ + private array $searchResult = []; + + /** @var array */ + private array $processedItems = []; + private EventLoop\TimerInterface|null $handlerTimer = null; private Datagram\SocketInterface|null $sender = null; @@ -78,6 +89,7 @@ public function __construct( private readonly Viera\Logger $logger, private readonly Services\MulticastFactory $multicastFactory, private readonly EventLoop\LoopInterface $eventLoop, + private readonly ObjectMapper\Processing\Processor $objectMapper, private readonly PsrEventDispatcher\EventDispatcherInterface|null $dispatcher = null, ) { @@ -112,7 +124,7 @@ public function discover(): void return; } - $this->sender->on('message', async(function (string $data): void { + $this->sender->on('message', function (string $data): void { if (preg_match(self::MATCH_DEVICE_LOCATION, $data, $matches) === 1) { $urlParts = parse_url($matches['location']); @@ -121,17 +133,55 @@ public function discover(): void && array_key_exists('host', $urlParts) && preg_match(self::MATCH_DEVICE_ID, $data, $matches) === 1 ) { + try { + $searchResult = $this->objectMapper->process( + [ + 'id' => $matches['usn'], + 'host' => $urlParts['host'], + 'port' => array_key_exists( + 'port', + $urlParts, + ) ? $urlParts['port'] : Entities\Devices\Device::DEFAULT_PORT, + ], + ValueObjects\LocalDevice::class, + ); + + if (!array_key_exists(serialize($searchResult), $this->searchResult)) { + $this->searchResult[serialize($searchResult)] = $searchResult; + } + } catch (Throwable $ex) { + $this->logger->error( + 'Received data could not be transformed to message', + [ + 'source' => MetadataTypes\Sources\Connector::VIERA->value, + 'type' => 'discovery-client', + 'exception' => ApplicationHelpers\Logger::buildException($ex), + ], + ); + } + } + } + }); + + // Processing handler + $this->eventLoop->addPeriodicTimer( + self::PROCESS_RESULTS_TIMER, + async(function (): void { + foreach ($this->searchResult as $item) { + if (array_key_exists(serialize($item), $this->processedItems)) { + continue; + } + + $this->processedItems[serialize($item)] = $item; + $this->handleDiscoveredDevice( - $matches['usn'], - $urlParts['host'], - array_key_exists( - 'port', - $urlParts, - ) ? $urlParts['port'] : Entities\Devices\Device::DEFAULT_PORT, + $item->getId(), + $item->getHost(), + $item->getPort(), ); } - } - })); + }), + ); // Searching timeout $this->handlerTimer = $this->eventLoop->addTimer( diff --git a/src/Translations/viera-connector.en_us.neon b/src/Translations/viera-connector.en_us.neon index bb5400f..7eb8bbf 100644 --- a/src/Translations/viera-connector.en_us.neon +++ b/src/Translations/viera-connector.en_us.neon @@ -144,6 +144,7 @@ cmd: hdmi: "Would you like to configure HDMI inputs?" nextHdmi: "Would you like to configure another HDMI inputs?" macAddress: "Would you like to configure television MAC address?" + pairDevice: "Would you like to pair this televisions?" data: id: "ID" @@ -202,6 +203,7 @@ cmd: foundDevices: "Found %d new televisions" noDevicesFound: "No televisions were found" missingIpAddress: "Something went wrong television: \"%device%\" has not defined its ip address." + foundEncryptedDevices: "Some televisions require to by paired to get encryption keys." pairing: started: "Pairing television: \"%device%\"." finished: "Television: \"%device%\" was successfully paired." diff --git a/src/ValueObjects/LocalDevice.php b/src/ValueObjects/LocalDevice.php new file mode 100644 index 0000000..aa4fb76 --- /dev/null +++ b/src/ValueObjects/LocalDevice.php @@ -0,0 +1,70 @@ + + * @package FastyBird:VieraConnector! + * @subpackage ValueObjects + * @since 1.0.0 + * + * @date 29.08.24 + */ + +namespace FastyBird\Connector\Viera\ValueObjects; + +use Orisai\ObjectMapper; +use function strtolower; + +/** + * Local device info + * + * @package FastyBird:VieraConnector! + * @subpackage ValueObjects + * + * @author Adam Kadlec + */ +final readonly class LocalDevice implements ObjectMapper\MappedObject +{ + + public function __construct( + #[ObjectMapper\Rules\StringValue(notEmpty: true)] + private string $id, + #[ObjectMapper\Rules\StringValue(notEmpty: true)] + private string $host, + #[ObjectMapper\Rules\IntValue(castNumericString: true)] + private int $port, + ) + { + } + + public function getId(): string + { + return $this->id; + } + + public function getHost(): string + { + return $this->host; + } + + public function getPort(): int + { + return $this->port; + } + + /** + * @return array + */ + public function __serialize(): array + { + return [ + 'id' => $this->getId(), + 'host' => strtolower($this->getHost()), + 'port' => $this->getPort(), + ]; + } + +}