Skip to content

Commit

Permalink
feat: 从旧目录获取没更新的文件
Browse files Browse the repository at this point in the history
  • Loading branch information
Loskh committed Oct 29, 2024
1 parent c00b458 commit 082b01a
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 32 deletions.
177 changes: 146 additions & 31 deletions Dalamud.Updater/Dalamud/AssetManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -40,7 +43,7 @@ public static async Task<DirectoryInfo> 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();

Expand All @@ -50,77 +53,189 @@ public static async Task<DirectoryInfo> 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<AssetInfo.Asset>();
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)
{
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;
}

/// <summary>
/// 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
Expand Down
2 changes: 1 addition & 1 deletion Dalamud.Updater/FormMain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ private void UpdateSelf()
{
try
{
#if DEBUG
#if false
var json = JsonConvert.DeserializeObject<VersionInfo>(File.ReadAllText(@"D:\Code\ottercorp\version.txt"), new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
Expand Down

0 comments on commit 082b01a

Please sign in to comment.