From 082b01aad446a7f76e144d269080b8ad2420050b Mon Sep 17 00:00:00 2001 From: Loskh <1020612624@qq.com> Date: Tue, 29 Oct 2024 22:00:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BB=8E=E6=97=A7=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E6=B2=A1=E6=9B=B4=E6=96=B0=E7=9A=84=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dalamud.Updater/Dalamud/AssetManager.cs | 177 +++++++++++++++++++----- Dalamud.Updater/FormMain.cs | 2 +- 2 files changed, 147 insertions(+), 32 deletions(-) diff --git a/Dalamud.Updater/Dalamud/AssetManager.cs b/Dalamud.Updater/Dalamud/AssetManager.cs index 7f21d4c..d534370 100644 --- a/Dalamud.Updater/Dalamud/AssetManager.cs +++ b/Dalamud.Updater/Dalamud/AssetManager.cs @@ -8,6 +8,9 @@ using Serilog; using System.Security.Cryptography; using System.Threading.Tasks; +using SharpCompress.Common; +using System.Diagnostics; +using System.Linq; namespace XIVLauncher.Common.Dalamud { @@ -40,7 +43,7 @@ public static async Task EnsureAssets(DirectoryInfo baseDir) { NoCache = true, }; - client.DefaultRequestHeaders.Add("User-Agent", "Wget/1.21.1 (linux-gnu)"); + client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Mobile Safari/537.36 Edg/130.0.0.0"); client.DefaultRequestHeaders.Add("accept-encoding", "gzip, deflate, br"); using var sha1 = SHA1.Create(); @@ -50,70 +53,139 @@ public static async Task EnsureAssets(DirectoryInfo baseDir) // NOTE(goat): We should use a junction instead of copying assets to a new folder. There is no C# API for junctions in .NET Framework. - var assetsDir = new DirectoryInfo(Path.Combine(baseDir.FullName, info.Version.ToString())); + var currentDir = new DirectoryInfo(Path.Combine(baseDir.FullName, info.Version.ToString())); var devDir = new DirectoryInfo(Path.Combine(baseDir.FullName, "dev")); + var assetFileDownloadList = new List(); foreach (var entry in info.Assets) { - var filePath = Path.Combine(assetsDir.FullName, entry.FileName); - var filePathDev = Path.Combine(devDir.FullName, entry.FileName); + var filePath = Path.Combine(currentDir.FullName, entry.FileName); - Directory.CreateDirectory(Path.GetDirectoryName(filePath)!); + if (!File.Exists(filePath)) + { + Log.Error("[DASSET] {0} not found locally", entry.FileName); + assetFileDownloadList.Add(entry); + //break; + continue; + } + + if (string.IsNullOrEmpty(entry.Hash)) + continue; try { - Directory.CreateDirectory(Path.GetDirectoryName(filePathDev)!); + using var file = File.OpenRead(filePath); + var fileHash = sha1.ComputeHash(file); + var stringHash = BitConverter.ToString(fileHash).Replace("-", ""); + + if (stringHash != entry.Hash) + { + Log.Error("[DASSET] {0} has {1}, remote {2}, need refresh", entry.FileName, stringHash, entry.Hash); + assetFileDownloadList.Add(entry); + //break; + } } - catch + catch (Exception ex) { - // ignored + Log.Error(ex, "[DASSET] Could not read asset"); + assetFileDownloadList.Add(entry); + continue; } + } - var refreshFile = false; + foreach (var entry in assetFileDownloadList) + { + var oldFilePath = Path.Combine(devDir.FullName, entry.FileName); + var newFilePath = Path.Combine(currentDir.FullName, entry.FileName); + Directory.CreateDirectory(Path.GetDirectoryName(newFilePath)!); - if (File.Exists(filePath) && !string.IsNullOrEmpty(entry.Hash)) + try { - try + if (File.Exists(oldFilePath)) { - using var file = File.OpenRead(filePath); + using var file = File.OpenRead(oldFilePath); var fileHash = sha1.ComputeHash(file); var stringHash = BitConverter.ToString(fileHash).Replace("-", ""); - refreshFile = stringHash != entry.Hash; - Log.Verbose("[DASSET] {0} has {1}, remote {2}", entry.FileName, stringHash, entry.Hash); - } - catch (Exception ex) - { - Log.Error(ex, "[DASSET] Could not read asset"); + + if (stringHash == entry.Hash) + { + Log.Verbose("[DASSET] Get asset from old file: {0}", entry.FileName); + File.Copy(oldFilePath, newFilePath, true); + isRefreshNeeded = true; + continue; + } } } + catch (Exception ex) + { + Log.Error(ex, "[DASSET] Could not copy from old asset: {0}", entry.FileName); + } - if (!File.Exists(filePath) || isRefreshNeeded || refreshFile) + try { Log.Information("[DASSET] Downloading {0} to {1}...", entry.Url, entry.FileName); var request = await client.GetAsync(entry.Url).ConfigureAwait(true); request.EnsureSuccessStatusCode(); - File.WriteAllBytes(filePath, await request.Content.ReadAsByteArrayAsync().ConfigureAwait(true)); + File.WriteAllBytes(newFilePath, await request.Content.ReadAsByteArrayAsync().ConfigureAwait(true)); - try - { - File.Copy(filePath, filePathDev, true); - } - catch - { - // ignored - } + isRefreshNeeded = true; + } + catch (Exception ex) + { + Log.Error(ex, "[DASSET] Could not download old asset: {0}", entry.FileName); } } if (isRefreshNeeded) + { + try + { + DeleteAndRecreateDirectory(devDir); + CopyFilesRecursively(currentDir, devDir); + } + catch (Exception ex) + { + Log.Error(ex, "[DASSET] Could not copy to dev dir"); + } + SetLocalAssetVer(baseDir, info.Version); + } - Log.Verbose("[DASSET] Assets OK at {0}", assetsDir.FullName); + Log.Verbose("[DASSET] Assets OK at {0}", currentDir.FullName); - CleanUpOld(baseDir, info.Version - 1); + try + { + CleanUpOld(baseDir, devDir, currentDir); + } + catch (Exception ex) + { + Log.Error(ex, "[DASSET] Could not clean up old assets"); + } + + return currentDir; + } + + public static void DeleteAndRecreateDirectory(DirectoryInfo dir) + { + if (!dir.Exists) + { + dir.Create(); + } + else + { + dir.Delete(true); + dir.Create(); + } + } + + public static void CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target) + { + foreach (var dir in source.GetDirectories()) + CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name)); - return assetsDir; + foreach (var file in source.GetFiles()) + file.CopyTo(Path.Combine(target.FullName, file.Name)); } private static string GetAssetVerPath(DirectoryInfo baseDir) @@ -121,6 +193,49 @@ private static string GetAssetVerPath(DirectoryInfo baseDir) return Path.Combine(baseDir.FullName, "asset.ver"); } + private static void CleanUpOld(DirectoryInfo baseDir, DirectoryInfo devDir, DirectoryInfo currentDir) + { + if (CheckIsGameOpen()) + return; + + if (!baseDir.Exists) + return; + + foreach (var toDelete in baseDir.GetDirectories()) + { + if (toDelete.Name != devDir.Name && toDelete.Name != currentDir.Name) + { + toDelete.Delete(true); + Log.Verbose("[DASSET] Cleaned out {Path}", toDelete.FullName); + } + } + + Log.Verbose("[DASSET] Finished cleaning"); + } + + public static bool CheckIsGameOpen() + { +#if DEBUG + return false; +#endif + + var procs = Process.GetProcesses(); + + if (procs.Any(x => x.ProcessName == "ffxiv")) + return true; + + if (procs.Any(x => x.ProcessName == "ffxiv_dx11")) + return true; + + if (procs.Any(x => x.ProcessName == "ffxivboot")) + return true; + + if (procs.Any(x => x.ProcessName == "ffxivlauncher")) + return true; + + return false; + } + /// /// Check if an asset update is needed. When this fails, just return false - the route to github /// might be bad, don't wanna just bail out in that case diff --git a/Dalamud.Updater/FormMain.cs b/Dalamud.Updater/FormMain.cs index d1ba274..c1bf7ec 100644 --- a/Dalamud.Updater/FormMain.cs +++ b/Dalamud.Updater/FormMain.cs @@ -352,7 +352,7 @@ private void UpdateSelf() { try { -#if DEBUG +#if false var json = JsonConvert.DeserializeObject(File.ReadAllText(@"D:\Code\ottercorp\version.txt"), new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All,