From 059384ef2b09576e379843736259872cda088f58 Mon Sep 17 00:00:00 2001 From: Steve Hamblett Date: Thu, 4 Jul 2024 11:05:55 +0100 Subject: [PATCH 1/6] Issue 523 --- .../mqtt_client_imqtt_connection_handler.dart | 3 +++ .../mqtt_client_mqtt_connection_handler_base.dart | 4 ++++ ...nt_synchronous_mqtt_server_connection_handler.dart | 3 +++ lib/src/mqtt_client.dart | 11 +++++++++++ 4 files changed, 21 insertions(+) diff --git a/lib/src/connectionhandling/mqtt_client_imqtt_connection_handler.dart b/lib/src/connectionhandling/mqtt_client_imqtt_connection_handler.dart index 9e663c9..5ddec5e 100644 --- a/lib/src/connectionhandling/mqtt_client_imqtt_connection_handler.dart +++ b/lib/src/connectionhandling/mqtt_client_imqtt_connection_handler.dart @@ -27,6 +27,9 @@ abstract class IMqttConnectionHandler { /// Auto reconnected callback AutoReconnectCompleteCallback? onAutoReconnected; + /// Failed connection attempt callback + FailedConnectionAttemptCallback? onFailedConnectionAttempt; + /// Auto reconnect in progress bool autoReconnectInProgress = false; diff --git a/lib/src/connectionhandling/mqtt_client_mqtt_connection_handler_base.dart b/lib/src/connectionhandling/mqtt_client_mqtt_connection_handler_base.dart index b710d67..fde412a 100644 --- a/lib/src/connectionhandling/mqtt_client_mqtt_connection_handler_base.dart +++ b/lib/src/connectionhandling/mqtt_client_mqtt_connection_handler_base.dart @@ -30,6 +30,10 @@ abstract class MqttConnectionHandlerBase implements IMqttConnectionHandler { @override AutoReconnectCompleteCallback? onAutoReconnected; + /// Failed connection attempt callback + @override + FailedConnectionAttemptCallback? onFailedConnectionAttempt; + /// Auto reconnect in progress @override bool autoReconnectInProgress = false; diff --git a/lib/src/connectionhandling/server/mqtt_client_synchronous_mqtt_server_connection_handler.dart b/lib/src/connectionhandling/server/mqtt_client_synchronous_mqtt_server_connection_handler.dart index 306dc3a..698bd21 100644 --- a/lib/src/connectionhandling/server/mqtt_client_synchronous_mqtt_server_connection_handler.dart +++ b/lib/src/connectionhandling/server/mqtt_client_synchronous_mqtt_server_connection_handler.dart @@ -118,6 +118,9 @@ class SynchronousMqttServerConnectionHandler if (!autoReconnectInProgress) { MqttLogger.log( 'SynchronousMqttServerConnectionHandler::internalConnect failed'); + if (onFailedConnectionAttempt != null) { + onFailedConnectionAttempt!(connectionAttempts); + } if (connectionStatus.returnCode == MqttConnectReturnCode.noneSpecified) { throw NoConnectionException('The maximum allowed connection attempts ' diff --git a/lib/src/mqtt_client.dart b/lib/src/mqtt_client.dart index a4becca..d67f9ee 100755 --- a/lib/src/mqtt_client.dart +++ b/lib/src/mqtt_client.dart @@ -19,6 +19,9 @@ typedef AutoReconnectCallback = void Function(); /// The client auto reconnect complete callback type typedef AutoReconnectCompleteCallback = void Function(); +/// The client failed connection attempt callback +typedef FailedConnectionAttemptCallback = void Function(int attemptNumber); + /// A client class for interacting with MQTT Data Packets. /// Do not instantiate this class directly, instead instantiate /// either a [MqttClientServer] class or an [MqttBrowserClient] as needed. @@ -201,6 +204,12 @@ class MqttClient { /// perform any post auto reconnect actions. AutoReconnectCompleteCallback? onAutoReconnected; + /// Failed Connection attempt callback. + /// Called on every failed connection attempt, if [maxConnectionAttempts] is + /// set to 5 say this will be called 5 times if the connection fails, + /// one for every failed attempt. + FailedConnectionAttemptCallback? onFailedConnectionAttempt; + /// Subscribed callback, function returns a void and takes a /// string parameter, the topic that has been subscribed to. SubscribeCallback? _onSubscribed; @@ -288,6 +297,8 @@ class MqttClient { connectionHandler.onConnected = onConnected; connectionHandler.onAutoReconnect = onAutoReconnect; connectionHandler.onAutoReconnected = onAutoReconnected; + connectionHandler.onFailedConnectionAttempt = onFailedConnectionAttempt; + MqttLogger.log( 'MqttClient::connect - Connection timeout period is $connectTimeoutPeriod milliseconds'); publishingManager = PublishingManager(connectionHandler, clientEventBus); From 10a55eacb2c0db536d5b0cab117efb8c3f391925 Mon Sep 17 00:00:00 2001 From: Steve Hamblett Date: Thu, 4 Jul 2024 14:40:24 +0100 Subject: [PATCH 2/6] Issue 523 --- ...onous_mqtt_browser_connection_handler.dart | 14 +++- ...ronous_mqtt_server_connection_handler.dart | 17 +++- lib/src/mqtt_client.dart | 3 +- ...onnection_autoreconnect_nobroker_test.dart | 7 ++ .../mqtt_client_connection_unsecure_test.dart | 84 +++++++++++++++++++ 5 files changed, 119 insertions(+), 6 deletions(-) diff --git a/lib/src/connectionhandling/browser/mqtt_client_synchronous_mqtt_browser_connection_handler.dart b/lib/src/connectionhandling/browser/mqtt_client_synchronous_mqtt_browser_connection_handler.dart index 927a60c..ae9c344 100644 --- a/lib/src/connectionhandling/browser/mqtt_client_synchronous_mqtt_browser_connection_handler.dart +++ b/lib/src/connectionhandling/browser/mqtt_client_synchronous_mqtt_browser_connection_handler.dart @@ -78,11 +78,23 @@ class SynchronousMqttBrowserConnectionHandler // We're the sync connection handler so we need to wait for the // brokers acknowledgement of the connections await connectTimer.sleep(); + connectionAttempts++; MqttLogger.log( 'SynchronousMqttBrowserConnectionHandler::internalConnect - ' 'post sleep, state = $connectionStatus'); + if (connectionStatus.state != MqttConnectionState.connected) { + if (!autoReconnectInProgress) { + MqttLogger.log( + 'SynchronousMqttBrowserConnectionHandler::internalConnect failed, attempt $connectionAttempts'); + if (onFailedConnectionAttempt != null) { + MqttLogger.log( + 'SynchronousMqttBrowserConnectionHandler::calling onFailedConnectionAttempt'); + onFailedConnectionAttempt!(connectionAttempts); + } + } + } } while (connectionStatus.state != MqttConnectionState.connected && - ++connectionAttempts < maxConnectionAttempts!); + connectionAttempts < maxConnectionAttempts!); // If we've failed to handshake with the broker, throw an exception. if (connectionStatus.state != MqttConnectionState.connected) { if (!autoReconnectInProgress) { diff --git a/lib/src/connectionhandling/server/mqtt_client_synchronous_mqtt_server_connection_handler.dart b/lib/src/connectionhandling/server/mqtt_client_synchronous_mqtt_server_connection_handler.dart index 698bd21..b05d41f 100644 --- a/lib/src/connectionhandling/server/mqtt_client_synchronous_mqtt_server_connection_handler.dart +++ b/lib/src/connectionhandling/server/mqtt_client_synchronous_mqtt_server_connection_handler.dart @@ -108,19 +108,28 @@ class SynchronousMqttServerConnectionHandler // We're the sync connection handler so we need to wait for the // brokers acknowledgement of the connections await connectTimer.sleep(); + connectionAttempts++; MqttLogger.log( 'SynchronousMqttServerConnectionHandler::internalConnect - ' 'post sleep, state = $connectionStatus'); + if (connectionStatus.state != MqttConnectionState.connected) { + if (!autoReconnectInProgress) { + MqttLogger.log( + 'SynchronousMqttServerConnectionHandler::internalConnect failed, attempt $connectionAttempts'); + if (onFailedConnectionAttempt != null) { + MqttLogger.log( + 'SynchronousMqttServerConnectionHandler::calling onFailedConnectionAttempt'); + onFailedConnectionAttempt!(connectionAttempts); + } + } + } } while (connectionStatus.state != MqttConnectionState.connected && - ++connectionAttempts < maxConnectionAttempts!); + connectionAttempts < maxConnectionAttempts!); // If we've failed to handshake with the broker, throw an exception. if (connectionStatus.state != MqttConnectionState.connected) { if (!autoReconnectInProgress) { MqttLogger.log( 'SynchronousMqttServerConnectionHandler::internalConnect failed'); - if (onFailedConnectionAttempt != null) { - onFailedConnectionAttempt!(connectionAttempts); - } if (connectionStatus.returnCode == MqttConnectReturnCode.noneSpecified) { throw NoConnectionException('The maximum allowed connection attempts ' diff --git a/lib/src/mqtt_client.dart b/lib/src/mqtt_client.dart index d67f9ee..3db2d79 100755 --- a/lib/src/mqtt_client.dart +++ b/lib/src/mqtt_client.dart @@ -207,7 +207,8 @@ class MqttClient { /// Failed Connection attempt callback. /// Called on every failed connection attempt, if [maxConnectionAttempts] is /// set to 5 say this will be called 5 times if the connection fails, - /// one for every failed attempt. + /// one for every failed attempt. Note this is never called + /// if [autoReconnect] is set. FailedConnectionAttemptCallback? onFailedConnectionAttempt; /// Subscribed callback, function returns a void and takes a diff --git a/test/mqtt_client_connection_autoreconnect_nobroker_test.dart b/test/mqtt_client_connection_autoreconnect_nobroker_test.dart index 53f71f1..488a596 100644 --- a/test/mqtt_client_connection_autoreconnect_nobroker_test.dart +++ b/test/mqtt_client_connection_autoreconnect_nobroker_test.dart @@ -21,6 +21,7 @@ void main() { await IOOverrides.runZoned(() async { var autoReconnectCallbackCalled = false; var disconnectCallbackCalled = false; + var connectionFailedCallbackCalled = false; void autoReconnect() { autoReconnectCallbackCalled = true; @@ -30,6 +31,10 @@ void main() { disconnectCallbackCalled = true; } + void connectionFailed(int attempt) { + connectionFailedCallbackCalled = true; + } + final client = MqttServerClient('localhost', testClientId); client.logging(on: true); client.keepAlivePeriod = 1; @@ -38,6 +43,7 @@ void main() { client.socketOptions.add(socketOption); client.onAutoReconnect = autoReconnect; client.onDisconnected = disconnect; + client.onFailedConnectionAttempt = connectionFailed; const username = 'unused 4'; print(username); const password = 'password 4'; @@ -48,6 +54,7 @@ void main() { await MqttUtilities.asyncSleep(2); expect(autoReconnectCallbackCalled, isTrue); expect(disconnectCallbackCalled, isFalse); + expect(connectionFailedCallbackCalled, isFalse); expect(client.connectionStatus!.state == MqttConnectionState.connecting, isTrue); }, diff --git a/test/mqtt_client_connection_unsecure_test.dart b/test/mqtt_client_connection_unsecure_test.dart index 4b8a3b6..4f22d78 100644 --- a/test/mqtt_client_connection_unsecure_test.dart +++ b/test/mqtt_client_connection_unsecure_test.dart @@ -121,6 +121,90 @@ void main() { timeout: timeout)); }); + test('Connect no connect ack onFailedConnectionAttempt callback set', + () async { + await IOOverrides.runZoned(() async { + bool connectionFailed = false; + int tAttempt = 0; + final lAttempt = []; + void onFailedConnectionAttempt(int attempt) { + tAttempt++; + lAttempt.add(attempt); + connectionFailed = true; + } + + final clientEventBus = events.EventBus(); + final ch = SynchronousMqttServerConnectionHandler(clientEventBus, + maxConnectionAttempts: 3, socketOptions: socketOptions); + ch.onFailedConnectionAttempt = onFailedConnectionAttempt; + final start = DateTime.now(); + try { + await ch.connect(mockBrokerAddress, mockBrokerPort, + MqttConnectMessage().withClientIdentifier(testClientId)); + } on Exception catch (e) { + expect(e is NoConnectionException, isTrue); + } + expect(connectionFailed, isTrue); + expect(tAttempt, 3); + expect(lAttempt, [1, 2, 3]); + expect(ch.connectionStatus.state, MqttConnectionState.faulted); + expect(ch.connectionStatus.returnCode, + MqttConnectReturnCode.noneSpecified); + final end = DateTime.now(); + expect(end.difference(start).inSeconds > 4, true); + }, + socketConnect: (dynamic host, int port, + {dynamic sourceAddress, + int sourcePort = 0, + Duration? timeout}) => + MqttMockSocketSimpleConnectNoAck.connect(host, port, + sourceAddress: sourceAddress, + sourcePort: sourcePort, + timeout: timeout)); + }); + + test('Connect no connect ack onFailedConnectionAttempt callback set', + () async { + await IOOverrides.runZoned(() async { + bool connectionFailed = false; + int tAttempt = 0; + final lAttempt = []; + void onFailedConnectionAttempt(int attempt) { + tAttempt++; + lAttempt.add(attempt); + connectionFailed = true; + } + + final clientEventBus = events.EventBus(); + final ch = SynchronousMqttServerConnectionHandler(clientEventBus, + maxConnectionAttempts: 3, socketOptions: socketOptions); + ch.onFailedConnectionAttempt = onFailedConnectionAttempt; + final start = DateTime.now(); + try { + await ch.connect(mockBrokerAddress, mockBrokerPort, + MqttConnectMessage().withClientIdentifier(testClientId)); + } on Exception catch (e) { + expect(e is NoConnectionException, isTrue); + } + expect(connectionFailed, isTrue); + expect(tAttempt, 3); + expect(lAttempt, [1, 2, 3]); + expect(ch.connectionStatus.state, MqttConnectionState.faulted); + expect(ch.connectionStatus.returnCode, + MqttConnectReturnCode.noneSpecified); + final end = DateTime.now(); + expect(end.difference(start).inSeconds > 4, true); + }, + socketConnect: (dynamic host, int port, + {dynamic sourceAddress, + int sourcePort = 0, + Duration? timeout}) => + MqttMockSocketSimpleConnectNoAck.connect(host, port, + sourceAddress: sourceAddress, + sourcePort: sourcePort, + timeout: timeout)); + }); + test('1000ms connect period', () async { await IOOverrides.runZoned(() async { final clientEventBus = events.EventBus(); From 3786c0d8d178f0e00ece2bf55d4f2ef3b4be7959 Mon Sep 17 00:00:00 2001 From: Steve Hamblett Date: Fri, 5 Jul 2024 10:01:28 +0100 Subject: [PATCH 3/6] Issue 523 --- lib/src/mqtt_browser_client.dart | 6 ++++-- lib/src/mqtt_client_constants.dart | 5 ++++- lib/src/mqtt_server_client.dart | 6 ++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/src/mqtt_browser_client.dart b/lib/src/mqtt_browser_client.dart index 21346a5..a06f5c8 100644 --- a/lib/src/mqtt_browser_client.dart +++ b/lib/src/mqtt_browser_client.dart @@ -15,7 +15,8 @@ class MqttBrowserClient extends MqttClient { MqttBrowserClient( super.server, super.clientIdentifier, { - this.maxConnectionAttempts = 3, + this.maxConnectionAttempts = + MqttClientConstants.defaultMaxConnectionAttempts, }); /// Initializes a new instance of the MqttServerClient class using @@ -27,7 +28,8 @@ class MqttBrowserClient extends MqttClient { super.server, super.clientIdentifier, super.port, { - this.maxConnectionAttempts = 3, + this.maxConnectionAttempts = + MqttClientConstants.defaultMaxConnectionAttempts, }) : super.withPort(); /// Max connection attempts diff --git a/lib/src/mqtt_client_constants.dart b/lib/src/mqtt_client_constants.dart index 42ff4c2..b8531e5 100644 --- a/lib/src/mqtt_client_constants.dart +++ b/lib/src/mqtt_client_constants.dart @@ -26,7 +26,10 @@ class MqttClientConstants { /// Default keep alive in seconds. /// The default of 0 disables keep alive. - static int defaultKeepAlive = 0; + static const int defaultKeepAlive = 0; + + /// Default maximum connection attempts + static const int defaultMaxConnectionAttempts = 3; /// Protocol variants /// V3 diff --git a/lib/src/mqtt_server_client.dart b/lib/src/mqtt_server_client.dart index f9f98ac..fe022b7 100644 --- a/lib/src/mqtt_server_client.dart +++ b/lib/src/mqtt_server_client.dart @@ -15,7 +15,8 @@ class MqttServerClient extends MqttClient { MqttServerClient( super.server, super.clientIdentifier, { - this.maxConnectionAttempts = 3, + this.maxConnectionAttempts = + MqttClientConstants.defaultMaxConnectionAttempts, }); /// Initializes a new instance of the MqttServerClient class using @@ -27,7 +28,8 @@ class MqttServerClient extends MqttClient { super.server, super.clientIdentifier, super.port, { - this.maxConnectionAttempts = 3, + this.maxConnectionAttempts = + MqttClientConstants.defaultMaxConnectionAttempts, }) : super.withPort(); /// The security context for secure usage From cfbb71e5db0021930e0598e326105773bf63d156 Mon Sep 17 00:00:00 2001 From: Steve Hamblett Date: Fri, 5 Jul 2024 10:27:41 +0100 Subject: [PATCH 4/6] Issue 523 --- .../mqtt_server_client_failed_connection.dart | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 example/mqtt_server_client_failed_connection.dart diff --git a/example/mqtt_server_client_failed_connection.dart b/example/mqtt_server_client_failed_connection.dart new file mode 100644 index 0000000..364dcad --- /dev/null +++ b/example/mqtt_server_client_failed_connection.dart @@ -0,0 +1,85 @@ +/* + * Package : mqtt_client + * Author : S. Hamblett + * Date : 31/05/2017 + * Copyright : S.Hamblett + */ + +import 'dart:async'; +import 'dart:io'; +import 'package:mqtt_client/mqtt_client.dart'; +import 'package:mqtt_client/mqtt_server_client.dart'; + +/// An annotated connection attempt failed usage example for mqtt_server_client. +/// to run this example on a linux host please execute 'netcat -l 1883' at the command line. +/// +/// First create a client, the client is constructed with a broker name, client identifier +/// and port if needed. The client identifier (short ClientId) is an identifier of each MQTT +/// client connecting to a MQTT broker. As the word identifier already suggests, it should be unique per broker. +/// The broker uses it for identifying the client and the current state of the client. If you don’t need a state +/// to be hold by the broker, in MQTT 3.1.1 you can set an empty ClientId, which results in a connection without any state. +/// A condition is that clean session connect flag is true, otherwise the connection will be rejected. +/// The client identifier can be a maximum length of 23 characters. If a port is not specified the standard port +/// of 1883 is used. +/// If you want to use websockets rather than TCP see below. + +/// Connect to a resolvable host that is not running a broker, hence the connection will fail. +/// Set the maximum connection attempts to 3. +final client = MqttServerClient('localhost', '', maxConnectionAttempts: 3); + +Future main() async { + /// Set logging on if needed, defaults to off + client.logging(on: false); + + /// Set the correct MQTT protocol for mosquito + client.setProtocolV311(); + + /// The connection timeout period can be set if needed, the default is 5 seconds. + client.connectTimeoutPeriod = 2000; // milliseconds + + /// Add the failed connection attempt callback. + /// This callback will be called on every failed connection attempt, in the case of this + /// example it will be called 3 times at a period of 2 seconds. + client.onFailedConnectionAttempt = failedConnectionAttemptCallback; + + /// Create a connection message to use or use the default one. The default one sets the + /// client identifier, any supplied username/password and clean session, + /// an example of a specific one below. + final connMess = MqttConnectMessage() + .withClientIdentifier('Mqtt_MyClientUniqueId') + .withWillTopic('willtopic') // If you set this you must set a will message + .withWillMessage('My Will message') + .startClean() // Non persistent session for testing + .withWillQos(MqttQos.atLeastOnce); + print('EXAMPLE::Mosquitto client connecting....'); + client.connectionMessage = connMess; + + /// Connect the client, any errors here are communicated via the failed + /// connection attempts callback + + try { + await client.connect(); + } on NoConnectionException catch (e) { + // Raised by the client when connection fails. + print('EXAMPLE::client exception - $e'); + client.disconnect(); + return -1; + } on SocketException catch (e) { + // Raised by the socket layer + print('EXAMPLE::socket exception - $e'); + client.disconnect(); + return -1; + } + + /// Check we are not connected + if (client.connectionStatus!.state != MqttConnectionState.connected) { + print('EXAMPLE::Mosquitto client not connected'); + } + + return 0; +} + +/// Failed connection attempt callback +void failedConnectionAttemptCallback(int attempt) { + print('EXAMPLE::onFailedConnectionAttempt, attempt number is $attempt'); +} From a6a9aa7b2fa1bd7caffcd4dfc139f6bc19440680 Mon Sep 17 00:00:00 2001 From: Steve Hamblett Date: Fri, 5 Jul 2024 10:46:21 +0100 Subject: [PATCH 5/6] Issue 523 --- .../mqtt_server_client_failed_connection.dart | 7 ++--- ...onous_mqtt_browser_connection_handler.dart | 26 ++++++++++++------- ...ronous_mqtt_server_connection_handler.dart | 26 ++++++++++++------- lib/src/mqtt_client.dart | 3 ++- 4 files changed, 38 insertions(+), 24 deletions(-) diff --git a/example/mqtt_server_client_failed_connection.dart b/example/mqtt_server_client_failed_connection.dart index 364dcad..cc88ac0 100644 --- a/example/mqtt_server_client_failed_connection.dart +++ b/example/mqtt_server_client_failed_connection.dart @@ -63,20 +63,21 @@ Future main() async { // Raised by the client when connection fails. print('EXAMPLE::client exception - $e'); client.disconnect(); - return -1; + exit(-1); } on SocketException catch (e) { // Raised by the socket layer print('EXAMPLE::socket exception - $e'); client.disconnect(); - return -1; + exit(-1); } /// Check we are not connected if (client.connectionStatus!.state != MqttConnectionState.connected) { print('EXAMPLE::Mosquitto client not connected'); + exit(0); } - return 0; + exit(0); } /// Failed connection attempt callback diff --git a/lib/src/connectionhandling/browser/mqtt_client_synchronous_mqtt_browser_connection_handler.dart b/lib/src/connectionhandling/browser/mqtt_client_synchronous_mqtt_browser_connection_handler.dart index ae9c344..5ca3818 100644 --- a/lib/src/connectionhandling/browser/mqtt_client_synchronous_mqtt_browser_connection_handler.dart +++ b/lib/src/connectionhandling/browser/mqtt_client_synchronous_mqtt_browser_connection_handler.dart @@ -100,17 +100,23 @@ class SynchronousMqttBrowserConnectionHandler if (!autoReconnectInProgress) { MqttLogger.log( 'SynchronousMqttBrowserConnectionHandler::internalConnect failed'); - if (connectionStatus.returnCode == - MqttConnectReturnCode.noneSpecified) { - throw NoConnectionException('The maximum allowed connection attempts ' - '({$maxConnectionAttempts}) were exceeded. ' - 'The broker is not responding to the connection request message ' - '(Missing Connection Acknowledgement?'); + if (onFailedConnectionAttempt == null) { + if (connectionStatus.returnCode == + MqttConnectReturnCode.noneSpecified) { + throw NoConnectionException( + 'The maximum allowed connection attempts ' + '({$maxConnectionAttempts}) were exceeded. ' + 'The broker is not responding to the connection request message ' + '(Missing Connection Acknowledgement?'); + } else { + throw NoConnectionException( + 'The maximum allowed connection attempts ' + '({$maxConnectionAttempts}) were exceeded. ' + 'The broker is not responding to the connection request message correctly ' + 'The return code is ${connectionStatus.returnCode}'); + } } else { - throw NoConnectionException('The maximum allowed connection attempts ' - '({$maxConnectionAttempts}) were exceeded. ' - 'The broker is not responding to the connection request message correctly ' - 'The return code is ${connectionStatus.returnCode}'); + connectionStatus.state = MqttConnectionState.faulted; } } } diff --git a/lib/src/connectionhandling/server/mqtt_client_synchronous_mqtt_server_connection_handler.dart b/lib/src/connectionhandling/server/mqtt_client_synchronous_mqtt_server_connection_handler.dart index b05d41f..c8abf3b 100644 --- a/lib/src/connectionhandling/server/mqtt_client_synchronous_mqtt_server_connection_handler.dart +++ b/lib/src/connectionhandling/server/mqtt_client_synchronous_mqtt_server_connection_handler.dart @@ -130,17 +130,23 @@ class SynchronousMqttServerConnectionHandler if (!autoReconnectInProgress) { MqttLogger.log( 'SynchronousMqttServerConnectionHandler::internalConnect failed'); - if (connectionStatus.returnCode == - MqttConnectReturnCode.noneSpecified) { - throw NoConnectionException('The maximum allowed connection attempts ' - '({$maxConnectionAttempts}) were exceeded. ' - 'The broker is not responding to the connection request message ' - '(Missing Connection Acknowledgement?'); + if (onFailedConnectionAttempt == null) { + if (connectionStatus.returnCode == + MqttConnectReturnCode.noneSpecified) { + throw NoConnectionException( + 'The maximum allowed connection attempts ' + '({$maxConnectionAttempts}) were exceeded. ' + 'The broker is not responding to the connection request message ' + '(Missing Connection Acknowledgement?'); + } else { + throw NoConnectionException( + 'The maximum allowed connection attempts ' + '({$maxConnectionAttempts}) were exceeded. ' + 'The broker is not responding to the connection request message correctly ' + 'The return code is ${connectionStatus.returnCode}'); + } } else { - throw NoConnectionException('The maximum allowed connection attempts ' - '({$maxConnectionAttempts}) were exceeded. ' - 'The broker is not responding to the connection request message correctly ' - 'The return code is ${connectionStatus.returnCode}'); + connectionStatus.state = MqttConnectionState.faulted; } } } diff --git a/lib/src/mqtt_client.dart b/lib/src/mqtt_client.dart index 3db2d79..c2bfb7b 100755 --- a/lib/src/mqtt_client.dart +++ b/lib/src/mqtt_client.dart @@ -208,7 +208,8 @@ class MqttClient { /// Called on every failed connection attempt, if [maxConnectionAttempts] is /// set to 5 say this will be called 5 times if the connection fails, /// one for every failed attempt. Note this is never called - /// if [autoReconnect] is set. + /// if [autoReconnect] is set, also the [NoConnectionException] is not raised + /// if this callback is supplied. FailedConnectionAttemptCallback? onFailedConnectionAttempt; /// Subscribed callback, function returns a void and takes a From 2c932194dd7a7959237e93da05a5b80bcc4e2b2f Mon Sep 17 00:00:00 2001 From: Steve Hamblett Date: Fri, 5 Jul 2024 13:40:28 +0100 Subject: [PATCH 6/6] Issue 523 --- .../mqtt_server_client_failed_connection.dart | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/example/mqtt_server_client_failed_connection.dart b/example/mqtt_server_client_failed_connection.dart index cc88ac0..0c8de95 100644 --- a/example/mqtt_server_client_failed_connection.dart +++ b/example/mqtt_server_client_failed_connection.dart @@ -11,7 +11,9 @@ import 'package:mqtt_client/mqtt_client.dart'; import 'package:mqtt_client/mqtt_server_client.dart'; /// An annotated connection attempt failed usage example for mqtt_server_client. -/// to run this example on a linux host please execute 'netcat -l 1883' at the command line. +/// +/// To run this example on a linux host please execute 'netcat -l 1883' at the command line. +/// Use a suitably equivalent command for other hosts. /// /// First create a client, the client is constructed with a broker name, client identifier /// and port if needed. The client identifier (short ClientId) is an identifier of each MQTT @@ -21,7 +23,6 @@ import 'package:mqtt_client/mqtt_server_client.dart'; /// A condition is that clean session connect flag is true, otherwise the connection will be rejected. /// The client identifier can be a maximum length of 23 characters. If a port is not specified the standard port /// of 1883 is used. -/// If you want to use websockets rather than TCP see below. /// Connect to a resolvable host that is not running a broker, hence the connection will fail. /// Set the maximum connection attempts to 3. @@ -37,6 +38,9 @@ Future main() async { /// The connection timeout period can be set if needed, the default is 5 seconds. client.connectTimeoutPeriod = 2000; // milliseconds + /// Add the unsolicited disconnection callback + client.onDisconnected = onDisconnected; + /// Add the failed connection attempt callback. /// This callback will be called on every failed connection attempt, in the case of this /// example it will be called 3 times at a period of 2 seconds. @@ -74,7 +78,6 @@ Future main() async { /// Check we are not connected if (client.connectionStatus!.state != MqttConnectionState.connected) { print('EXAMPLE::Mosquitto client not connected'); - exit(0); } exit(0); @@ -83,4 +86,20 @@ Future main() async { /// Failed connection attempt callback void failedConnectionAttemptCallback(int attempt) { print('EXAMPLE::onFailedConnectionAttempt, attempt number is $attempt'); + if (attempt == 3) { + client.disconnect(); + } +} + +/// The unsolicited disconnect callback +void onDisconnected() { + print('EXAMPLE::OnDisconnected client callback - Client disconnection'); + if (client.connectionStatus!.disconnectionOrigin == + MqttDisconnectionOrigin.solicited) { + print('EXAMPLE::OnDisconnected callback is solicited, this is correct'); + } else { + print( + 'EXAMPLE::OnDisconnected callback is unsolicited or none, this is incorrect - exiting'); + exit(-1); + } }