private async Task ManualStartClientConnectionLoop(TcpClient client, IManagedNetworkClient <TPayloadReadType, TPayloadWriteType> internalNetworkClient, ManagedClientSession <TPayloadReadType, TPayloadWriteType> networkSession)
        {
            //So that sessions invoking the disconnection can internally disconnect to
            networkSession.OnSessionDisconnection += async(source, args) => await internalNetworkClient.DisconnectAsync(0).ConfigureAwait(false);

            //TODO: Better way to syncronize the strategies used?
            var dispatchingStrategy = new InPlaceAsyncLockedNetworkMessageDispatchingStrategy <TPayloadReadType, TPayloadWriteType>();

            while (client.Connected && internalNetworkClient.isConnected)
            {
                NetworkIncomingMessage <TPayloadWriteType> message = await internalNetworkClient.ReadMessageAsync(CancellationToken.None)
                                                                     .ConfigureAwait(false);

                //We don't want to stop the client just because an exception occurred.
                try
                {
                    //TODO: This will work for World of Warcraft since it requires no more than one packet
                    //from the same client be handled at one time. However it limits throughput and maybe we should
                    //handle this at a different level instead.
                    await dispatchingStrategy.DispatchNetworkMessage(new SessionMessageContext <TPayloadReadType, TPayloadWriteType>(networkSession, message))
                    .ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    //TODO: Remove this console log
                    Logger.Error($"[Error]: {e.Message}\n\nStack: {e.StackTrace}");
                }
            }

            client.Dispose();

            //TODO: Should we tell the client something when it ends?
            await networkSession.DisconnectClientSession()
            .ConfigureAwait(false);
        }
Example #2
0
        /// <inheritdoc />
        public SessionMessageContext(ManagedClientSession <TPayloadWriteType, TPayloadReadType> session, NetworkIncomingMessage <TPayloadReadType> message)
        {
            if (session == null)
            {
                throw new ArgumentNullException(nameof(session));
            }
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            Session = session;
            Message = message;
        }
        /// <inheritdoc />
        public async Task <NetworkIncomingMessage <TReadPayloadBaseType> > ReadAsync(CancellationToken token)
        {
            using (await ReadLock.LockAsync(token).ConfigureAwait(false))
            {
                //We want to clear the read buffers after reaiding a full message.
                NetworkIncomingMessage <TReadPayloadBaseType> message = await DecoratedClient.ReadAsync(token)
                                                                        .ConfigureAwait(false);

                //Do not call the object's ClearBuffer or we will deadlock; isn't re-enterant
                await DecoratedClient.ClearReadBuffers()
                .ConfigureAwait(false);

                //Could be null if the socket disconnected
                return(message);
            }
        }
 /// <inheritdoc />
 public abstract Task OnNetworkMessageRecieved(NetworkIncomingMessage <TPayloadReadType> message);
        /// <summary>
        /// Reading the incoming messages from the network client and schedules them
        /// with the incoming message queue.
        /// </summary>
        /// <returns>A future which will complete when the client disconnects.</returns>
        private async Task EnqueueIncomingMessages()
        {
            //We need a token for canceling this task when a user disconnects
            CancellationToken incomingCancellationToken = CreateNewManagedCancellationTokenSource().Token;

            try
            {
                while (!incomingCancellationToken.IsCancellationRequested)
                {
                    NetworkIncomingMessage <TPayloadReadType> message = await UnmanagedClient.ReadAsync(incomingCancellationToken)
                                                                        .ConfigureAwait(false);

                    //If the message is null then the connection is no longer valid
                    //The socket likely disconnected so we should stop the network thread
                    if (message == null)
                    {
                        //We have to publish a null so it can be consumed by the user
                        //to know that the socket is dead
                        await IncomingMessageQueue.EnqueueAsync(null, CancellationToken.None)
                        .ConfigureAwait(false);

                        StopNetwork();
                    }


                    //if have to check the token again because the message may be null and may have been canceled mid-read
                    if (incomingCancellationToken.IsCancellationRequested)
                    {
                        continue;
                    }

                    //Try to notify interceptors of a payload that has come in. They may want it
                    if (!InterceptorManager.TryNotifyOutstandingInterceptors(message.Payload))
                    {
                        await IncomingMessageQueue.EnqueueAsync(message, incomingCancellationToken)
                        .ConfigureAwait(false);
                    }
                }
            }
            catch (TaskCanceledException e)
            {
                //This is an expected exception that happens when the token is canceled
                if (Logger.IsDebugEnabled)
                {
                    Logger.Debug($"Expected Task Canceled Exception: {e.Message}\n\n Stack: {e.StackTrace}");
                }

                //We cannot rethrow because this can cause application instability on threadpools
            }
            catch (Exception e)
            {
                if (Logger.IsErrorEnabled)
                {
                    Logger.Error($"Error: {e.Message}\n\n Stack: {e.StackTrace}");
                }

                //We cannot rethrow because this can cause application instability on threadpools
            }
            finally
            {
                try
                {
                    await DisconnectAsync(0);
                }
                catch (Exception)
                {
                }
            }

            //TODO: Should we do anything after the dispatch has stopped?
        }
 /// <inheritdoc />
 public override Task OnNetworkMessageRecieved(NetworkIncomingMessage <TPayloadReadType> message)
 {
     //TODO: How should we handle server not having interceptor
     return(AuthMessageHandlerService.TryHandleMessage(MessageContextFactory.CreateMessageContext(Connection, SendService, Details), message));
 }