/// <summary>Registers the client described by client.</summary>
        /// <param name="client">The client.</param>
        public static void RegisterClient(WebsocketClientInformation client)
        {
            if (client == null)
            {
                return;
            }

            // add this client to our dictionary
            if (!_instance._guidInfoDict.ContainsKey(client.Uid))
            {
                _instance._guidInfoDict.Add(client.Uid, client);
            }

            if (!_instance._clientsAndTimeouts.ContainsKey(client.Uid))
            {
                _instance._clientsAndTimeouts.TryAdd(client.Uid, DateTime.Now.Ticks + _keepaliveTimeoutTicks);
            }
        }
        /// <summary>Expires and Removes the token described by tokenGuid.</summary>
        /// <param name="tokenGuid">Unique identifier for the token.</param>
        public static void ExpireToken(Guid tokenGuid)
        {
            if (!_instance._guidTokenDict.ContainsKey(tokenGuid))
            {
                return;
            }

            Guid clientGuid = _instance._guidTokenDict[tokenGuid].BoundClient;

            if (clientGuid == Guid.Empty)
            {
                _instance._guidTokenDict.Remove(tokenGuid);
                return;
            }

            if (!_instance._guidInfoDict.ContainsKey(clientGuid))
            {
                _instance._guidTokenDict.Remove(tokenGuid);
                return;
            }

            SubscriptionWsBindingToken token      = _instance._guidTokenDict[tokenGuid];
            WebsocketClientInformation clientInfo = _instance._guidInfoDict[clientGuid];

            // if the client only has one token (this one), deactivate everything
            if (clientInfo.BoundTokenGuids.Count == 1)
            {
                foreach (string subscriptionId in token.SubscriptionIds)
                {
                    RemoveSubscriptionFromClient(subscriptionId, clientGuid);
                }
            }

            // TODO: for now, just assume it has been replaced with a newer replica
            _instance._guidTokenDict.Remove(tokenGuid);
            _instance._guidInfoDict[clientGuid].BoundTokenGuids.Remove(tokenGuid);

            return;
        }
        /// <summary>Attempts to get client a WebsocketClientInformation from the given GUID.</summary>
        /// <param name="guid">  Unique identifier.</param>
        /// <param name="client">[out] The client.</param>
        /// <returns>True if it succeeds, false if it fails.</returns>
        public static bool TryGetClient(Guid guid, out WebsocketClientInformation client)
        {
            if (guid == Guid.Empty)
            {
                client = null;
                return(false);
            }

            // check for this client existing
            if (_instance._guidInfoDict.ContainsKey(guid))
            {
                // set our client object
                client = _instance._guidInfoDict[guid];

                // success
                return(true);
            }

            // not found
            client = null;

            // failure
            return(false);
        }
예제 #4
0
        /// <summary>Executes the asynchronous on a different thread, and waits for the result.</summary>
        /// <param name="context">The context.</param>
        /// <returns>An asynchronous result.</returns>
        public async Task InvokeAsync(HttpContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            // check for requests to our URL
            if (!context.Request.Path.Equals(_matchUrl, StringComparison.OrdinalIgnoreCase))
            {
                // pass to next caller in chain
                await _nextDelegate.Invoke(context).ConfigureAwait(false);

                return;
            }

            // check for not being a WebSocket request
            if (!context.WebSockets.IsWebSocketRequest)
            {
                Console.WriteLine($" <<< Received non-websocket request at: {_matchUrl}");
                context.Response.StatusCode = 400;
                return;
            }

            string payloadType = string.Empty;

            // check for specified payload type
            if (context.Request.Query.ContainsKey("payload-type"))
            {
                payloadType = context.Request.Query["payload-type"];
            }

            // figure out the websocket payload type
            switch (payloadType)
            {
            case WebsocketClientInformation.WebsocketPayloadTypes.Empty:
                break;

            case WebsocketClientInformation.WebsocketPayloadTypes.IdOnly:
                break;

            case WebsocketClientInformation.WebsocketPayloadTypes.FullResource:
                break;

            case WebsocketClientInformation.WebsocketPayloadTypes.R4:
                break;

            default:
                // assume R4
                payloadType = WebsocketClientInformation.WebsocketPayloadTypes.R4;
                break;
            }

            // create our management record
            WebsocketClientInformation client = new WebsocketClientInformation()
            {
                Uid               = Guid.NewGuid(),
                PayloadType       = payloadType,
                MessageQ          = new ConcurrentQueue <string>(),
                SubscriptionIdSet = new HashSet <string>(),
            };

            // accept this connection
            await AcceptAndProcessWebSocket(context, client).ConfigureAwait(false);
        }
예제 #5
0
        /// <summary>Accept and process web socket.</summary>
        /// <param name="context">The context.</param>
        /// <param name="client"> The client.</param>
        /// <returns>An asynchronous result.</returns>
        private async Task AcceptAndProcessWebSocket(
            HttpContext context,
            WebsocketClientInformation client)
        {
            // prevent WebSocket errors from bubbling up
            try
            {
                // accept the connection
                using (var webSocket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false))
                {
                    // register our client
                    WebsocketManager.RegisterClient(client);

                    // create a cancellation token source so we can cancel our read/write tasks
                    CancellationTokenSource processCancelSource = new CancellationTokenSource();

                    // link our local close with the application lifetime close for simplicity
                    CancellationToken cancelToken = CancellationTokenSource.CreateLinkedTokenSource(
                        _applicationStopping,
                        processCancelSource.Token).Token;

                    Task[] webSocketTasks = new Task[2];

                    // create send task
                    webSocketTasks[0] = Task.Run(async() =>
                    {
                        try
                        {
                            await WriteClientMessages(webSocket, client.Uid, cancelToken).ConfigureAwait(false);
                        }
                        finally
                        {
                            // **** cancel read if write task has exited ***
                            processCancelSource.Cancel();
                        }
                    });

                    // create receive task
                    webSocketTasks[1] = Task.Run(async() =>
                    {
                        try
                        {
                            await ReadClientMessages(webSocket, client.Uid, cancelToken).ConfigureAwait(false);
                        }
                        finally
                        {
                            // cancel write if read task has exited
                            processCancelSource.Cancel();
                        }
                    });

                    // start tasks and wait for them to complete
                    await Task.WhenAll(webSocketTasks).ConfigureAwait(false);

                    // close our web socket (do not allow cancel)
                    await webSocket.CloseAsync(
                        WebSocketCloseStatus.EndpointUnavailable,
                        "Connection closing",
                        CancellationToken.None).ConfigureAwait(false);
                }
            }
            catch (WebSocketException wsEx)
            {
                // just log for now
                Console.WriteLine($" <<< caught exception: {wsEx.Message}");
            }
            finally
            {
                WebsocketManager.UnregisterClient(client.Uid);
            }

            return;
        }