public void FileDownloadItem() { var fileId = GenerateFileId(); var readStream = new ByteArrayStream(128 * 1024); var client = new Client(KTestHost, TestPort); client.Connect(); client.BeginTransaction(fileId); client.Upload(FileType.Asset, readStream); client.EndTransaction(); Thread.Sleep(50); // give the server a little time to finish the transaction var targetFile = Path.GetTempFileName(); var downloadItem = new FileDownloadItem(fileId, FileType.Asset, targetFile); var mre = new ManualResetEvent(false); Exception err = null; client.DownloadFinished += (sender, args) => { try { Assert.AreEqual(DownloadResult.Success, args.Result); Assert.AreEqual(args.DownloadItem.Id, fileId); Assert.IsTrue(File.Exists(targetFile)); var fileBytes = File.ReadAllBytes(targetFile); Assert.IsTrue(Util.ByteArraysAreEqual(readStream.BackingBuffer, fileBytes)); } catch (Exception e) { err = e; } finally { if (File.Exists(targetFile)) { File.Delete(targetFile); } mre.Set(); } }; client.QueueDownload(downloadItem); Assert.IsTrue(mre.WaitOne(2000)); if (err != null) { throw err; } }
// We don't return from this function until all downloads are processed. So it is safe to dispose immediately after. public void DownloadMissing(IList <CacheEntry> entries, IList <CachedInfo> cachedInfos) { Assert.AreEqual(entries.Count, cachedInfos.Count); Directory.CreateDirectory(k_CachePath); m_Semaphore = new Semaphore(0, entries.Count); m_Client.DownloadFinished += ThreadedDownloadFinished; // Queue up downloads for the missing or invalid local data for (var index = 0; index < entries.Count; index++) { // Only download data for cachedInfos that are invalid if (cachedInfos[index] != null) { continue; } var entry = entries[index]; string finalHash = HashingMethods.Calculate(entry.Hash, m_GlobalHash).ToHash128().ToString(); var fileId = FileId.From(entry.Guid.ToString(), finalHash); // Download artifacts before info to ensure both are available when download for info returns var downloadArtifact = new FileDownloadItem(fileId, FileType.Resource, GetCachedArtifactsFile(entry)); m_Client.QueueDownload(downloadArtifact); var downloadInfo = new FileDownloadItem(fileId, FileType.Info, GetCachedInfoFile(entry)); m_Client.QueueDownload(downloadInfo); } // Check downloads to see if it is usable data var formatter = new BinaryFormatter(); for (var index = 0; index < entries.Count; index++) { // find the next invalid cachedInfo while (index < entries.Count && cachedInfos[index] != null) { index++; } // make sure we didn't go out of bounds looking for invalid entries if (index >= entries.Count) { break; } // Wait for info download m_Semaphore.WaitOne(); string tempInfoFile = GetCachedInfoFile(entries[index]); if (!File.Exists(tempInfoFile)) { continue; } try { CachedInfo info; using (var fileStream = new FileStream(tempInfoFile, FileMode.Open, FileAccess.Read)) info = formatter.Deserialize(fileStream) as CachedInfo; if (m_Cache.HasAssetOrDependencyChanged(info)) { continue; } // Not every info file will have artifacts. So just check to see if we downloaded something. // TODO: May want to extend CachedInfo with Artifact knowledge if there is a performance benefit? string tempArtifactFile = GetCachedArtifactsFile(entries[index]); string tempArtifactDir = Path.ChangeExtension(tempArtifactFile, ""); if (File.Exists(tempArtifactFile) && !FileCompressor.Decompress(tempArtifactFile, tempArtifactDir)) { continue; } // All valid, move downloaded data into place cachedInfos[index] = info; string targetInfoFile = m_Cache.GetCachedInfoFile(info.Asset); if (File.Exists(targetInfoFile)) { File.Delete(targetInfoFile); } else { Directory.CreateDirectory(Path.GetDirectoryName(targetInfoFile)); } File.Move(tempInfoFile, targetInfoFile); if (Directory.Exists(tempArtifactDir)) { string targetArtifactDir = m_Cache.GetCachedArtifactsDirectory(info.Asset); if (Directory.Exists(targetArtifactDir)) { Directory.Delete(targetArtifactDir, true); } Directory.Move(tempArtifactDir, targetArtifactDir); } } catch (Exception e) { BuildLogger.LogException(e); } } m_Client.ResetDownloadFinishedEventHandler(); ((IDisposable)m_Semaphore).Dispose(); m_Semaphore = null; Directory.Delete(k_CachePath, true); }