33using System ;
44using System . Collections . Concurrent ;
55using System . Collections . Generic ;
6+ using System . Collections . ObjectModel ;
67using System . IO ;
78using System . Linq ;
89using System . Net ;
@@ -23,6 +24,8 @@ public record class KestrelWebSocketServerStats(PagingMessageQueueStats QueueSta
2324public class KestrelWebSocketServer : IDisposable
2425{
2526 private ConcurrentDictionary < Guid , WebSocket > _clients ;
27+ private Dictionary < string , List < Guid > > path_to_clients_map ;
28+
2629 private ConcurrentDictionary < string , Func < KestrelWebSocketServerBehavior > > _behaviors ;
2730 private PagingMessageQueue _messageQueue = null ;
2831 private CancellationTokenSource _cancellationTokenSource = null ;
@@ -93,6 +96,25 @@ public IList<Guid> GetActiveConnectionIds()
9396 {
9497 return _clients . Where ( c => c . Value . State == WebSocketState . Open ) . Select ( c => c . Key ) . ToList ( ) ;
9598 }
99+ public List < WebSocket > GetWebsocketsByPath ( string path )
100+ {
101+ if ( ! path_to_clients_map . TryGetValue ( path , out List < Guid > sockets ) )
102+ return new List < WebSocket > ( ) ;
103+
104+
105+ var websocks = sockets . Select ( s =>
106+ {
107+ WebSocket ws = null ;
108+ if ( _clients . TryGetValue ( s , out ws )
109+ && ws . State == WebSocketState . Open )
110+ return ws ;
111+ return null ;
112+ } )
113+ . Where ( s => s != null )
114+ . ToList ( ) ;
115+
116+ return websocks ;
117+ }
96118
97119 public bool IsListening ( )
98120 {
@@ -167,6 +189,9 @@ public bool AddRouteBehavior<TBehavior>(string route, Func<TBehavior> p) where T
167189 {
168190 stopListeningThread ( ) ;
169191
192+ path_to_clients_map = new Dictionary < string , List < Guid > > ( ) ;
193+
194+
170195 var listenerThredStarted = new TaskCompletionSource < bool > ( ) ;
171196
172197 _cancellationTokenSource = new CancellationTokenSource ( ) ;
@@ -196,7 +221,17 @@ public bool AddRouteBehavior<TBehavior>(string route, Func<TBehavior> p) where T
196221 Func < KestrelWebSocketServerBehavior > builder = null ;
197222 if ( _behaviors . TryGetValue ( context . Request . Path , out builder ) )
198223 {
199- await handleClient ( context , builder , _cancellationTokenSource . Token ) ;
224+ List < Guid > sockets = null ;
225+ if ( ! path_to_clients_map . ContainsKey ( context . Request . Path ) )
226+ {
227+ sockets = new List < Guid > ( ) ;
228+ path_to_clients_map . Add ( context . Request . Path , sockets ) ;
229+ }
230+ else
231+ {
232+ sockets = path_to_clients_map [ context . Request . Path ] ;
233+ }
234+ await handleClient ( context , builder , sockets , _cancellationTokenSource . Token ) ;
200235 }
201236
202237 if ( context . Request . Path . HasValue
@@ -268,8 +303,13 @@ public Action<T, T2> MakeSafe<T, T2>(Action<T, T2> torun, string handlerName)
268303 }
269304 } ;
270305 }
306+ object socketsLock = new object ( ) ;
271307
272- private async Task handleClient < TWebSocketBehavior > ( HttpContext listenerContext , Func < TWebSocketBehavior > behaviorBuilder , CancellationToken token )
308+ private async Task handleClient < TWebSocketBehavior > (
309+ HttpContext listenerContext ,
310+ Func < TWebSocketBehavior > behaviorBuilder ,
311+ List < Guid > sockets ,
312+ CancellationToken token )
273313 where TWebSocketBehavior : KestrelWebSocketServerBehavior
274314 {
275315 Guid connectionId ;
@@ -314,6 +354,11 @@ private async Task handleClient<TWebSocketBehavior>(HttpContext listenerContext,
314354
315355 var safeconnected = MakeSafe < Guid , HttpContext > ( behavior . OnConnectionEstablished , "behavior.OnClientConnected" ) ;
316356 safeconnected ( connectionId , listenerContext ) ;
357+ lock ( socketsLock )
358+ {
359+ sockets . Add ( connectionId ) ;
360+ }
361+
317362 }
318363 catch ( Exception e )
319364 {
@@ -350,6 +395,10 @@ private async Task handleClient<TWebSocketBehavior>(HttpContext listenerContext,
350395
351396 webSocket ? . CleanupSendMutex ( ) ;
352397 listenerContext . Abort ( ) ;
398+ lock ( socketsLock )
399+ {
400+ sockets . Remove ( connectionId ) ;
401+ }
353402
354403 bool clientRemoved = _clients . TryRemove ( connectionId , out webSocket ) ;
355404 if ( clientRemoved )
0 commit comments