251 lines
6.9 KiB
C#
251 lines
6.9 KiB
C#
//
|
||
// Download.cs
|
||
//
|
||
// Author:
|
||
// fjy <jiyuan.feng@live.com>
|
||
//
|
||
// Copyright (c) 2020 fjy
|
||
//
|
||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
// of this software and associated documentation files (the "Software"), to deal
|
||
// in the Software without restriction, including without limitation the rights
|
||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
// copies of the Software, and to permit persons to whom the Software is
|
||
// furnished to do so, subject to the following conditions:
|
||
//
|
||
// The above copyright notice and this permission notice shall be included in
|
||
// all copies or substantial portions of the Software.
|
||
//
|
||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
// THE SOFTWARE.
|
||
|
||
using System;
|
||
using System.IO;
|
||
using UnityEngine;
|
||
using UnityEngine.Networking;
|
||
|
||
namespace libx
|
||
{
|
||
public class Download : DownloadHandlerScript, IDisposable, ICloneable
|
||
{
|
||
#region ICloneable implementation
|
||
|
||
public object Clone()
|
||
{
|
||
return new Download()
|
||
{
|
||
id = id,
|
||
hash = hash,
|
||
url = url,
|
||
len = len,
|
||
savePath = savePath,
|
||
completed = completed,
|
||
name = name
|
||
};
|
||
}
|
||
|
||
#endregion
|
||
|
||
public int id { get; set; }
|
||
|
||
public string error { get; private set; }
|
||
|
||
public long len { get; set; }
|
||
|
||
public string hash { get; set; }
|
||
|
||
public string url { get; set; }
|
||
|
||
public long position { get; private set; }
|
||
|
||
public string name { get; set; }
|
||
|
||
public string tempPath
|
||
{
|
||
get
|
||
{
|
||
var dir = Path.GetDirectoryName(savePath);
|
||
return string.Format("{0}/{1}", dir, hash);
|
||
}
|
||
}
|
||
|
||
public string savePath;
|
||
|
||
public Action<Download> completed { get; set; }
|
||
|
||
private UnityWebRequest _request;
|
||
private FileStream _stream;
|
||
private bool _running;
|
||
private bool _finished = false;
|
||
|
||
protected override float GetProgress()
|
||
{
|
||
return position * 1f / len;
|
||
}
|
||
|
||
protected override byte[] GetData()
|
||
{
|
||
return null;
|
||
}
|
||
|
||
protected override void ReceiveContentLength(int contentLength)
|
||
{
|
||
}
|
||
|
||
protected override bool ReceiveData(byte[] buffer, int dataLength)
|
||
{
|
||
if (!string.IsNullOrEmpty(_request.error))
|
||
{
|
||
error = _request.error;
|
||
Complete();
|
||
return true;
|
||
}
|
||
|
||
_stream.Write(buffer, 0, dataLength);
|
||
position += dataLength;
|
||
return _running;
|
||
}
|
||
|
||
protected override void CompleteContent()
|
||
{
|
||
Complete();
|
||
}
|
||
|
||
public override string ToString()
|
||
{
|
||
return string.Format("{0}, size:{1}, hash:{2}", url, len, hash);
|
||
}
|
||
|
||
public void Start()
|
||
{
|
||
if (_running)
|
||
{
|
||
return;
|
||
}
|
||
|
||
error = null;
|
||
finished = false;
|
||
_running = true;
|
||
_stream = new FileStream(tempPath, FileMode.OpenOrCreate, FileAccess.Write);
|
||
position = _stream.Length;
|
||
if (position < len)
|
||
{
|
||
_stream.Seek(position, SeekOrigin.Begin);
|
||
_request = UnityWebRequest.Get(url);
|
||
_request.SetRequestHeader("Range", "bytes=" + position + "-");
|
||
_request.downloadHandler = this;
|
||
_request.SendWebRequest();
|
||
Debug.Log("Start Download:" + url);
|
||
}
|
||
else
|
||
{
|
||
Complete();
|
||
}
|
||
}
|
||
|
||
public void Update()
|
||
{
|
||
if (_running)
|
||
{
|
||
if (_request.isDone && _request.downloadedBytes < (ulong)len)
|
||
{
|
||
error = "unknown error: downloadedBytes < len";
|
||
}
|
||
if (!string.IsNullOrEmpty(_request.error))
|
||
{
|
||
error = _request.error;
|
||
}
|
||
}
|
||
}
|
||
|
||
public new void Dispose()
|
||
{
|
||
if (_stream != null)
|
||
{
|
||
_stream.Close();
|
||
_stream.Dispose();
|
||
_stream = null;
|
||
}
|
||
if (_request != null)
|
||
{
|
||
_request.Abort();
|
||
_request.Dispose();
|
||
_request = null;
|
||
}
|
||
base.Dispose();
|
||
_running = false;
|
||
finished = true;
|
||
}
|
||
|
||
public void Complete(bool stop = false)
|
||
{
|
||
Dispose();
|
||
if (stop)
|
||
{
|
||
return;
|
||
}
|
||
CheckError();
|
||
}
|
||
|
||
private void CheckError()
|
||
{
|
||
if (File.Exists(tempPath))
|
||
{
|
||
if (string.IsNullOrEmpty(error))
|
||
{
|
||
using (var fs = File.OpenRead(tempPath))
|
||
{
|
||
if (fs.Length != len)
|
||
{
|
||
error = "下载文件长度异常:" + fs.Length;
|
||
}
|
||
if (Versions.verifyBy == VerifyBy.Hash)
|
||
{
|
||
const StringComparison compare = StringComparison.OrdinalIgnoreCase;
|
||
if (!hash.Equals(Utilitys.GetCRC32Hash(fs), compare))
|
||
{
|
||
error = "下载文件哈希异常:" + hash;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (string.IsNullOrEmpty(error))
|
||
{
|
||
File.Copy(tempPath, savePath, true);
|
||
File.Delete(tempPath);
|
||
Debug.Log("Complete Download:" + url);
|
||
if (completed == null)
|
||
return;
|
||
completed.Invoke(this);
|
||
completed = null;
|
||
}
|
||
else
|
||
{
|
||
File.Delete(tempPath);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
error = "文件不存在";
|
||
}
|
||
}
|
||
|
||
public void Retry()
|
||
{
|
||
Dispose();
|
||
Start();
|
||
}
|
||
|
||
public bool finished
|
||
{
|
||
get { return _finished; }
|
||
private set { _finished = value; }
|
||
}
|
||
}
|
||
|
||
} |