/// <summary>
 /// Simulates a client message being sent to the server.
 /// </summary>
 /// <param name="message">The message.</param>
 public void QueueClientMessage(MockClientMessage message)
 {
     Validation.ThrowIfNull(message, nameof(message));
     lock (_incomingMessageQueue)
     {
         _incomingMessageQueue.Enqueue(message);
     }
 }
        /// <summary>
        /// Sends data over the connection asynchronously.
        /// </summary>
        /// <param name="buffer">The buffer to be sent over the connection.</param>
        /// <param name="messageType">TIndicates whether the application is sending a binary or text message.</param>
        /// <param name="endOfMessage">Indicates whether the data in "buffer" is the last part of a message.</param>
        /// <param name="cancellationToken">The token that propagates the notification that operations should be canceled.</param>
        /// <returns>Task.</returns>
        public Task SendAsync(ArraySegment <byte> buffer, ClientMessageType messageType, bool endOfMessage, CancellationToken cancellationToken)
        {
            var message = new MockClientMessage(buffer.ToArray(), messageType, endOfMessage);

            lock (_outgoingMessageQueue)
            {
                _outgoingMessageQueue.Enqueue(message);
            }

            return(Task.CompletedTask);
        }
        /// <summary>
        /// Receives data from the connection asynchronously.
        /// </summary>
        /// <param name="buffer">References the application buffer that is the storage location for the received
        ///  data.</param>
        /// <param name="cancelToken">Propagates the notification that operations should be canceled.</param>
        /// <returns>Task&lt;IClientConnectionResult&gt;.</returns>
        public async Task <IClientConnectionReceiveResult> ReceiveAsync(ArraySegment <byte> buffer, CancellationToken cancelToken = default)
        {
            if (_connectionClosed)
            {
                throw new InvalidOperationException("can't recieve on a closed connection");
            }

            while (_currentMessage == null && !_connectionClosed)
            {
                lock (_incomingMessageQueue)
                {
                    if (_incomingMessageQueue.Count > 0)
                    {
                        _currentMessage = _incomingMessageQueue.Dequeue();
                    }
                }

                if (_currentMessage == null)
                {
                    await Task.Delay(5).ConfigureAwait(false);
                }
            }

            if (_currentMessage == null)
            {
                throw new InvalidOperationException("No message was recieved, this should be impossible.");
            }

            bool hasRemainingBytes = _currentMessage.ReadNextBytes(buffer, out int bytesRead);

            var result = new MockClientMessageResult(
                bytesRead,
                _currentMessage.MessageType,
                !hasRemainingBytes,
                !hasRemainingBytes ? _currentMessage.CloseStatus : null,
                !hasRemainingBytes ? _currentMessage.CloseStatusDescription : null);

            _connectionClosed = !hasRemainingBytes && result.CloseStatus != null;
            if (_connectionClosed && _autoCloseOnReadCloseMessage)
            {
                await this
                .CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, cancelToken)
                .ConfigureAwait(false);
            }

            // clear the message from the being read if its complete
            if (!hasRemainingBytes)
            {
                _currentMessage = null;
            }

            return(result);
        }