Files
YooAsset/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/internal/Scheduler/DownloadAndCacheLocalFileOperation.cs
2026-01-17 18:44:48 +08:00

192 lines
6.9 KiB
C#

using System.IO;
namespace YooAsset
{
internal sealed class DownloadAndCacheLocalFileOperation : DownloadAndCacheFileOperation
{
private enum ESteps
{
None,
CheckCopy,
CopyLocalFile,
CreateRequest,
CheckRequest,
VerifyBundleFile,
CacheBundleFile,
Done,
}
private readonly DefaultCacheFileSystem _fileSystem;
private readonly PackageBundle _bundle;
private readonly string _tempFilePath;
private IDownloadRequest _request;
private VerifyTempFileOperation _verifyOperation;
private ESteps _steps = ESteps.None;
internal DownloadAndCacheLocalFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, string url) : base(url)
{
_fileSystem = fileSystem;
_bundle = bundle;
_tempFilePath = _fileSystem.GetTempFilePath(_bundle);
}
internal override void InternalStart()
{
_steps = ESteps.CheckCopy;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
// 检测文件拷贝
if (_steps == ESteps.CheckCopy)
{
// 删除历史缓存文件
FileUtility.CreateFileDirectory(_tempFilePath);
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
if (_fileSystem.CopyLocalFileServices != null)
_steps = ESteps.CopyLocalFile;
else
_steps = ESteps.CreateRequest;
}
// 拷贝本地文件
if (_steps == ESteps.CopyLocalFile)
{
try
{
//TODO 团结引擎,在某些机型(红米),拷贝包内文件会小概率失败!需要借助其它方式来拷贝包内文件。
var localFileInfo = new LocalFileInfo();
localFileInfo.PackageName = _fileSystem.PackageName;
localFileInfo.BundleName = _bundle.BundleName;
localFileInfo.SourceFileURL = URL;
_fileSystem.CopyLocalFileServices.CopyFile(localFileInfo, _tempFilePath);
if (File.Exists(_tempFilePath))
{
DownloadProgress = 1f;
DownloadedBytes = _bundle.FileSize;
_steps = ESteps.VerifyBundleFile;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed copy local file : {URL}";
}
}
catch (System.Exception ex)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed copy local file : {ex.Message}";
}
}
// 创建下载请求
if (_steps == ESteps.CreateRequest)
{
int watchdogTime = _fileSystem.DownloadWatchDogTime;
int timeout = 0; //注意:文件下载不做超时检测
var args = new DownloadFileRequestArgs(URL, _tempFilePath, timeout, watchdogTime);
_request = _fileSystem.DownloadBackend.CreateFileRequest(args);
_request.SendRequest();
_steps = ESteps.CheckRequest;
}
// 检测下载结果
if (_steps == ESteps.CheckRequest)
{
//TODO 更新下载后台,防止无限挂起
if (IsWaitForAsyncComplete)
_fileSystem.DownloadBackend.Update();
DownloadProgress = _request.DownloadProgress;
DownloadedBytes = _request.DownloadedBytes;
Progress = DownloadProgress;
if (_request.IsDone == false)
return;
// 检查网络错误
if (_request.Status == EDownloadRequestStatus.Succeed)
{
_steps = ESteps.VerifyBundleFile;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _request.Error;
}
// 最终释放请求器
_request.Dispose();
}
// 验证下载结果
if (_steps == ESteps.VerifyBundleFile)
{
if (_verifyOperation == null)
{
var element = new TempFileElement(_tempFilePath, _bundle.FileCRC, _bundle.FileSize);
_verifyOperation = new VerifyTempFileOperation(element);
_verifyOperation.StartOperation();
AddChildOperation(_verifyOperation);
}
if (IsWaitForAsyncComplete)
_verifyOperation.WaitForAsyncComplete();
_verifyOperation.UpdateOperation();
if (_verifyOperation.IsDone == false)
return;
if (_verifyOperation.Status == EOperationStatus.Succeed)
{
_steps = ESteps.CacheBundleFile;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _verifyOperation.Error;
// 注意:验证失败后直接删除文件
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
}
// 缓存文件
if (_steps == ESteps.CacheBundleFile)
{
if (_fileSystem.WriteCacheBundleFile(_bundle, _tempFilePath))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{_fileSystem.GetType().FullName} failed to write file.";
}
// 注意:缓存完成后直接删除临时文件
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
}
internal override void InternalAbort()
{
if (_request != null)
_request.Dispose();
}
internal override void InternalWaitForAsyncComplete()
{
//TODO 等待导入或解压本地文件完毕,该操作会挂起主线程!
RunUntilCompletion();
}
}
}