Skip to content

Commit

Permalink
Restructures SocketConnectionAttempt
Browse files Browse the repository at this point in the history
  • Loading branch information
kpsroka committed Aug 14, 2024
1 parent 6c27b0e commit aaf981b
Showing 1 changed file with 71 additions and 16 deletions.
87 changes: 71 additions & 16 deletions lib/src/socket_connection_attempt.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,56 @@ import 'dart:math';

final _random = Random();

final class SocketConnectionAttempt {
SocketConnectionAttempt({required Duration delay}) {
sealed class SocketConnectionAttempt {
SocketConnectionAttempt._();

// Created a socket connection attempt whose delayFuture will complete after
// the given delay.
factory SocketConnectionAttempt({required Duration delay}) =>
_DelayedSocketConnectionAttempt(delay: delay);

// Creates a socket connection attempt whose delayFuture is completed with an
// error.
factory SocketConnectionAttempt.aborted() =>
_AbortedSocketConnectionAttempt();

final int _id = _random.nextInt(1 << 32);
late final idAsString = _id.toRadixString(16).padLeft(8, '0');

/// Whether the delayFuture has completed with either succesfully or with an
/// error.
bool get delayDone;

// Future that completes successfully when the delay connection attempt should
// be performed.
Future<void> get delayFuture;

// Immediately successfully completes [delayFuture]. Has no effect if the
// future was already completed.
void skipDelay();

// Immediately completes [delayFuture] with an error. Has no effect if the
// future was already completed.
void abort();
}

final class _DelayedSocketConnectionAttempt extends SocketConnectionAttempt {
_DelayedSocketConnectionAttempt({required Duration delay}) : super._() {
_delayTimer = Timer(delay, () {
if (!_delayCompleter.isCompleted) {
_delayCompleter.complete();
}
});
}

SocketConnectionAttempt.aborted() {
_delayTimer = Timer(Duration.zero, () {});
delayFuture.ignore();
abort();
}

final int _id = _random.nextInt(1 << 32);
late final idAsString = _id.toRadixString(16).padLeft(8, '0');

late Timer _delayTimer;
final Completer<void> _delayCompleter = Completer();
bool get delayDone => _delayCompleter.isCompleted;
@override
late final Future<void> delayFuture = _delayCompleter.future;
@override
bool get delayDone => _delayCompleter.isCompleted;

late Timer _delayTimer;

@override
void skipDelay() {
if (_delayTimer.isActive) {
_delayTimer.cancel();
Expand All @@ -36,6 +62,7 @@ final class SocketConnectionAttempt {
}
}

@override
void abort() {
if (_delayTimer.isActive) {
_delayTimer.cancel();
Expand All @@ -50,14 +77,42 @@ final class SocketConnectionAttempt {

@override
bool operator ==(Object other) {
return other is SocketConnectionAttempt && _id == other._id;
return other is _DelayedSocketConnectionAttempt && _id == other._id;
}

@override
int get hashCode => _id.hashCode;

@override
String toString() {
return 'SocketConnectionAttempt(id: $idAsString)';
return 'DelayedSocketConnectionAttempt(id: $idAsString)';
}
}

final class _AbortedSocketConnectionAttempt extends SocketConnectionAttempt {
_AbortedSocketConnectionAttempt() : super._();

@override
bool delayDone = false;

@override
late final Future<void> delayFuture =
// Future.error completes after a microtask, so to be perfectly ok with
// the superclass API, we set delayDone to true after the microtask is
// done.
Future.error('Attempt aborted').whenComplete(() => delayDone = true);

@override
void abort() {}

@override
void skipDelay() {}

@override
bool operator ==(Object other) {
return other is _AbortedSocketConnectionAttempt && other._id == _id;
}

@override
int get hashCode => _id.hashCode;
}

0 comments on commit aaf981b

Please sign in to comment.