2021-04-08 20:09:59 +08:00
|
|
|
//
|
|
|
|
// Downloader.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 ET;
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.IO;
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
namespace libx
|
|
|
|
{
|
|
|
|
public class DownloaderUpdateSystem : UpdateSystem<Downloader>
|
|
|
|
{
|
|
|
|
public override void Update(Downloader self)
|
|
|
|
{
|
|
|
|
self.Update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public class Downloader : Entity
|
|
|
|
{
|
|
|
|
private const float BYTES_2_MB = 1f / (1024 * 1024);
|
|
|
|
|
|
|
|
public int maxDownloads = 3;
|
|
|
|
|
|
|
|
private readonly List<Download> _downloads = new List<Download>();
|
|
|
|
private readonly List<Download> _tostart = new List<Download>();
|
|
|
|
private readonly List<Download> _progressing = new List<Download>();
|
|
|
|
public Action<long, long, float> onUpdate;
|
|
|
|
public Action onFinished;
|
|
|
|
|
|
|
|
private int _finishedIndex;
|
|
|
|
private int _downloadIndex;
|
|
|
|
private float _startTime;
|
|
|
|
private float _lastTime;
|
|
|
|
private long _lastSize;
|
|
|
|
|
|
|
|
public long size { get; private set; }
|
|
|
|
|
|
|
|
public long position { get; private set; }
|
|
|
|
|
|
|
|
public float speed { get; private set; }
|
|
|
|
|
|
|
|
public List<Download> downloads { get { return _downloads; } }
|
|
|
|
|
|
|
|
private long GetDownloadSize()
|
|
|
|
{
|
2021-04-11 19:50:39 +08:00
|
|
|
long len = 0L;
|
|
|
|
long downloadSize = 0L;
|
|
|
|
foreach (Download download in _downloads)
|
2021-04-08 20:09:59 +08:00
|
|
|
{
|
|
|
|
downloadSize += download.position;
|
|
|
|
len += download.len;
|
|
|
|
}
|
|
|
|
return downloadSize - (len - size);
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool _started;
|
|
|
|
[SerializeField]private float sampleTime = 0.5f;
|
|
|
|
|
|
|
|
public void StartDownload()
|
|
|
|
{
|
|
|
|
_tostart.Clear();
|
|
|
|
_finishedIndex = 0;
|
|
|
|
_lastSize = 0L;
|
|
|
|
Restart();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Restart()
|
|
|
|
{
|
|
|
|
_startTime = Time.realtimeSinceStartup;
|
|
|
|
_lastTime = 0;
|
|
|
|
_started = true;
|
|
|
|
_downloadIndex = _finishedIndex;
|
2021-04-11 19:50:39 +08:00
|
|
|
int max = Math.Min(_downloads.Count, maxDownloads);
|
|
|
|
for (int i = _finishedIndex; i < max; i++)
|
2021-04-08 20:09:59 +08:00
|
|
|
{
|
2021-04-11 19:50:39 +08:00
|
|
|
Download item = _downloads[i];
|
2021-04-08 20:09:59 +08:00
|
|
|
_tostart.Add(item);
|
|
|
|
_downloadIndex++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Stop()
|
|
|
|
{
|
|
|
|
_tostart.Clear();
|
2021-04-11 19:50:39 +08:00
|
|
|
foreach (Download download in _progressing)
|
2021-04-08 20:09:59 +08:00
|
|
|
{
|
|
|
|
download.Complete(true);
|
|
|
|
_downloads[download.id] = download.Clone() as Download;
|
|
|
|
|
|
|
|
}
|
|
|
|
_progressing.Clear();
|
|
|
|
_started = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Clear()
|
|
|
|
{
|
|
|
|
size = 0;
|
|
|
|
position = 0;
|
|
|
|
|
|
|
|
_downloadIndex = 0;
|
|
|
|
_finishedIndex = 0;
|
|
|
|
_lastTime = 0f;
|
|
|
|
_lastSize = 0L;
|
|
|
|
_startTime = 0;
|
|
|
|
_started = false;
|
2021-04-11 19:50:39 +08:00
|
|
|
foreach (Download item in _progressing)
|
2021-04-08 20:09:59 +08:00
|
|
|
{
|
|
|
|
item.Complete(true);
|
|
|
|
}
|
|
|
|
_progressing.Clear();
|
|
|
|
_downloads.Clear();
|
|
|
|
_tostart.Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void AddDownload(string url, string filename, string savePath, string hash, long len)
|
|
|
|
{
|
2021-04-11 19:50:39 +08:00
|
|
|
Download download = new Download
|
2021-04-08 20:09:59 +08:00
|
|
|
{
|
|
|
|
id = _downloads.Count,
|
|
|
|
url = url,
|
|
|
|
name = filename,
|
|
|
|
hash = hash,
|
|
|
|
len = len,
|
|
|
|
savePath = savePath,
|
|
|
|
completed = OnFinished
|
|
|
|
};
|
|
|
|
_downloads.Add(download);
|
2021-04-11 19:50:39 +08:00
|
|
|
FileInfo info = new FileInfo(download.tempPath);
|
2021-04-08 20:09:59 +08:00
|
|
|
if (info.Exists)
|
|
|
|
{
|
|
|
|
size += len - info.Length;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size += len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void OnFinished(Download download)
|
|
|
|
{
|
|
|
|
if (_downloadIndex < _downloads.Count)
|
|
|
|
{
|
|
|
|
_tostart.Add(_downloads[_downloadIndex]);
|
|
|
|
_downloadIndex++;
|
|
|
|
}
|
|
|
|
_finishedIndex++;
|
|
|
|
Debug.Log(string.Format("OnFinished:{0}, {1}", _finishedIndex, _downloads.Count));
|
|
|
|
if (_finishedIndex != downloads.Count)
|
|
|
|
return;
|
|
|
|
if (onFinished != null)
|
|
|
|
{
|
|
|
|
onFinished.Invoke();
|
|
|
|
}
|
|
|
|
_started = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static string GetDisplaySpeed(float downloadSpeed)
|
|
|
|
{
|
|
|
|
if (downloadSpeed >= 1024 * 1024)
|
|
|
|
{
|
|
|
|
return string.Format("{0:f2}MB/s", downloadSpeed * BYTES_2_MB);
|
|
|
|
}
|
|
|
|
if (downloadSpeed >= 1024)
|
|
|
|
{
|
|
|
|
return string.Format("{0:f2}KB/s", downloadSpeed / 1024);
|
|
|
|
}
|
|
|
|
return string.Format("{0:f2}B/s", downloadSpeed);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static string GetDisplaySize(long downloadSize)
|
|
|
|
{
|
|
|
|
if (downloadSize >= 1024 * 1024)
|
|
|
|
{
|
|
|
|
return string.Format("{0:f2}MB", downloadSize * BYTES_2_MB);
|
|
|
|
}
|
|
|
|
if (downloadSize >= 1024)
|
|
|
|
{
|
|
|
|
return string.Format("{0:f2}KB", downloadSize / 1024);
|
|
|
|
}
|
|
|
|
return string.Format("{0:f2}B", downloadSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void Update()
|
|
|
|
{
|
|
|
|
if (!_started)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (_tostart.Count > 0)
|
|
|
|
{
|
2021-04-11 19:50:39 +08:00
|
|
|
for (int i = 0; i < Math.Min(maxDownloads, _tostart.Count); i++)
|
2021-04-08 20:09:59 +08:00
|
|
|
{
|
2021-04-11 19:50:39 +08:00
|
|
|
Download item = _tostart[i];
|
2021-04-08 20:09:59 +08:00
|
|
|
item.Start();
|
|
|
|
_tostart.RemoveAt(i);
|
|
|
|
_progressing.Add(item);
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-11 19:50:39 +08:00
|
|
|
for (int index = 0; index < _progressing.Count; index++)
|
2021-04-08 20:09:59 +08:00
|
|
|
{
|
2021-04-11 19:50:39 +08:00
|
|
|
Download download = _progressing[index];
|
2021-04-08 20:09:59 +08:00
|
|
|
download.Update();
|
|
|
|
if (!download.finished)
|
|
|
|
continue;
|
|
|
|
_progressing.RemoveAt(index);
|
|
|
|
index--;
|
|
|
|
}
|
|
|
|
|
|
|
|
position = GetDownloadSize();
|
|
|
|
|
2021-04-11 19:50:39 +08:00
|
|
|
float elapsed = Time.realtimeSinceStartup - _startTime;
|
2021-04-08 20:09:59 +08:00
|
|
|
if (elapsed - _lastTime < sampleTime)
|
|
|
|
return;
|
|
|
|
|
2021-04-11 19:50:39 +08:00
|
|
|
float deltaTime = elapsed - _lastTime;
|
2021-04-08 20:09:59 +08:00
|
|
|
speed = (position - _lastSize) / deltaTime;
|
|
|
|
if (onUpdate != null)
|
|
|
|
{
|
|
|
|
onUpdate(position, size, speed);
|
|
|
|
}
|
|
|
|
|
|
|
|
_lastTime = elapsed;
|
|
|
|
_lastSize = position;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|