Update DownloadSystem

pull/4/head
hevinci 2022-04-04 22:43:37 +08:00
parent a0c8c9dc67
commit f1615b4487
10 changed files with 146 additions and 59 deletions

View File

@ -15,7 +15,15 @@ namespace YooAsset
private static readonly Dictionary<string, DownloaderBase> _downloaderDic = new Dictionary<string, DownloaderBase>(); private static readonly Dictionary<string, DownloaderBase> _downloaderDic = new Dictionary<string, DownloaderBase>();
private static readonly List<string> _removeList = new List<string>(100); private static readonly List<string> _removeList = new List<string>(100);
private static readonly Dictionary<string, string> _cachedHashList = new Dictionary<string, string>(1000); private static readonly Dictionary<string, string> _cachedHashList = new Dictionary<string, string>(1000);
private static int _breakpointResumeFileSize;
/// <summary>
/// 初始化
/// </summary>
public static void Initialize(int breakpointResumeFileSize)
{
_breakpointResumeFileSize = breakpointResumeFileSize;
}
/// <summary> /// <summary>
/// 更新所有下载器 /// 更新所有下载器
@ -39,6 +47,21 @@ namespace YooAsset
} }
} }
/// <summary>
/// 销毁所有下载器
/// </summary>
public static void DestroyAll()
{
foreach (var valuePair in _downloaderDic)
{
var downloader = valuePair.Value;
downloader.Abort();
}
_downloaderDic.Clear();
YooLogger.Log("DownloadSystem destroy all !");
}
/// <summary> /// <summary>
/// 开始下载资源文件 /// 开始下载资源文件
/// 注意:只有第一次请求的参数才是有效的 /// 注意:只有第一次请求的参数才是有效的
@ -54,16 +77,19 @@ namespace YooAsset
// 如果资源已经缓存 // 如果资源已经缓存
if (ContainsVerifyFile(bundleInfo.Hash)) if (ContainsVerifyFile(bundleInfo.Hash))
{ {
var newDownloader = new FileDownloader(bundleInfo); var tempDownloader = new TempDownloader(bundleInfo);
newDownloader.SetDone(); return tempDownloader;
return newDownloader;
} }
// 创建新的下载器 // 创建新的下载器
{ {
YooLogger.Log($"Beginning to download file : {bundleInfo.BundleName} URL : {bundleInfo.RemoteMainURL}"); YooLogger.Log($"Beginning to download file : {bundleInfo.BundleName} URL : {bundleInfo.RemoteMainURL}");
FileUtility.CreateFileDirectory(bundleInfo.LocalPath); FileUtility.CreateFileDirectory(bundleInfo.LocalPath);
var newDownloader = new HttpDownloader(bundleInfo); DownloaderBase newDownloader;
if (bundleInfo.SizeBytes >= _breakpointResumeFileSize)
newDownloader = new HttpDownloader(bundleInfo);
else
newDownloader = new FileDownloader(bundleInfo);
newDownloader.SendRequest(failedTryAgain, timeout); newDownloader.SendRequest(failedTryAgain, timeout);
_downloaderDic.Add(bundleInfo.Hash, newDownloader); _downloaderDic.Add(bundleInfo.Hash, newDownloader);
return newDownloader; return newDownloader;

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a82eeb6a47cd02c4cb38e851c8ed8784
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -44,11 +44,11 @@ namespace YooAsset
} }
internal DownloaderBase(BundleInfo bundleInfo) public DownloaderBase(BundleInfo bundleInfo)
{ {
_bundleInfo = bundleInfo; _bundleInfo = bundleInfo;
} }
internal void SendRequest(int failedTryAgain, int timeout) public void SendRequest(int failedTryAgain, int timeout)
{ {
if (string.IsNullOrEmpty(_bundleInfo.LocalPath)) if (string.IsNullOrEmpty(_bundleInfo.LocalPath))
throw new System.ArgumentNullException(); throw new System.ArgumentNullException();
@ -60,11 +60,8 @@ namespace YooAsset
_steps = ESteps.CreateDownload; _steps = ESteps.CreateDownload;
} }
} }
internal void SetDone() public abstract void Update();
{ public abstract void Abort();
_steps = ESteps.Succeed;
}
internal abstract void Update();
/// <summary> /// <summary>
/// 获取网络请求地址 /// 获取网络请求地址

View File

@ -19,10 +19,10 @@ namespace YooAsset
private float _tryAgainTimer; private float _tryAgainTimer;
internal FileDownloader(BundleInfo bundleInfo) : base(bundleInfo) public FileDownloader(BundleInfo bundleInfo) : base(bundleInfo)
{ {
} }
internal override void Update() public override void Update()
{ {
if (_steps == ESteps.None) if (_steps == ESteps.None)
return; return;
@ -123,6 +123,16 @@ namespace YooAsset
} }
} }
} }
public override void Abort()
{
if (IsDone() == false)
{
_steps = ESteps.Failed;
_lastError = "user abort";
DisposeWebRequest();
}
}
private void CheckTimeout() private void CheckTimeout()
{ {
// 注意:在连续时间段内无新增下载数据及判定为超时 // 注意:在连续时间段内无新增下载数据及判定为超时

View File

@ -18,6 +18,7 @@ namespace YooAsset
private const int BufferSize = 1042 * 4; private const int BufferSize = 1042 * 4;
private Thread _thread; private Thread _thread;
private bool _running = true;
private string _url; private string _url;
private string _savePath; private string _savePath;
private string _fileHash; private string _fileHash;
@ -30,11 +31,6 @@ namespace YooAsset
/// </summary> /// </summary>
public bool IsDone = false; public bool IsDone = false;
/// <summary>
/// 下载结果(成功或失败)
/// </summary>
public bool Result = true;
/// <summary> /// <summary>
/// 错误日志 /// 错误日志
/// </summary> /// </summary>
@ -69,51 +65,57 @@ namespace YooAsset
} }
/// <summary> /// <summary>
/// 销毁下载器 /// 中断下载线程
/// </summary> /// </summary>
public void Dispose() public void Abort()
{ {
if (_thread != null) _running = false;
{
_thread.Abort();
_thread = null;
}
} }
/// <summary>
/// 下载结果
/// </summary>
public bool HasError()
{
if (string.IsNullOrEmpty(Error))
return false;
else
return true;
}
private void ThreadRun() private void ThreadRun()
{ {
long fileTotalSize = _fileSize; long fileTotalSize = _fileSize;
FileStream fileStream = null; FileStream fileStream = null;
Stream webStream = null; HttpWebResponse webResponse = null;
HttpWebResponse fileResponse = null; Stream responseStream = null;
try try
{ {
// 创建文件流 // 创建文件流
fileStream = new FileStream(_savePath, FileMode.OpenOrCreate, FileAccess.Write); fileStream = new FileStream(_savePath, FileMode.OpenOrCreate, FileAccess.Write);
long fileLength = fileStream.Length - 1; long fileLength = fileStream.Length;
// 创建HTTP下载请求 // 创建HTTP下载请求
HttpWebRequest fileRequest = WebRequest.Create(_url) as HttpWebRequest; HttpWebRequest webRequest = WebRequest.Create(_url) as HttpWebRequest;
fileRequest.Timeout = _timeout * 1000; webRequest.Timeout = _timeout * 1000;
fileRequest.ProtocolVersion = HttpVersion.Version10; webRequest.ProtocolVersion = HttpVersion.Version10;
if (fileLength > 0) if (fileLength > 0)
{ {
// 注意:设置远端请求文件的起始位置 // 注意:设置远端请求文件的起始位置
fileRequest.AddRange(fileLength); webRequest.AddRange(fileLength);
// 注意:设置本地文件流的起始位置 // 注意:设置本地文件流的起始位置
fileStream.Seek(-1, SeekOrigin.End); fileStream.Seek(fileLength, SeekOrigin.Begin);
} }
// 读取下载数据并保存到文件 // 读取下载数据并保存到文件
fileResponse = fileRequest.GetResponse() as HttpWebResponse; webResponse = webRequest.GetResponse() as HttpWebResponse;
webStream = fileResponse.GetResponseStream(); responseStream = webResponse.GetResponseStream();
byte[] buffer = new byte[BufferSize]; byte[] buffer = new byte[BufferSize];
while (true) while (_running)
{ {
int length = webStream.Read(buffer, 0, buffer.Length); int length = responseStream.Read(buffer, 0, buffer.Length);
if (length <= 0) if (length <= 0)
break; break;
@ -129,20 +131,20 @@ namespace YooAsset
} }
catch (Exception e) catch (Exception e)
{ {
Result = false;
Error = e.Message; Error = e.Message;
} }
finally finally
{ {
if (webStream != null) if (responseStream != null)
{ {
webStream.Close(); responseStream.Close();
webStream.Dispose(); responseStream.Dispose();
} }
if (fileResponse != null) if (webResponse != null)
{ {
fileResponse.Close(); webResponse.Close();
webResponse.Dispose();
} }
if (fileStream != null) if (fileStream != null)
@ -152,17 +154,20 @@ namespace YooAsset
} }
// 验证下载文件完整性 // 验证下载文件完整性
if (Result) if (DownloadedBytes == (ulong)_fileSize)
{ {
bool verfiyResult = DownloadSystem.CheckContentIntegrity(_savePath, _fileSize, _fileCRC); bool verfiyResult = DownloadSystem.CheckContentIntegrity(_savePath, _fileSize, _fileCRC);
if (verfiyResult == false) if (verfiyResult == false)
{ {
Result = false; Error = $"Verify download content failed : {_fileHash}";
Error = $"Verify file content failed : {_fileHash}";
if (File.Exists(_savePath)) if (File.Exists(_savePath))
File.Delete(_savePath); File.Delete(_savePath);
} }
} }
else
{
Error = $"Download content is incomplete : {_fileHash}";
}
IsDone = true; IsDone = true;
} }
@ -173,10 +178,10 @@ namespace YooAsset
private ThreadDownloader _threadDownloader; private ThreadDownloader _threadDownloader;
private float _tryAgainTimer; private float _tryAgainTimer;
internal HttpDownloader(BundleInfo bundleInfo) : base(bundleInfo) public HttpDownloader(BundleInfo bundleInfo) : base(bundleInfo)
{ {
} }
internal override void Update() public override void Update()
{ {
if (_steps == ESteps.None) if (_steps == ESteps.None)
return; return;
@ -203,12 +208,7 @@ namespace YooAsset
if (_threadDownloader.IsDone == false) if (_threadDownloader.IsDone == false)
return; return;
if (_threadDownloader.Result) if (_threadDownloader.HasError())
{
DownloadSystem.CacheVerifyFile(_bundleInfo.Hash, _bundleInfo.BundleName);
_steps = ESteps.Succeed;
}
else
{ {
_lastError = _threadDownloader.Error; _lastError = _threadDownloader.Error;
ReportError(); ReportError();
@ -219,9 +219,11 @@ namespace YooAsset
else else
_steps = ESteps.Failed; _steps = ESteps.Failed;
} }
else
// 释放下载器 {
_threadDownloader.Dispose(); DownloadSystem.CacheVerifyFile(_bundleInfo.Hash, _bundleInfo.BundleName);
_steps = ESteps.Succeed;
}
} }
// 重新尝试下载 // 重新尝试下载
@ -236,5 +238,18 @@ namespace YooAsset
} }
} }
} }
public override void Abort()
{
if(IsDone() == false)
{
_steps = ESteps.Failed;
_lastError = "user abort";
if (_threadDownloader != null)
{
_threadDownloader.Abort();
_threadDownloader = null;
}
}
}
} }
} }

View File

@ -0,0 +1,20 @@

namespace YooAsset
{
internal sealed class TempDownloader : DownloaderBase
{
public TempDownloader(BundleInfo bundleInfo) : base(bundleInfo)
{
_downloadProgress = 1f;
_downloadedBytes = (ulong)bundleInfo.SizeBytes;
_steps = ESteps.Succeed;
}
public override void Update()
{
}
public override void Abort()
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3c7907ead85e2f94786308b28c37a8aa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: