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