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

View File

@ -25,7 +25,7 @@ namespace YooAsset
/// <summary> /// <summary>
/// 需要验证的元素 /// 需要验证的元素
/// </summary> /// </summary>
public readonly List<VerifyElement> VerifyElements = new List<VerifyElement>(5000); public readonly List<VerifyCacheElement> VerifyElements = new List<VerifyCacheElement>(5000);
public FindCacheFilesOperation(string packageName) public FindCacheFilesOperation(string packageName)
{ {
@ -113,7 +113,7 @@ namespace YooAsset
string fileRootPath = chidDirectory.FullName; string fileRootPath = chidDirectory.FullName;
string dataFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleDataFileName}"; string dataFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleDataFileName}";
string infoFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleInfoFileName}"; 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); VerifyElements.Add(element);
} }
@ -161,7 +161,7 @@ namespace YooAsset
string fileRootPath = chidDirectory.FullName; string fileRootPath = chidDirectory.FullName;
string dataFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleDataFileName}{dataFileExtension}"; string dataFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleDataFileName}{dataFileExtension}";
string infoFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleInfoFileName}"; 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); VerifyElements.Add(element);
} }

View File

@ -8,7 +8,7 @@ namespace YooAsset
{ {
internal abstract class VerifyCacheFilesOperation : AsyncOperationBase internal abstract class VerifyCacheFilesOperation : AsyncOperationBase
{ {
public static VerifyCacheFilesOperation CreateOperation(List<VerifyElement> elements) public static VerifyCacheFilesOperation CreateOperation(List<VerifyCacheElement> elements)
{ {
#if UNITY_WEBGL #if UNITY_WEBGL
var operation = new VerifyCacheFilesWithoutThreadOperation(elements); var operation = new VerifyCacheFilesWithoutThreadOperation(elements);
@ -33,8 +33,8 @@ namespace YooAsset
} }
private readonly ThreadSyncContext _syncContext = new ThreadSyncContext(); private readonly ThreadSyncContext _syncContext = new ThreadSyncContext();
private List<VerifyElement> _waitingList; private List<VerifyCacheElement> _waitingList;
private List<VerifyElement> _verifyingList; private List<VerifyCacheElement> _verifyingList;
private int _verifyMaxNum; private int _verifyMaxNum;
private int _verifyTotalCount; private int _verifyTotalCount;
private float _verifyStartTime; private float _verifyStartTime;
@ -42,7 +42,7 @@ namespace YooAsset
private int _failedCount; private int _failedCount;
private ESteps _steps = ESteps.None; private ESteps _steps = ESteps.None;
public VerifyCacheFilesWithThreadOperation(List<VerifyElement> elements) public VerifyCacheFilesWithThreadOperation(List<VerifyCacheElement> elements)
{ {
_waitingList = elements; _waitingList = elements;
} }
@ -68,7 +68,7 @@ namespace YooAsset
if (_verifyMaxNum < 1) if (_verifyMaxNum < 1)
_verifyMaxNum = 1; _verifyMaxNum = 1;
_verifyingList = new List<VerifyElement>(_verifyMaxNum); _verifyingList = new List<VerifyCacheElement>(_verifyMaxNum);
_steps = ESteps.UpdateVerify; _steps = ESteps.UpdateVerify;
} }
@ -114,19 +114,19 @@ namespace YooAsset
return 1f; return 1f;
return (float)(_succeedCount + _failedCount) / _verifyTotalCount; return (float)(_succeedCount + _failedCount) / _verifyTotalCount;
} }
private bool BeginVerifyFileWithThread(VerifyElement element) private bool BeginVerifyFileWithThread(VerifyCacheElement element)
{ {
return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), element); return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), element);
} }
private void VerifyInThread(object obj) private void VerifyInThread(object obj)
{ {
VerifyElement element = (VerifyElement)obj; VerifyCacheElement element = (VerifyCacheElement)obj;
element.Result = CacheSystem.VerifyingCacheFile(element); element.Result = CacheSystem.VerifyingCacheFile(element);
_syncContext.Post(VerifyCallback, element); _syncContext.Post(VerifyCallback, element);
} }
private void VerifyCallback(object obj) private void VerifyCallback(object obj)
{ {
VerifyElement element = (VerifyElement)obj; VerifyCacheElement element = (VerifyCacheElement)obj;
_verifyingList.Remove(element); _verifyingList.Remove(element);
if (element.Result == EVerifyResult.Succeed) if (element.Result == EVerifyResult.Succeed)
@ -158,8 +158,8 @@ namespace YooAsset
Done, Done,
} }
private List<VerifyElement> _waitingList; private List<VerifyCacheElement> _waitingList;
private List<VerifyElement> _verifyingList; private List<VerifyCacheElement> _verifyingList;
private int _verifyMaxNum; private int _verifyMaxNum;
private int _verifyTotalCount; private int _verifyTotalCount;
private float _verifyStartTime; private float _verifyStartTime;
@ -167,7 +167,7 @@ namespace YooAsset
private int _failedCount; private int _failedCount;
private ESteps _steps = ESteps.None; private ESteps _steps = ESteps.None;
public VerifyCacheFilesWithoutThreadOperation(List<VerifyElement> elements) public VerifyCacheFilesWithoutThreadOperation(List<VerifyCacheElement> elements)
{ {
_waitingList = elements; _waitingList = elements;
} }
@ -189,7 +189,7 @@ namespace YooAsset
_verifyMaxNum = fileCount; _verifyMaxNum = fileCount;
_verifyTotalCount = fileCount; _verifyTotalCount = fileCount;
_verifyingList = new List<VerifyElement>(_verifyMaxNum); _verifyingList = new List<VerifyCacheElement>(_verifyMaxNum);
_steps = ESteps.UpdateVerify; _steps = ESteps.UpdateVerify;
} }
@ -229,7 +229,7 @@ namespace YooAsset
return 1f; return 1f;
return (float)(_succeedCount + _failedCount) / _verifyTotalCount; return (float)(_succeedCount + _failedCount) / _verifyTotalCount;
} }
private void BeginVerifyFileWithoutThread(VerifyElement element) private void BeginVerifyFileWithoutThread(VerifyCacheElement element)
{ {
element.Result = CacheSystem.VerifyingCacheFile(element); element.Result = CacheSystem.VerifyingCacheFile(element);
if (element.Result == EVerifyResult.Succeed) 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 namespace YooAsset
{ {
internal class VerifyElement /// <summary>
/// 缓存文件验证元素
/// </summary>
internal class VerifyCacheElement
{ {
public string PackageName { private set; get; } public string PackageName { private set; get; }
public string CacheGUID { private set; get; } public string CacheGUID { private set; get; }
@ -14,7 +17,7 @@ namespace YooAsset
public string DataFileCRC; public string DataFileCRC;
public long DataFileSize; 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; PackageName = packageName;
CacheGUID = cacheGUID; 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.IO;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using UnityEngine.Networking; using UnityEngine.Networking;
namespace YooAsset namespace YooAsset
@ -21,6 +22,10 @@ namespace YooAsset
private static readonly Dictionary<string, DownloaderBase> _downloaderDic = new Dictionary<string, DownloaderBase>(); private static readonly Dictionary<string, DownloaderBase> _downloaderDic = new Dictionary<string, DownloaderBase>();
private static readonly List<string> _removeList = new List<string>(100); private static readonly List<string> _removeList = new List<string>(100);
/// <summary>
/// 线程同步
/// </summary>
public static ThreadSyncContext SyncContext { set; get; }
/// <summary> /// <summary>
/// 自定义下载器的请求委托 /// 自定义下载器的请求委托
@ -44,10 +49,21 @@ namespace YooAsset
/// <summary> /// <summary>
/// 更新所有下载器 /// 初始化下载器
/// </summary>
public static void Initialize()
{
SyncContext = new ThreadSyncContext();
}
/// <summary>
/// 更新下载器
/// </summary> /// </summary>
public static void Update() public static void Update()
{ {
if (SyncContext != null)
SyncContext.Update();
// 更新下载器 // 更新下载器
_removeList.Clear(); _removeList.Clear();
foreach (var valuePair in _downloaderDic) foreach (var valuePair in _downloaderDic)
@ -78,6 +94,7 @@ namespace YooAsset
_downloaderDic.Clear(); _downloaderDic.Clear();
_removeList.Clear(); _removeList.Clear();
SyncContext = null;
RequestDelegate = null; RequestDelegate = null;
CertificateHandlerInstance = null; CertificateHandlerInstance = null;
BreakpointResumeFileSize = int.MaxValue; BreakpointResumeFileSize = int.MaxValue;

View File

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

View File

@ -13,6 +13,8 @@ namespace YooAsset
private readonly string _tempFilePath; private readonly string _tempFilePath;
private UnityWebRequest _webRequest = null; private UnityWebRequest _webRequest = null;
private DownloadHandlerFileRange _downloadHandle = null; private DownloadHandlerFileRange _downloadHandle = null;
private VerifyTempFileOperation _checkFileOp = null;
private VerifyTempFileOperation _verifyFileOp = null;
// 重置变量 // 重置变量
private bool _isAbort = false; private bool _isAbort = false;
@ -34,17 +36,28 @@ namespace YooAsset
if (IsDone()) if (IsDone())
return; return;
// 检测本地临时文件 // 检测临时文件
if (_steps == ESteps.CheckTempFile) if (_steps == ESteps.CheckTempFile)
{ {
var verifyResult = CacheSystem.VerifyingTempFile(_bundleInfo.Bundle); VerifyTempElement element = new VerifyTempElement(_bundleInfo.Bundle.TempDataFilePath, _bundleInfo.Bundle.FileCRC, _bundleInfo.Bundle.FileSize);
if (verifyResult == EVerifyResult.Succeed) _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; _steps = ESteps.CachingFile;
} }
else else
{ {
if (verifyResult == EVerifyResult.FileOverflow) if (_checkFileOp.VerifyResult == EVerifyResult.FileOverflow)
{ {
if (File.Exists(_tempFilePath)) if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath); File.Delete(_tempFilePath);
@ -188,7 +201,7 @@ namespace YooAsset
} }
else 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); VerifyTempElement element = new VerifyTempElement(_bundleInfo.Bundle.TempDataFilePath, _bundleInfo.Bundle.FileCRC, _bundleInfo.Bundle.FileSize);
if (verifyResult == EVerifyResult.Succeed) _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; _steps = ESteps.CachingFile;
} }
else else
{ {
_lastError = $"Failed to verifying file : {_bundleInfo.Bundle.FileName}, ErrorCode : {verifyResult}";
// 注意:验证失败后删除文件
if (File.Exists(_tempFilePath)) if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath); File.Delete(_tempFilePath);
_lastError = _verifyFileOp.Error;
_steps = ESteps.TryAgain; _steps = ESteps.TryAgain;
} }
} }

View File

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