Files
moxxy/lib/xmpp/reconnect.dart

108 lines
2.6 KiB
Dart

import 'dart:async';
import 'dart:math';
import 'package:logging/logging.dart';
import 'package:meta/meta.dart';
abstract class ReconnectionPolicy {
ReconnectionPolicy() : _shouldAttemptReconnection = false;
/// Function provided by XmppConnection that allows the policy
/// to perform a reconnection.
void Function()? performReconnect;
/// Function provided by XmppConnection that allows the policy
/// to say that we lost the connection.
void Function()? triggerConnectionLost;
/// Indicate if should try to reconnect.
bool _shouldAttemptReconnection;
/// Called by XmppConnection to register the policy.
void register(void Function() performReconnect, void Function() triggerConnectionLost) {
this.performReconnect = performReconnect;
this.triggerConnectionLost = triggerConnectionLost;
reset();
}
/// In case the policy depends on some internal state, this state must be reset
/// to an initial state when reset is called. In case timers run, they must be
/// terminated.
void reset();
/// Called by the XmppConnection when the reconnection failed.
void onFailure();
/// Caled by the XmppConnection when the reconnection was successful.
void onSuccess();
bool get shouldReconnect => _shouldAttemptReconnection;
/// Set whether a reconnection attempt should be made.
void setShouldReconnect(bool value) {
_shouldAttemptReconnection = value;
}
}
/// A simple reconnection strategy: Make the reconnection delays exponentially longer
/// for every failed attempt.
class ExponentialBackoffReconnectionPolicy extends ReconnectionPolicy {
ExponentialBackoffReconnectionPolicy()
: _counter = 0,
_log = Logger('ExponentialBackoffReconnectionPolicy'),
super();
int _counter;
Timer? _timer;
final Logger _log;
/// Called when the backoff expired
void _onTimerElapsed() {
if (shouldReconnect) {
performReconnect!();
}
}
@override
void reset() {
_log.finest('Resetting internal state');
_counter = 0;
if (_timer != null) {
_timer!.cancel();
_timer = null;
}
}
@override
void onFailure() {
_log.finest('Failure occured. Starting exponential backoff');
_counter++;
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(Duration(seconds: pow(2, _counter).toInt()), _onTimerElapsed);
}
@override
void onSuccess() {
reset();
}
}
/// A stub reconnection policy for tests
@visibleForTesting
class TestingReconnectionPolicy extends ReconnectionPolicy {
TestingReconnectionPolicy() : super();
@override
void onSuccess() {}
@override
void onFailure() {}
@override
void reset() {}
}