protected override async Task ExecuteAsync(HttpContext context, WebSocket socket) { await Task.Yield(); SemaphoreSlim socketSemaphore = new SemaphoreSlim(1, 1); async void handler(object sender, object e) { await socketSemaphore.WaitAsync(context.RequestAborted); try { if (socket.State != WebSocketState.Open) { return; } await socket.SendObjectAsync(e, context.RequestAborted).ConfigureAwait(false); } catch { // Ignored. } finally { socketSemaphore.Release(); } } var subscription = Guid.NewGuid().ToString("n"); using (var subscriptions = new JoinedDisposable()) { subscriptions.Add(string.Empty, _messenger.Subscribe($"WebSocket.{subscription}", handler)); await socket.SendObjectAsync(new { @event = "Connected", data = null as object }); while (socket.State == WebSocketState.Open) { var result = await socket.ReadObjectAsync <JObject>(context.RequestAborted); if (result == null) { continue; } if (result.TryGetValue("subscribe", StringComparison.OrdinalIgnoreCase, out var subscribeTo)) { HandleSubscribes(subscribeTo, subscription, subscriptions); } if (result.TryGetValue("unsubscribe", StringComparison.OrdinalIgnoreCase, out var unsubscribeFrom)) { HandleUnsubscribes(unsubscribeFrom, subscription, subscriptions); } } } }
private void HandleSubscribe(string item, string subscription, JoinedDisposable subscriptions) { void handler(object sender, object data) => _messenger.Publish($"WebSocket.{subscription}", sender, new { @event = item, data }); subscriptions.Add(item, _messenger.Subscribe($"Public.{item}", handler)); }
private void HandleSubscribes(JToken subscribeTo, string subscription, JoinedDisposable subscriptions) { if (subscribeTo.Type == JTokenType.String) { HandleSubscribe(subscribeTo.ToObject <string>(), subscription, subscriptions); } else if (subscribeTo.Type == JTokenType.Array) { var jarray = (JArray)subscribeTo; foreach (var item in jarray.Children().OfType <JValue>().Where(i => i.Type == JTokenType.String).Select(x => x.ToObject <string>())) { HandleSubscribe(item, subscription, subscriptions); } } }
void HandleUnsubscribe(string unsubscribeFrom, string subscription, JoinedDisposable subscriptions) { subscriptions.Remove(unsubscribeFrom); }