using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Text; using System.Threading.Tasks; namespace Pithos.Network { public class FileBlockContent : HttpContent { private IProgress _progress; private readonly string _filePath; private readonly long _offset; private readonly int _blockSize; private readonly FileInfo _fileInfo; public FileBlockContent(string filePath, long offset, int blockSize, IProgress progress) { if (progress== null) throw new ArgumentNullException("progress"); _progress = progress; _filePath = filePath; _offset = offset; _blockSize = blockSize; _fileInfo=new FileInfo(filePath); } public FileBlockContent Clone() { return new FileBlockContent(_filePath, _offset, _blockSize, _progress); } protected override bool TryComputeLength(out long length) { var availableLength=_fileInfo.Length - _offset; length = availableLength > _blockSize ? _blockSize : availableLength; return true; } protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context) { const int buffer_size = 65536; var buffer = new byte[buffer_size]; var total = 0; long remainder; TryComputeLength(out remainder); var watch= new Stopwatch(); using(var fileStream=new FileStream(_filePath,FileMode.Open,FileAccess.Read,FileShare.Read,buffer_size)) { fileStream.Seek(_offset, SeekOrigin.Begin); int read = 0; //Make sure we read only up to the block size var size = buffer_size > remainder ? remainder : buffer_size; int timerTotal = 0; watch.Start(); while(remainder>0 && 0<(read=await fileStream.ReadAsync(buffer, 0, (int)size).ConfigureAwait(false))) { await stream.WriteAsync(buffer, 0, read).ConfigureAwait(false); watch.Stop(); total += read; remainder -= read; //Calculate the new size, size = buffer_size > remainder ? remainder : buffer_size; timerTotal += read; //Only report every second if (watch.ElapsedMilliseconds > 1000) { var speed = 1000*timerTotal/(double) watch.ElapsedMilliseconds; var percentage = Convert.ToInt32(100*total/(double) _blockSize); _progress.Report(new UploadArgs(percentage, null, total, _blockSize, 0, 0, speed)); //Reset the counter and total timerTotal = 0; watch.Reset(); } watch.Start(); } } } } }