Don't store xxHash caches in binary format

This commit is contained in:
Timothy Baldridge 2020-02-15 19:50:02 -07:00
parent 9343d38047
commit 5da39fe223
4 changed files with 62 additions and 16 deletions

View File

@ -3,6 +3,8 @@
#### Version - 0.9.20.0
* Don't reuse HTTP request objects (#532)
* Block popups in the in-app browser (#535)
* Don't print API keys in logs (#532)
* Store xxHash caches in binary format (#530)
#### Version - 0.9.19.0

View File

@ -229,27 +229,53 @@ namespace Wabbajack.Common
public static string FileHashCached(this string file, bool nullOnIOError = false)
{
var hashPath = file + Consts.HashFileExtension;
if (File.Exists(hashPath) && File.GetLastWriteTime(file) <= File.GetLastWriteTime(hashPath))
{
return File.ReadAllText(hashPath);
}
if (TryGetHashCache(file, out var foundHash)) return foundHash;
var hash = file.FileHash(nullOnIOError);
File.WriteAllText(hashPath, hash);
if (hash != null)
WriteHashCache(file, hash);
return hash;
}
public static bool TryGetHashCache(string file, out string hash)
{
var hashFile = file + Consts.HashFileExtension;
hash = null;
if (!File.Exists(hashFile)) return false;
var fi = new FileInfo(hashFile);
if (fi.Length != 20) return false;
using var fs = File.OpenRead(hashFile);
using var br = new BinaryReader(fs);
var version = br.ReadUInt32();
if (version != HashCacheVersion) return false;
var lastModified = br.ReadUInt64();
if (lastModified != fi.LastWriteTimeUtc.AsUnixTime()) return false;
hash = BitConverter.GetBytes(br.ReadUInt64()).ToBase64();
return true;
}
private const uint HashCacheVersion = 0x01;
private static void WriteHashCache(string file, string hash)
{
using var fs = File.Create(file + Consts.HashFileExtension);
using var bw = new BinaryWriter(fs);
bw.Write(HashCacheVersion);
var lastModified = File.GetLastWriteTimeUtc(file).AsUnixTime();
bw.Write(lastModified);
bw.Write(BitConverter.ToUInt64(hash.FromBase64()));
}
public static async Task<string> FileHashCachedAsync(this string file, bool nullOnIOError = false)
{
var hashPath = file + Consts.HashFileExtension;
if (File.Exists(hashPath) && File.GetLastWriteTime(file) <= File.GetLastWriteTime(hashPath))
{
return File.ReadAllText(hashPath);
}
if (TryGetHashCache(file, out var foundHash)) return foundHash;
var hash = await file.FileHashAsync(nullOnIOError);
File.WriteAllText(hashPath, hash);
if (hash != null)
WriteHashCache(file, hash);
return hash;
}
@ -345,6 +371,12 @@ namespace Wabbajack.Common
dtDateTime = dtDateTime.AddSeconds(timestamp);
return dtDateTime;
}
public static ulong AsUnixTime(this DateTime timestamp)
{
var diff = timestamp - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
return (ulong)diff.TotalSeconds;
}
/// <summary>
/// Returns data from a base64 stream

View File

@ -228,7 +228,7 @@ namespace Wabbajack.Lib.NexusApi
UpdateRemaining(response);
if (!response.IsSuccessStatusCode)
{
Utils.Log($"Nexus call failed: {response.RequestMessage}");
Utils.Log($"Nexus call failed: {response.RequestMessage.RequestUri}");
throw new HttpRequestException($"{response.StatusCode} - {response.ReasonPhrase}");
}

View File

@ -1,4 +1,5 @@
using Wabbajack.Common;
using Alphaleonis.Win32.Filesystem;
using Wabbajack.Common;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Utils = Wabbajack.Common.Utils;
@ -14,6 +15,17 @@ namespace Wabbajack.Test
{
var speed = Utils.TestDiskSpeed(queue, @".\");
}
}
}
[TestMethod]
public void TestHash()
{
const string data = "Cheese for Everyone!";
File.WriteAllText("test.data", data);
Assert.AreEqual("eSIyd+KOG3s=", "test.data".FileHashCached(), "Hash is cached");
Assert.IsTrue(Utils.TryGetHashCache("test.data", out var fileHash), "New caching method is invoked");
Assert.AreEqual("eSIyd+KOG3s=", fileHash, "The correct hash value is cached");
Assert.AreNotEqual("eSIyd+KOG3s=", File.ReadAllText("test.data" + Consts.HashFileExtension), "We don't store the hash in plaintext");
}
}
}