@@ -19,7 +19,13 @@ namespace SymphonyOSS.RestApiClient.Api.PodApi
19
19
{
20
20
using System ;
21
21
using System . Collections . Generic ;
22
+ using System . Diagnostics ;
23
+ using System . Linq ;
24
+ using System . Threading ;
25
+ using System . Threading . Tasks ;
26
+ using AgentApi ;
22
27
using Authentication ;
28
+ using Generated . OpenApi . AgentApi . Model ;
23
29
using Generated . OpenApi . PodApi . Client ;
24
30
using Generated . OpenApi . PodApi . Model ;
25
31
@@ -30,12 +36,37 @@ namespace SymphonyOSS.RestApiClient.Api.PodApi
30
36
/// </summary>
31
37
public class ConnectionApi
32
38
{
39
+ private static readonly TraceSource TraceSource = new TraceSource ( "SymphonyOSS.RestApiClient" ) ;
40
+
33
41
private readonly Generated . OpenApi . PodApi . Api . IConnectionApi _connectionApi ;
34
42
35
43
private readonly IAuthTokens _authTokens ;
36
44
37
45
private readonly IApiExecutor _apiExecutor ;
38
46
47
+ private readonly Dictionary < EventHandler < ConnectionRequestEventArgs > , Task > _tasks =
48
+ new Dictionary < EventHandler < ConnectionRequestEventArgs > , Task > ( ) ;
49
+
50
+ private Timer connectionPollTimer ;
51
+
52
+ private event EventHandler < ConnectionRequestEventArgs > _onConnectionRequest ;
53
+
54
+ public event EventHandler < ConnectionRequestEventArgs > OnConnectionRequest
55
+ {
56
+ add
57
+ {
58
+ _onConnectionRequest += value ;
59
+ }
60
+ remove
61
+ {
62
+ _onConnectionRequest -= value ;
63
+ lock ( _tasks )
64
+ {
65
+ _tasks . Remove ( value ) ;
66
+ }
67
+ }
68
+ }
69
+
39
70
/// <summary>
40
71
/// Initializes a new instance of the <see cref="UsersApi" /> class.
41
72
/// See <see cref="Factories.PodApiFactory"/> for conveniently constructing
@@ -51,6 +82,54 @@ public ConnectionApi(IAuthTokens authTokens, Configuration configuration, IApiEx
51
82
_apiExecutor = apiExecutor ;
52
83
}
53
84
85
+ /// <summary>
86
+ /// Starts listening, notifying event handlers about incoming connection requests. Blocks
87
+ /// until <see cref="ConnectionApi.Stop"/> is invoked.
88
+ /// </summary>
89
+ public void Listen ( long timeout )
90
+ {
91
+ connectionPollTimer = new Timer (
92
+ cb =>
93
+ {
94
+ try
95
+ {
96
+ var connectionList =
97
+ List ( ) . Where ( connection => connection . Status != UserConnection . StatusEnum . Accepted ) ;
98
+
99
+ ProcessConnectionList ( connectionList ) ;
100
+ }
101
+ catch ( Exception ex )
102
+ {
103
+ TraceSource . TraceEvent (
104
+ TraceEventType . Error , 0 ,
105
+ "Unhandled exception caught when fecthing list of connection request {1}" ,
106
+ ex ) ;
107
+ }
108
+ } , null , 0 , timeout ) ;
109
+ }
110
+
111
+ /// <summary>
112
+ /// Requests that <see cref="Listen"/> should stop.
113
+ /// </summary>
114
+ public void Stop ( )
115
+ {
116
+ connectionPollTimer . Dispose ( ) ;
117
+ connectionPollTimer = null ;
118
+ }
119
+
120
+ protected void ProcessConnectionList ( IEnumerable < UserConnection > connectionList )
121
+ {
122
+ if ( connectionList == null || _onConnectionRequest == null )
123
+ {
124
+ return ;
125
+ }
126
+
127
+ foreach ( var eventHandler in _onConnectionRequest . GetInvocationList ( ) )
128
+ {
129
+ NotifyAsync ( ( EventHandler < ConnectionRequestEventArgs > ) eventHandler , connectionList ) ;
130
+ }
131
+ }
132
+
54
133
/// <summary>
55
134
/// Get the status of a connection invitation to another user.
56
135
/// </summary>
@@ -120,5 +199,41 @@ private string GetStatusAsString(UserConnection.StatusEnum status)
120
199
return status . ToString ( ) . ToLower ( ) ;
121
200
}
122
201
}
202
+
203
+ protected async void NotifyAsync ( EventHandler < ConnectionRequestEventArgs > connectionEventHandler ,
204
+ IEnumerable < UserConnection > connectionList )
205
+ {
206
+ // Notify each handler in a separate task, maintaining the order of connections in the list, and
207
+ // get back to reading the connectio list again without waiting for listeners to process connection requests.
208
+ Task task ;
209
+ if ( _tasks . TryGetValue ( connectionEventHandler , out task ) )
210
+ {
211
+ await task ;
212
+ }
213
+ _tasks [ connectionEventHandler ] = Task . Run ( ( ) => Notify ( connectionEventHandler , connectionList ) ) ;
214
+ }
215
+
216
+ private void Notify ( EventHandler < ConnectionRequestEventArgs > connectionEventHandler ,
217
+ IEnumerable < UserConnection > connectionList )
218
+ {
219
+ foreach ( var connection in connectionList )
220
+ {
221
+ TraceSource . TraceEvent (
222
+ TraceEventType . Verbose , 0 ,
223
+ "Notifying listener about connection request for user with ID \" {0}\" and status \" {1}\" " ,
224
+ connection ? . UserId , connection ? . Status ) ;
225
+ try
226
+ {
227
+ connectionEventHandler . Invoke ( this , new ConnectionRequestEventArgs ( connection ) ) ;
228
+ }
229
+ catch ( Exception e )
230
+ {
231
+ TraceSource . TraceEvent (
232
+ TraceEventType . Error , 0 ,
233
+ "Unhandled exception caught when notifying listener about connection request for user with ID \" {0}\" : {1}" ,
234
+ connection ? . UserId , e ) ;
235
+ }
236
+ }
237
+ }
123
238
}
124
239
}
0 commit comments