From ca2238c9b5c772cd1b246fbb015811953c56ce2a Mon Sep 17 00:00:00 2001 From: Namoshek Date: Sun, 15 Sep 2019 21:41:06 +0200 Subject: [PATCH] add connection manager and facade with implementation --- composer.json | 7 +- config/mqtt-client.php | 53 +++++- src/ConnectionManager.php | 160 ++++++++++++++++++ .../ConnectionNotAvailableException.php | 18 ++ src/Facades/MQTT.php | 30 ++++ src/MqttClientServiceProvider.php | 50 +++--- 6 files changed, 285 insertions(+), 33 deletions(-) create mode 100644 src/ConnectionManager.php create mode 100644 src/Exceptions/ConnectionNotAvailableException.php create mode 100644 src/Facades/MQTT.php diff --git a/composer.json b/composer.json index 7867dee..3c61fb2 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,10 @@ "laravel": { "providers": [ "PhpMqtt\\Client\\MqttClientServiceProvider" - ] + ], + "aliases": { + "MQTT": "PhpMqtt\\Client\\Facades\\MQTT" + } } } -} \ No newline at end of file +} diff --git a/config/mqtt-client.php b/config/mqtt-client.php index 0dae23d..f42bb37 100644 --- a/config/mqtt-client.php +++ b/config/mqtt-client.php @@ -2,4 +2,55 @@ declare(strict_types=1); -return []; +use PhpMqtt\Client\Repositories\MemoryRepository; + +return [ + + /* + |-------------------------------------------------------------------------- + | Default MQTT Connection + |-------------------------------------------------------------------------- + | + | This setting defines the default MQTT connection returned when requesting + | a connection without name from the facade. + | + */ + + 'default_connection' => 'default', + + /* + |-------------------------------------------------------------------------- + | MQTT Connections + |-------------------------------------------------------------------------- + | + | These are the MQTT connections used by the application. You can also open + | an individual connection from the application itself, but all connections + | defined here can be accessed via name conveniently. + | + */ + + 'connections' => [ + 'default' => [ + 'host' => env('MQTT_HOST'), + 'port' => env('MQTT_PORT', 1883), + 'username' => env('MQTT_USERNAME'), + 'password' => env('MQTT_PASSWORD'), + 'client_id' => env('MQTT_CLIENT_ID'), + 'cafile' => env('MQTT_CAFILE'), + 'clean_session' => env('MQTT_CLEAN_SESSION', true), + 'logging_enabled' => env('MQTT_LOGGING', true), + 'repository' => MemoryRepository::class, + 'settings' => [ + 'quality_of_service' => env('MQTT_QUALITY_OF_SERVICE', 0), + 'block_socket' => env('MQTT_BLOCK_SOCKET', false), + 'keep_alive' => env('MQTT_KEEP_ALIVE', 10), + 'socket_timeout' => env('MQTT_TIMEOUT', 5), + 'resend_timeout' => env('MQTT_RESEND_TIMEOUT', 10), + 'retain' => env('MQTT_RETAIN', false), + 'last_will_topic' => env('MQTT_WILL_TOPIC'), + 'last_will_message' => env('MQTT_WILL_MESSAGE'), + ], + ], + ], + +]; diff --git a/src/ConnectionManager.php b/src/ConnectionManager.php new file mode 100644 index 0000000..a16d94c --- /dev/null +++ b/src/ConnectionManager.php @@ -0,0 +1,160 @@ +application = $application; + $this->config = $config; + $this->defaultConnection = array_get($config, 'default_connection', 'default'); + } + + /** + * Gets the connection with the specified name. + * + * @param string|null $name + * @return MQTTClient + * @throws BindingResolutionException + * @throws ConnectingToBrokerFailedException + * @throws ConnectionNotAvailableException + */ + public function connection(string $name = null): MQTTClient + { + if ($name === null) { + $name = $this->defaultConnection; + } + + if (!array_key_exists($name, $this->connections)) { + $this->connections[$name] = $this->createConnection($name); + } + + return $this->connections[$name]; + } + + /** + * Closes the given connection if opened. + * + * @param string|null $connection + * @throws DataTransferException + */ + public function close(string $connection = null): void + { + if ($connection === null) { + $connection = $this->defaultConnection; + } + + if (array_key_exists($connection, $this->connections)) { + $this->connections[$connection]->close(); + unset($this->connections[$connection]); + } + } + + /** + * Publishes a message on the given connection. The QoS level will be 0 + * and the message will not be retained by the broker. + * + * @param string $topic + * @param string $message + * @param string|null $connection + * @throws BindingResolutionException + * @throws ConnectingToBrokerFailedException + * @throws ConnectionNotAvailableException + * @throws DataTransferException + */ + public function publish(string $topic, string $message, string $connection = null): void + { + $client = $this->connection($connection); + + $client->publish($topic, $message); + } + + /** + * Creates a new MQTT client and connects to the specified server. + * + * @param string $name + * @return MQTTClient + * @throws BindingResolutionException + * @throws ConnectingToBrokerFailedException + * @throws ConnectionNotAvailableException + */ + protected function createConnection(string $name): MQTTClient + { + $config = array_get($this->config, "connections.{$name}"); + if ($config === null) { + throw new ConnectionNotAvailableException($name); + } + + $host = array_get($config, 'host'); + $port = array_get($config, 'port', 1883); + $username = array_get($config, 'username'); + $password = array_get($config, 'password'); + $clientId = array_get($config, 'client_id'); + $caFile = array_get($config, 'cafile'); + $cleanSession = array_get($config, 'clean_session', true); + $loggingEnabled = array_get($config, 'logging_enabled', true); + $repository = array_get($config, 'repository', Repository::class); + + $settings = $this->parseConnectionSettings(array_get($config, 'settings', [])); + $repository = $this->application->make($repository); + $logger = $loggingEnabled ? $this->application->make('log') : null; + + $client = new MQTTClient($host, $port, $clientId, $caFile, $repository, $logger); + $client->connect($username, $password, $settings, $cleanSession); + + return $client; + } + + /** + * Parses the given settings and returns a populated settings object. + * + * @param array $settings + * @return ConnectionSettings + */ + protected function parseConnectionSettings(array $settings): ConnectionSettings + { + $qos = array_get($settings, 'quality_of_service', 0); + $blockSocket = array_get($settings, 'block_socket', false); + $keepAlive = array_get($settings, 'keep_alive', 10); + $socketTimeout = array_get($settings, 'socket_timeout', 5); + $resendTimeout = array_get($settings, 'resend_timeout', 10); + $retain = array_get($settings, 'retain', false); + $lastWillTopic = array_get($settings, 'last_will_topic'); + $lastWillMessage = array_get($settings, 'last_will_message'); + + return new ConnectionSettings($qos, $retain, $blockSocket, $socketTimeout, $keepAlive, $resendTimeout, $lastWillTopic, $lastWillMessage); + } +} diff --git a/src/Exceptions/ConnectionNotAvailableException.php b/src/Exceptions/ConnectionNotAvailableException.php new file mode 100644 index 0000000..087df7e --- /dev/null +++ b/src/Exceptions/ConnectionNotAvailableException.php @@ -0,0 +1,18 @@ +handleConfigs(); - } - /** * Register the service provider. * @@ -35,17 +19,8 @@ class MqttClientServiceProvider extends ServiceProvider */ public function register(): void { - // Bind any implementations. - } - - /** - * Get the services provided by the provider. - * - * @return array - */ - public function provides(): array - { - return []; + $this->registerConfig(); + $this->registerServices(); } /** @@ -53,12 +28,27 @@ class MqttClientServiceProvider extends ServiceProvider * * @return void */ - protected function handleConfigs(): void + protected function registerConfig(): void { $configPath = __DIR__ . '/../config/mqtt-client.php'; - $this->publishes([$configPath => config_path('mqtt-client.php')], 'config'); + if ($this->app->runningInConsole()) { + $this->publishes([$configPath => config_path('mqtt-client.php')], 'config'); + } $this->mergeConfigFrom($configPath, 'mqtt-client'); } + + /** + * Registers the services offered by this package. + * + * @return void + */ + protected function registerServices(): void + { + $this->app->bind(ConnectionManager::class, function (Application $app) { + $config = $app->make('config')->get('mqtt-client', []); + return new ConnectionManager($app, $config); + }); + } }