diff --git a/lib/src/kuzzle.dart b/lib/src/kuzzle.dart index 4a3e7949..c1c8db50 100644 --- a/lib/src/kuzzle.dart +++ b/lib/src/kuzzle.dart @@ -51,8 +51,8 @@ class Kuzzle extends KuzzleEventEmitter { } globalVolatile ??= {}; - queueTTL ??= Duration(minutes: 2); - replayInterval ??= Duration(milliseconds: 10); + queueTTL ??= const Duration(minutes: 2); + replayInterval ??= const Duration(milliseconds: 10); server = ServerController(this); bulk = BulkController(this); @@ -153,12 +153,7 @@ class Kuzzle extends KuzzleEventEmitter { /// Common volatile data, will be sent to all future requests Map globalVolatile; - final List _requests = List(); - - bool get autoReconnect => protocol.autoReconnect; - set autoReconnect(bool value) { - protocol.autoReconnect = value; - } + final List _requests = []; final Map _controllers = {}; @@ -174,7 +169,7 @@ class Kuzzle extends KuzzleEventEmitter { if (protocol.state == KuzzleProtocolState.connecting) { final completer = Completer(); - // todo: handle reconnect event + protocol.once(ProtocolEvents.RECONNECT, completer.complete); protocol.once(ProtocolEvents.CONNECT, completer.complete); return completer.future; diff --git a/lib/src/protocols/abstract.dart b/lib/src/protocols/abstract.dart index af871e90..ea18e1ac 100644 --- a/lib/src/protocols/abstract.dart +++ b/lib/src/protocols/abstract.dart @@ -20,24 +20,16 @@ enum KuzzleProtocolState { abstract class KuzzleProtocol extends KuzzleEventEmitter { KuzzleProtocol( - this.uri, { - this.autoReconnect = true, - Duration reconnectionDelay, - }) : _state = KuzzleProtocolState.offline, - _reconnectionDelay = reconnectionDelay ?? Duration(seconds: 1), - id = _uuid.v4(); - - bool autoReconnect; + this.uri, + ) : _state = KuzzleProtocolState.offline, + id = _uuid.v4(); + final Uri uri; final String id; - final Duration _reconnectionDelay; @protected bool wasConnected = false; - @protected - bool stopRetryingToConnect = false; - @protected bool retrying = false; @@ -59,7 +51,6 @@ abstract class KuzzleProtocol extends KuzzleEventEmitter { KuzzleProtocolState state = KuzzleProtocolState.connected, }) { _state = state; - stopRetryingToConnect = false; emit(wasConnected ? ProtocolEvents.RECONNECT : ProtocolEvents.CONNECT); wasConnected = true; @@ -74,27 +65,16 @@ abstract class KuzzleProtocol extends KuzzleEventEmitter { void clientNetworkError([dynamic error]) { _state = KuzzleProtocolState.offline; - emit(ProtocolEvents.NETWORK_ERROR, - [ - KuzzleError('Unable to connect to kuzzle server at ${uri.toString()}') - ]); - - if (autoReconnect && !retrying && !stopRetryingToConnect) { - retrying = true; - - Timer(_reconnectionDelay, () async { - retrying = false; - await connect().catchError(clientNetworkError); - }); - } else { - emit(ProtocolEvents.DISCONNECT); - } + emit(ProtocolEvents.NETWORK_ERROR, [ + KuzzleError('Unable to connect to kuzzle server at ${uri.toString()}') + ]); } /// Called when the client's connection is closed @mustCallSuper void close() { _state = KuzzleProtocolState.offline; + clientDisconnected(); } // todo: implement query options diff --git a/lib/src/protocols/websocket_browser.dart b/lib/src/protocols/websocket_browser.dart index 07a6d1e5..b4da8cea 100644 --- a/lib/src/protocols/websocket_browser.dart +++ b/lib/src/protocols/websocket_browser.dart @@ -15,8 +15,9 @@ class KuzzleWebSocket extends KuzzleProtocol { bool autoReconnect = true, Duration reconnectionDelay, this.pingInterval, - }) : super(uri, - autoReconnect: autoReconnect, reconnectionDelay: reconnectionDelay); + }) : super( + uri, + ); String _lastUrl; WebSocket _webSocket; @@ -64,7 +65,6 @@ class KuzzleWebSocket extends KuzzleProtocol { super.close(); removeAllListeners(); - stopRetryingToConnect = true; wasConnected = false; _subscription?.cancel(); diff --git a/lib/src/protocols/websocket_io.dart b/lib/src/protocols/websocket_io.dart index 9bf35d57..cf8ad174 100644 --- a/lib/src/protocols/websocket_io.dart +++ b/lib/src/protocols/websocket_io.dart @@ -13,20 +13,32 @@ import 'events.dart'; class KuzzleWebSocket extends KuzzleProtocol { KuzzleWebSocket( Uri uri, { - bool autoReconnect = true, + this.autoReconnect = true, Duration reconnectionDelay, this.pingInterval, - }) : - super(uri, - autoReconnect: autoReconnect, reconnectionDelay: reconnectionDelay); + }) : super(uri) { + _reconnectionDelay = reconnectionDelay ?? Duration(seconds: 1); + } String _lastUrl; WebSocket _webSocket; StreamSubscription _subscription; Duration pingInterval; + Duration _reconnectionDelay; + bool autoReconnect; + bool _stopRetryingToConnect = false; + bool _hasBeenClosed = false; @override Future connect() async { + // If a reconnection is going on + // and the enduser called disconnect in between + // then don't try to connect + if (_hasBeenClosed && retrying) { + return; + } + _hasBeenClosed = false; + final url = '${uri.scheme}://${uri.host}:${uri.port}'; await super.connect(); @@ -42,12 +54,15 @@ class KuzzleWebSocket extends KuzzleProtocol { await _webSocket?.close(); _webSocket = null; + _stopRetryingToConnect = false; + try { _webSocket = await WebSocket.connect(url); } on IOException { - if (wasConnected) { + if (wasConnected || autoReconnect) { clientNetworkError( KuzzleError('WebSocketProtocol: Unable to connect to $url')); + _handleAutoReconnect(); return; } @@ -80,8 +95,10 @@ class KuzzleWebSocket extends KuzzleProtocol { void close() { super.close(); + _hasBeenClosed = true; + removeAllListeners(); - stopRetryingToConnect = true; + _stopRetryingToConnect = true; wasConnected = false; _subscription?.cancel(); @@ -103,12 +120,27 @@ class KuzzleWebSocket extends KuzzleProtocol { } } + void _handleAutoReconnect() { + if (autoReconnect && !retrying && !_stopRetryingToConnect) { + retrying = true; + + Timer(_reconnectionDelay, () async { + await connect().catchError(clientNetworkError); + retrying = false; + }); + } else { + emit(ProtocolEvents.DISCONNECT); + } + } + void _handleDone() { if (_webSocket.closeCode == 1000) { clientDisconnected(); - } else if (wasConnected) { + } else if (wasConnected || autoReconnect) { + clientDisconnected(); clientNetworkError(KuzzleError( 'clientNetworkError', _webSocket.closeReason, _webSocket.closeCode)); + _handleAutoReconnect(); } } }