Files
2025-01-25 04:38:09 +08:00

437 lines
14 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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