Update DownloadSystem
parent
e0e9f90073
commit
32d422aeaa
|
@ -0,0 +1,122 @@
|
||||||
|
|
||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
internal abstract class DownloaderBase
|
||||||
|
{
|
||||||
|
protected enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
CreateDownload,
|
||||||
|
CheckDownload,
|
||||||
|
TryAgain,
|
||||||
|
Succeed,
|
||||||
|
Failed,
|
||||||
|
}
|
||||||
|
|
||||||
|
protected readonly BundleInfo _bundleInfo;
|
||||||
|
|
||||||
|
protected ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
protected int _timeout;
|
||||||
|
protected int _failedTryAgain;
|
||||||
|
protected int _requestCount;
|
||||||
|
protected string _requestURL;
|
||||||
|
|
||||||
|
protected string _lastError = string.Empty;
|
||||||
|
protected float _downloadProgress = 0f;
|
||||||
|
protected ulong _downloadedBytes = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载进度(0-100f)
|
||||||
|
/// </summary>
|
||||||
|
public float DownloadProgress
|
||||||
|
{
|
||||||
|
get { return _downloadProgress; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 已经下载的总字节数
|
||||||
|
/// </summary>
|
||||||
|
public ulong DownloadedBytes
|
||||||
|
{
|
||||||
|
get { return _downloadedBytes; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal DownloaderBase(BundleInfo bundleInfo)
|
||||||
|
{
|
||||||
|
_bundleInfo = bundleInfo;
|
||||||
|
}
|
||||||
|
internal void SendRequest(int failedTryAgain, int timeout)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_bundleInfo.LocalPath))
|
||||||
|
throw new System.ArgumentNullException();
|
||||||
|
|
||||||
|
if (_steps == ESteps.None)
|
||||||
|
{
|
||||||
|
_failedTryAgain = failedTryAgain;
|
||||||
|
_timeout = timeout;
|
||||||
|
_steps = ESteps.CreateDownload;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal void SetDone()
|
||||||
|
{
|
||||||
|
_steps = ESteps.Succeed;
|
||||||
|
}
|
||||||
|
internal abstract void Update();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取网络请求地址
|
||||||
|
/// </summary>
|
||||||
|
protected string GetRequestURL()
|
||||||
|
{
|
||||||
|
// 轮流返回请求地址
|
||||||
|
_requestCount++;
|
||||||
|
if (_requestCount % 2 == 0)
|
||||||
|
return _bundleInfo.RemoteFallbackURL;
|
||||||
|
else
|
||||||
|
return _bundleInfo.RemoteMainURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取资源包信息
|
||||||
|
/// </summary>
|
||||||
|
public BundleInfo GetBundleInfo()
|
||||||
|
{
|
||||||
|
return _bundleInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检测下载器是否已经完成(无论成功或失败)
|
||||||
|
/// </summary>
|
||||||
|
public bool IsDone()
|
||||||
|
{
|
||||||
|
return _steps == ESteps.Succeed || _steps == ESteps.Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载过程是否发生错误
|
||||||
|
/// </summary>
|
||||||
|
public bool HasError()
|
||||||
|
{
|
||||||
|
return _steps == ESteps.Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 报告错误信息
|
||||||
|
/// </summary>
|
||||||
|
public void ReportError()
|
||||||
|
{
|
||||||
|
YooLogger.Error($"Failed to download : {_requestURL} Error : {_lastError}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取最近一条错误日志
|
||||||
|
/// </summary>
|
||||||
|
public string GetLastError()
|
||||||
|
{
|
||||||
|
return _lastError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: dda4d1eafa2c9f34fade509f8dae9c04
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -7,82 +7,39 @@ using UnityEngine.Networking;
|
||||||
|
|
||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
internal class FileDownloader
|
internal sealed class FileDownloader : DownloaderBase
|
||||||
{
|
{
|
||||||
private enum ESteps
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
CreateDownload,
|
|
||||||
CheckDownload,
|
|
||||||
TryAgain,
|
|
||||||
Succeed,
|
|
||||||
Failed,
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly BundleInfo _bundleInfo;
|
|
||||||
private UnityWebRequest _webRequest;
|
private UnityWebRequest _webRequest;
|
||||||
private UnityWebRequestAsyncOperation _operationHandle;
|
private UnityWebRequestAsyncOperation _operationHandle;
|
||||||
|
|
||||||
private ESteps _steps = ESteps.None;
|
|
||||||
private string _lastError = string.Empty;
|
|
||||||
|
|
||||||
private int _timeout;
|
|
||||||
private int _failedTryAgain;
|
|
||||||
private int _requestCount;
|
|
||||||
private string _requestURL;
|
|
||||||
|
|
||||||
// 重置变量
|
// 重置变量
|
||||||
private bool _isAbort = false;
|
private bool _isAbort = false;
|
||||||
private ulong _latestDownloadBytes;
|
private ulong _latestDownloadBytes;
|
||||||
private float _latestDownloadRealtime;
|
private float _latestDownloadRealtime;
|
||||||
private float _tryAgainTimer;
|
private float _tryAgainTimer;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 下载进度(0-100f)
|
|
||||||
/// </summary>
|
|
||||||
public float DownloadProgress { private set; get; }
|
|
||||||
|
|
||||||
/// <summary>
|
internal FileDownloader(BundleInfo bundleInfo) : base(bundleInfo)
|
||||||
/// 已经下载的总字节数
|
|
||||||
/// </summary>
|
|
||||||
public ulong DownloadedBytes { private set; get; }
|
|
||||||
|
|
||||||
|
|
||||||
internal FileDownloader(BundleInfo bundleInfo)
|
|
||||||
{
|
{
|
||||||
_bundleInfo = bundleInfo;
|
|
||||||
}
|
}
|
||||||
internal void SendRequest(int failedTryAgain, int timeout)
|
internal override void Update()
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(_bundleInfo.LocalPath))
|
|
||||||
throw new ArgumentNullException();
|
|
||||||
|
|
||||||
if (_steps == ESteps.None)
|
|
||||||
{
|
|
||||||
_failedTryAgain = failedTryAgain;
|
|
||||||
_timeout = timeout;
|
|
||||||
_steps = ESteps.CreateDownload;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal void Update()
|
|
||||||
{
|
{
|
||||||
if (_steps == ESteps.None)
|
if (_steps == ESteps.None)
|
||||||
return;
|
return;
|
||||||
if (_steps == ESteps.Failed || _steps == ESteps.Succeed)
|
if (IsDone())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// 创建下载器
|
// 创建下载器
|
||||||
if (_steps == ESteps.CreateDownload)
|
if (_steps == ESteps.CreateDownload)
|
||||||
{
|
{
|
||||||
// 重置变量
|
// 重置变量
|
||||||
DownloadProgress = 0f;
|
_downloadProgress = 0f;
|
||||||
DownloadedBytes = 0;
|
_downloadedBytes = 0;
|
||||||
_isAbort = false;
|
_isAbort = false;
|
||||||
_latestDownloadBytes = 0;
|
_latestDownloadBytes = 0;
|
||||||
_latestDownloadRealtime = Time.realtimeSinceStartup;
|
_latestDownloadRealtime = Time.realtimeSinceStartup;
|
||||||
_tryAgainTimer = 0f;
|
_tryAgainTimer = 0f;
|
||||||
|
|
||||||
_requestCount++;
|
|
||||||
_requestURL = GetRequestURL();
|
_requestURL = GetRequestURL();
|
||||||
_webRequest = new UnityWebRequest(_requestURL, UnityWebRequest.kHttpVerbGET);
|
_webRequest = new UnityWebRequest(_requestURL, UnityWebRequest.kHttpVerbGET);
|
||||||
DownloadHandlerFile handler = new DownloadHandlerFile(_bundleInfo.LocalPath);
|
DownloadHandlerFile handler = new DownloadHandlerFile(_bundleInfo.LocalPath);
|
||||||
|
@ -96,8 +53,8 @@ namespace YooAsset
|
||||||
// 检测下载结果
|
// 检测下载结果
|
||||||
if (_steps == ESteps.CheckDownload)
|
if (_steps == ESteps.CheckDownload)
|
||||||
{
|
{
|
||||||
DownloadProgress = _webRequest.downloadProgress * 100f;
|
_downloadProgress = _webRequest.downloadProgress * 100f;
|
||||||
DownloadedBytes = _webRequest.downloadedBytes;
|
_downloadedBytes = _webRequest.downloadedBytes;
|
||||||
if (_operationHandle.isDone == false)
|
if (_operationHandle.isDone == false)
|
||||||
{
|
{
|
||||||
CheckTimeout();
|
CheckTimeout();
|
||||||
|
@ -105,47 +62,50 @@ namespace YooAsset
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查网络错误
|
// 检查网络错误
|
||||||
bool isError = false;
|
bool hasError = false;
|
||||||
#if UNITY_2020_3_OR_NEWER
|
#if UNITY_2020_3_OR_NEWER
|
||||||
if (_webRequest.result != UnityWebRequest.Result.Success)
|
if (_webRequest.result != UnityWebRequest.Result.Success)
|
||||||
{
|
{
|
||||||
isError = true;
|
hasError = true;
|
||||||
_lastError = _webRequest.error;
|
_lastError = _webRequest.error;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (_webRequest.isNetworkError || _webRequest.isHttpError)
|
if (_webRequest.isNetworkError || _webRequest.isHttpError)
|
||||||
{
|
{
|
||||||
isError = true;
|
hasError = true;
|
||||||
_lastError = _webRequest.error;
|
_lastError = _webRequest.error;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// 检查文件完整性
|
// 检查文件完整性
|
||||||
if (isError == false)
|
if (hasError == false)
|
||||||
{
|
{
|
||||||
// 注意:如果文件验证失败需要删除文件
|
// 注意:如果文件验证失败需要删除文件
|
||||||
if (DownloadSystem.CheckContentIntegrity(_bundleInfo) == false)
|
if (DownloadSystem.CheckContentIntegrity(_bundleInfo) == false)
|
||||||
{
|
{
|
||||||
isError = true;
|
hasError = true;
|
||||||
_lastError = $"Verification failed";
|
_lastError = $"Verification failed";
|
||||||
if (File.Exists(_bundleInfo.LocalPath))
|
|
||||||
File.Delete(_bundleInfo.LocalPath);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isError)
|
if (hasError == false)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Succeed;
|
||||||
|
DownloadSystem.CacheVerifyFile(_bundleInfo.Hash, _bundleInfo.BundleName);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
ReportError();
|
ReportError();
|
||||||
|
|
||||||
|
if (File.Exists(_bundleInfo.LocalPath))
|
||||||
|
File.Delete(_bundleInfo.LocalPath);
|
||||||
|
|
||||||
|
// 失败后重新尝试
|
||||||
if (_failedTryAgain > 0)
|
if (_failedTryAgain > 0)
|
||||||
_steps = ESteps.TryAgain;
|
_steps = ESteps.TryAgain;
|
||||||
else
|
else
|
||||||
_steps = ESteps.Failed;
|
_steps = ESteps.Failed;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
_steps = ESteps.Succeed;
|
|
||||||
DownloadSystem.CacheVerifyFile(_bundleInfo.Hash, _bundleInfo.BundleName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 释放下载器
|
// 释放下载器
|
||||||
DisposeWebRequest();
|
DisposeWebRequest();
|
||||||
|
@ -155,7 +115,7 @@ namespace YooAsset
|
||||||
if (_steps == ESteps.TryAgain)
|
if (_steps == ESteps.TryAgain)
|
||||||
{
|
{
|
||||||
_tryAgainTimer += Time.unscaledDeltaTime;
|
_tryAgainTimer += Time.unscaledDeltaTime;
|
||||||
if (_tryAgainTimer > 0.5f)
|
if (_tryAgainTimer > 1f)
|
||||||
{
|
{
|
||||||
_failedTryAgain--;
|
_failedTryAgain--;
|
||||||
_steps = ESteps.CreateDownload;
|
_steps = ESteps.CreateDownload;
|
||||||
|
@ -163,19 +123,6 @@ namespace YooAsset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal void SetDone()
|
|
||||||
{
|
|
||||||
_steps = ESteps.Succeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetRequestURL()
|
|
||||||
{
|
|
||||||
// 轮流返回请求地址
|
|
||||||
if (_requestCount % 2 == 0)
|
|
||||||
return _bundleInfo.RemoteFallbackURL;
|
|
||||||
else
|
|
||||||
return _bundleInfo.RemoteMainURL;
|
|
||||||
}
|
|
||||||
private void CheckTimeout()
|
private void CheckTimeout()
|
||||||
{
|
{
|
||||||
// 注意:在连续时间段内无新增下载数据及判定为超时
|
// 注意:在连续时间段内无新增下载数据及判定为超时
|
||||||
|
@ -205,46 +152,5 @@ namespace YooAsset
|
||||||
_operationHandle = null;
|
_operationHandle = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取资源包信息
|
|
||||||
/// </summary>
|
|
||||||
public BundleInfo GetBundleInfo()
|
|
||||||
{
|
|
||||||
return _bundleInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 检测下载器是否已经完成(无论成功或失败)
|
|
||||||
/// </summary>
|
|
||||||
public bool IsDone()
|
|
||||||
{
|
|
||||||
return _steps == ESteps.Succeed || _steps == ESteps.Failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 下载过程是否发生错误
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool HasError()
|
|
||||||
{
|
|
||||||
return _steps == ESteps.Failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 报告错误信息
|
|
||||||
/// </summary>
|
|
||||||
public void ReportError()
|
|
||||||
{
|
|
||||||
YooLogger.Error($"Failed to download : {_requestURL} Error : {_lastError}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取最近一条错误日志
|
|
||||||
/// </summary>
|
|
||||||
public string GetLastError()
|
|
||||||
{
|
|
||||||
return _lastError;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,243 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Security;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
internal sealed class HttpDownloader : DownloaderBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 多线程下载器
|
||||||
|
/// </summary>
|
||||||
|
private class ThreadDownloader
|
||||||
|
{
|
||||||
|
private const int BufferSize = 1042 * 4;
|
||||||
|
|
||||||
|
private Thread _thread;
|
||||||
|
private string _url;
|
||||||
|
private string _savePath;
|
||||||
|
private string _fileHash;
|
||||||
|
private string _fileCRC;
|
||||||
|
private long _fileSize;
|
||||||
|
private int _timeout;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载是否结束
|
||||||
|
/// </summary>
|
||||||
|
public bool IsDone = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载结果(成功或失败)
|
||||||
|
/// </summary>
|
||||||
|
public bool Result = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 错误日志
|
||||||
|
/// </summary>
|
||||||
|
public string Error = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载进度
|
||||||
|
/// </summary>
|
||||||
|
public float DownloadProgress = 0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 已经下载的总字节数
|
||||||
|
/// </summary>
|
||||||
|
public ulong DownloadedBytes = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开始下载
|
||||||
|
/// </summary>
|
||||||
|
public void Run(string url, string savePath, string fileHash, string fileCRC, long fileSize, int timeout)
|
||||||
|
{
|
||||||
|
_url = url;
|
||||||
|
_savePath = savePath;
|
||||||
|
_fileHash = fileHash;
|
||||||
|
_fileCRC = fileCRC;
|
||||||
|
_fileSize = fileSize;
|
||||||
|
_timeout = timeout;
|
||||||
|
|
||||||
|
_thread = new Thread(ThreadRun);
|
||||||
|
_thread.IsBackground = true;
|
||||||
|
_thread.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 销毁下载器
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_thread != null)
|
||||||
|
{
|
||||||
|
_thread.Abort();
|
||||||
|
_thread = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void ThreadRun()
|
||||||
|
{
|
||||||
|
long fileTotalSize = _fileSize;
|
||||||
|
|
||||||
|
FileStream fileStream = null;
|
||||||
|
Stream webStream = null;
|
||||||
|
HttpWebResponse fileResponse = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 创建文件流
|
||||||
|
fileStream = new FileStream(_savePath, FileMode.OpenOrCreate, FileAccess.Write);
|
||||||
|
long fileLength = fileStream.Length;
|
||||||
|
|
||||||
|
// 创建HTTP下载请求
|
||||||
|
HttpWebRequest fileRequest = WebRequest.Create(_url) as HttpWebRequest;
|
||||||
|
fileRequest.Timeout = _timeout;
|
||||||
|
fileRequest.ReadWriteTimeout = _timeout;
|
||||||
|
fileRequest.ProtocolVersion = HttpVersion.Version10;
|
||||||
|
if (fileLength > 0)
|
||||||
|
{
|
||||||
|
// 注意:设置远端请求文件的起始位置
|
||||||
|
fileRequest.AddRange(fileLength);
|
||||||
|
// 注意:设置本地文件流的起始位置
|
||||||
|
fileStream.Seek(fileLength, SeekOrigin.Begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取下载数据并保存到文件
|
||||||
|
fileResponse = fileRequest.GetResponse() as HttpWebResponse;
|
||||||
|
webStream = fileResponse.GetResponseStream();
|
||||||
|
byte[] buffer = new byte[BufferSize];
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int length = webStream.Read(buffer, 0, buffer.Length);
|
||||||
|
if (length <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
fileStream.Write(buffer, 0, length);
|
||||||
|
|
||||||
|
// 计算下载进度
|
||||||
|
// 注意:原子操作保证数据安全
|
||||||
|
fileLength += length;
|
||||||
|
float progress = fileLength / fileTotalSize;
|
||||||
|
DownloadProgress = progress;
|
||||||
|
DownloadedBytes = (ulong)fileLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证下载文件完整性
|
||||||
|
bool verfiyResult = DownloadSystem.CheckContentIntegrity(_savePath, _fileSize, _fileCRC);
|
||||||
|
if (verfiyResult)
|
||||||
|
{
|
||||||
|
Result = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Result = false;
|
||||||
|
Error = $"Verify file content failed : {_fileHash}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Result = false;
|
||||||
|
Error = e.Message;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (webStream != null)
|
||||||
|
{
|
||||||
|
webStream.Close();
|
||||||
|
webStream.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileResponse != null)
|
||||||
|
{
|
||||||
|
fileResponse.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileStream != null)
|
||||||
|
{
|
||||||
|
fileStream.Close();
|
||||||
|
fileStream.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
IsDone = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ThreadDownloader _threadDownloader;
|
||||||
|
private float _tryAgainTimer;
|
||||||
|
|
||||||
|
internal HttpDownloader(BundleInfo bundleInfo) : base(bundleInfo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
internal override void Update()
|
||||||
|
{
|
||||||
|
if (_steps == ESteps.None)
|
||||||
|
return;
|
||||||
|
if (IsDone())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_steps == ESteps.CreateDownload)
|
||||||
|
{
|
||||||
|
// 重置变量
|
||||||
|
_downloadProgress = 0f;
|
||||||
|
_downloadedBytes = 0;
|
||||||
|
_tryAgainTimer = 0f;
|
||||||
|
|
||||||
|
_requestURL = GetRequestURL();
|
||||||
|
_threadDownloader = new ThreadDownloader();
|
||||||
|
_threadDownloader.Run(_requestURL, _bundleInfo.LocalPath, _bundleInfo.Hash, _bundleInfo.CRC, _bundleInfo.SizeBytes, _timeout);
|
||||||
|
_steps = ESteps.CheckDownload;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.CheckDownload)
|
||||||
|
{
|
||||||
|
_downloadProgress = _threadDownloader.DownloadProgress * 100f;
|
||||||
|
_downloadedBytes = _threadDownloader.DownloadedBytes;
|
||||||
|
if (_threadDownloader.IsDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_threadDownloader.Result)
|
||||||
|
{
|
||||||
|
DownloadSystem.CacheVerifyFile(_bundleInfo.Hash, _bundleInfo.BundleName);
|
||||||
|
_steps = ESteps.Succeed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_lastError = _threadDownloader.Error;
|
||||||
|
ReportError();
|
||||||
|
|
||||||
|
if (File.Exists(_bundleInfo.LocalPath))
|
||||||
|
File.Delete(_bundleInfo.LocalPath);
|
||||||
|
|
||||||
|
// 失败后重新尝试
|
||||||
|
if (_failedTryAgain > 0)
|
||||||
|
_steps = ESteps.TryAgain;
|
||||||
|
else
|
||||||
|
_steps = ESteps.Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 释放下载器
|
||||||
|
_threadDownloader.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新尝试下载
|
||||||
|
if (_steps == ESteps.TryAgain)
|
||||||
|
{
|
||||||
|
_tryAgainTimer += UnityEngine.Time.unscaledDeltaTime;
|
||||||
|
if (_tryAgainTimer > 1f)
|
||||||
|
{
|
||||||
|
_failedTryAgain--;
|
||||||
|
_steps = ESteps.CreateDownload;
|
||||||
|
YooLogger.Warning($"Try again download : {_requestURL}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,266 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Security;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace YooAsset
|
|
||||||
{
|
|
||||||
internal class HttpDownloader
|
|
||||||
{
|
|
||||||
private enum ESteps
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
CreateDownload,
|
|
||||||
CheckDownload,
|
|
||||||
Succeed,
|
|
||||||
Failed,
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly BundleInfo _bundleInfo;
|
|
||||||
private ESteps _steps = ESteps.None;
|
|
||||||
|
|
||||||
// 线程
|
|
||||||
private bool _threadOver = false;
|
|
||||||
private bool _threadResult = false;
|
|
||||||
private string _threadError = string.Empty;
|
|
||||||
private Thread _thread;
|
|
||||||
|
|
||||||
// 保留参数
|
|
||||||
private int _timeout;
|
|
||||||
private int _failedTryAgain;
|
|
||||||
private int _requestCount;
|
|
||||||
|
|
||||||
// 下载结果
|
|
||||||
private string _downloadError = string.Empty;
|
|
||||||
private float _downloadProgress = 0f;
|
|
||||||
private long _downloadBytes = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 下载进度(0-100f)
|
|
||||||
/// </summary>
|
|
||||||
public float DownloadProgress
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _downloadProgress;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 已经下载的总字节数
|
|
||||||
/// </summary>
|
|
||||||
public long DownloadedBytes
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _downloadBytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
internal HttpDownloader(BundleInfo bundleInfo)
|
|
||||||
{
|
|
||||||
_bundleInfo = bundleInfo;
|
|
||||||
}
|
|
||||||
internal void SendRequest(int failedTryAgain, int timeout)
|
|
||||||
{
|
|
||||||
_failedTryAgain = failedTryAgain;
|
|
||||||
_timeout = timeout;
|
|
||||||
}
|
|
||||||
internal void Update()
|
|
||||||
{
|
|
||||||
if (_steps == ESteps.None)
|
|
||||||
return;
|
|
||||||
if (_steps == ESteps.Succeed || _steps == ESteps.Failed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(_steps == ESteps.CreateDownload)
|
|
||||||
{
|
|
||||||
_downloadError = string.Empty;
|
|
||||||
_downloadProgress = 0f;
|
|
||||||
_downloadBytes = 0;
|
|
||||||
|
|
||||||
_threadOver = false;
|
|
||||||
_threadResult = false;
|
|
||||||
_threadError = string.Empty;
|
|
||||||
_thread = new Thread(ThreadRun);
|
|
||||||
_thread.IsBackground = true;
|
|
||||||
_thread.Start();
|
|
||||||
_steps = ESteps.CheckDownload;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_steps == ESteps.CheckDownload)
|
|
||||||
{
|
|
||||||
if (_threadOver == false)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(_thread != null)
|
|
||||||
{
|
|
||||||
_thread.Abort();
|
|
||||||
_thread = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
_downloadError = _threadError;
|
|
||||||
if (_threadResult)
|
|
||||||
{
|
|
||||||
DownloadSystem.CacheVerifyFile(_bundleInfo.Hash, _bundleInfo.BundleName);
|
|
||||||
_steps = ESteps.Succeed;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 失败后重新尝试
|
|
||||||
if(_failedTryAgain > 0)
|
|
||||||
{
|
|
||||||
_failedTryAgain--;
|
|
||||||
_steps = ESteps.CreateDownload;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_steps = ESteps.Failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal void SetDone()
|
|
||||||
{
|
|
||||||
_steps = ESteps.Succeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取资源包信息
|
|
||||||
/// </summary>
|
|
||||||
public BundleInfo GetBundleInfo()
|
|
||||||
{
|
|
||||||
return _bundleInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 检测下载器是否已经完成(无论成功或失败)
|
|
||||||
/// </summary>
|
|
||||||
public bool IsDone()
|
|
||||||
{
|
|
||||||
return _steps == ESteps.Succeed || _steps == ESteps.Failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 下载过程是否发生错误
|
|
||||||
/// </summary>
|
|
||||||
public bool HasError()
|
|
||||||
{
|
|
||||||
return _steps == ESteps.Failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 报告错误信息
|
|
||||||
/// </summary>
|
|
||||||
public void ReportError()
|
|
||||||
{
|
|
||||||
YooLogger.Error(_downloadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#region 多线程下载
|
|
||||||
public const int BufferSize = 1042 * 4;
|
|
||||||
private void ThreadRun()
|
|
||||||
{
|
|
||||||
string url = GetRequestURL();
|
|
||||||
string savePath = _bundleInfo.LocalPath;
|
|
||||||
long fileTotalSize = _bundleInfo.SizeBytes;
|
|
||||||
|
|
||||||
FileStream fileStream = null;
|
|
||||||
Stream webStream = null;
|
|
||||||
HttpWebResponse fileResponse = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 创建文件流
|
|
||||||
fileStream = new FileStream(savePath, FileMode.OpenOrCreate, FileAccess.Write);
|
|
||||||
long fileLength = fileStream.Length;
|
|
||||||
|
|
||||||
// 创建HTTP下载请求
|
|
||||||
HttpWebRequest fileRequest = WebRequest.Create(url) as HttpWebRequest;
|
|
||||||
fileRequest.Timeout = _timeout;
|
|
||||||
fileRequest.ReadWriteTimeout = _timeout;
|
|
||||||
fileRequest.ProtocolVersion = HttpVersion.Version10;
|
|
||||||
if (fileLength > 0)
|
|
||||||
{
|
|
||||||
// 注意:设置远端请求文件的起始位置
|
|
||||||
fileRequest.AddRange(fileLength);
|
|
||||||
// 注意:设置本地文件流的起始位置
|
|
||||||
fileStream.Seek(fileLength, SeekOrigin.Begin);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 读取下载数据并保存到文件
|
|
||||||
fileResponse = fileRequest.GetResponse() as HttpWebResponse;
|
|
||||||
webStream = fileResponse.GetResponseStream();
|
|
||||||
byte[] buffer = new byte[BufferSize];
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
int length = webStream.Read(buffer, 0, buffer.Length);
|
|
||||||
if (length <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
fileStream.Write(buffer, 0, length);
|
|
||||||
|
|
||||||
// 计算下载进度
|
|
||||||
// 注意:原子操作保证数据安全
|
|
||||||
fileLength += length;
|
|
||||||
float progress = (fileLength / fileTotalSize) * 100f;
|
|
||||||
_downloadProgress = progress;
|
|
||||||
_downloadBytes = fileLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证下载文件完整性
|
|
||||||
bool verfiyResult = DownloadSystem.CheckContentIntegrity(savePath, _bundleInfo.SizeBytes, _bundleInfo.CRC);
|
|
||||||
if(verfiyResult)
|
|
||||||
{
|
|
||||||
_threadResult = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_threadResult = false;
|
|
||||||
_threadError = $"Verify file content failed : {_bundleInfo.Hash}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
_threadResult = false;
|
|
||||||
_threadError = e.Message;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (webStream != null)
|
|
||||||
{
|
|
||||||
webStream.Close();
|
|
||||||
webStream.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileResponse != null)
|
|
||||||
{
|
|
||||||
fileResponse.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileStream != null)
|
|
||||||
{
|
|
||||||
fileStream.Close();
|
|
||||||
fileStream.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
_threadOver = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private string GetRequestURL()
|
|
||||||
{
|
|
||||||
// 轮流返回请求地址
|
|
||||||
_requestCount++;
|
|
||||||
if (_requestCount % 2 == 0)
|
|
||||||
return _bundleInfo.RemoteFallbackURL;
|
|
||||||
else
|
|
||||||
return _bundleInfo.RemoteMainURL;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue