update download system

优化资源文件下载流程。
pull/62/head
hevinci 2022-12-13 23:30:16 +08:00
parent 15a605b677
commit 7b9fda2298
5 changed files with 155 additions and 98 deletions

View File

@ -73,9 +73,9 @@ namespace YooAsset
} }
/// <summary> /// <summary>
/// 验证并缓存补丁包文件 /// 验证并缓存本地文件
/// </summary> /// </summary>
public static EVerifyResult VerifyAndCacheBundle(PatchBundle patchBundle, EVerifyLevel verifyLevel) public static EVerifyResult VerifyAndCacheLocalBundleFile(PatchBundle patchBundle, EVerifyLevel verifyLevel)
{ {
var verifyResult = VerifyContentInternal(patchBundle.CachedFilePath, patchBundle.FileSize, patchBundle.FileCRC, verifyLevel); var verifyResult = VerifyContentInternal(patchBundle.CachedFilePath, patchBundle.FileSize, patchBundle.FileCRC, verifyLevel);
if (verifyResult == EVerifyResult.Succeed) if (verifyResult == EVerifyResult.Succeed)
@ -83,10 +83,41 @@ namespace YooAsset
return verifyResult; return verifyResult;
} }
/// <summary>
/// 验证并缓存下载文件
/// </summary>
public static EVerifyResult VerifyAndCacheDownloadBundleFile(PatchBundle patchBundle, EVerifyLevel verifyLevel)
{
string tempFilePath = patchBundle.CachedFilePath + ".temp";
var verifyResult = VerifyContentInternal(tempFilePath, patchBundle.FileSize, patchBundle.FileCRC, verifyLevel);
if (verifyResult == EVerifyResult.Succeed)
{
try
{
string destFilePath = patchBundle.CachedFilePath;
if (File.Exists(destFilePath))
File.Delete(destFilePath);
FileInfo fileInfo = new FileInfo(tempFilePath);
fileInfo.MoveTo(destFilePath);
}
catch (Exception)
{
verifyResult = EVerifyResult.FileMoveFailed;
}
if (verifyResult == EVerifyResult.Succeed)
{
CacheBundle(patchBundle);
}
}
return verifyResult;
}
/// <summary> /// <summary>
/// 验证文件完整性 /// 验证文件完整性
/// </summary> /// </summary>
public static EVerifyResult VerifyContentInternal(string filePath, long fileSize, string fileCRC, EVerifyLevel verifyLevel) private static EVerifyResult VerifyContentInternal(string filePath, long fileSize, string fileCRC, EVerifyLevel verifyLevel)
{ {
try try
{ {

View File

@ -161,7 +161,7 @@ namespace YooAsset
private void VerifyFileWithoutThread(VerifyInfo verifyIno) private void VerifyFileWithoutThread(VerifyInfo verifyIno)
{ {
var verifyResult = CacheSystem.VerifyAndCacheBundle(verifyIno.VerifyBundle, CacheSystem.InitVerifyLevel); var verifyResult = CacheSystem.VerifyAndCacheLocalBundleFile(verifyIno.VerifyBundle, CacheSystem.InitVerifyLevel);
if (verifyResult == EVerifyResult.Succeed) if (verifyResult == EVerifyResult.Succeed)
{ {
VerifySuccessList.Add(verifyIno); VerifySuccessList.Add(verifyIno);

View File

@ -9,7 +9,12 @@ namespace YooAsset
/// <summary> /// <summary>
/// 文件不存在 /// 文件不存在
/// </summary> /// </summary>
FileNotExisted = -4, FileNotExisted = -5,
/// <summary>
/// 文件移动失败(重命名失败)
/// </summary>
FileMoveFailed = -4,
/// <summary> /// <summary>
/// 文件内容不足(小于正常大小) /// 文件内容不足(小于正常大小)

View File

@ -6,9 +6,12 @@ namespace YooAsset
protected enum ESteps protected enum ESteps
{ {
None, None,
CheckLocalFile, CheckTempFile,
CreateDownload, PrepareDownload,
CreateResumeDownloader,
CreateGeneralDownloader,
CheckDownload, CheckDownload,
VerifyDownload,
TryAgain, TryAgain,
Succeed, Succeed,
Failed, Failed,
@ -56,7 +59,7 @@ namespace YooAsset
{ {
_failedTryAgain = failedTryAgain; _failedTryAgain = failedTryAgain;
_timeout = timeout; _timeout = timeout;
_steps = ESteps.CheckLocalFile; _steps = ESteps.CheckTempFile;
} }
} }
public abstract void Update(); public abstract void Update();

View File

@ -10,6 +10,7 @@ namespace YooAsset
internal sealed class FileDownloader : DownloaderBase internal sealed class FileDownloader : DownloaderBase
{ {
private readonly bool _breakResume; private readonly bool _breakResume;
private readonly string _tempFilePath;
private UnityWebRequest _webRequest = null; private UnityWebRequest _webRequest = null;
private DownloadHandlerFileRange _downloadHandle = null; private DownloadHandlerFileRange _downloadHandle = null;
@ -24,6 +25,7 @@ namespace YooAsset
public FileDownloader(BundleInfo bundleInfo, bool breakResume) : base(bundleInfo) public FileDownloader(BundleInfo bundleInfo, bool breakResume) : base(bundleInfo)
{ {
_breakResume = breakResume; _breakResume = breakResume;
_tempFilePath = bundleInfo.Bundle.CachedFilePath + ".temp";
} }
public override void Update() public override void Update()
{ {
@ -33,9 +35,9 @@ namespace YooAsset
return; return;
// 检测本地文件 // 检测本地文件
if (_steps == ESteps.CheckLocalFile) if (_steps == ESteps.CheckTempFile)
{ {
var verifyResult = CacheSystem.VerifyAndCacheBundle(_bundleInfo.Bundle, EVerifyLevel.High); var verifyResult = CacheSystem.VerifyAndCacheDownloadBundleFile(_bundleInfo.Bundle, EVerifyLevel.High);
if (verifyResult == EVerifyResult.Succeed) if (verifyResult == EVerifyResult.Succeed)
{ {
_steps = ESteps.Succeed; _steps = ESteps.Succeed;
@ -44,19 +46,16 @@ namespace YooAsset
{ {
if (verifyResult == EVerifyResult.FileOverflow) if (verifyResult == EVerifyResult.FileOverflow)
{ {
string cacheFilePath = _bundleInfo.Bundle.CachedFilePath; if (File.Exists(_tempFilePath))
if (File.Exists(cacheFilePath)) File.Delete(_tempFilePath);
File.Delete(cacheFilePath);
} }
_steps = ESteps.CreateDownload; _steps = ESteps.PrepareDownload;
} }
} }
// 创建下载器 // 创建下载器
if (_steps == ESteps.CreateDownload) if (_steps == ESteps.PrepareDownload)
{ {
string fileSavePath = _bundleInfo.Bundle.CachedFilePath;
// 重置变量 // 重置变量
_downloadProgress = 0f; _downloadProgress = 0f;
_downloadedBytes = 0; _downloadedBytes = 0;
@ -66,28 +65,28 @@ namespace YooAsset
_latestDownloadRealtime = Time.realtimeSinceStartup; _latestDownloadRealtime = Time.realtimeSinceStartup;
_tryAgainTimer = 0f; _tryAgainTimer = 0f;
// 是否开启断点续传下载 // 获取请求地址
_requestURL = GetRequestURL();
if (_breakResume) if (_breakResume)
{ _steps = ESteps.CreateResumeDownloader;
long fileLength = -1; else
if (File.Exists(fileSavePath)) _steps = ESteps.CreateGeneralDownloader;
{
FileInfo fileInfo = new FileInfo(fileSavePath);
fileLength = fileInfo.Length;
_fileOriginLength = (ulong)fileLength;
_downloadedBytes = _fileOriginLength;
} }
_requestURL = GetRequestURL(); // 创建普通的下载器
_webRequest = UnityWebRequest.Get(_requestURL); if (_steps == ESteps.CreateGeneralDownloader)
{
if (File.Exists(_tempFilePath))
{
File.Delete(_tempFilePath);
}
#if UNITY_2019_4_OR_NEWER _webRequest = new UnityWebRequest(_requestURL, UnityWebRequest.kHttpVerbGET);
var handler = new DownloadHandlerFile(fileSavePath, true); DownloadHandlerFile handler = new DownloadHandlerFile(_tempFilePath);
handler.removeFileOnAbort = false; handler.removeFileOnAbort = true;
#else _webRequest.downloadHandler = handler;
var handler = new DownloadHandlerFileRange(fileSavePath, _bundleInfo.Bundle.FileSize, _webRequest); _webRequest.disposeDownloadHandlerOnDispose = true;
_downloadHandle = handler;
#endif
if (DownloadSystem.CertificateHandlerInstance != null) if (DownloadSystem.CertificateHandlerInstance != null)
{ {
@ -95,25 +94,45 @@ namespace YooAsset
_webRequest.disposeCertificateHandlerOnDispose = false; _webRequest.disposeCertificateHandlerOnDispose = false;
} }
_webRequest.SendWebRequest();
_steps = ESteps.CheckDownload;
}
// 创建断点续传下载器
if (_steps == ESteps.CreateResumeDownloader)
{
long fileLength = -1;
if (File.Exists(_tempFilePath))
{
FileInfo fileInfo = new FileInfo(_tempFilePath);
fileLength = fileInfo.Length;
_fileOriginLength = (ulong)fileLength;
_downloadedBytes = _fileOriginLength;
}
#if UNITY_2019_4_OR_NEWER
_webRequest = new UnityWebRequest(_requestURL, UnityWebRequest.kHttpVerbGET);
var handler = new DownloadHandlerFile(_tempFilePath, true);
handler.removeFileOnAbort = false;
#else
_webRequest = new UnityWebRequest(_requestURL, UnityWebRequest.kHttpVerbGET);
var handler = new DownloadHandlerFileRange(_tempFilePath, _bundleInfo.Bundle.FileSize, _webRequest);
_downloadHandle = handler;
#endif
_webRequest.downloadHandler = handler; _webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true; _webRequest.disposeDownloadHandlerOnDispose = true;
if (fileLength > 0) if (fileLength > 0)
_webRequest.SetRequestHeader("Range", $"bytes={fileLength}-"); _webRequest.SetRequestHeader("Range", $"bytes={fileLength}-");
_webRequest.SendWebRequest();
_steps = ESteps.CheckDownload; if (DownloadSystem.CertificateHandlerInstance != null)
}
else
{ {
_requestURL = GetRequestURL(); _webRequest.certificateHandler = DownloadSystem.CertificateHandlerInstance;
_webRequest = new UnityWebRequest(_requestURL, UnityWebRequest.kHttpVerbGET); _webRequest.disposeCertificateHandlerOnDispose = false;
DownloadHandlerFile handler = new DownloadHandlerFile(fileSavePath); }
handler.removeFileOnAbort = true;
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_webRequest.SendWebRequest(); _webRequest.SendWebRequest();
_steps = ESteps.CheckDownload; _steps = ESteps.CheckDownload;
} }
}
// 检测下载结果 // 检测下载结果
if (_steps == ESteps.CheckDownload) if (_steps == ESteps.CheckDownload)
@ -145,78 +164,77 @@ namespace YooAsset
} }
#endif #endif
// 检查文件完整性 // 如果网络异常
if (hasError == false)
{
var verifyResult = CacheSystem.VerifyAndCacheBundle(_bundleInfo.Bundle, EVerifyLevel.High);
if (verifyResult != EVerifyResult.Succeed)
{
hasError = true;
_lastError = $"Verify bundle content failed : {_bundleInfo.Bundle.FileName}";
_lastCode = _webRequest.responseCode;
// 验证失败后删除文件
string cacheFilePath = _bundleInfo.Bundle.CachedFilePath;
if (File.Exists(cacheFilePath))
File.Delete(cacheFilePath);
}
}
// 如果下载失败
if (hasError) if (hasError)
{ {
// 注意:非断点续传下载失败之后删除文件 if (_breakResume)
if (_breakResume == false)
{
string cacheFilePath = _bundleInfo.Bundle.CachedFilePath;
if (File.Exists(cacheFilePath))
File.Delete(cacheFilePath);
}
else
{ {
// 注意:下载断点续传文件发生特殊错误码之后删除文件 // 注意:下载断点续传文件发生特殊错误码之后删除文件
if (DownloadSystem.ClearFileResponseCodes != null) if (DownloadSystem.ClearFileResponseCodes != null)
{ {
if (DownloadSystem.ClearFileResponseCodes.Contains(_webRequest.responseCode)) if (DownloadSystem.ClearFileResponseCodes.Contains(_webRequest.responseCode))
{ {
string cacheFilePath = _bundleInfo.Bundle.CachedFilePath; if (File.Exists(_tempFilePath))
if (File.Exists(cacheFilePath)) File.Delete(_tempFilePath);
File.Delete(cacheFilePath);
} }
} }
} }
else
{
// 注意:非断点续传下载失败之后删除文件
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
// 失败后重新尝试
if (_failedTryAgain > 0)
{
ReportWarning();
_steps = ESteps.TryAgain; _steps = ESteps.TryAgain;
} }
else else
{ {
ReportError(); _steps = ESteps.VerifyDownload;
_steps = ESteps.Failed;
}
}
else
{
_lastError = string.Empty;
_lastCode = 0;
_steps = ESteps.Succeed;
} }
// 释放下载器 // 释放下载器
DisposeWebRequest(); DisposeWebRequest();
} }
// 验证下载文件
if (_steps == ESteps.VerifyDownload)
{
var verifyResult = CacheSystem.VerifyAndCacheDownloadBundleFile(_bundleInfo.Bundle, EVerifyLevel.High);
if (verifyResult == EVerifyResult.Succeed)
{
_lastError = string.Empty;
_lastCode = 0;
_steps = ESteps.Succeed;
}
else
{
_lastError = $"Verify bundle content failed : {_bundleInfo.Bundle.FileName}";
// 验证失败后删除文件
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
_steps = ESteps.TryAgain;
}
}
// 重新尝试下载 // 重新尝试下载
if (_steps == ESteps.TryAgain) if (_steps == ESteps.TryAgain)
{ {
if (_failedTryAgain <= 0)
{
ReportError();
_steps = ESteps.Failed;
return;
}
_tryAgainTimer += Time.unscaledDeltaTime; _tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f) if (_tryAgainTimer > 1f)
{ {
_failedTryAgain--; _failedTryAgain--;
_steps = ESteps.CreateDownload; _steps = ESteps.PrepareDownload;
ReportWarning();
YooLogger.Warning($"Try again download : {_requestURL}"); YooLogger.Warning($"Try again download : {_requestURL}");
} }
} }