From ab29069af58c501b645f792af0b030837daa9f21 Mon Sep 17 00:00:00 2001 From: hevinci Date: Fri, 3 Mar 2023 16:12:17 +0800 Subject: [PATCH] update download system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 下载文件验证支持多线程。 --- .../Runtime/CacheSystem/CacheSystem.cs | 12 +- .../Internal/FindCacheFilesOperation.cs | 6 +- .../Internal/VerifyCacheFilesOperation.cs | 26 ++-- .../Internal/VerifyTempFileOperation.cs | 136 ++++++++++++++++++ .../Internal/VerifyTempFileOperation.cs.meta | 11 ++ .../Runtime/CacheSystem/VerifyElement.cs | 28 +++- .../Runtime/DownloadSystem/DownloadSystem.cs | 19 ++- .../Downloader/DownloaderBase.cs | 4 +- .../Downloader/FileDownloader.cs | 46 ++++-- Assets/YooAsset/Runtime/YooAssets.cs | 2 +- 10 files changed, 250 insertions(+), 40 deletions(-) create mode 100644 Assets/YooAsset/Runtime/CacheSystem/Operations/Internal/VerifyTempFileOperation.cs create mode 100644 Assets/YooAsset/Runtime/CacheSystem/Operations/Internal/VerifyTempFileOperation.cs.meta diff --git a/Assets/YooAsset/Runtime/CacheSystem/CacheSystem.cs b/Assets/YooAsset/Runtime/CacheSystem/CacheSystem.cs index 7b812d8..02107ff 100644 --- a/Assets/YooAsset/Runtime/CacheSystem/CacheSystem.cs +++ b/Assets/YooAsset/Runtime/CacheSystem/CacheSystem.cs @@ -79,7 +79,7 @@ namespace YooAsset /// /// 验证缓存文件(子线程内操作) /// - public static EVerifyResult VerifyingCacheFile(VerifyElement element) + public static EVerifyResult VerifyingCacheFile(VerifyCacheElement element) { try { @@ -109,15 +109,15 @@ namespace YooAsset } /// - /// 验证下载文件 + /// 验证下载文件(子线程内操作) /// - public static EVerifyResult VerifyingTempFile(PatchBundle patchBundle) + public static EVerifyResult VerifyingTempFile(VerifyTempElement element) { - return VerifyingInternal(patchBundle.TempDataFilePath, patchBundle.FileSize, patchBundle.FileCRC, EVerifyLevel.High); + return VerifyingInternal(element.TempDataFilePath, element.FileSize, element.FileCRC, EVerifyLevel.High); } - + /// - /// 验证记录文件 + /// 验证记录文件(主线程内操作) /// public static EVerifyResult VerifyingRecordFile(string packageName, string cacheGUID) { diff --git a/Assets/YooAsset/Runtime/CacheSystem/Operations/Internal/FindCacheFilesOperation.cs b/Assets/YooAsset/Runtime/CacheSystem/Operations/Internal/FindCacheFilesOperation.cs index 4149c7a..b442ed1 100644 --- a/Assets/YooAsset/Runtime/CacheSystem/Operations/Internal/FindCacheFilesOperation.cs +++ b/Assets/YooAsset/Runtime/CacheSystem/Operations/Internal/FindCacheFilesOperation.cs @@ -25,7 +25,7 @@ namespace YooAsset /// /// 需要验证的元素 /// - public readonly List VerifyElements = new List(5000); + public readonly List VerifyElements = new List(5000); public FindCacheFilesOperation(string packageName) { @@ -113,7 +113,7 @@ namespace YooAsset string fileRootPath = chidDirectory.FullName; string dataFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleDataFileName}"; string infoFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleInfoFileName}"; - VerifyElement element = new VerifyElement(_packageName, cacheGUID, fileRootPath, dataFilePath, infoFilePath); + VerifyCacheElement element = new VerifyCacheElement(_packageName, cacheGUID, fileRootPath, dataFilePath, infoFilePath); VerifyElements.Add(element); } @@ -161,7 +161,7 @@ namespace YooAsset string fileRootPath = chidDirectory.FullName; string dataFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleDataFileName}{dataFileExtension}"; string infoFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleInfoFileName}"; - VerifyElement element = new VerifyElement(_packageName, cacheGUID, fileRootPath, dataFilePath, infoFilePath); + VerifyCacheElement element = new VerifyCacheElement(_packageName, cacheGUID, fileRootPath, dataFilePath, infoFilePath); VerifyElements.Add(element); } diff --git a/Assets/YooAsset/Runtime/CacheSystem/Operations/Internal/VerifyCacheFilesOperation.cs b/Assets/YooAsset/Runtime/CacheSystem/Operations/Internal/VerifyCacheFilesOperation.cs index 3ee1bfb..0ab4d61 100644 --- a/Assets/YooAsset/Runtime/CacheSystem/Operations/Internal/VerifyCacheFilesOperation.cs +++ b/Assets/YooAsset/Runtime/CacheSystem/Operations/Internal/VerifyCacheFilesOperation.cs @@ -8,7 +8,7 @@ namespace YooAsset { internal abstract class VerifyCacheFilesOperation : AsyncOperationBase { - public static VerifyCacheFilesOperation CreateOperation(List elements) + public static VerifyCacheFilesOperation CreateOperation(List elements) { #if UNITY_WEBGL var operation = new VerifyCacheFilesWithoutThreadOperation(elements); @@ -33,8 +33,8 @@ namespace YooAsset } private readonly ThreadSyncContext _syncContext = new ThreadSyncContext(); - private List _waitingList; - private List _verifyingList; + private List _waitingList; + private List _verifyingList; private int _verifyMaxNum; private int _verifyTotalCount; private float _verifyStartTime; @@ -42,7 +42,7 @@ namespace YooAsset private int _failedCount; private ESteps _steps = ESteps.None; - public VerifyCacheFilesWithThreadOperation(List elements) + public VerifyCacheFilesWithThreadOperation(List elements) { _waitingList = elements; } @@ -68,7 +68,7 @@ namespace YooAsset if (_verifyMaxNum < 1) _verifyMaxNum = 1; - _verifyingList = new List(_verifyMaxNum); + _verifyingList = new List(_verifyMaxNum); _steps = ESteps.UpdateVerify; } @@ -114,19 +114,19 @@ namespace YooAsset return 1f; return (float)(_succeedCount + _failedCount) / _verifyTotalCount; } - private bool BeginVerifyFileWithThread(VerifyElement element) + private bool BeginVerifyFileWithThread(VerifyCacheElement element) { return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), element); } private void VerifyInThread(object obj) { - VerifyElement element = (VerifyElement)obj; + VerifyCacheElement element = (VerifyCacheElement)obj; element.Result = CacheSystem.VerifyingCacheFile(element); _syncContext.Post(VerifyCallback, element); } private void VerifyCallback(object obj) { - VerifyElement element = (VerifyElement)obj; + VerifyCacheElement element = (VerifyCacheElement)obj; _verifyingList.Remove(element); if (element.Result == EVerifyResult.Succeed) @@ -158,8 +158,8 @@ namespace YooAsset Done, } - private List _waitingList; - private List _verifyingList; + private List _waitingList; + private List _verifyingList; private int _verifyMaxNum; private int _verifyTotalCount; private float _verifyStartTime; @@ -167,7 +167,7 @@ namespace YooAsset private int _failedCount; private ESteps _steps = ESteps.None; - public VerifyCacheFilesWithoutThreadOperation(List elements) + public VerifyCacheFilesWithoutThreadOperation(List elements) { _waitingList = elements; } @@ -189,7 +189,7 @@ namespace YooAsset _verifyMaxNum = fileCount; _verifyTotalCount = fileCount; - _verifyingList = new List(_verifyMaxNum); + _verifyingList = new List(_verifyMaxNum); _steps = ESteps.UpdateVerify; } @@ -229,7 +229,7 @@ namespace YooAsset return 1f; return (float)(_succeedCount + _failedCount) / _verifyTotalCount; } - private void BeginVerifyFileWithoutThread(VerifyElement element) + private void BeginVerifyFileWithoutThread(VerifyCacheElement element) { element.Result = CacheSystem.VerifyingCacheFile(element); if (element.Result == EVerifyResult.Succeed) diff --git a/Assets/YooAsset/Runtime/CacheSystem/Operations/Internal/VerifyTempFileOperation.cs b/Assets/YooAsset/Runtime/CacheSystem/Operations/Internal/VerifyTempFileOperation.cs new file mode 100644 index 0000000..95470b6 --- /dev/null +++ b/Assets/YooAsset/Runtime/CacheSystem/Operations/Internal/VerifyTempFileOperation.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading; + +namespace YooAsset +{ + internal abstract class VerifyTempFileOperation : AsyncOperationBase + { + public EVerifyResult VerifyResult { protected set; get; } + + public static VerifyTempFileOperation CreateOperation(VerifyTempElement element) + { +#if UNITY_WEBGL + var operation = new VerifyTempFileWithoutThreadOperation(element); +#else + var operation = new VerifyTempFileWithThreadOperation(element); +#endif + return operation; + } + } + + /// + /// 下载文件验证(线程版) + /// + internal class VerifyTempFileWithThreadOperation : VerifyTempFileOperation + { + private enum ESteps + { + None, + VerifyFile, + Waiting, + Done, + } + + private readonly VerifyTempElement _element; + private ESteps _steps = ESteps.None; + + public VerifyTempFileWithThreadOperation(VerifyTempElement element) + { + _element = element; + } + internal override void Start() + { + _steps = ESteps.VerifyFile; + } + internal override void Update() + { + if (_steps == ESteps.None || _steps == ESteps.Done) + return; + + if (_steps == ESteps.VerifyFile) + { + if (BeginVerifyFileWithThread(_element)) + { + _steps = ESteps.Waiting; + } + } + } + + private bool BeginVerifyFileWithThread(VerifyTempElement element) + { + return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), element); + } + private void VerifyInThread(object obj) + { + VerifyTempElement element = (VerifyTempElement)obj; + element.Result = CacheSystem.VerifyingTempFile(element); + DownloadSystem.SyncContext.Post(VerifyCallback, element); + } + private void VerifyCallback(object obj) + { + VerifyTempElement element = (VerifyTempElement)obj; + VerifyResult = element.Result; + if (element.Result == EVerifyResult.Succeed) + { + _steps = ESteps.Done; + Status = EOperationStatus.Succeed; + } + else + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = $"Failed verify file : {element.TempDataFilePath} ! ErrorCode : {element.Result}"; + } + } + } + + /// + /// 下载文件验证(非线程版) + /// + internal class VerifyTempFileWithoutThreadOperation : VerifyTempFileOperation + { + private enum ESteps + { + None, + VerifyFile, + Done, + } + + private readonly VerifyTempElement _element; + private ESteps _steps = ESteps.None; + + public VerifyTempFileWithoutThreadOperation(VerifyTempElement element) + { + _element = element; + } + internal override void Start() + { + _steps = ESteps.VerifyFile; + } + internal override void Update() + { + if (_steps == ESteps.None || _steps == ESteps.Done) + return; + + if (_steps == ESteps.VerifyFile) + { + _element.Result = CacheSystem.VerifyingTempFile(_element); + VerifyResult = _element.Result; + if (_element.Result == EVerifyResult.Succeed) + { + _steps = ESteps.Done; + Status = EOperationStatus.Succeed; + } + else + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = $"Failed verify file : {_element.TempDataFilePath} ! ErrorCode : {_element.Result}"; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/CacheSystem/Operations/Internal/VerifyTempFileOperation.cs.meta b/Assets/YooAsset/Runtime/CacheSystem/Operations/Internal/VerifyTempFileOperation.cs.meta new file mode 100644 index 0000000..9abd50f --- /dev/null +++ b/Assets/YooAsset/Runtime/CacheSystem/Operations/Internal/VerifyTempFileOperation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cd356e68c5b4ef04ab018a6388f5173a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/CacheSystem/VerifyElement.cs b/Assets/YooAsset/Runtime/CacheSystem/VerifyElement.cs index f59ca7a..9384583 100644 --- a/Assets/YooAsset/Runtime/CacheSystem/VerifyElement.cs +++ b/Assets/YooAsset/Runtime/CacheSystem/VerifyElement.cs @@ -2,19 +2,22 @@ namespace YooAsset { - internal class VerifyElement + /// + /// 缓存文件验证元素 + /// + internal class VerifyCacheElement { public string PackageName { private set; get; } public string CacheGUID { private set; get; } public string FileRootPath { private set; get; } public string DataFilePath { private set; get; } public string InfoFilePath { private set; get; } - + public EVerifyResult Result; public string DataFileCRC; public long DataFileSize; - public VerifyElement(string packageName, string cacheGUID, string fileRootPath, string dataFilePath, string infoFilePath) + public VerifyCacheElement(string packageName, string cacheGUID, string fileRootPath, string dataFilePath, string infoFilePath) { PackageName = packageName; CacheGUID = cacheGUID; @@ -36,4 +39,23 @@ namespace YooAsset } } } + + /// + /// 下载文件验证元素 + /// + internal class VerifyTempElement + { + public string TempDataFilePath { private set; get; } + public string FileCRC { private set; get; } + public long FileSize { private set; get; } + + public EVerifyResult Result; + + public VerifyTempElement(string tempDataFilePath, string fileCRC, long fileSize) + { + TempDataFilePath = tempDataFilePath; + FileCRC = fileCRC; + FileSize = fileSize; + } + } } \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystem.cs b/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystem.cs index 2cd2295..180d7d0 100644 --- a/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystem.cs +++ b/Assets/YooAsset/Runtime/DownloadSystem/DownloadSystem.cs @@ -2,6 +2,7 @@ using System.IO; using System.Collections; using System.Collections.Generic; +using System.Threading; using UnityEngine.Networking; namespace YooAsset @@ -21,6 +22,10 @@ namespace YooAsset private static readonly Dictionary _downloaderDic = new Dictionary(); private static readonly List _removeList = new List(100); + /// + /// 线程同步 + /// + public static ThreadSyncContext SyncContext { set; get; } /// /// 自定义下载器的请求委托 @@ -44,10 +49,21 @@ namespace YooAsset /// - /// 更新所有下载器 + /// 初始化下载器 + /// + public static void Initialize() + { + SyncContext = new ThreadSyncContext(); + } + + /// + /// 更新下载器 /// public static void Update() { + if (SyncContext != null) + SyncContext.Update(); + // 更新下载器 _removeList.Clear(); foreach (var valuePair in _downloaderDic) @@ -78,6 +94,7 @@ namespace YooAsset _downloaderDic.Clear(); _removeList.Clear(); + SyncContext = null; RequestDelegate = null; CertificateHandlerInstance = null; BreakpointResumeFileSize = int.MaxValue; diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Downloader/DownloaderBase.cs b/Assets/YooAsset/Runtime/DownloadSystem/Downloader/DownloaderBase.cs index 8bb039d..1269d76 100644 --- a/Assets/YooAsset/Runtime/DownloadSystem/Downloader/DownloaderBase.cs +++ b/Assets/YooAsset/Runtime/DownloadSystem/Downloader/DownloaderBase.cs @@ -7,11 +7,13 @@ namespace YooAsset { None, CheckTempFile, + WaitingCheckTempFile, PrepareDownload, CreateResumeDownloader, CreateGeneralDownloader, CheckDownload, - VerifyingFile, + VerifyTempFile, + WaitingVerifyTempFile, CachingFile, TryAgain, Succeed, diff --git a/Assets/YooAsset/Runtime/DownloadSystem/Downloader/FileDownloader.cs b/Assets/YooAsset/Runtime/DownloadSystem/Downloader/FileDownloader.cs index 5576674..3551619 100644 --- a/Assets/YooAsset/Runtime/DownloadSystem/Downloader/FileDownloader.cs +++ b/Assets/YooAsset/Runtime/DownloadSystem/Downloader/FileDownloader.cs @@ -13,6 +13,8 @@ namespace YooAsset private readonly string _tempFilePath; private UnityWebRequest _webRequest = null; private DownloadHandlerFileRange _downloadHandle = null; + private VerifyTempFileOperation _checkFileOp = null; + private VerifyTempFileOperation _verifyFileOp = null; // 重置变量 private bool _isAbort = false; @@ -34,17 +36,28 @@ namespace YooAsset if (IsDone()) return; - // 检测本地临时文件 + // 检测临时文件 if (_steps == ESteps.CheckTempFile) { - var verifyResult = CacheSystem.VerifyingTempFile(_bundleInfo.Bundle); - if (verifyResult == EVerifyResult.Succeed) + VerifyTempElement element = new VerifyTempElement(_bundleInfo.Bundle.TempDataFilePath, _bundleInfo.Bundle.FileCRC, _bundleInfo.Bundle.FileSize); + _checkFileOp = VerifyTempFileOperation.CreateOperation(element); + OperationSystem.StartOperation(_checkFileOp); + _steps = ESteps.WaitingCheckTempFile; + } + + // 等待检测结果 + if (_steps == ESteps.WaitingCheckTempFile) + { + if (_checkFileOp.IsDone == false) + return; + + if (_checkFileOp.Status == EOperationStatus.Succeed) { _steps = ESteps.CachingFile; } else { - if (verifyResult == EVerifyResult.FileOverflow) + if (_checkFileOp.VerifyResult == EVerifyResult.FileOverflow) { if (File.Exists(_tempFilePath)) File.Delete(_tempFilePath); @@ -188,7 +201,7 @@ namespace YooAsset } else { - _steps = ESteps.VerifyingFile; + _steps = ESteps.VerifyTempFile; } // 释放下载器 @@ -196,21 +209,30 @@ namespace YooAsset } // 验证下载文件 - if (_steps == ESteps.VerifyingFile) + if (_steps == ESteps.VerifyTempFile) { - var verifyResult = CacheSystem.VerifyingTempFile(_bundleInfo.Bundle); - if (verifyResult == EVerifyResult.Succeed) + VerifyTempElement element = new VerifyTempElement(_bundleInfo.Bundle.TempDataFilePath, _bundleInfo.Bundle.FileCRC, _bundleInfo.Bundle.FileSize); + _verifyFileOp = VerifyTempFileOperation.CreateOperation(element); + OperationSystem.StartOperation(_verifyFileOp); + _steps = ESteps.WaitingVerifyTempFile; + } + + // 等待验证完成 + if (_steps == ESteps.WaitingVerifyTempFile) + { + if (_verifyFileOp.IsDone == false) + return; + + if (_verifyFileOp.Status == EOperationStatus.Succeed) { _steps = ESteps.CachingFile; } else { - _lastError = $"Failed to verifying file : {_bundleInfo.Bundle.FileName}, ErrorCode : {verifyResult}"; - - // 注意:验证失败后删除文件 if (File.Exists(_tempFilePath)) File.Delete(_tempFilePath); + _lastError = _verifyFileOp.Error; _steps = ESteps.TryAgain; } } @@ -226,7 +248,7 @@ namespace YooAsset long dataFileSize = _bundleInfo.Bundle.FileSize; if (File.Exists(infoFilePath)) - File.Delete(infoFilePath); + File.Delete(infoFilePath); if (File.Exists(dataFilePath)) File.Delete(dataFilePath); diff --git a/Assets/YooAsset/Runtime/YooAssets.cs b/Assets/YooAsset/Runtime/YooAssets.cs index 466be01..9b5a5f4 100644 --- a/Assets/YooAsset/Runtime/YooAssets.cs +++ b/Assets/YooAsset/Runtime/YooAssets.cs @@ -34,8 +34,8 @@ namespace YooAsset _driver.AddComponent(); #endif - // 初始化异步系统 OperationSystem.Initialize(); + DownloadSystem.Initialize(); } }