Beispiel #1
0
        private async Task WriteUnifiedFrameContent(
            AsyncBinaryWriter writer,
            int streamId,
            UnifiedFrameContent unifiedFrameContent)
        {
            if (this.logger.IsEnabled(LogLevel.Debug))
            {
                using var memoryStream = new MemoryStream();
                using var memoryWriter = new AsyncBinaryWriter(memoryStream, Encoding.ASCII, false);

                await WriteFrame(memoryWriter, 2, 0, streamId, unifiedFrameContent.ToByteArray())
                .ConfigureAwait(false);

                byte[] sendingBytes = memoryStream.ToArray();

                this.logger.LogDebug(
                    "Sending to {0} with streamId={1}:" + Environment.NewLine + "{2}",
                    unifiedFrameContent.Header.Path,
                    streamId,
                    HexUtils.Dump(new ReadOnlyMemory <byte>(sendingBytes)));
                await writer.WriteAsync(sendingBytes).ConfigureAwait(false);
            }
            else
            {
                await WriteFrame(writer, 2, 0, streamId, unifiedFrameContent.ToByteArray())
                .ConfigureAwait(false);
            }
        }
Beispiel #2
0
        private async Task <TResponse> InvokeAsync <TRequest, TResponse>(
            string path,
            TRequest request,
            MessageParser <TResponse> responseParser,
            DateTime?deadline = null,
            CancellationToken cancellationToken = default)
            where TRequest : IMessage <TRequest>
            where TResponse : IMessage <TResponse>
        {
            var promise = new TaskCompletionSource <UnifiedFrameContent>();

            await this.requestQueue
            .SendAsync(
                new RequestContext
            {
                Path                 = path,
                Message              = request,
                Deadline             = deadline,
                CancellationToken    = cancellationToken,
                TaskCompletionSource = promise,
            },
                cancellationToken)
            .ConfigureAwait(false);

            return(await promise.Task
                   .ContinueWith(
                       future =>
            {
                if (future.IsFaulted)
                {
                    throw new RpcException(new Status(
                                               StatusCode.Internal, future.Exception.ToString()));
                }

                if (future.IsCanceled)
                {
                    throw new RpcException(Status.DefaultCancelled);
                }

                UnifiedFrameContent frame = future.Result;
                if (frame.Header.Status == 0)
                {
                    return responseParser.ParseFrom(frame.Payload);
                }
                else
                {
                    throw new RpcException(new Status(
                                               (StatusCode)frame.Header.Status,
                                               frame.Header.StatusMessage));
                }
            },
                       cancellationToken,
                       TaskContinuationOptions.DenyChildAttach,
                       TaskScheduler.Default)
                   .ConfigureAwait(false));
        }
Beispiel #3
0
        private static async Task <TcpClient> StartPlcAsync(ILogger logger, string hostname, int port)
        {
            var fakePlc = new TcpClient(hostname, port);

            logger.LogInformation("Fake PLC connected.");

            NetworkStream networkStream = fakePlc.GetStream();

            using var reader = new AsyncBinaryReader(networkStream, Encoding.ASCII, true);
            using var writer = new AsyncBinaryWriter(networkStream, Encoding.ASCII, true);

            logger.LogDebug("Receiving TestRequest frame...");
            byte[] receivedBytes = await reader.ReadBytesAsync(0x53).ConfigureAwait(false);

            logger.LogInformation("Received {0} bytes.", 0x53);

            byte[] sendingPayload = new UnifiedFrameContent
            {
                Header = new Header {
                    Status = 0
                },
                Payload = new TestResponse
                {
                    A = 42,
                    B = 3.1415926F,
                    C = "Hello World!",
                    D = Timestamp.FromDateTimeOffset(DateTimeOffset.Parse("2019-10-29T21:42:13.00000+8:00", CultureInfo.InvariantCulture)),
                }.ToByteString(),
            }.ToByteArray();
            var sendingHeader = new FrameHeader(
                version: 1,
                type: 2,
                sequenceNumber: 0,
                streamId: 1,
                contentOffset: 20,
                contentLength: (ushort)sendingPayload.Length,
                contentChecksum: Crc32C.Crc32CAlgorithm.Compute(sendingPayload));

            logger.LogDebug("Sending TestResponse frame header...");
            await sendingHeader.WriteTo(writer).ConfigureAwait(false);

            logger.LogDebug("Sending TestResponse frame body...");
            await writer.WriteAsync(sendingPayload).ConfigureAwait(false);

            logger.LogInformation("Sent TestResponse.");

            return(fakePlc);
        }
Beispiel #4
0
        private async Task DrainSendingRequestContexts(AsyncBinaryWriter binaryWriter)
        {
            while (this.requestQueue.TryReceive(out RequestContext requestContext))
            {
                if (requestContext.CancellationToken.IsCancellationRequested ||
                    DateTime.Now > requestContext.Deadline)
                {
                    requestContext.TaskCompletionSource.SetResult(new UnifiedFrameContent
                    {
                        Header = new Header
                        {
                            Status        = (int)StatusCode.DeadlineExceeded,
                            StatusMessage = Status.DefaultCancelled.Detail,
                        },
                    });
                }

                var unifiedFrameContent = new UnifiedFrameContent()
                {
                    Header = new Header()
                    {
                        Path = requestContext.Path,
                    },
                    Payload = requestContext.Message.ToByteString(),
                };
                int streamId = Interlocked.Increment(ref this.counter);
                await this.WriteUnifiedFrameContent(binaryWriter, streamId, unifiedFrameContent)
                .ConfigureAwait(false);

                if (!this.receivingContexts.TryAdd(streamId, requestContext))
                {
                    throw new InvalidOperationException("Impossible");
                }

                this.logger.LogDebug("Request recorded as streamId={0}: {1}", streamId, requestContext.Message);
            }
        }