Files

437 lines
14 KiB
C#
Raw Permalink Normal View History

2025-01-25 04:38:09 +08:00
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);
}
}
}
}