From 24422642249a4f4dd52b1422dc1594b4d62b674c Mon Sep 17 00:00:00 2001 From: HolographicHat Date: Mon, 15 Aug 2022 23:35:29 +0800 Subject: [PATCH] Add CacheFile --- src/CacheFile.cs | 39 ++++++++++++ src/Utils.cs | 150 ++++++++++++++++++----------------------------- 2 files changed, 95 insertions(+), 94 deletions(-) create mode 100644 src/CacheFile.cs diff --git a/src/CacheFile.cs b/src/CacheFile.cs new file mode 100644 index 0000000..fc717de --- /dev/null +++ b/src/CacheFile.cs @@ -0,0 +1,39 @@ +using System.IO.Compression; +using Google.Protobuf; + +namespace YaeAchievement; + +public class CacheFile { + + private readonly string _cacheName; + private CacheItem? _content; + + public DateTime LastWriteTime => Exists() ? File.GetLastWriteTimeUtc(_cacheName) : DateTime.UnixEpoch; + + public CacheFile(string identifier) { + Directory.CreateDirectory(Path.Combine(GlobalVars.AppPath, "cache")); + _cacheName = Path.Combine(GlobalVars.AppPath, $"cache/{identifier.MD5Hash()[..16]}.miko"); + } + + public bool Exists() => File.Exists(_cacheName); + + public CacheItem Read() { + if (_content == null) { + using var fInput = File.OpenRead(_cacheName); + using var dInput = new GZipStream(fInput, CompressionMode.Decompress); + _content = CacheItem.Parser.ParseFrom(dInput); + } + return _content; + } + + public void Write(byte[] data, string? etag = null) { + using var fOut = File.OpenWrite(_cacheName); + using var cOut = new GZipStream(fOut, CompressionLevel.SmallestSize); + new CacheItem { + Etag = etag ?? string.Empty, + Version = 3, + Checksum = data.MD5Hash(), + Content = ByteString.CopyFrom(data) + }.WriteTo(cOut); + } +} diff --git a/src/Utils.cs b/src/Utils.cs index 2e45806..cd50f18 100644 --- a/src/Utils.cs +++ b/src/Utils.cs @@ -1,14 +1,10 @@ using System.ComponentModel; using System.Diagnostics; -using System.IO.Compression; using System.IO.Pipes; using System.Net; using System.Net.Http.Headers; using System.Runtime.InteropServices; -using System.Security.Cryptography; -using System.Text; using System.Text.Json.Nodes; -using Google.Protobuf; using Microsoft.Win32; using YaeAchievement.AppCenterSDK; using YaeAchievement.Win32; @@ -32,58 +28,28 @@ public static class Utils { return c; }); - public static string GetBucketFileAsString(string path, bool cache = true) { - return Encoding.UTF8.GetString(GetBucketFileAsByteArray(path, cache)); - } - public static byte[] GetBucketFileAsByteArray(string path, bool cache = true) { using var msg = new HttpRequestMessage { Method = HttpMethod.Get, RequestUri = new Uri($"{GlobalVars.BucketHost}/{path}") }; - CacheItem? ci = null; - var cacheName = cache ? $"./cache/{CalculateMD5(path)[..16]}.miko" : ""; - if (cache) { - Directory.CreateDirectory("cache"); - if (File.Exists(cacheName)) { - using var input = File.OpenRead(cacheName); - using var dInput = new GZipStream(input, CompressionMode.Decompress); - ci = CacheItem.Parser.ParseFrom(dInput); - msg.Headers.TryAddWithoutValidation("If-None-Match", $"{ci.Etag}"); - } + var cacheFile = new CacheFile(path); + if (cache && cacheFile.Exists()) { + msg.Headers.TryAddWithoutValidation("If-None-Match", $"{cacheFile.Read().Etag}"); } using var response = CHttpClient.Value.Send(msg); if (cache && response.StatusCode == HttpStatusCode.NotModified) { - return ci!.Content.ToByteArray(); + return cacheFile.Read().Content.ToByteArray(); } response.EnsureSuccessStatusCode(); var responseBytes = response.Content.ReadAsByteArrayAsync().Result; if (cache) { var etag = response.Headers.ETag!.Tag; - using var os = File.OpenWrite(cacheName); - using var cos = new GZipStream(os, CompressionLevel.SmallestSize); - new CacheItem { - Etag = etag, - Version = 3, - Checksum = CalculateMD5(responseBytes), - Content = ByteString.CopyFrom(responseBytes) - }.WriteTo(cos); + cacheFile.Write(responseBytes, etag); } return responseBytes; } - // ReSharper disable once InconsistentNaming - private static string CalculateMD5(string text) { - return CalculateMD5(Encoding.UTF8.GetBytes(text)); - } - - // ReSharper disable once InconsistentNaming - private static string CalculateMD5(byte[] bytes) { - using var md5 = MD5.Create(); - var b = md5.ComputeHash(bytes); - return Convert.ToHexString(b).ToLower(); - } - public static void CopyToClipboard(string text) { if (Native.OpenClipboard(IntPtr.Zero)) { Native.EmptyClipboard(); @@ -134,7 +100,6 @@ public static class Utils { } Console.WriteLine($"下载地址: {info.PackageLink}"); if (info.ForceUpdate) { - //Console.WriteLine("在完成此次更新前, 程序可能无法正常使用."); Environment.Exit(0); } } @@ -148,7 +113,7 @@ public static class Utils { var cur = Process.GetCurrentProcess(); foreach (var process in Process.GetProcesses().Where(process => process.Id != cur.Id)) { if (process.ProcessName == cur.ProcessName) { - Logger.Error("另一个实例正在运行,请关闭后重试"); + Console.WriteLine("另一个实例正在运行,请关闭后重试"); Environment.Exit(302); } } @@ -166,8 +131,7 @@ public static class Utils { private static bool CheckGamePathValid(string path) { var dir = Path.GetDirectoryName(path)!; - return !GlobalVars.CheckGamePath || - File.Exists($"{dir}/UnityPlayer.dll") && File.Exists($"{dir}/mhypbase.dll"); + return !GlobalVars.CheckGamePath || File.Exists($"{dir}/UnityPlayer.dll"); } private static string SelectGameExecutable() { @@ -208,63 +172,17 @@ public static class Utils { return path; } - #pragma warning disable CA1416 // 验证平台兼容性 - /// - /// 从注册表中寻找安装路径 暂时只支持国服 - /// - /// - private static string? FindGamePathFromRegistry() { - try { - using var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64); - using var key = hklm.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\原神"); - if (key == null) { - return null; - } - var installLocation = key.GetValue("InstallPath")?.ToString(); - if (!string.IsNullOrEmpty(installLocation)) { - var folder = Path.Combine(installLocation, "Genshin Impact Game\\"); - var exePath = Path.Combine(folder, "YuanShen.exe"); - if (File.Exists(Path.Combine(folder, "UnityPlayer.dll")) - && File.Exists(Path.Combine(folder, "mhypbase.dll")) - && File.Exists(exePath)) { - return exePath; - } - } - } catch (Exception e) { - Logger.Warn(e.Message); - } - return null; - } - #pragma warning restore CA1416 - // ReSharper disable once UnusedMethodReturnValue.Global public static bool TryDisableQuickEdit() { var handle = Native.GetStdHandle(); return Native.GetConsoleMode(handle, out var mode) && Native.SetConsoleMode(handle, mode&~64); } - -#pragma warning disable CA1416 - public static void CheckVcRuntime() { - using var root = Registry.LocalMachine; - using var sub = root.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall")!; - var installed = sub.GetSubKeyNames() - .Select(subKeyName => sub.OpenSubKey(subKeyName)) - .Select(item => item?.GetValue("DisplayName") as string ?? string.Empty) - .Any(name => name.Contains("Microsoft Visual C++ 2022 X64 ")); - if (!installed) { - Logger.Error("未安装 VcRuntime"); - Logger.Error("下载地址: https://aka.ms/vs/17/release/vc_redist.x64.exe"); - Logger.Error("安装完成后,重新打开 YaeAchievement"); - Environment.Exit(303); - } - } -#pragma warning restore CA1416 public static void CheckGenshinIsRunning() { Process.EnterDebugMode(); foreach (var process in Process.GetProcesses()) { if (process.ProcessName is "GenshinImpact" or "YuanShen") { - Console.WriteLine("原神正在运行,请关闭后重试"); + Console.WriteLine($"原神正在运行,请关闭后重试 ({process.Id})"); Environment.Exit(301); } } @@ -277,7 +195,7 @@ public static class Utils { public static void InstallExitHook() { AppDomain.CurrentDomain.ProcessExit += (_, _) => { proc?.Kill(); - Logger.Info("按任意键退出"); + Console.WriteLine("按任意键退出"); Console.ReadKey(); }; } @@ -285,7 +203,7 @@ public static class Utils { public static void InstallExceptionHook() { AppDomain.CurrentDomain.UnhandledException += (_, e) => { Console.WriteLine(e.ExceptionObject.ToString()); - Logger.Error("正在上报错误信息..."); + Console.WriteLine("正在上报错误信息..."); AppCenter.TrackCrash((Exception) e.ExceptionObject); AppCenter.Upload(); Environment.Exit(-1); @@ -307,7 +225,7 @@ public static class Utils { Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail")); } } - Logger.Info($"原神正在启动 ({pid})"); + Console.WriteLine($"原神正在启动 ({pid})"); proc = Process.GetProcessById(Convert.ToInt32(pid)); proc.EnableRaisingEvents = true; proc.Exited += (_, _) => { @@ -346,4 +264,48 @@ public static class Utils { th.Start(); return th; } -} \ No newline at end of file + + #pragma warning disable CA1416 + /// + /// 从注册表中寻找安装路径 暂时只支持国服 + /// + /// + private static string? FindGamePathFromRegistry() { + try { + using var root = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64); + using var key = root.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\原神"); + if (key == null) { + return null; + } + var installLocation = key.GetValue("InstallPath")?.ToString(); + if (!string.IsNullOrEmpty(installLocation)) { + var folder = Path.Combine(installLocation, "Genshin Impact Game\\"); + var exePath = Path.Combine(folder, "YuanShen.exe"); + if (File.Exists(Path.Combine(folder, "UnityPlayer.dll")) + && File.Exists(exePath)) { + return exePath; + } + } + } catch (Exception e) { + Console.WriteLine(e.Message); + } + return null; + } + + public static void CheckVcRuntime() { + using var root = Registry.LocalMachine; + using var sub = root.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall")!; + var installed = sub.GetSubKeyNames() + .Select(subKeyName => sub.OpenSubKey(subKeyName)) + .Select(item => item?.GetValue("DisplayName") as string ?? string.Empty) + .Any(name => name.Contains("Microsoft Visual C++ 2022 X64 ")); + if (!installed) { + const string vcDownloadUrl = "https://aka.ms/vs/17/release/vc_redist.x64.exe"; + Console.WriteLine("未安装 VcRuntime"); + Console.WriteLine($"下载地址: {vcDownloadUrl}"); + Console.WriteLine("安装完成后,重新打开 YaeAchievement"); + ShellOpen(vcDownloadUrl); + Environment.Exit(303); + } + } +}