Пример #1
0
        /// <summary>
        /// Retrieves the next EFT response from the client
        /// </summary>
        /// <param name="cancellationToken">The token to monitor for cancellation requests</param>
        /// <returns> An EFTResponse if one could be read, otherwise null </returns>
        /// <exception cref="ConnectionException">The socket is closed.</exception>
        /// <exception cref="TaskCanceledException">The task was cancelled by cancellationToken</exception>
        public async Task <EFTResponse> ReadResponseAsync(System.Threading.CancellationToken cancellationToken)
        {
            // Clear the receive buffer if we have been waiting for more than
            // 5 seconds for the remaining parts of the message to arrive
            var tc = System.Environment.TickCount;

            if (_recvBufWaiting && tc - _recvTickCount > 5000 && _recvBuf.Length > 0)
            {
                Log(LogLevel.Debug, tr => tr.Set($"Data is being cleared from the buffer due to a timeout. Content {_recvBuf.ToString()}"));
                _recvBufWaiting = false;
                _recvBuf.Clear();
            }

            // Only try to read more data if our receive buffer is empty
            Log(LogLevel.Debug, tr => tr.Set($"ReadResponseAsync() _recvBuf.Length={_recvBuf.Length} _recvBufWaiting={_recvBufWaiting}"));
            if (_recvBuf.Length == 0 || _recvBufWaiting == true)
            {
                var bytesRead = 0;
                try
                {
                    bytesRead = await _clientStream.ReadResponseAsync(_buffer, cancellationToken);

                    _recvTickCount = System.Environment.TickCount;
                }
                catch (TaskCanceledException e)
                {
                    Log(LogLevel.Debug, tr => tr.Set($"Socket read cancelled", e));
                    throw e;
                }
                catch (Exception e)
                {
                    Log(LogLevel.Error, tr => tr.Set($"An error occured sending the request", e));
                    Disconnect();
                    throw new ConnectionException(e.Message, e.InnerException);
                }

                // Check for socket closed
                if (bytesRead <= 0)
                {
                    Log(LogLevel.Error, tr => tr.Set("Recv 0 bytes. Socket closed"));
                    Disconnect();
                    throw new ConnectionException("Socket closed.");
                }

                var msgString = DirectEncoding.DIRECT.GetString(_buffer, 0, bytesRead);
                Log(LogLevel.Info, tr => tr.Set($"Rx {msgString}"));
                // Append receive data to our buffer
                _recvBuf.Append(msgString);
            }

            // Keep parsing until no more characters
            try
            {
                bool isXMLFormatted = false;
                int  index          = 0;
                while (index < _recvBuf.Length)
                {
                    // If the current char isn't #/& then keep cycling through the message until we find one
                    if (_recvBuf[index] != (byte)'#' && !(isXMLFormatted = _recvBuf[index] == (byte)'&'))
                    {
                        index++;
                        continue;
                    }

                    // We have a valid start char, check for length.
                    index++;

                    int lengthSize = isXMLFormatted ? 6 : 4;

                    // Check that we have enough bytes to validate length, if not wait for more
                    if (_recvBuf.Length < index + lengthSize)
                    {
                        Log(LogLevel.Debug, tr => tr.Set($"Unable to validate message header. Waiting for more data. Length:{_recvBuf.Length} Required:{index + lengthSize + 1}"));
                        _recvBufWaiting = true;
                        break;
                    }

                    // Try to get the length of the new message. If it's not a valid length
                    // we might have some corrupt data, keep checking for a valid message
                    var lengthStr = _recvBuf.Substring(index, lengthSize);
                    if (!int.TryParse(lengthStr, out int length) || length <= (lengthSize + 1))
                    {
                        Log(LogLevel.Error, tr => tr.Set($"Invalid length. Content:{lengthStr}"));
                        continue;
                    }

                    // We have a valid length
                    index += lengthSize;

                    // If the defined message length is > our current buffer size, wait for more data
                    if (_recvBuf.Length < index + length - (lengthSize + 1))
                    {
                        Log(LogLevel.Debug, tr => tr.Set($"Buffer is less than the indicate length. Waiting for more data. Length:{_recvBuf.Length < index} Required:{length - (lengthSize + 1)}"));
                        _recvBuf        = _recvBuf.Remove(0, index - (lengthSize + 1));
                        _recvBufWaiting = true;
                        break;
                    }

                    // We have a valid response
                    _recvBufWaiting = false;
                    var response = _recvBuf.Substring(index, length - (lengthSize + 1));
                    index += (length - (lengthSize + 1));
                    _recvBuf.Remove(0, index);

                    // Process the response
                    EFTResponse eftResponse = null;
                    try
                    {
                        //if (response.Equals("3M") || response.Equals("3C")) // FOR PREPRINT TIMEOUT
                        //if (response.Substring(0,2).Equals("3R")) // FOR PRINT TIMEOUT
                        //	System.Threading.Thread.Sleep(61000);
                        eftResponse = (isXMLFormatted) ? _parser.XMLStringToEFTResponse(response) : _parser.StringToEFTResponse(response);

                        // If we have an EFTResponse we need to return it.
                        if (eftResponse != null)
                        {
                            // Print requests need a response
                            if (eftResponse is EFTReceiptResponse)
                            {
                                await WriteRequestAsync(new EFTReceiptRequest());
                            }
                            //DialogUIHandler needs to be notified of display messages
                            else if (eftResponse is EFTDisplayResponse && DialogUIHandlerAsync != null)
                            {
                                await DialogUIHandlerAsync.HandleDisplayResponseAsync(eftResponse as EFTDisplayResponse);
                            }
                            else if (eftResponse.GetType() == _currentStartTxnRequest?.GetPairedResponseType() && DialogUIHandlerAsync != null)
                            {
                                await DialogUIHandlerAsync.HandleCloseDisplayAsync();
                            }


                            return(eftResponse);
                        }
                    }
                    catch (Exception e)
                    {
                        Log(LogLevel.Error, tr => tr.Set("Error parsing response string", e));
                    }
                }

                // Clear our buffer if we are all done (this shouldn't happen)
                if (index == _recvBuf.Length)
                {
                    _recvBufWaiting = false;
                    _recvBuf.Clear();
                }
            }
            catch (Exception ex)
            {
                Log(LogLevel.Error, tr => tr.Set($"Exception (ReceiveEFTResponse): {ex.Message}", ex));
                throw ex;
            }

            return(null);
        }