private Downloader StartDownload(FSItem item, string path) { var downloader = new Downloader(item, path); lock (DownloadersLock) { Downloader result; if (Downloaders.TryGetValue(item.Path, out result)) { if (result.Task == null) { throw new Exception("Downloader Task is Null"); } return(result); } Directory.CreateDirectory(cachePath); var fileinfo = new FileInfo(path); if (fileinfo.Exists && fileinfo.Length == item.Length) { return(Downloader.CreateCompleted(item, path, item.Length)); } Stream writer; if (!fileinfo.Exists || fileinfo.Length < item.Length) { writer = new FileStream( path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite, 4096, FileOptions.Asynchronous | FileOptions.SequentialScan); if (writer.Length > 0) { Log.Warn( $"File was not totally downloaded before. Should be {item.Length} but was {writer.Length}: {item.Path} - {item.Id}"); downloader.Downloaded = writer.Length; } } else { writer = new FileStream( path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite, 4096, FileOptions.Asynchronous | FileOptions.SequentialScan); } downloader.Task = Task.Factory.StartNew(async() => await Download(item, writer, downloader), TaskCreationOptions.LongRunning); Downloaders.Add(item.Path, downloader); return(downloader); } }
private async Task Download(FSItem item, Stream result, Downloader downloader) { try { Log.Trace($"Started download: {item.Name} - {item.Id}"); var start = Stopwatch.StartNew(); var buf = new byte[64 << 10]; var uncommitedSize = 0; const int commitSize = 512 << 10; using (result) using (var writer = new BufferedStream(result)) { OnDownloadStarted?.Invoke(item); while (writer.Length < item.Length) { var stream = await cloud.Files.Download(item.Id); stream.Position = writer.Length; int red; do { red = await stream.ReadAsync(buf, 0, buf.Length); if (writer.Length == 0) { Log.Trace($"Got first part: {item.Name} - {item.Id} in {start.ElapsedMilliseconds}"); } await writer.WriteAsync(buf, 0, red); uncommitedSize += red; if (uncommitedSize <= commitSize) { continue; } uncommitedSize = 0; await writer.FlushAsync(); downloader.Downloaded = writer.Length; }while (red > 0); } await writer.FlushAsync(); downloader.Downloaded = writer.Length; } Log.Trace($"Finished download: {item.Name} - {item.Id}"); OnDownloaded?.Invoke(item); BoschHelper.Decrypt(downloader.Path); if (access.TryAdd( item.Id, new CacheEntry { Id = item.Id, AccessTime = DateTime.UtcNow, Length = item.Length })) { TotalSizeIncrease(item.Length); } if (TotalSize > CacheSize) { var task = cleanSizeWorker.Run(TotalSize - CacheSize); } if (start.ElapsedMilliseconds > 29000) { Log.Warn($"Downloading {item.Path} took: {start.ElapsedMilliseconds}"); } } catch (Exception ex) { Log.ErrorTrace($"Download failed: {item.Name} - {item.Id}\r\n{ex}"); await downloader.Failed(); OnDownloadFailed?.Invoke(item); } finally { lock (DownloadersLock) { Downloaders.Remove(item.Path); } } }