11namespace Ecng . Net ;
22
33/// <summary>
4- /// Tracks the connection states of multiple IConnection instances and aggregates their overall state.
4+ /// Tracks the connection states of multiple <see cref="IAsyncConnection"/> instances and aggregates their overall state.
55/// </summary>
6- public class ConnectionStateTracker : Disposable , IConnection
6+ public class ConnectionStateTracker : Disposable , IAsyncConnection ,
7+ #pragma warning disable CS0618 // Type or member is obsolete
8+ IConnection
9+ #pragma warning restore CS0618
710{
811 /// <summary>
9- /// Wraps an IConnection instance to listen for its state changes.
12+ /// Wraps an <see cref="IAsyncConnection"/> instance to listen for its state changes.
1013 /// </summary>
1114 private class ConnectionWrapper : Disposable
1215 {
13- private readonly IConnection _connection ;
16+ private readonly IAsyncConnection _connection ;
1417 private readonly Action _stateChanged ;
1518
1619 /// <summary>
@@ -24,7 +27,7 @@ private class ConnectionWrapper : Disposable
2427 /// <param name="connection">The connection to wrap.</param>
2528 /// <param name="stateChanged">Callback invoked when the connection state changes.</param>
2629 /// <exception cref="ArgumentNullException">Thrown when connection or stateChanged is null.</exception>
27- public ConnectionWrapper ( IConnection connection , Action stateChanged )
30+ public ConnectionWrapper ( IAsyncConnection connection , Action stateChanged )
2831 {
2932 _connection = connection ?? throw new ArgumentNullException ( nameof ( connection ) ) ;
3033 _stateChanged = stateChanged ?? throw new ArgumentNullException ( nameof ( stateChanged ) ) ;
@@ -46,22 +49,56 @@ protected override void DisposeManaged()
4649 /// <summary>
4750 /// Handles the state change event from the wrapped connection.
4851 /// </summary>
49- /// <param name="newState">The new state of the connection.</param>
50- private void OnStateChanged ( ConnectionStates newState )
52+ private ValueTask OnStateChanged ( ConnectionStates newState , CancellationToken cancellationToken )
5153 {
5254 State = newState ;
5355 _stateChanged ( ) ;
56+ return default ;
5457 }
5558 }
5659
57- private readonly CachedSynchronizedDictionary < IConnection , ConnectionWrapper > _connections = [ ] ;
60+ #pragma warning disable CS0618 // Type or member is obsolete
61+ /// <summary>
62+ /// Adapts an <see cref="IConnection"/> to <see cref="IAsyncConnection"/>.
63+ /// </summary>
64+ private sealed class ConnectionAdapter ( IConnection connection ) : IAsyncConnection
65+ {
66+ public event Func < ConnectionStates , CancellationToken , ValueTask > StateChanged
67+ {
68+ add => connection . StateChanged += state => value ( state , default ) ;
69+ remove { }
70+ }
71+
72+ public ValueTask ConnectAsync ( CancellationToken cancellationToken )
73+ => connection . ConnectAsync ( cancellationToken ) ;
74+
75+ public void Disconnect ( )
76+ => connection . Disconnect ( ) ;
77+ }
78+ #pragma warning restore CS0618
79+
80+ private readonly CachedSynchronizedDictionary < IAsyncConnection , ConnectionWrapper > _connections = [ ] ;
5881 private readonly Lock _currStateLock = new ( ) ;
5982 private ConnectionStates _currState = ConnectionStates . Disconnected ;
6083
61- /// <summary>
62- /// Occurs when the overall connection state changes.
63- /// </summary>
64- public event Action < ConnectionStates > StateChanged ;
84+ private event Func < ConnectionStates , CancellationToken , ValueTask > _asyncStateChanged ;
85+ #pragma warning disable CS0618 // Type or member is obsolete
86+ private event Action < ConnectionStates > _syncStateChanged ;
87+
88+ /// <inheritdoc />
89+ event Action < ConnectionStates > IConnection . StateChanged
90+ {
91+ add => _syncStateChanged += value ;
92+ remove => _syncStateChanged -= value ;
93+ }
94+ #pragma warning restore CS0618
95+
96+ /// <inheritdoc />
97+ event Func < ConnectionStates , CancellationToken , ValueTask > IAsyncConnection . StateChanged
98+ {
99+ add => _asyncStateChanged += value ;
100+ remove => _asyncStateChanged -= value ;
101+ }
65102
66103 /// <summary>
67104 /// Connects all tracked connections asynchronously.
@@ -89,15 +126,25 @@ public void Disconnect()
89126 /// Adds a connection to be tracked.
90127 /// </summary>
91128 /// <param name="connection">The connection to add.</param>
92- public void Add ( IConnection connection )
129+ public void Add ( IAsyncConnection connection )
93130 => _connections . Add ( connection , new ( connection , UpdateOverallState ) ) ;
94131
132+ /// <summary>
133+ /// Adds a connection to be tracked.
134+ /// </summary>
135+ /// <param name="connection">The connection to add.</param>
136+ [ Obsolete ( "Use Add(IAsyncConnection) instead." ) ]
137+ #pragma warning disable CS0618 // Type or member is obsolete
138+ public void Add ( IConnection connection )
139+ #pragma warning restore CS0618
140+ => Add ( new ConnectionAdapter ( connection ) ) ;
141+
95142 /// <summary>
96143 /// Removes a tracked connection.
97144 /// </summary>
98145 /// <param name="connection">The connection to remove.</param>
99146 /// <returns>True if the connection was successfully removed; otherwise, false.</returns>
100- public bool Remove ( IConnection connection )
147+ public bool Remove ( IAsyncConnection connection )
101148 {
102149 if ( ! _connections . TryGetAndRemove ( connection , out var wrapper ) )
103150 return false ;
@@ -107,7 +154,24 @@ public bool Remove(IConnection connection)
107154 return true ;
108155 }
109156
110- private IConnection [ ] Connections => _connections . CachedKeys ;
157+ /// <summary>
158+ /// Removes a tracked connection.
159+ /// </summary>
160+ /// <param name="connection">The connection to remove.</param>
161+ /// <returns>True if the connection was successfully removed; otherwise, false.</returns>
162+ [ Obsolete ( "Use Remove(IAsyncConnection) instead." ) ]
163+ #pragma warning disable CS0618 // Type or member is obsolete
164+ public bool Remove ( IConnection connection )
165+ #pragma warning restore CS0618
166+ {
167+ var key = _connections . CachedPairs . FirstOrDefault ( p => p . Key is ConnectionAdapter ) . Key ;
168+ if ( key is null )
169+ return false ;
170+
171+ return Remove ( key ) ;
172+ }
173+
174+ private IAsyncConnection [ ] Connections => _connections . CachedKeys ;
111175 private ConnectionWrapper [ ] Wrappers => _connections . CachedValues ;
112176
113177 /// <summary>
@@ -161,6 +225,6 @@ private void UpdateOverallState()
161225 _currState = newState ;
162226 }
163227
164- StateChanged ? . Invoke ( newState ) ;
228+ _syncStateChanged ? . Invoke ( newState ) ;
165229 }
166230}
0 commit comments