YooAsset/Assets/YooAsset/Runtime/CacheSystem/PatchCacheVerifier.cs

254 lines
7.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace YooAsset
{
/// <summary>
/// 本地缓存文件验证器
/// </summary>
internal abstract class PatchCacheVerifier
{
public abstract bool InitVerifier(PatchManifest appPatchManifest, PatchManifest localPatchManifest, bool weaklyUpdate);
public abstract bool UpdateVerifier();
public abstract float GetVerifierProgress();
public int VerifySuccessCount { protected set; get; } = 0;
public int VerifyFailCount { protected set; get; } = 0;
}
/// <summary>
/// 本地缓存文件验证器(线程版)
/// </summary>
internal class PatchCacheVerifierWithThread : PatchCacheVerifier
{
private class ThreadInfo
{
public bool Result = false;
public string FilePath { private set; get; }
public PatchBundle Bundle { private set; get; }
public ThreadInfo(string filePath, PatchBundle bundle)
{
FilePath = filePath;
Bundle = bundle;
}
}
private readonly ThreadSyncContext _syncContext = new ThreadSyncContext();
private readonly List<PatchBundle> _waitingList = new List<PatchBundle>(1000);
private readonly List<PatchBundle> _verifyingList = new List<PatchBundle>(100);
private int _verifyMaxNum;
private int _verifyTotalCount;
public override bool InitVerifier(PatchManifest appPatchManifest, PatchManifest localPatchManifest, bool weaklyUpdate)
{
// 遍历所有文件然后验证并缓存合法文件
foreach (var patchBundle in localPatchManifest.BundleList)
{
// 忽略缓存文件
if (CacheSystem.IsCached(patchBundle))
continue;
// 忽略APP资源
// 注意如果是APP资源并且哈希值相同则不需要下载
if (appPatchManifest.TryGetPatchBundle(patchBundle.BundleName, out PatchBundle appPatchBundle))
{
if (appPatchBundle.IsBuildin && appPatchBundle.Equals(patchBundle))
continue;
}
// 注意:在弱联网模式下,我们需要验证指定资源版本的所有资源完整性
if (weaklyUpdate)
{
string filePath = patchBundle.CachedFilePath;
if (File.Exists(filePath))
_waitingList.Add(patchBundle);
else
return false;
}
else
{
string filePath = patchBundle.CachedFilePath;
if (File.Exists(filePath))
_waitingList.Add(patchBundle);
}
}
// 设置同时验证的最大数
ThreadPool.GetMaxThreads(out int workerThreads, out int ioThreads);
YooLogger.Log($"Work threads : {workerThreads}, IO threads : {ioThreads}");
_verifyMaxNum = Math.Min(workerThreads, ioThreads);
_verifyTotalCount = _waitingList.Count;
if (_verifyMaxNum < 1)
_verifyMaxNum = 1;
return true;
}
public override bool UpdateVerifier()
{
_syncContext.Update();
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
return true;
if (_verifyingList.Count >= _verifyMaxNum)
return false;
for (int i = _waitingList.Count - 1; i >= 0; i--)
{
if (_verifyingList.Count >= _verifyMaxNum)
break;
var patchBundle = _waitingList[i];
if (VerifyFile(patchBundle))
{
_waitingList.RemoveAt(i);
_verifyingList.Add(patchBundle);
}
else
{
YooLogger.Warning("The thread pool is failed queued.");
break;
}
}
return false;
}
public override float GetVerifierProgress()
{
if (_verifyTotalCount == 0)
return 1f;
return (float)(VerifySuccessCount + VerifyFailCount) / _verifyTotalCount;
}
private bool VerifyFile(PatchBundle patchBundle)
{
string filePath = patchBundle.CachedFilePath;
ThreadInfo info = new ThreadInfo(filePath, patchBundle);
return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), info);
}
private void VerifyInThread(object infoObj)
{
ThreadInfo info = (ThreadInfo)infoObj;
info.Result = CacheSystem.VerifyBundle(info.Bundle, CacheSystem.InitVerifyLevel);
_syncContext.Post(VerifyCallback, info);
}
private void VerifyCallback(object obj)
{
ThreadInfo info = (ThreadInfo)obj;
if (info.Result)
{
VerifySuccessCount++;
CacheSystem.CacheBundle(info.Bundle);
}
else
{
VerifyFailCount++;
YooLogger.Warning($"Failed to verify file : {info.Bundle.CachedFilePath}");
// NOTE不期望删除断点续传的资源文件
/*
if (File.Exists(patchBundle.CachedBundleFilePath))
File.Delete(patchBundle.CachedBundleFilePath);
*/
}
_verifyingList.Remove(info.Bundle);
}
}
/// <summary>
/// 本地缓存文件验证器(非线程版)
/// </summary>
internal class PatchCacheVerifierWithoutThread : PatchCacheVerifier
{
private readonly List<PatchBundle> _waitingList = new List<PatchBundle>(1000);
private readonly List<PatchBundle> _verifyingList = new List<PatchBundle>(100);
private int _verifyMaxNum;
private int _verifyTotalCount;
public override bool InitVerifier(PatchManifest appPatchManifest, PatchManifest localPatchManifest, bool weaklyUpdate)
{
// 遍历所有文件然后验证并缓存合法文件
foreach (var patchBundle in localPatchManifest.BundleList)
{
// 忽略缓存文件
if (CacheSystem.IsCached(patchBundle))
continue;
// 忽略APP资源
// 注意如果是APP资源并且哈希值相同则不需要下载
if (appPatchManifest.TryGetPatchBundle(patchBundle.BundleName, out PatchBundle appPatchBundle))
{
if (appPatchBundle.IsBuildin && appPatchBundle.Equals(patchBundle))
continue;
}
// 注意:在弱联网模式下,我们需要验证指定资源版本的所有资源完整性
if (weaklyUpdate)
{
string filePath = patchBundle.CachedFilePath;
if (File.Exists(filePath))
_waitingList.Add(patchBundle);
else
return false;
}
else
{
string filePath = patchBundle.CachedFilePath;
if (File.Exists(filePath))
_waitingList.Add(patchBundle);
}
}
// 设置同时验证的最大数
_verifyMaxNum = 32;
_verifyTotalCount = _waitingList.Count;
return true;
}
public override bool UpdateVerifier()
{
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
return true;
for (int i = _waitingList.Count - 1; i >= 0; i--)
{
if (_verifyingList.Count >= _verifyMaxNum)
break;
var patchBundle = _waitingList[i];
VerifyFile(patchBundle);
_waitingList.RemoveAt(i);
_verifyingList.Add(patchBundle);
}
_verifyingList.Clear();
return false;
}
public override float GetVerifierProgress()
{
if (_verifyTotalCount == 0)
return 1f;
return (float)(VerifySuccessCount + VerifyFailCount) / _verifyTotalCount;
}
private void VerifyFile(PatchBundle patchBundle)
{
if (CacheSystem.VerifyAndCacheBundle(patchBundle, CacheSystem.InitVerifyLevel))
{
VerifySuccessCount++;
}
else
{
VerifyFailCount++;
YooLogger.Warning($"Failed to verify file : {patchBundle.CachedFilePath}");
// NOTE不期望删除断点续传的资源文件
/*
if (File.Exists(patchBundle.CachedBundleFilePath))
File.Delete(patchBundle.CachedBundleFilePath);
*/
}
}
}
}