xmpp: Add support for setting reconnection policies

This commit is contained in:
2022-05-30 16:26:34 +02:00
parent dfacbca446
commit aae126a3de
7 changed files with 130 additions and 39 deletions

87
lib/xmpp/reconnect.dart Normal file
View File

@@ -0,0 +1,87 @@
import "dart:async";
import "dart:math";
import "package:logging/logging.dart";
import "package:meta/meta.dart";
abstract class ReconnectionPolicy {
/// Function provided by [XmppConnection] that allows the policy
/// to perform a reconnection.
void Function()? performReconnect;
/// Called by [XmppConnection] to register the policy.
void register(void Function() performReconnect) {
this.performReconnect = performReconnect;
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();
}
/// A simple reconnection strategy: Make the reconnection delays exponentially longer
/// for every failed attempt.
class ExponentialBackoffReconnectionPolicy extends ReconnectionPolicy {
int _counter;
Timer? _timer;
Logger _log;
ExponentialBackoffReconnectionPolicy()
: _counter = 0,
_log = Logger("ExponentialBackoffReconnectionPolicy");
/// Called when the backoff expired
void _onTimerElapsed() {
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 {
@override
void onSuccess() {}
@override
void onFailure() {}
@override
void reset() {}
}