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; }
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|