public async Task <TResponse> DeserializeResponseAsync(IResponseFuture inputStream, AsyncOperationInfo operationInfo) { var sw = Stopwatch.StartNew(); await ThreadingUtils.ContinueAtThreadPull(); var loggedResponseFuture = new LoggingResponseFutureDecorator(inputStream, MAX_AMOUNT_OF_BYTES_INSIDE_LOG_ENTRY); TResponse response = null; using (Logger.Indent) { Logger.LogInfo(null, "Чтение ответа..."); try { response = await deserializeResponseAsync(loggedResponseFuture, operationInfo); logDataRead(); } catch (TimeoutException ex) { logError(ex); response = BuildErrorResponse(RequestStatus.READ_TIMEOUT); } catch (Exception ex) { logError(ex); response = BuildErrorResponse(RequestStatus.DESERIALIZATION_ERROR); } } return(response); void logDataRead() { Logger.LogInfo(null, $"Пакет ответа был успешно прочитан{Global.NL}Полная длина: {loggedResponseFuture.ReadCount}, длительность чтения: {sw.Elapsed.TotalMilliseconds.ToString("F2")} мс{getBufferRepresentation()}"); } void logError(Exception ex) { Logger.LogError(null, $"Ошибка во время чтения/десериализации пакета. Было прочитано: {loggedResponseFuture.ReadCount}, длительность чтения: {sw.Elapsed.TotalMilliseconds.ToString("F2")} мс{getBufferRepresentation()}", ex); } string getBufferRepresentation() { var tooManyData = loggedResponseFuture.StorageCount < loggedResponseFuture.ReadCount; return($"{Global.NL}Первые {loggedResponseFuture.Capacity} байт из {loggedResponseFuture.ReadCount}".IfOrDefault(tooManyData) + $"{Global.NL}Данные<HEX>:{loggedResponseFuture.Storage.Select(b => b.ToString("X2").PadLeft(3)).Aggregate(" ")}" + $"{Global.NL}Данные<DEC>:{loggedResponseFuture.Storage.Select(b => b.ToString("D3").PadLeft(3)).Aggregate(" ")}"); } }
protected override async Task <SalachovResponse> deserializeResponseAsync(IResponseFuture inputStream, AsyncOperationInfo operationInfo) { SalachovResponse result = null; var answerIterator = new BackedResponseFutureDecorator(inputStream); if (DeviceId == RUSDeviceId.ALL) // If broadcast { Logger.LogInfo(null, "Чтение ответа не требуется, поскольку запрос не предполагает ответа"); result = new SalachovResponse(this, RequestStatus.OK, ResponseData.NONE, ResponseData.NONE, ResponseData.NONE); } else { var header = await answerIterator.WaitAsync(4, WaitMode.EXACT, operationInfo); var headerValid = header.SequenceEqual(_header); var length = _hasLengthField ? bytesToWord(await answerIterator.WaitAsync(2, WaitMode.EXACT, operationInfo)) : 0; var isLengthValid = _responseFullLength.IsUnknown ? true : (length + _header.Length + 2 /* CRC */ + (_hasLengthField ? 2 : 0)) == _responseFullLength.Length; var answerBody = await answerIterator.WaitAsync(length, WaitMode.EXACT, operationInfo); var calculatedChecksum = _checksum.ComputeChecksum(answerIterator.Storage); var sentChecksum = bytesToWord(await answerIterator.WaitAsync(2, WaitMode.EXACT, operationInfo)); var isCRCValid = calculatedChecksum == sentChecksum; if (isCRCValid) { if (headerValid) { if (isLengthValid) { result = instantiateResponse(RequestStatus.OK); } else { Logger.LogError(null, $"Некорректная длина. Ожидалась: {_responseFullLength.Length.ToString("X2")}, пришла в пакете: {(_hasLengthField ? length.ToString("X2") : "NONE")}"); result = instantiateResponse(RequestStatus.WRONG_LENGTH); } } else { Logger.LogError(null, $"Некорректный заголовок. Ожидалась: {_header.ToHex()}, пришла в пакете: {header.ToHex()}"); result = instantiateResponse(RequestStatus.WRONG_HEADER); } } else { Logger.LogError(null, $"CRC не совпадает. Ожидалась: {calculatedChecksum.ToString("X2")}, пришла в пакете: {sentChecksum.ToString("X2")}"); result = instantiateResponse(RequestStatus.WRONG_CHECKSUM); } SalachovResponse instantiateResponse(RequestStatus status) { return(new SalachovResponse(this, status, new InMemoryResponseData(answerIterator.Storage), new InMemoryResponseData(header), new InMemoryResponseData(answerBody))); } } return(result); }
Task <IResponse> IRequest.DeserializeResponseAsync(IResponseFuture inputStream, AsyncOperationInfo operationInfo) { return(DeserializeResponseAsync(inputStream, operationInfo).ThenDo(r => (IResponse)r)); }
protected abstract Task <TResponse> deserializeResponseAsync( IResponseFuture inputStream, AsyncOperationInfo operationInfo);
public ResponseFutureProxyBase(IResponseFuture @base) { _base = @base ?? throw new ArgumentNullException(nameof(@base)); }
protected override async Task <IResponse> deserializeResponseAsync(IResponseFuture inputStream, AsyncOperationInfo operationInfo) { IResponse result = null; Stream stream = createReadBuffer(); var dataRead = new StreamResponseData(stream); switch (_responseInfo.ReadMode) { case ResponseReadMode.TILL_TIMEOUT: try { var readTimeout = new Timeouter(CHUNK_READ_TIMEOUT); while (true) { var piece = await inputStream.WaitAsync(READ_CHUNK_SIZE, WaitMode.NO_MORE_THAN, operationInfo); await stream.WriteAsync(piece, 0, piece.Length); operationInfo.Progress.AddProgress(piece.Length); if (piece.Length != 0) { readTimeout.Restart(); } readTimeout.ThrowIfTimeout(); } } catch (TimeoutException) { } break; case ResponseReadMode.CONSTRAINED_BY_ANSWER: var max = _responseInfo.ResponseFullLength.IsUnknown ? long.MaxValue : _responseInfo.ResponseFullLength.Length; for (long i = 0; i < max; i++) { var data = await inputStream.WaitAsync(1, WaitMode.EXACT, operationInfo); stream.WriteByte(data.Single()); operationInfo.Progress.AddProgress(1D / max); } break; case ResponseReadMode.READ_BY_TARGET: result = await _deviceRequest.DeserializeResponseAsync(inputStream, operationInfo); break; default: throw new NotSupportedException(); } if (result == null) { if (!_responseInfo.ResponseFullLength.IsUnknown && _responseInfo.ExpectedAnswer != null && !stream.AsEnumerable().Take((int)_responseInfo.ResponseFullLength.Length).SequenceEqual(_responseInfo.ExpectedAnswer)) { result = new FTDIBoxResponse(this, RequestStatus.NOT_EXPECTED_RESPONSE_BYTES, dataRead, null, null); } else { await stream.FlushAsync(operationInfo.CancellationToken); IResponseData serviceSection = null; IResponseData bodySection = null; switch (Address) { case FTDIBoxRequestAddress.HS_SET_LOW_SPEED_MODE: case FTDIBoxRequestAddress.LS_SET_HIGH_SPEED_MODE: case FTDIBoxRequestAddress.HS_ACTIVATE_CHANNEL4: case FTDIBoxRequestAddress.LS_ACTIVATE_CHANNEL4: break; case FTDIBoxRequestAddress.HS_GET_FLASH_LENGTH: case FTDIBoxRequestAddress.HS_READ_ALL_FLASH: serviceSection = new ResponseDataAreaProxy(dataRead, dataRead.Count - 6, dataRead.Count); bodySection = new ResponseDataAreaProxy(dataRead, 0, dataRead.Count - 6); break; case FTDIBoxRequestAddress.LS_DEVICE_REQUEST: bodySection = dataRead; break; default: throw new NotSupportedException(); } result = new FTDIBoxResponse(this, RequestStatus.OK, dataRead, serviceSection, bodySection); } } return(result); Stream createReadBuffer() { Stream buffer = new MemoryStream(); if (Address == FTDIBoxRequestAddress.HS_READ_ALL_FLASH) { buffer = _scope.TryGetFirstParameter <FlashDumpStreamParameter>()?.Stream; if (buffer == null) { var path = Path.GetTempFileName(); buffer = File.Open(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); Logger.LogInfo(null, $"Создан буфер чтения по пути {path}"); } else { Logger.LogInfo(null, $"Буфер чтения предоставлен через параметр"); } } return(buffer); } }
public LoggingResponseFutureDecorator(IResponseFuture @base, int storageCapacity) : base(@base) { Capacity = storageCapacity; }
public BackedResponseFutureDecorator(IResponseFuture @base) : base(@base) { }