diff --git a/lib/stomp_config.dart b/lib/stomp_config.dart index 3e26785..3ad0755 100644 --- a/lib/stomp_config.dart +++ b/lib/stomp_config.dart @@ -70,10 +70,13 @@ class StompConfig { /// Callback for debug messages final StompDebugCallback onDebugMessage; + /// The transport url of the WebSocket to connect to String get connectUrl => - useSockJS ? SockJsUtils().generateTransportUrl(url) : url; + _connectUrl ??= useSockJS ? SockJsUtils().generateTransportUrl(url) : url; - const StompConfig({ + String? _connectUrl; + + StompConfig({ required this.url, this.reconnectDelay = const Duration(seconds: 5), this.heartbeatIncoming = const Duration(seconds: 5), @@ -157,6 +160,9 @@ class StompConfig { ); } + /// Resets the transport URL + void resetSession() => _connectUrl = null; + static void _noOp([_, __]) {} static Future _noOpFuture() => Future.value(); diff --git a/lib/stomp_handler.dart b/lib/stomp_handler.dart index fa92eca..a821080 100644 --- a/lib/stomp_handler.dart +++ b/lib/stomp_handler.dart @@ -53,7 +53,7 @@ class StompHandler { void start() async { _isActive = true; try { - _channel = await platform.connect(config); + _channel = await platform.connect(config..resetSession()); // It can happen that dispose was called while the future above hasn't completed yet // To prevent lingering connections we need to make sure that we disconnect cleanly if (!_isActive) { diff --git a/test/stomp_config_test.dart b/test/stomp_config_test.dart new file mode 100644 index 0000000..47e44de --- /dev/null +++ b/test/stomp_config_test.dart @@ -0,0 +1,51 @@ +import 'dart:async'; + +import 'package:test/test.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; + +import 'package:stomp_dart_client/stomp_config.dart'; +import 'package:stomp_dart_client/src/_connect_api.dart' + if (dart.library.html) '../lib/src/_connect_html.dart' + if (dart.library.io) '../lib/src/_connect_io.dart' as platform; + +void main() { + group('StompConfig', () { + test('Generate session URL once per connection', () async { + final config = StompConfig.sockJS( + url: 'http://localhost', + reconnectDelay: Duration(milliseconds: 500), + ); + + final connectUrls = {}; + + void connect() async { + try { + await platform.connect(config..resetSession()); + } on WebSocketChannelException catch (_) { + // Save subsequent calls of `connectUrl`. + connectUrls.addAll({config.connectUrl: config.connectUrl}); + if (connectUrls.length == 1) { + // On 1st connect we expect that the current stored values are equal + expect(connectUrls.entries.first.key, + equals(connectUrls.entries.first.value)); + } else if (connectUrls.length == 2) { + // On 2nd connect we expect that the current stored values are equal + expect(connectUrls.entries.last.key, + equals(connectUrls.entries.last.value)); + // But they are different from the values saved on 1st connect + expect(connectUrls.entries.first.key, + isNot(equals(connectUrls.entries.last.key))); + expect(connectUrls.entries.first.value, + isNot(equals(connectUrls.entries.last.value))); + } + Timer(config.reconnectDelay, connect); + } + } + + connect(); + + // Wait until exit + await Future.delayed(Duration(seconds: 3)); + }); + }); +}