public Stream GetStream(Metadata metadata, long maxLength) { if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } DownloadItemInfo info; lock (_lockObject) { info = _volatileDownloadItemInfoManager.GetInfo(metadata); if (info != null && info.State == DownloadState.Error) { _volatileDownloadItemInfoManager.Remove(metadata); info = null; } if (info == null) { info = new DownloadItemInfo(metadata, null, maxLength, 0, null, DownloadState.Downloading, Array.Empty <Hash>()); _volatileDownloadItemInfoManager.Add(info); } else { info.MaxLength = Math.Max(info.MaxLength, maxLength); } if (info.State != DownloadState.Completed) { return(null); } } Stream stream = null; try { stream = _cacheManager.Decoding(info.ResultHashes); if (stream.Length > info.MaxLength) { throw new ArgumentException(); } return(stream); } catch (Exception) { if (stream != null) { stream.Dispose(); stream = null; } info.State = DownloadState.Error; } return(stream); }
private bool CheckSize(DownloadItemInfo info) { lock (_lockObject) { if (info.Metadata.Depth > 32) { return(false); } var hashes = new List <Hash>(); { if (info.Depth == 0) { hashes.Add(info.Metadata.Hash); } else { hashes.AddRange(info.Index.Groups.SelectMany(n => n.Hashes)); } } long sumLength = hashes.Sum(n => (long)_cacheManager.GetLength(n)); return(sumLength < (info.MaxLength * 3)); } }
private void Event_AddInfo(DownloadItemInfo info) { lock (_lockObject) { _cacheManager.Lock(info.Metadata.Hash); this.CheckState(info.Index); } }
private void Event_AddInfo(DownloadItemInfo info) { lock (_lockObject) { _cacheManager.Lock(info.Clue.Hash); this.CheckState(info.DownloadingMerkleTreeNode); } }
private void Event_RemoveInfo(DownloadItemInfo info) { lock (_lockObject) { _cacheManager.Unlock(info.Metadata.Hash); this.UncheckState(info.Index); info.State = DownloadState.Error; } }
private void Event_RemoveInfo(DownloadItemInfo info) { lock (_lockObject) { _cacheManager.Unlock(info.Clue.Hash); this.UncheckState(info.DownloadingMerkleTreeNode); info.State = DownloadState.Error; } }
public void Add(Metadata metadata, string path, long maxLength) { if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } lock (_lockObject) { if (_downloadItemInfoManager.Contains(metadata, path)) { return; } var info = new DownloadItemInfo(metadata, path, maxLength, 0, null, DownloadState.Downloading, Array.Empty <Hash>()); _downloadItemInfoManager.Add(info); } }
public void Add(Metadata metadata, string path, long maxLength) { if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } lock (_lockObject) { if (_downloadItemInfoManager.Contains(metadata, path)) { return; } var info = new DownloadItemInfo(metadata, path); info.MaxLength = maxLength; info.State = DownloadState.Downloading; _downloadItemInfoManager.Add(info); } }
private void DecodingThread(CancellationToken token) { for (; ;) { if (token.WaitHandle.WaitOne(1000)) { return; } DownloadItemInfo item = null; lock (_lockObject) { item = CollectionUtils.Unite(_volatileDownloadItemInfoManager, _downloadItemInfoManager) .Where(n => !_workingItems.Contains(n)) .Where(n => n.State == DownloadState.Decoding || n.State == DownloadState.ParityDecoding) .OrderBy(n => (n.Depth == n.Metadata.Depth) ? 0 : 1) .OrderBy(n => (n.State == DownloadState.Decoding) ? 0 : 1) .FirstOrDefault(); if (item != null) { _workingItems.Add(item); } } if (item == null) { continue; } try { if ((item.Depth == 0 && !_cacheManager.Contains(item.Metadata.Hash)) || (item.Depth > 0 && !item.Index.Groups.All(n => _existManager.GetCount(n, true) >= n.Hashes.Count() / 2))) { item.State = DownloadState.Downloading; } else { var hashes = new HashCollection(); var totalHashes = new HashCollection(); if (item.Depth == 0) { hashes.Add(item.Metadata.Hash); totalHashes.Add(item.Metadata.Hash); } else { try { foreach (var group in item.Index.Groups) { if (item.State == DownloadState.Error) { throw new OperationCanceledException(); } hashes.AddRange(_cacheManager.ParityDecoding(group, token).Result); } totalHashes.AddRange(item.Index.Groups.SelectMany(n => n.Hashes)); } catch (OperationCanceledException) { continue; } item.State = DownloadState.Decoding; } if (item.Depth < item.Metadata.Depth) { Index index; try { using (var stream = _cacheManager.Decoding(hashes)) using (var progressStream = new ProgressStream(stream, null, 1024 * 1024, token)) { if (item.State == DownloadState.Error) { throw new OperationCanceledException(); } if (progressStream.Length > item.MaxLength) { throw new ArgumentException(); } index = Index.Import(progressStream, _bufferManager); } } catch (OperationCanceledException) { continue; } lock (_lockObject) { if (item.Path != null) { _protectCacheInfoManager.Add(new ProtectedCacheInfo(DateTime.UtcNow, totalHashes)); } this.CheckState(index); this.UncheckState(item.Index); item.Index = index; item.Depth++; item.State = DownloadState.Downloading; } } else { if (item.Path != null) { string filePath = null; try { token.ThrowIfCancellationRequested(); string targetPath; if (Path.IsPathRooted(item.Path)) { targetPath = item.Path; } else { targetPath = Path.GetFullPath(Path.Combine(_basePath, item.Path)); // ディレクトリトラバーサル対策 if (!targetPath.StartsWith(Path.GetFullPath(_basePath))) { targetPath = Path.GetFullPath(Path.Combine(_basePath, Path.GetFileName(item.Path))); } } Directory.CreateDirectory(Path.GetDirectoryName(targetPath)); using (var inStream = _cacheManager.Decoding(hashes)) using (var outStream = DownloadManager.GetUniqueFileStream(targetPath + ".tmp")) using (var safeBuffer = _bufferManager.CreateSafeBuffer(1024 * 1024)) { filePath = outStream.Name; int readLength; while ((readLength = inStream.Read(safeBuffer.Value, 0, safeBuffer.Value.Length)) > 0) { if (item.State == DownloadState.Error) { throw new OperationCanceledException(); } token.ThrowIfCancellationRequested(); outStream.Write(safeBuffer.Value, 0, readLength); } } File.Move(filePath, DownloadManager.GetUniqueFilePath(targetPath)); } catch (OperationCanceledException) { if (filePath != null) { File.Delete(filePath); } continue; } } lock (_lockObject) { if (item.Path != null) { _protectCacheInfoManager.Add(new ProtectedCacheInfo(DateTime.UtcNow, totalHashes)); } item.ResultHashes.AddRange(hashes); item.State = DownloadState.Completed; } } } } catch (Exception e) { item.State = DownloadState.Error; Log.Error(e); } finally { _workingItems.Remove(item); } } }