437 lines
14 KiB
C#
437 lines
14 KiB
C#
|
using Thousandto.Update.Data;
|
|||
|
using Thousandto.Update.Delegate;
|
|||
|
using Thousandto.Update.Flow;
|
|||
|
using Thousandto.Update.Log;
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.IO;
|
|||
|
using MD5Utils = UnityEngine.Gonbest.MagicCube.MD5Utils;
|
|||
|
using BaseDownloader = UnityEngine.Gonbest.MagicCube.BaseDownloader;
|
|||
|
using DownloadSpeeder = UnityEngine.Gonbest.MagicCube.DownloadSpeeder;
|
|||
|
using UnityEngine.Gonbest.MagicCube;
|
|||
|
using Thousandto.Update.Manager;
|
|||
|
|
|||
|
namespace Thousandto.Update.Download
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// 背后静默下载处理
|
|||
|
/// </summary>
|
|||
|
public class BackDownload
|
|||
|
{
|
|||
|
private const int _MAX_THREAD_COUNT = 4;
|
|||
|
private const int _RETRAY_TIMES = 3;
|
|||
|
private static UpdateAction<string, int, object> _finishDownloadCallback = null;
|
|||
|
private static List<BaseDownloader> _httpInsList = new List<BaseDownloader>();
|
|||
|
private static bool _init = false;
|
|||
|
private static string _TAG = "BackDownload.cs ";
|
|||
|
private static ThreadMapDataPool _threadPool = null;
|
|||
|
//线程池的同步锁
|
|||
|
private static object m_locker;
|
|||
|
//下载完成后需要线程同步
|
|||
|
private static object m_downloadedLocker = new object();
|
|||
|
|
|||
|
//总下载文件大小
|
|||
|
public static int TotalDownloadedSize;
|
|||
|
|
|||
|
private static string _downloadFileRecordPath = "";
|
|||
|
|
|||
|
internal static void InitPool(int cpuCoreCount, UpdateAction<string, int, object> callback)
|
|||
|
{
|
|||
|
if (!_init)
|
|||
|
{
|
|||
|
_init = true;
|
|||
|
_finishDownloadCallback = callback;
|
|||
|
DownloadSpeeder.Reset();
|
|||
|
_threadPool = new ThreadMapDataPool(cpuCoreCount, (BackDownload.DownloadAction));
|
|||
|
m_locker = _threadPool.Locker;
|
|||
|
_downloadFileRecordPath = PathUtils.GetWritePath(string.Format("DownloadFile-{0}.txt", AppPersistData.ResVersion));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//设置限速
|
|||
|
internal static void SetDownloadSpeed(int kbPerSecond)
|
|||
|
{
|
|||
|
DownloadSpeeder.SetMaxSpeed(kbPerSecond);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 中断下载
|
|||
|
/// </summary>
|
|||
|
/// <param name="callback"></param>
|
|||
|
internal static void AbortAll(AbortFinishCallback callback)
|
|||
|
{
|
|||
|
UpdateLog.DEBUG_LOG("Abort back download!!!");
|
|||
|
if (m_locker == null)
|
|||
|
return;
|
|||
|
|
|||
|
lock (m_locker)
|
|||
|
{
|
|||
|
if (_threadPool != null)
|
|||
|
{
|
|||
|
_threadPool.WaitForFinish();
|
|||
|
}
|
|||
|
for (int i = 0; i < _httpInsList.Count; i++)
|
|||
|
{
|
|||
|
_httpInsList[i].Abort(null);
|
|||
|
}
|
|||
|
}
|
|||
|
if (callback != null)
|
|||
|
{
|
|||
|
callback(true);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 添加数据到下载队列, level:队列类型
|
|||
|
/// </summary>
|
|||
|
/// <param name="data"></param>
|
|||
|
/// <param name="level"></param>
|
|||
|
internal static void AddDataToPool(MapFileData data, DataLevel level)
|
|||
|
{
|
|||
|
_threadPool.AddData(data, level);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 添加失败的数据到下载队列, 如果是因为中断操作造成的,则添加到之前的下载队列中
|
|||
|
/// 如果是正常失败,则添加到失败队列,在所有资源下载完成后在重新下载
|
|||
|
/// </summary>
|
|||
|
/// <param name="data"></param>
|
|||
|
/// <param name="byAbort"></param>
|
|||
|
internal static void AddFailDataToPool(MapFileData data)
|
|||
|
{
|
|||
|
//只有需要静默更新的数据才重新添加到下载队列,保证下载完整
|
|||
|
if (data.PriorityLevel == (int)DataLevel.Low)
|
|||
|
{
|
|||
|
_threadPool.AddData(data, (DataLevel)data.PriorityLevel, true);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 添加下载实例,正在执行下载的线程
|
|||
|
/// </summary>
|
|||
|
/// <param name="ins"></param>
|
|||
|
private static void AddIns(BaseDownloader ins)
|
|||
|
{
|
|||
|
lock (m_locker)
|
|||
|
{
|
|||
|
_httpInsList.Add(ins);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
internal static void ClearData(DataLevel level)
|
|||
|
{
|
|||
|
_threadPool.ClearData(level);
|
|||
|
}
|
|||
|
|
|||
|
//获取后台更新中正在下载的文件的已经下载的大小
|
|||
|
internal static int GetMapDataDownloadedSize(MapFileData mapData)
|
|||
|
{
|
|||
|
for(int i = 0; i < _httpInsList.Count; ++i)
|
|||
|
{
|
|||
|
if (_httpInsList[i].DownloadInfo.FullPath == mapData.FullPath)
|
|||
|
return _httpInsList[i].DownloadedSize;
|
|||
|
}
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
private static void DownloadAction(MapFileData state)
|
|||
|
{
|
|||
|
MapFileData fileData = state;
|
|||
|
fileData.ErrorCode = CodeDefine.RET_INIT;
|
|||
|
|
|||
|
string saveFilePath = fileData.SaveDir + "/" + fileData.Dir + fileData.Name;
|
|||
|
string saveFilePathBackup = saveFilePath + ".bak";
|
|||
|
int num = DownloadMapData(fileData, saveFilePathBackup);
|
|||
|
string str2 = MD5Utils.GetFileMD5(saveFilePathBackup);
|
|||
|
bool success = (num >= CodeDefine.RET_SUCCESS) && fileData.Md5.Equals(str2);
|
|||
|
//UpdateLog.DEBUG_LOG("download finish: " + saveFilePath + " success=" + success);
|
|||
|
if (!success)
|
|||
|
{
|
|||
|
UpdateLog.ERROR_LOG("download fail: " + saveFilePath);
|
|||
|
//总下载减去失败的文件
|
|||
|
if (File.Exists(saveFilePathBackup))
|
|||
|
TotalDownloadedSize -= (int)(new FileInfo(saveFilePathBackup).Length);
|
|||
|
//下载失败,删除已下载文件
|
|||
|
File.Delete(saveFilePathBackup);
|
|||
|
//重置下载状态
|
|||
|
state.Downloading = false;
|
|||
|
//将失败data放回下载队列
|
|||
|
AddFailDataToPool(fileData);
|
|||
|
|
|||
|
//如果是因为中止操作造成下载失败,则把文件加入到当前场景下载队列,继续下载
|
|||
|
if (num == CodeDefine.RET_SKIP_BY_ABORT)
|
|||
|
{
|
|||
|
num = CodeDefine.RET_BACKDOWNLOAD_SKIPBYPAUSE;
|
|||
|
UpdateLog.ERROR_LOG("download fail because of stop action: " + saveFilePath);
|
|||
|
//return;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if(num != CodeDefine.RET_FAIL_FULL_DISK)
|
|||
|
num = CodeDefine.RET_BACKDOWNLOAD_HTTPFAIL;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
File.Copy(saveFilePathBackup, saveFilePath, true);
|
|||
|
File.Delete(saveFilePathBackup);
|
|||
|
//累加下载大小
|
|||
|
TotalDownloadedSize += state.FileSize;
|
|||
|
num = CodeDefine.RET_BACKDOWNLOAD_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
lock (m_downloadedLocker)
|
|||
|
{
|
|||
|
fileData.Downloaded = success;
|
|||
|
if (fileData.DownloadCallBack == null)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (_finishDownloadCallback != null)
|
|||
|
{
|
|||
|
_finishDownloadCallback(saveFilePath, num, state);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private static int DownloadFile(MapFileData data, string url, string saveFilePath, long begin = 0L, long end = 0L)
|
|||
|
{
|
|||
|
int num = 0;
|
|||
|
FileStream outFile = new FileStream(saveFilePath, FileMode.Create);
|
|||
|
BaseDownloader ins = new BaseDownloader();
|
|||
|
ins.DownloadInfo = data;
|
|||
|
//生成下载文件的列表记录文件
|
|||
|
if (UpdateManager.SAVA_DOWNLOAD_FILE_LOG)
|
|||
|
{
|
|||
|
using (StreamWriter fs = new StreamWriter(_downloadFileRecordPath, true))
|
|||
|
{
|
|||
|
string downloadLog = string.Format("Name:{0} Path:{1}", data.Name, data.ResUrl);
|
|||
|
//UpdateLog.ERROR_LOG("downloadLog: " + downloadLog);
|
|||
|
fs.WriteLine(downloadLog);
|
|||
|
}
|
|||
|
}
|
|||
|
AddIns(ins);
|
|||
|
ins.ToDownload(url, outFile, begin, end);
|
|||
|
num = CodeDefine.FormDownloadCode(ins.Status);
|
|||
|
RemoveIns(ins);
|
|||
|
return num;
|
|||
|
}
|
|||
|
|
|||
|
private static int DownloadMapData(MapFileData fileData, string saveFilePath)
|
|||
|
{
|
|||
|
int code = CodeDefine.RET_INIT;
|
|||
|
try
|
|||
|
{
|
|||
|
lock (m_locker)
|
|||
|
{
|
|||
|
if (!Directory.Exists(fileData.SaveDir + "/" + fileData.Dir))
|
|||
|
{
|
|||
|
Directory.CreateDirectory(fileData.SaveDir + "/" + fileData.Dir);
|
|||
|
}
|
|||
|
}
|
|||
|
long begin = fileData.Begin + 4*32 + fileData.DirLen + fileData.NameLen + fileData.Md5Len;
|
|||
|
long end = fileData.End - 1;
|
|||
|
int retryTimes = _RETRAY_TIMES;
|
|||
|
while ((retryTimes > 0) && (code <= CodeDefine.RET_INIT))
|
|||
|
{
|
|||
|
retryTimes--;
|
|||
|
if (fileData.Name.Contains("RemoteVersion.xml") || fileData.Name.ToLower().Contains("localversion.xml"))
|
|||
|
{
|
|||
|
return CodeDefine.RET_SUCCESS;
|
|||
|
}
|
|||
|
code = DownloadUseBackCdn(fileData, fileData.ResUrl, saveFilePath, begin, end);
|
|||
|
if (code == CodeDefine.RET_SKIP_BY_ABORT)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
catch (Exception exception)
|
|||
|
{
|
|||
|
if (saveFilePath.Contains("ClassesResources.xml"))
|
|||
|
{
|
|||
|
code = CodeDefine.RET_SUCCESS;
|
|||
|
}
|
|||
|
UpdateLog.ERROR_LOG(_TAG + "ThreadCallBack(object state) download fail: file= " + saveFilePath +
|
|||
|
"\n error" + exception.Message + "\n" + exception.StackTrace);
|
|||
|
UpdateLog.EXCEPTION_LOG(exception);
|
|||
|
}
|
|||
|
return code;
|
|||
|
}
|
|||
|
|
|||
|
private static int DownloadUseBackCdn(MapFileData data, string url, string saveFilePath, long begin = 0L, long end = 0L)
|
|||
|
{
|
|||
|
int num = 0;
|
|||
|
return DownloadFile(data, url, saveFilePath, begin, end);
|
|||
|
}
|
|||
|
|
|||
|
internal static object GetLocker()
|
|||
|
{
|
|||
|
return m_downloadedLocker;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 暂停后台下载
|
|||
|
/// </summary>
|
|||
|
internal static void PauseAll()
|
|||
|
{
|
|||
|
//先暂停线程池
|
|||
|
if (_threadPool != null)
|
|||
|
{
|
|||
|
_threadPool.Pause();
|
|||
|
}
|
|||
|
//中断所有正在下载的http请求
|
|||
|
PauseLevel(DataLevel.High);
|
|||
|
PauseLevel(DataLevel.CurScene);
|
|||
|
PauseLevel(DataLevel.NextScene);
|
|||
|
PauseLevel(DataLevel.Low);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 恢复下载
|
|||
|
/// </summary>
|
|||
|
internal static void ResumeAll()
|
|||
|
{
|
|||
|
ResumeLevel(DataLevel.High);
|
|||
|
ResumeLevel(DataLevel.CurScene);
|
|||
|
ResumeLevel(DataLevel.NextScene);
|
|||
|
ResumeLevel(DataLevel.Low);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 暂停指定下载队列
|
|||
|
/// </summary>
|
|||
|
/// <param name="level"></param>
|
|||
|
internal static void PauseLevel(DataLevel level)
|
|||
|
{
|
|||
|
if (_threadPool != null)
|
|||
|
{
|
|||
|
//1.设置暂停等级
|
|||
|
_threadPool.PauseLevel(level);
|
|||
|
//2.中断http下载,让线程尽快结束任务
|
|||
|
AbortHttp(level);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
internal static void ResumeLevel(DataLevel level)
|
|||
|
{
|
|||
|
if (_threadPool != null)
|
|||
|
{
|
|||
|
UpdateLog.DEBUG_LOG("ResumeLevel : " + level);
|
|||
|
//1.设置恢复等级
|
|||
|
_threadPool.ResumeLevel(level);
|
|||
|
//2.线程池唤醒
|
|||
|
_threadPool.Resume();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 是否暂停中
|
|||
|
/// </summary>
|
|||
|
/// <returns></returns>
|
|||
|
internal static bool IsPaused()
|
|||
|
{
|
|||
|
bool paused = true;
|
|||
|
if (_threadPool != null)
|
|||
|
{
|
|||
|
paused = _threadPool.IsPaused();
|
|||
|
}
|
|||
|
|
|||
|
return paused;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 是否暂停了静默更新
|
|||
|
/// </summary>
|
|||
|
/// <returns></returns>
|
|||
|
internal static bool IsBaseResPaused()
|
|||
|
{
|
|||
|
bool paused = true;
|
|||
|
if (_threadPool != null)
|
|||
|
{
|
|||
|
paused = _threadPool.IsBaseResPaused();
|
|||
|
}
|
|||
|
|
|||
|
return paused;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 是否暂停了当前场景资源更新
|
|||
|
/// </summary>
|
|||
|
/// <returns></returns>
|
|||
|
internal static bool IsCurScenePaused()
|
|||
|
{
|
|||
|
bool paused = true;
|
|||
|
if (_threadPool != null)
|
|||
|
{
|
|||
|
paused = _threadPool.IsCurScenePaused();
|
|||
|
}
|
|||
|
|
|||
|
return paused;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 获取对应队列数据个数
|
|||
|
/// </summary>
|
|||
|
/// <param name="level"></param>
|
|||
|
/// <returns></returns>
|
|||
|
internal static int GetDataCount(DataLevel level)
|
|||
|
{
|
|||
|
int count = 0;
|
|||
|
if (_threadPool != null)
|
|||
|
{
|
|||
|
count = _threadPool.GetDataCount(level);
|
|||
|
}
|
|||
|
return count;
|
|||
|
}
|
|||
|
|
|||
|
internal static bool IsDateLevelDownloading(DataLevel level)
|
|||
|
{
|
|||
|
lock (m_locker)
|
|||
|
{
|
|||
|
for (int i = 0; i < _httpInsList.Count; i++)
|
|||
|
{
|
|||
|
if (_httpInsList[i].DownloadInfo.PriorityLevel == (int)level)
|
|||
|
{
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 中断指定http下载
|
|||
|
/// </summary>
|
|||
|
private static void AbortHttp(DataLevel level)
|
|||
|
{
|
|||
|
lock (m_locker)
|
|||
|
{
|
|||
|
for (int i = 0; i < _httpInsList.Count; i++)
|
|||
|
{
|
|||
|
if (level == DataLevel.All)
|
|||
|
{
|
|||
|
_httpInsList[i].Abort(null);
|
|||
|
}
|
|||
|
else if (_httpInsList[i].DownloadInfo != null &&
|
|||
|
_httpInsList[i].DownloadInfo.PriorityLevel == (int)level)
|
|||
|
{
|
|||
|
_httpInsList[i].Abort(null);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private static void RemoveIns(BaseDownloader ins)
|
|||
|
{
|
|||
|
lock (m_locker)
|
|||
|
{
|
|||
|
_httpInsList.Remove(ins);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|