首次提交
This commit is contained in:
@@ -0,0 +1,300 @@
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace NBC.Asset
|
||||
{
|
||||
/// <summary>
|
||||
/// 下载文件
|
||||
/// </summary>
|
||||
public class DownloadFileTask : DownloadTaskBase
|
||||
{
|
||||
private const string DownloadHeaderKey = "Content-Length";
|
||||
private const int RetryDownloadCount = 3;
|
||||
|
||||
public readonly string DownloadPath;
|
||||
|
||||
public readonly string SavePath;
|
||||
public readonly string FileHash;
|
||||
|
||||
/// <summary>
|
||||
/// 开启断点续传
|
||||
/// </summary>
|
||||
public bool ReDownload = true;
|
||||
|
||||
public DownloadFileTask(string path, string savePath, string hash = "")
|
||||
{
|
||||
DownloadPath = path;
|
||||
SavePath = savePath;
|
||||
FileHash = hash;
|
||||
}
|
||||
|
||||
public enum DownLoadStatus
|
||||
{
|
||||
None,
|
||||
GetHeader,
|
||||
PrepareDownload,
|
||||
Download,
|
||||
VerifyingFile,
|
||||
Success,
|
||||
Failed,
|
||||
}
|
||||
|
||||
private ulong _downloadTotalSize = 1;
|
||||
private UnityWebRequest _content;
|
||||
private UnityWebRequest _header;
|
||||
private bool _isAbort;
|
||||
private ulong _latestDownloadBytes;
|
||||
private float _latestDownloadRealtime;
|
||||
private ulong _fileOriginLength;
|
||||
private int RetryCount;
|
||||
|
||||
private long ResponseCode = 0;
|
||||
|
||||
public DownLoadStatus DownloadStatus { get; protected internal set; } = DownLoadStatus.None;
|
||||
public override float Progress => DownloadedBytes * 1f / DownloadTotalSize;
|
||||
|
||||
public ulong DownloadedBytes { get; protected set; }
|
||||
|
||||
public ulong DownloadTotalSize
|
||||
{
|
||||
get => _downloadTotalSize;
|
||||
set
|
||||
{
|
||||
_downloadTotalSize = value;
|
||||
if (_downloadTotalSize < 1) _downloadTotalSize = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Abort()
|
||||
{
|
||||
Fail("abort");
|
||||
Dispose();
|
||||
}
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
DownloadStatus = DownLoadStatus.GetHeader;
|
||||
}
|
||||
|
||||
protected override NTaskStatus OnProcess()
|
||||
{
|
||||
if (DownloadStatus == DownLoadStatus.GetHeader)
|
||||
{
|
||||
_header = UnityWebRequest.Head(DownloadPath);
|
||||
_header.SendWebRequest();
|
||||
DownloadStatus = DownLoadStatus.PrepareDownload;
|
||||
}
|
||||
|
||||
if (DownloadStatus == DownLoadStatus.PrepareDownload)
|
||||
{
|
||||
if (_header == null)
|
||||
{
|
||||
Fail($"get header info error");
|
||||
Debug.LogError("get header info error");
|
||||
return NTaskStatus.Fail;
|
||||
}
|
||||
|
||||
if (!_header.isDone) return NTaskStatus.Running;
|
||||
|
||||
Reset();
|
||||
//远程文件信息
|
||||
var value = _header.GetResponseHeader(DownloadHeaderKey);
|
||||
if (ulong.TryParse(value, out var totalSize))
|
||||
{
|
||||
DownloadTotalSize = totalSize;
|
||||
}
|
||||
|
||||
if (ReDownload)
|
||||
{
|
||||
//读取未下载完成的文件信息
|
||||
var tempInfo = new FileInfo(SavePath);
|
||||
if (tempInfo.Exists)
|
||||
{
|
||||
_fileOriginLength = (ulong)tempInfo.Length;
|
||||
if (_fileOriginLength == DownloadTotalSize)
|
||||
{
|
||||
DownloadedBytes = _fileOriginLength;
|
||||
DownloadStatus = DownLoadStatus.VerifyingFile;
|
||||
return NTaskStatus.Running;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_fileOriginLength = 0;
|
||||
}
|
||||
|
||||
_content = UnityWebRequest.Get(DownloadPath);
|
||||
if (_fileOriginLength > 0)
|
||||
{
|
||||
Debug.Log($"断点续传===={_fileOriginLength} path={DownloadPath}");
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
_content.SetRequestHeader("Range", $"bytes={_fileOriginLength}-");
|
||||
_content.downloadHandler = new DownloadHandlerFile(SavePath, true);
|
||||
#else
|
||||
_request.DownloadedBytes = 0;
|
||||
_content.downloadHandler = new DownloadHandlerFile(TempPath);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
_content.downloadHandler = new DownloadHandlerFile(SavePath);
|
||||
}
|
||||
|
||||
_content.certificateHandler = new DownloadCertificateHandler();
|
||||
_content.disposeDownloadHandlerOnDispose = true;
|
||||
_content.disposeCertificateHandlerOnDispose = true;
|
||||
_content.disposeUploadHandlerOnDispose = true;
|
||||
_content.SendWebRequest();
|
||||
DownloadStatus = DownLoadStatus.Download;
|
||||
}
|
||||
|
||||
if (DownloadStatus == DownLoadStatus.Download)
|
||||
{
|
||||
DownloadedBytes = _fileOriginLength + _content.downloadedBytes;
|
||||
if (!_content.isDone)
|
||||
{
|
||||
CheckTimeout();
|
||||
return NTaskStatus.Running;
|
||||
}
|
||||
|
||||
bool hasError = false;
|
||||
// 检查网络错误
|
||||
#if UNITY_2020_3_OR_NEWER
|
||||
if (_content.result != UnityWebRequest.Result.Success)
|
||||
{
|
||||
hasError = true;
|
||||
_errorMsg = _content.error;
|
||||
ResponseCode = _content.responseCode;
|
||||
}
|
||||
#else
|
||||
if (_content.isNetworkError || _content.isHttpError)
|
||||
{
|
||||
hasError = true;
|
||||
_errorMsg = _content.error;
|
||||
ResponseCode = _content.responseCode;
|
||||
}
|
||||
#endif
|
||||
// 如果网络异常
|
||||
if (hasError)
|
||||
{
|
||||
RetryCount++;
|
||||
if (RetryCount <= RetryDownloadCount)
|
||||
{
|
||||
Debug.Log($"网络异常 重新开始下载={DownloadPath} code={ResponseCode} msg={_content.error}");
|
||||
//重新开始下载
|
||||
DownloadStatus = DownLoadStatus.PrepareDownload;
|
||||
}
|
||||
else
|
||||
{
|
||||
//重试后还是网络错误,直接失败
|
||||
Debug.Log("重试后还是网络错误,直接失败");
|
||||
DownloadStatus = DownLoadStatus.Failed;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DownloadStatus = DownLoadStatus.VerifyingFile;
|
||||
}
|
||||
}
|
||||
|
||||
if (DownloadStatus == DownLoadStatus.VerifyingFile)
|
||||
{
|
||||
Dispose();
|
||||
var tryPass = false;
|
||||
var tempInfo = new FileInfo(SavePath);
|
||||
|
||||
if (tempInfo.Exists)
|
||||
{
|
||||
if (tempInfo.Length == (long)DownloadTotalSize)
|
||||
{
|
||||
tryPass = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_errorMsg = "file size error";
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(FileHash))
|
||||
{
|
||||
var hash = Util.ComputeHash(SavePath);
|
||||
if (FileHash.Equals(hash))
|
||||
{
|
||||
tryPass = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_errorMsg = "file hash error";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_errorMsg = "file not exists";
|
||||
}
|
||||
|
||||
if (!tryPass)
|
||||
{
|
||||
// 验证失败后删除文件
|
||||
if (File.Exists(SavePath))
|
||||
File.Delete(SavePath);
|
||||
Debug.Log("验证失败后删除文件,尝试重新下载");
|
||||
//重新下载
|
||||
DownloadStatus = DownLoadStatus.PrepareDownload;
|
||||
}
|
||||
else
|
||||
{
|
||||
DownloadStatus = DownLoadStatus.Success;
|
||||
}
|
||||
}
|
||||
|
||||
if (DownloadStatus == DownLoadStatus.Success)
|
||||
{
|
||||
return NTaskStatus.Success;
|
||||
}
|
||||
|
||||
if (DownloadStatus == DownLoadStatus.Failed)
|
||||
{
|
||||
return NTaskStatus.Fail;
|
||||
}
|
||||
|
||||
return NTaskStatus.Running;
|
||||
}
|
||||
|
||||
|
||||
private void CheckTimeout()
|
||||
{
|
||||
if (_isAbort) return;
|
||||
|
||||
if (_latestDownloadBytes != DownloadedBytes)
|
||||
{
|
||||
_latestDownloadBytes = DownloadedBytes;
|
||||
_latestDownloadRealtime = Time.realtimeSinceStartup;
|
||||
}
|
||||
|
||||
float offset = Time.realtimeSinceStartup - _latestDownloadRealtime;
|
||||
if (_latestDownloadRealtime > 0 && offset > Const.DownloadTimeOut)
|
||||
{
|
||||
_content.Abort();
|
||||
_isAbort = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void Dispose()
|
||||
{
|
||||
if (_header != null)
|
||||
{
|
||||
_header.Dispose();
|
||||
_header = null;
|
||||
}
|
||||
|
||||
if (_content != null)
|
||||
{
|
||||
_content.Dispose();
|
||||
_content = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user