@@ -3,30 +3,56 @@ import 'dart:math';
3
3
4
4
final _random = Random ();
5
5
6
- final class SocketConnectionAttempt {
7
- SocketConnectionAttempt ({required Duration delay}) {
6
+ sealed class SocketConnectionAttempt {
7
+ SocketConnectionAttempt ._();
8
+
9
+ // Created a socket connection attempt whose delayFuture will complete after
10
+ // the given delay.
11
+ factory SocketConnectionAttempt ({required Duration delay}) =>
12
+ _DelayedSocketConnectionAttempt (delay: delay);
13
+
14
+ // Creates a socket connection attempt whose delayFuture is completed with an
15
+ // error.
16
+ factory SocketConnectionAttempt .aborted () =>
17
+ _AbortedSocketConnectionAttempt ();
18
+
19
+ final int _id = _random.nextInt (1 << 32 );
20
+ late final idAsString = _id.toRadixString (16 ).padLeft (8 , '0' );
21
+
22
+ /// Whether the delayFuture has completed with either succesfully or with an
23
+ /// error.
24
+ bool get delayDone;
25
+
26
+ // Future that completes successfully when the delay connection attempt should
27
+ // be performed.
28
+ Future <void > get delayFuture;
29
+
30
+ // Immediately successfully completes [delayFuture]. Has no effect if the
31
+ // future was already completed.
32
+ void skipDelay ();
33
+
34
+ // Immediately completes [delayFuture] with an error. Has no effect if the
35
+ // future was already completed.
36
+ void abort ();
37
+ }
38
+
39
+ final class _DelayedSocketConnectionAttempt extends SocketConnectionAttempt {
40
+ _DelayedSocketConnectionAttempt ({required Duration delay}) : super ._() {
8
41
_delayTimer = Timer (delay, () {
9
42
if (! _delayCompleter.isCompleted) {
10
43
_delayCompleter.complete ();
11
44
}
12
45
});
13
46
}
14
47
15
- SocketConnectionAttempt .aborted () {
16
- _delayTimer = Timer (Duration .zero, () {});
17
- delayFuture.ignore ();
18
- abort ();
19
- }
20
-
21
- final int _id = _random.nextInt (1 << 32 );
22
- late final idAsString = _id.toRadixString (16 ).padLeft (8 , '0' );
23
-
48
+ late Timer _delayTimer;
24
49
final Completer <void > _delayCompleter = Completer ();
25
- bool get delayDone => _delayCompleter.isCompleted;
50
+ @override
26
51
late final Future <void > delayFuture = _delayCompleter.future;
52
+ @override
53
+ bool get delayDone => _delayCompleter.isCompleted;
27
54
28
- late Timer _delayTimer;
29
-
55
+ @override
30
56
void skipDelay () {
31
57
if (_delayTimer.isActive) {
32
58
_delayTimer.cancel ();
@@ -36,6 +62,7 @@ final class SocketConnectionAttempt {
36
62
}
37
63
}
38
64
65
+ @override
39
66
void abort () {
40
67
if (_delayTimer.isActive) {
41
68
_delayTimer.cancel ();
@@ -50,14 +77,42 @@ final class SocketConnectionAttempt {
50
77
51
78
@override
52
79
bool operator == (Object other) {
53
- return other is SocketConnectionAttempt && _id == other._id;
80
+ return other is _DelayedSocketConnectionAttempt && _id == other._id;
54
81
}
55
82
56
83
@override
57
84
int get hashCode => _id.hashCode;
58
85
59
86
@override
60
87
String toString () {
61
- return 'SocketConnectionAttempt (id: $idAsString )' ;
88
+ return 'DelayedSocketConnectionAttempt (id: $idAsString )' ;
62
89
}
63
90
}
91
+
92
+ final class _AbortedSocketConnectionAttempt extends SocketConnectionAttempt {
93
+ _AbortedSocketConnectionAttempt () : super ._();
94
+
95
+ @override
96
+ bool delayDone = false ;
97
+
98
+ @override
99
+ late final Future <void > delayFuture =
100
+ // Future.error completes after a microtask, so to be perfectly ok with
101
+ // the superclass API, we set delayDone to true after the microtask is
102
+ // done.
103
+ Future .error ('Attempt aborted' ).whenComplete (() => delayDone = true );
104
+
105
+ @override
106
+ void abort () {}
107
+
108
+ @override
109
+ void skipDelay () {}
110
+
111
+ @override
112
+ bool operator == (Object other) {
113
+ return other is _AbortedSocketConnectionAttempt && other._id == _id;
114
+ }
115
+
116
+ @override
117
+ int get hashCode => _id.hashCode;
118
+ }
0 commit comments