123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.IO;
- using UnityEngine;
- using UnityEngine.Networking;
- namespace YooAsset
- {
- internal sealed class FileDownloader : DownloaderBase
- {
- private readonly bool _breakResume;
- private readonly string _tempFilePath;
- private UnityWebRequest _webRequest = null;
- private DownloadHandlerFileRange _downloadHandle = null;
- private VerifyTempFileOperation _checkFileOp = null;
- private VerifyTempFileOperation _verifyFileOp = null;
- // 重置变量
- private bool _isAbort = false;
- private ulong _fileOriginLength;
- private ulong _latestDownloadBytes;
- private float _latestDownloadRealtime;
- private float _tryAgainTimer;
- public FileDownloader(BundleInfo bundleInfo, bool breakResume) : base(bundleInfo)
- {
- _breakResume = breakResume;
- _tempFilePath = bundleInfo.Bundle.TempDataFilePath;
- }
- public override void Update()
- {
- if (_steps == ESteps.None)
- return;
- if (IsDone())
- return;
- // 检测临时文件
- if (_steps == ESteps.CheckTempFile)
- {
- 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 (WaitForAsyncComplete)
- _checkFileOp.Update();
- if (_checkFileOp.IsDone == false)
- return;
- if (_checkFileOp.Status == EOperationStatus.Succeed)
- {
- _steps = ESteps.CachingFile;
- }
- else
- {
- if (_checkFileOp.VerifyResult == EVerifyResult.FileOverflow)
- {
- if (File.Exists(_tempFilePath))
- File.Delete(_tempFilePath);
- }
- _steps = ESteps.PrepareDownload;
- }
- }
- // 创建下载器
- if (_steps == ESteps.PrepareDownload)
- {
- // 重置变量
- _downloadProgress = 0f;
- _downloadedBytes = 0;
- _isAbort = false;
- _fileOriginLength = 0;
- _latestDownloadBytes = 0;
- _latestDownloadRealtime = Time.realtimeSinceStartup;
- _tryAgainTimer = 0f;
- // 获取请求地址
- _requestURL = GetRequestURL();
- if (_breakResume)
- _steps = ESteps.CreateResumeDownloader;
- else
- _steps = ESteps.CreateGeneralDownloader;
- }
- // 创建普通的下载器
- if (_steps == ESteps.CreateGeneralDownloader)
- {
- if (File.Exists(_tempFilePath))
- File.Delete(_tempFilePath);
- _webRequest = DownloadSystem.NewRequest(_requestURL);
- DownloadHandlerFile handler = new DownloadHandlerFile(_tempFilePath);
- handler.removeFileOnAbort = true;
- _webRequest.downloadHandler = handler;
- _webRequest.disposeDownloadHandlerOnDispose = true;
- _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 = DownloadSystem.NewRequest(_requestURL);
- var handler = new DownloadHandlerFile(_tempFilePath, true);
- handler.removeFileOnAbort = false;
- #else
- _webRequest = DownloadSystem.NewRequest(_requestURL);
- var handler = new DownloadHandlerFileRange(_tempFilePath, _bundleInfo.Bundle.FileSize, _webRequest);
- _downloadHandle = handler;
- #endif
- _webRequest.downloadHandler = handler;
- _webRequest.disposeDownloadHandlerOnDispose = true;
- if (fileLength > 0)
- _webRequest.SetRequestHeader("Range", $"bytes={fileLength}-");
- _webRequest.SendWebRequest();
- _steps = ESteps.CheckDownload;
- }
- // 检测下载结果
- if (_steps == ESteps.CheckDownload)
- {
- _downloadProgress = _webRequest.downloadProgress;
- _downloadedBytes = _fileOriginLength + _webRequest.downloadedBytes;
- if (_webRequest.isDone == false)
- {
- CheckTimeout();
- return;
- }
- bool hasError = false;
- // 检查网络错误
- #if UNITY_2020_3_OR_NEWER
- if (_webRequest.result != UnityWebRequest.Result.Success)
- {
- hasError = true;
- _lastError = _webRequest.error;
- _lastCode = _webRequest.responseCode;
- }
- #else
- if (_webRequest.isNetworkError || _webRequest.isHttpError)
- {
- hasError = true;
- _lastError = _webRequest.error;
- _lastCode = _webRequest.responseCode;
- }
- #endif
- // 如果网络异常
- if (hasError)
- {
- if (_breakResume)
- {
- // 注意:下载断点续传文件发生特殊错误码之后删除文件
- if (DownloadSystem.ClearFileResponseCodes != null)
- {
- if (DownloadSystem.ClearFileResponseCodes.Contains(_webRequest.responseCode))
- {
- if (File.Exists(_tempFilePath))
- File.Delete(_tempFilePath);
- }
- }
- }
- else
- {
- // 注意:非断点续传下载失败之后删除文件
- if (File.Exists(_tempFilePath))
- File.Delete(_tempFilePath);
- }
- _steps = ESteps.TryAgain;
- }
- else
- {
- _steps = ESteps.VerifyTempFile;
- }
- // 释放下载器
- DisposeWebRequest();
- }
- // 验证下载文件
- if (_steps == ESteps.VerifyTempFile)
- {
- 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 (WaitForAsyncComplete)
- _verifyFileOp.Update();
- if (_verifyFileOp.IsDone == false)
- return;
- if (_verifyFileOp.Status == EOperationStatus.Succeed)
- {
- _steps = ESteps.CachingFile;
- }
- else
- {
- if (File.Exists(_tempFilePath))
- File.Delete(_tempFilePath);
- _lastError = _verifyFileOp.Error;
- _steps = ESteps.TryAgain;
- }
- }
- // 缓存下载文件
- if (_steps == ESteps.CachingFile)
- {
- try
- {
- string infoFilePath = _bundleInfo.Bundle.CachedInfoFilePath;
- string dataFilePath = _bundleInfo.Bundle.CachedDataFilePath;
- string dataFileCRC = _bundleInfo.Bundle.FileCRC;
- long dataFileSize = _bundleInfo.Bundle.FileSize;
- if (File.Exists(infoFilePath))
- File.Delete(infoFilePath);
- if (File.Exists(dataFilePath))
- File.Delete(dataFilePath);
- FileInfo fileInfo = new FileInfo(_tempFilePath);
- fileInfo.MoveTo(dataFilePath);
- // 写入信息文件记录验证数据
- CacheFileInfo.WriteInfoToFile(infoFilePath, dataFileCRC, dataFileSize);
- // 记录缓存文件
- var wrapper = new PackageCache.RecordWrapper(infoFilePath, dataFilePath, dataFileCRC, dataFileSize);
- CacheSystem.RecordFile(_bundleInfo.Bundle.PackageName, _bundleInfo.Bundle.CacheGUID, wrapper);
- _lastError = string.Empty;
- _lastCode = 0;
- _steps = ESteps.Succeed;
- }
- catch (Exception e)
- {
- _lastError = e.Message;
- _steps = ESteps.TryAgain;
- }
- }
- // 重新尝试下载
- if (_steps == ESteps.TryAgain)
- {
- if (_failedTryAgain <= 0)
- {
- ReportError();
- _steps = ESteps.Failed;
- return;
- }
- _tryAgainTimer += Time.unscaledDeltaTime;
- if (_tryAgainTimer > 1f)
- {
- _failedTryAgain--;
- _steps = ESteps.PrepareDownload;
- ReportWarning();
- YooLogger.Warning($"Try again download : {_requestURL}");
- }
- }
- }
- public override void Abort()
- {
- if (IsDone() == false)
- {
- _steps = ESteps.Failed;
- _lastError = "user abort";
- _lastCode = 0;
- DisposeWebRequest();
- }
- }
- private void CheckTimeout()
- {
- // 注意:在连续时间段内无新增下载数据及判定为超时
- if (_isAbort == false)
- {
- if (_latestDownloadBytes != DownloadedBytes)
- {
- _latestDownloadBytes = DownloadedBytes;
- _latestDownloadRealtime = Time.realtimeSinceStartup;
- }
- float offset = Time.realtimeSinceStartup - _latestDownloadRealtime;
- if (offset > _timeout)
- {
- YooLogger.Warning($"Web file request timeout : {_requestURL}");
- _webRequest.Abort();
- _isAbort = true;
- }
- }
- }
- private void DisposeWebRequest()
- {
- if (_downloadHandle != null)
- {
- _downloadHandle.Cleanup();
- _downloadHandle = null;
- }
- if (_webRequest != null)
- {
- _webRequest.Dispose();
- _webRequest = null;
- }
- }
- }
- }
|