private async Task UnregisterChannels(WebSocket webSocket)
        {
            logger_.LogInformation("Unregistering websockets channels");
            bool removedSocket = false;
            int  tries         = 0;

            logger_.LogInformation("Removing websocket");
            while (!removedSocket && tries < MAX_CHANNEL_REMOVAL_TRIES)
            {
                removedSocket = subscriptions_.TryRemove(webSocket, out _);
                if (!removedSocket)
                {
                    ++tries;
                    await Task.Delay(TimeSpan.FromSeconds(DICT_REMOVAL_HOLDOFF));
                }
            }

            WebSocketStats.DecrementSubscriberCount();

            logger_.LogDebug("WebSocket status " + webSocket.State);

            logger_.LogInformation("Closing websocket");
            if (WebSocketCanSend(webSocket))
            {
                await webSocket.CloseOutputAsync(WebSocketCloseStatus.EndpointUnavailable, "All subscriptions cancelled", CancellationToken.None);

                logger_.LogInformation("Websocket closed");
            }

            logger_.LogInformation("Channel unregistered");

            //TODO
            // If the last subscriber is removed , clear the pending queue
        }
 private void RegisterChannel(WebSocket webSocket, string channelName)
 {
     if (subscriptions_.TryAdd(webSocket, new ConcurrentDictionary <string, byte>()))
     {
         WebSocketStats.IncrementSubscriberCount();
     }
     subscriptions_[webSocket].TryAdd(channelName, 1);
 }
        private async Task PublisherThread()
        {
            logger_.LogInformation("Initializing websocket publisher thread");
            try
            {
                var keepRunning = true;
                while (keepRunning)
                {
                    //This call blocks on an empty queue
                    var message = await messageQueue_.DequeueAsync();

                    WebSocketStats.IncrementOutputMessages();
                    WebSocketStats.DecrementPendingQueueSize();

                    keepRunning = message.MessageType != BitprimWebSocketMessageType.SHUTDOWN;
                    if (keepRunning)
                    {
                        var buffer = Encoding.UTF8.GetBytes(message.Content);

                        foreach (var ws in subscriptions_)
                        {
                            if (ws.Value.TryGetValue(message.ChannelName, out var dummy))
                            {
                                try
                                {
                                    await retryPolicy_.ExecuteAsync(async() =>
                                    {
                                        await ws.Key.SendAsync
                                        (
                                            new ArraySegment <byte>(buffer, 0, message.Content.Length),
                                            WebSocketMessageType.Text,
                                            true,
                                            CancellationToken.None
                                        );
                                        WebSocketStats.IncrementSentMessages();
                                        logger_.LogDebug($"Sent Frame {WebSocketMessageType.Text}: Len={message.Content.Length}, Fin={true}: {message.Content}");
                                    });
                                }
                                catch (WebSocketException ex)
                                {
                                    logger_.LogWarning(ex, "Maxed out retries sending to client, closing channels");
                                    await UnregisterChannels(ws.Key);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                logger_.LogError(ex, "PublisherThread error");
            }
            logger_.LogInformation("Closing websocket publisher thread");
        }
        private async Task Publish(string channelName, string item)
        {
            logger_.LogDebug($"Adding websocket message to queue ({channelName})");
            if (subscriptions_.Count <= 0)
            {
                logger_.LogDebug("Zero subscriptions. websocket message dropped");
            }
            else
            {
                await messageQueue_.EnqueueAsync
                (
                    new BitprimWebSocketMessage
                {
                    ChannelName = channelName,
                    Content     = item,
                    MessageType = BitprimWebSocketMessageType.PUBLICATION
                }
                );

                WebSocketStats.IncrementInputMessages();
                WebSocketStats.IncrementPendingQueueSize();
            }
        }