Example #1
0
        public Task ListenAsync(CancellationToken ct)
        {
            return NetworkConnection.ListenAsync(_port, async connection =>
            {
                var lineNeedsToBeReset = false;
                
                var cts = new CancellationTokenSource();
                using (var timer = new Timer(state =>
                {
                    Util.Log("Idle Timeout");
                    cts.Cancel();
                }, null, _idleTimeout, Timeout.InfiniteTimeSpan))
                {
                    while (connection.Connected && !cts.Token.IsCancellationRequested)
                    {
                        var receiver = new Receiver(connection.Stream);
                        var message = await receiver.ReceiveMessageAsync(cts.Token);
                        if (message == null)
                            return;

                        // Stop the idle timeout timer, since we have data
                        timer.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);

                        // Ignore any backlog of messages
                        if (!message.LastInBuffer)
                        {
                            lineNeedsToBeReset = true;
                            continue;
                        }

                        // Make sure a good message came through
                        if (message.Response == null)
                            continue;

                        using (var client = new SynelClient(connection, message.Response.TerminalId))
                        {
                            // Reset the line if we detected a backlog earlier
                            if (lineNeedsToBeReset)
                            {
                                client.Terminal.ResetLine();
                                lineNeedsToBeReset = false;
                            }

                            var notification = new PushNotification(client, message.Response);

                            // Only push valid notifications
                            if (Enum.IsDefined(typeof (NotificationType), notification.Type))
                            {
                                Util.Log(string.Format("Listener Received: {0}", message.RawResponse), connection.RemoteEndPoint.Address);

                                if (AsyncMessageReceivedHandler != null)
                                {
                                    await AsyncMessageReceivedHandler(notification);
                                }
                            }
                        }
                    }
                }
            }, ct);
        }
Example #2
0
        /// <summary>
        /// Returns an awaitable task that communicates with the terminal by sending a request and receiving a response.
        /// </summary>
        /// <param name="requestCommand">The request command to send.</param>
        /// <param name="dataToSend">Any data that should be sent along with the command.</param>
        /// <param name="attempts">Number of times to attempt the command until receiving a response.</param>
        /// <param name="timeoutms">The timeout, in milliseconds, to wait for a response.</param>
        /// <param name="validResponses">If specified, the response must start with one of the valid responses (omit the terminal id).</param>
        /// <returns>A task that yields a validated <see cref="Response"/> object.</returns>
        internal async Task<Response> SendAndReceiveAsync(RequestCommand requestCommand, string dataToSend = null, int attempts = 1, int timeoutms = 5000, params string[] validResponses)
        {
            if (!Connected)
                throw new InvalidOperationException("Not connected!");

            // augment valid responses with the terminal id
            if (validResponses.Length > 0)
            {
                var tid = Util.TerminalIdToChar(_terminalId).ToString(CultureInfo.InvariantCulture);
                validResponses = validResponses.Select(x => x.Insert(1, tid)).ToArray();
            }

            var receiver = new Receiver(_connection.Stream);

            // retry loop
            for (int i = 1; i <= MaxRetries; i++)
            {
                try
                {
                    var cts = new CancellationTokenSource();
                    using (var timer = new Timer(state => cts.Cancel(), null, timeoutms, Timeout.Infinite))
                    {
                        // Send the request
                        var rawRequest = CreateCommand(requestCommand, dataToSend);
                        await SendAsync(rawRequest);

                        // Wait for the response or timeout
                        var message = await receiver.ReceiveMessageAsync(cts.Token);
                        if (message == null)
                            continue;

                        // Stop the idle timeout timer, since we have data
                        timer.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);

                        // Don't ever handle host query responses here.
                        if (message.RawResponse[0] == 'q')
                            continue;

                        // If the valid list is populated, don't handle responses that aren't in it.
                        if (validResponses.Length > 0 && !validResponses.Any(x => message.RawResponse.StartsWith(x)))
                            continue;

                        // Ignore responses intended for other terminals
                        if (message.Response != null && message.Response.TerminalId != _terminalId)
                            continue;

                        if (message.RawResponse != null)
                            Util.Log("Received: " + message.RawResponse, RemoteAddress);

                        if (message.Exception != null)
                            throw message.Exception;

                        if (message.Response == null)
                        {
                            if (i < attempts && i < MaxRetries)
                            {
                                Util.Log("No response.  Retrying...", RemoteAddress);
                                continue;
                            }

                            throw new TimeoutException("No response received from the terminal.");
                        }

                        return message.Response;
                    }
                }
                catch (InvalidCrcException)
                {
                    // swallow these until the retry limit is reached
                    if (i < MaxRetries)
                        Util.Log("Bad CRC.  Retrying...", RemoteAddress);
                }
            }

            // We've hit the retry limit, throw a CRC exception.
            throw new InvalidCrcException(string.Format("Retried the operation {0} times, but still got CRC errors.", MaxRetries));
        }