update download system

下载文件验证支持多线程。
pull/82/head
hevinci 2023-03-03 16:12:17 +08:00
parent fc3ed28eda
commit ab29069af5
10 changed files with 250 additions and 40 deletions

View File

@ -79,7 +79,7 @@ namespace YooAsset
/// <summary>
/// 验证缓存文件(子线程内操作)
/// </summary>
public static EVerifyResult VerifyingCacheFile(VerifyElement element)
public static EVerifyResult VerifyingCacheFile(VerifyCacheElement element)
{
try
{
@ -109,15 +109,15 @@ namespace YooAsset
}
/// <summary>
/// 验证下载文件
/// 验证下载文件(子线程内操作)
/// </summary>
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);
}
/// <summary>
/// 验证记录文件
/// 验证记录文件(主线程内操作)
/// </summary>
public static EVerifyResult VerifyingRecordFile(string packageName, string cacheGUID)
{

View File

@ -25,7 +25,7 @@ namespace YooAsset
/// <summary>
/// 需要验证的元素
/// </summary>
public readonly List<VerifyElement> VerifyElements = new List<VerifyElement>(5000);
public readonly List<VerifyCacheElement> VerifyElements = new List<VerifyCacheElement>(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);
}

View File

@ -8,7 +8,7 @@ namespace YooAsset
{
internal abstract class VerifyCacheFilesOperation : AsyncOperationBase
{
public static VerifyCacheFilesOperation CreateOperation(List<VerifyElement> elements)
public static VerifyCacheFilesOperation CreateOperation(List<VerifyCacheElement> elements)
{
#if UNITY_WEBGL
var operation = new VerifyCacheFilesWithoutThreadOperation(elements);
@ -33,8 +33,8 @@ namespace YooAsset
}
private readonly ThreadSyncContext _syncContext = new ThreadSyncContext();
private List<VerifyElement> _waitingList;
private List<VerifyElement> _verifyingList;
private List<VerifyCacheElement> _waitingList;
private List<VerifyCacheElement> _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<VerifyElement> elements)
public VerifyCacheFilesWithThreadOperation(List<VerifyCacheElement> elements)
{
_waitingList = elements;
}
@ -68,7 +68,7 @@ namespace YooAsset
if (_verifyMaxNum < 1)
_verifyMaxNum = 1;
_verifyingList = new List<VerifyElement>(_verifyMaxNum);
_verifyingList = new List<VerifyCacheElement>(_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<VerifyElement> _waitingList;
private List<VerifyElement> _verifyingList;
private List<VerifyCacheElement> _waitingList;
private List<VerifyCacheElement> _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<VerifyElement> elements)
public VerifyCacheFilesWithoutThreadOperation(List<VerifyCacheElement> elements)
{
_waitingList = elements;
}
@ -189,7 +189,7 @@ namespace YooAsset
_verifyMaxNum = fileCount;
_verifyTotalCount = fileCount;
_verifyingList = new List<VerifyElement>(_verifyMaxNum);
_verifyingList = new List<VerifyCacheElement>(_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)

View File

@ -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;
}
}
/// <summary>
/// 下载文件验证(线程版)
/// </summary>
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}";
}
}
}
/// <summary>
/// 下载文件验证(非线程版)
/// </summary>
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}";
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cd356e68c5b4ef04ab018a6388f5173a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -2,7 +2,10 @@
namespace YooAsset
{
internal class VerifyElement
/// <summary>
/// 缓存文件验证元素
/// </summary>
internal class VerifyCacheElement
{
public string PackageName { private set; get; }
public string CacheGUID { private set; get; }
@ -14,7 +17,7 @@ namespace YooAsset
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
}
}
}
/// <summary>
/// 下载文件验证元素
/// </summary>
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;
}
}
}

View File

@ -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<string, DownloaderBase> _downloaderDic = new Dictionary<string, DownloaderBase>();
private static readonly List<string> _removeList = new List<string>(100);
/// <summary>
/// 线程同步
/// </summary>
public static ThreadSyncContext SyncContext { set; get; }
/// <summary>
/// 自定义下载器的请求委托
@ -44,10 +49,21 @@ namespace YooAsset
/// <summary>
/// 更新所有下载器
/// 初始化下载器
/// </summary>
public static void Initialize()
{
SyncContext = new ThreadSyncContext();
}
/// <summary>
/// 更新下载器
/// </summary>
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;

View File

@ -7,11 +7,13 @@ namespace YooAsset
{
None,
CheckTempFile,
WaitingCheckTempFile,
PrepareDownload,
CreateResumeDownloader,
CreateGeneralDownloader,
CheckDownload,
VerifyingFile,
VerifyTempFile,
WaitingVerifyTempFile,
CachingFile,
TryAgain,
Succeed,

View File

@ -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;
}
}

View File

@ -34,8 +34,8 @@ namespace YooAsset
_driver.AddComponent<RemoteDebuggerInRuntime>();
#endif
// 初始化异步系统
OperationSystem.Initialize();
DownloadSystem.Initialize();
}
}