Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix autoreconnect #84

Merged
merged 5 commits into from
Apr 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 4 additions & 9 deletions lib/src/kuzzle.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ class Kuzzle extends KuzzleEventEmitter {
}

globalVolatile ??= <String, dynamic>{};
queueTTL ??= Duration(minutes: 2);
replayInterval ??= Duration(milliseconds: 10);
queueTTL ??= const Duration(minutes: 2);
replayInterval ??= const Duration(milliseconds: 10);

server = ServerController(this);
bulk = BulkController(this);
Expand Down Expand Up @@ -153,12 +153,7 @@ class Kuzzle extends KuzzleEventEmitter {
/// Common volatile data, will be sent to all future requests
Map<String, dynamic> globalVolatile;

final List<String> _requests = List();

bool get autoReconnect => protocol.autoReconnect;
set autoReconnect(bool value) {
protocol.autoReconnect = value;
}
final List<String> _requests = [];

final Map<String, KuzzleController> _controllers =
<String, KuzzleController>{};
Expand All @@ -174,7 +169,7 @@ class Kuzzle extends KuzzleEventEmitter {
if (protocol.state == KuzzleProtocolState.connecting) {
final completer = Completer<void>();

// todo: handle reconnect event
protocol.once(ProtocolEvents.RECONNECT, completer.complete);
protocol.once(ProtocolEvents.CONNECT, completer.complete);

return completer.future;
Expand Down
36 changes: 8 additions & 28 deletions lib/src/protocols/abstract.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -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
Expand Down
6 changes: 3 additions & 3 deletions lib/src/protocols/websocket_browser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -64,7 +65,6 @@ class KuzzleWebSocket extends KuzzleProtocol {
super.close();

removeAllListeners();
stopRetryingToConnect = true;
wasConnected = false;

_subscription?.cancel();
Expand Down
46 changes: 39 additions & 7 deletions lib/src/protocols/websocket_io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> 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();
Expand All @@ -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;
}
Expand Down Expand Up @@ -80,8 +95,10 @@ class KuzzleWebSocket extends KuzzleProtocol {
void close() {
super.close();

_hasBeenClosed = true;

removeAllListeners();
stopRetryingToConnect = true;
_stopRetryingToConnect = true;
Shiranuit marked this conversation as resolved.
Show resolved Hide resolved
wasConnected = false;

_subscription?.cancel();
Expand All @@ -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();
}
}
}