Example #1
0
        /// <inheritdoc />
        public virtual async Task DisconnectAsync(int delay)
        {
            await UnmanagedClient.DisconnectAsync(delay)
            .ConfigureAwait(false);

            isConnected = false;
        }
        /// <inheritdoc />
        public override async Task <SendResult> SendMessageImmediately <TPayloadType>(TPayloadType payload, DeliveryMethod method)
        {
            await UnmanagedClient.WriteAsync(payload)
            .ConfigureAwait(false);

            return(SendResult.Sent);
        }
        /// <inheritdoc />
        public override async Task <SendResult> SendMessage <TPayloadType>(TPayloadType payload, DeliveryMethod method)
        {
            if (this.isConnected)
            {
                try
                {
                    //TODO: Handle delivery method
                    //TODO: What should we do when this is being called during a critical section? Won't we want to queue this up so serialization and encryption
                    //doesn't block?
                    await UnmanagedClient.WriteAsync(payload)
                    .ConfigureAwait(false);
                }
                catch (NetworkDisconnectedException e)
                {
                    //The client/session/network that the caller
                    //was trying to send a message to is disconnected. This doesn't mean
                    //we want to throw though. Catching exceptions is EXPENSIVE but this should only happen on a rare occasion
                    //and the caller will see that the client is disconnected, and make decisions based on that
                    //and of course disconnection logic will likely be happening else where during this
                    return(SendResult.Disconnected);
                }

                //We should let other exceptions be thrown though, as they aren't related to connectivity.
            }
            else
            {
                return(SendResult.Disconnected);
            }

            return(SendResult.Sent);
        }
Example #4
0
 /// <inheritdoc />
 public Task WriteAsync(byte[] bytes, int offset, int count)
 {
     //TODO: This is a hack, but it was the quickest way to implement this feature. We need to bypass the highlevel networking sometimes.
     try
     {
         return(((IBytesWrittable)UnmanagedClient).WriteAsync(bytes, offset, count));
     }
     catch (Exception e)
     {
         throw new InvalidOperationException($"Cannot write bytes to Type: {UnmanagedClient.GetType().Name}. Does not imlpement {nameof(IBytesWrittable)}. Exception: {e.Message} \n\n Stack: {e.StackTrace}", e);
     }
 }
Example #5
0
        /// <inheritdoc />
        public virtual async Task <bool> ConnectAsync(string address, int port)
        {
            //Disconnect if we're already connected
            if (isConnected)
            {
                await DisconnectAsync(0)
                .ConfigureAwait(false);
            }

            //This COULD return false, so we need to handle that
            isConnected = await UnmanagedClient.ConnectAsync(address, port)
                          .ConfigureAwait(false);

            return(isConnected);
        }
        /// <summary>
        /// Dispatches the outgoing messages scheduled to be send
        /// over the network.
        /// </summary>
        /// <returns>A future which will complete when the client disconnects.</returns>
        private async Task DispatchOutgoingMessages()
        {
            try
            {
                //We need a token for canceling this task when a user disconnects
                CancellationToken dispatchCancelation = CreateNewManagedCancellationTokenSource().Token;

                while (!dispatchCancelation.IsCancellationRequested)
                {
                    TPayloadWriteType payload = await OutgoingMessageQueue.DequeueAsync(dispatchCancelation)
                                                .ConfigureAwait(false);

                    await UnmanagedClient.WriteAsync(payload)
                    .ConfigureAwait(false);
                }
            }
            catch (TaskCanceledException e)
            {
                //Supress this exception. We don't care about it. It's expected.
                //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?
        }
        /// <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 <NetworkIncomingMessage <TPayloadReadType> > ReadMessageAsync(CancellationToken token)
 {
     return(UnmanagedClient.ReadAsync(token));
 }