protected virtual TransportSendStats WriteMessageToBody(string formDataBoundary, Stream requestStream, IList <ITransportPacketInfo> packetInfos, IList <ConfigurationRequestDataItem> configurationsToDownloadInfos, SendIterationContext context) { var packetsSendStats = new Dictionary <ITransportPacketInfo, SendStats>(); using (var nonClosingStream = new NonClosingStreamWrapper(requestStream)) using (var sr = new StreamWriter(nonClosingStream, this.encoding ?? DefaultEncoding)) using (var formDataWriter = new FormDataWriter(nonClosingStream, formDataBoundary, this.encoding ?? DefaultEncoding)) { var maxMessageSizeReached = false; if (context.RequestConfigurations) { // записываем данные по конфигурациям for (int i = 0; i < configurationsToDownloadInfos.Count; i++) { var configurationsToDownloadInfo = configurationsToDownloadInfos[i]; // == confs[0]. var itemPrefix = string.Concat(TransportConstants.FormDataConfigurationProp, "[", i, "]."); // == confs[0].ProviderKey formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(ConfigurationRequestDataItem.ProviderKey)), configurationsToDownloadInfo.ProviderKey); formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(ConfigurationRequestDataItem.Token)), configurationsToDownloadInfo.Token); if (configurationsToDownloadInfo.StartPosition != null) { formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(ConfigurationRequestDataItem.StartPosition)), configurationsToDownloadInfo.StartPosition); } formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(ConfigurationRequestDataItem.IsCompleted)), configurationsToDownloadInfo.IsCompleted); } } if (context.SendPackets) { formDataWriter.ResetSize(); // записываем данные по пакетам for (int i = 0; i < packetInfos.Count; i++) { var packetInfo = packetInfos[i]; var sendStats = this.packetManager.ReadSendStats(packetInfo.ProviderKey, packetInfo.Id); if (sendStats?.TransferCompleted == true) { continue; } int packetBytesSended = sendStats?.TransferedBytes ?? 0; int bufferSize = 4096; bool packetTransferCompleted = false; string packetBlockHashStr; // == packets[0]. var itemPrefix = string.Concat(TransportConstants.FormDataPacketsProp, "[", i, "]."); // записываем данные пакета using (var packetStream = packetInfo.GetReadOnlyStreamOrDefault()) { // пакет был удалён if (packetStream == null) { continue; } // записываем метаданные о пакете // == packets[0].ProviderKey formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(PacketFormDataItem.ProviderKey)), packetInfo.ProviderKey); formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(PacketFormDataItem.PacketId)), packetInfo.Id); formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(PacketFormDataItem.StartPosition)), packetBytesSended); packetStream.Seek(packetBytesSended, SeekOrigin.Begin); using (var hashAlgorithm = this.hashAlgorithmFunc()) { var packetIdStr = packetInfo.Id.ToString(); formDataWriter.WriteFileHeader(string.Concat(itemPrefix, nameof(PacketFormDataItem.FileKey)), packetIdStr); byte[] buffer = new byte[bufferSize]; int read = 0; while (!maxMessageSizeReached && (read = packetStream.Read(buffer, 0, buffer.Length)) > 0) { if (formDataWriter.GetWrittenSize() + read > this.settings.PacketSizeLimits.Max) { // записываем только до максимального размера read = this.settings.PacketSizeLimits.Max - formDataWriter.GetWrittenSize(); maxMessageSizeReached = true; } formDataWriter.Write(buffer, 0, read); if (hashAlgorithm != null) { // hash contents hashAlgorithm.TransformBlock(buffer, 0, read, null, 0); } packetBytesSended = packetBytesSended + read; } if (read <= 0) { packetTransferCompleted = true; } if (hashAlgorithm != null) { hashAlgorithm.TransformFinalBlock(new byte[0], 0, 0); packetBlockHashStr = hashAlgorithm.GetHashString(); } } } formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(PacketFormDataItem.EndPosition)), packetBytesSended); //// записываем хеш данные блока пакета //formDataWriter.WriteValue(nameof(PacketFormDataItem.Hash) + suffix, packetBlockHashStr); formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(PacketFormDataItem.IsFinal)), packetTransferCompleted); packetsSendStats.Add(packetInfo, new SendStats { TransferedBytes = packetBytesSended, TransferCompleted = packetTransferCompleted, }); if (maxMessageSizeReached) { break; } } } } return(new TransportSendStats { SendedPacketsStats = packetsSendStats, ConfigurationsInfos = configurationsToDownloadInfos, }); }
protected virtual TransportSendStats WriteMessageToBody(string formDataBoundary, Stream requestStream, IList <ITransportPacketInfo> packetInfos, IList <ConfigurationRequestDataItem> configurationsToDownloadInfos, SendIterationContext context, Func <bool> cancelSendFunc) { var packetsSendStats = new Dictionary <ITransportPacketInfo, SendStats>(); var completedPackets = new List <ITransportPacketInfo>(); using (var nonClosingStream = new NonClosingStreamWrapper(requestStream)) using (var sr = new StreamWriter(nonClosingStream, this.encoding ?? DefaultEncoding)) using (var formDataWriter = new FormDataWriter(nonClosingStream, formDataBoundary, this.encoding ?? DefaultEncoding)) { var messageCapacityReached = false; if (context.RequestConfigurations) { // записываем данные по конфигурациям for (int i = 0; i < configurationsToDownloadInfos.Count; i++) { if (cancelSendFunc()) { break; } var configurationsToDownloadInfo = configurationsToDownloadInfos[i]; // == confs[0]. var itemPrefix = string.Concat(TransportConstants.FormDataConfigurationProp, "[", i, "]."); // == confs[0].ProviderKey formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(ConfigurationRequestDataItem.ProviderKey)), configurationsToDownloadInfo.ProviderKey); formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(ConfigurationRequestDataItem.Token)), configurationsToDownloadInfo.Token); if (configurationsToDownloadInfo.StartPosition != null) { formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(ConfigurationRequestDataItem.StartPosition)), configurationsToDownloadInfo.StartPosition); } formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(ConfigurationRequestDataItem.IsCompleted)), configurationsToDownloadInfo.IsCompleted); } } if (context.SendPackets) { //formDataWriter.ResetSize(); bool hasWrittenPackagePartToRequest = false; // записываем данные по пакетам for (int i = 0; i < packetInfos.Count; i++) { if (cancelSendFunc()) { break; } var packetInfo = packetInfos[i]; var sendStats = this.packetManager.ReadSendStats(packetInfo.ProviderKey, packetInfo.Identity); if (sendStats?.TransferCompleted == true) { completedPackets.Add(packetInfo); continue; } int packetBytesSended = sendStats?.TransferedBytes ?? 0; // буфер ~16 kb (довольно много можно уместить) int bufferSize = 4 * 4096; bool packetTransferCompleted = false; string packetBlockHashStr; // == packets[0]. var itemPrefix = string.Concat(TransportConstants.FormDataPacketsProp, "[", i, "]."); // записываем данные пакета using (var packetStream = packetInfo.GetReadOnlyStreamOrDefault()) { // пакет был удалён if (packetStream == null) { completedPackets.Add(packetInfo); continue; } // записываем метаданные о пакете // == packets[0].ProviderKey formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(PacketFormDataItem.ProviderKey)), packetInfo.ProviderKey); formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(PacketFormDataItem.PacketId)), packetInfo.Identity.PacketId); formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(PacketFormDataItem.StartPosition)), packetBytesSended); packetStream.Seek(packetBytesSended, SeekOrigin.Begin); using (var hashAlgorithm = this.hashAlgorithmFunc()) { var packetIdStr = packetInfo.Identity.PacketId.ToString(); formDataWriter.WriteFileHeader(string.Concat(itemPrefix, nameof(PacketFormDataItem.FileKey)), packetIdStr); byte[] buffer = new byte[bufferSize]; int read = 0; bool writtenToEnd = false; while (!messageCapacityReached && (read = packetStream.Read(buffer, 0, buffer.Length)) > 0) { // подумать над реализацией которая будет делать меньшую фрагментацию пакетови не будет записывать "лишние" if (formDataWriter.GetWrittenSize() + read > context.TransportSettings.PacketSizeLimits.Max) { // записываем только до максимального размера var toWrite = context.TransportSettings.PacketSizeLimits.Max - formDataWriter.GetWrittenSize(); if (toWrite < 0) { var originalReadFromPacket = read; if (hasWrittenPackagePartToRequest) { read = Math.Min(context.TransportSettings.PacketSizeLimits.Min, Math.Min(read, 4096)); } else { read = read < context.TransportSettings.PacketSizeLimits.Max ? read : context.TransportSettings.PacketSizeLimits.Max; } writtenToEnd = originalReadFromPacket <= read && packetStream.ReadByte() == -1; } else { read = toWrite; } messageCapacityReached = true; } formDataWriter.Write(buffer, 0, read); hasWrittenPackagePartToRequest = true; if (hashAlgorithm != null) { // hash contents hashAlgorithm.TransformBlock(buffer, 0, read, null, 0); } packetBytesSended = packetBytesSended + read; } if (read <= 0 || writtenToEnd) { packetTransferCompleted = true; } if (hashAlgorithm != null) { hashAlgorithm.TransformFinalBlock(new byte[0], 0, 0); packetBlockHashStr = hashAlgorithm.GetHashString(); } } } formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(PacketFormDataItem.EndPosition)), packetBytesSended); //// записываем хеш данные блока пакета //formDataWriter.WriteValue(nameof(PacketFormDataItem.Hash) + suffix, packetBlockHashStr); formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(PacketFormDataItem.IsFinal)), packetTransferCompleted); // данные о предыдущей части if (sendStats?.PreviousPartIdentity != null) { formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(PacketFormDataItem.PreviousPartId)), sendStats.PreviousPartIdentity.Id); formDataWriter.WriteValue(string.Concat(itemPrefix, nameof(PacketFormDataItem.PreviousPartStorageToken)), sendStats.PreviousPartIdentity.StorageToken); } packetsSendStats.Add(packetInfo, new SendStats { TransferedBytes = packetBytesSended, TransferCompleted = packetTransferCompleted, }); if (messageCapacityReached) { break; } } } } return(new TransportSendStats { IgnoredPackets = completedPackets, SendedPacketsStats = packetsSendStats, ConfigurationsInfos = configurationsToDownloadInfos, }); }