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 { /// /// 背后静默下载处理 /// public class BackDownload { private const int _MAX_THREAD_COUNT = 4; private const int _RETRAY_TIMES = 3; private static UpdateAction _finishDownloadCallback = null; private static List _httpInsList = new List(); 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 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); } /// /// 中断下载 /// /// 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); } } /// /// 添加数据到下载队列, level:队列类型 /// /// /// internal static void AddDataToPool(MapFileData data, DataLevel level) { _threadPool.AddData(data, level); } /// /// 添加失败的数据到下载队列, 如果是因为中断操作造成的,则添加到之前的下载队列中 /// 如果是正常失败,则添加到失败队列,在所有资源下载完成后在重新下载 /// /// /// internal static void AddFailDataToPool(MapFileData data) { //只有需要静默更新的数据才重新添加到下载队列,保证下载完整 if (data.PriorityLevel == (int)DataLevel.Low) { _threadPool.AddData(data, (DataLevel)data.PriorityLevel, true); } } /// /// 添加下载实例,正在执行下载的线程 /// /// 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; } /// /// 暂停后台下载 /// internal static void PauseAll() { //先暂停线程池 if (_threadPool != null) { _threadPool.Pause(); } //中断所有正在下载的http请求 PauseLevel(DataLevel.High); PauseLevel(DataLevel.CurScene); PauseLevel(DataLevel.NextScene); PauseLevel(DataLevel.Low); } /// /// 恢复下载 /// internal static void ResumeAll() { ResumeLevel(DataLevel.High); ResumeLevel(DataLevel.CurScene); ResumeLevel(DataLevel.NextScene); ResumeLevel(DataLevel.Low); } /// /// 暂停指定下载队列 /// /// 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(); } } /// /// 是否暂停中 /// /// internal static bool IsPaused() { bool paused = true; if (_threadPool != null) { paused = _threadPool.IsPaused(); } return paused; } /// /// 是否暂停了静默更新 /// /// internal static bool IsBaseResPaused() { bool paused = true; if (_threadPool != null) { paused = _threadPool.IsBaseResPaused(); } return paused; } /// /// 是否暂停了当前场景资源更新 /// /// internal static bool IsCurScenePaused() { bool paused = true; if (_threadPool != null) { paused = _threadPool.IsCurScenePaused(); } return paused; } /// /// 获取对应队列数据个数 /// /// /// 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; } /// /// 中断指定http下载 /// 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); } } } }