diff --git a/Libraries/SPTarkov.Server.Core/Callbacks/BundleCallbacks.cs b/Libraries/SPTarkov.Server.Core/Callbacks/BundleCallbacks.cs
index 18dc9ffa..24594d07 100644
--- a/Libraries/SPTarkov.Server.Core/Callbacks/BundleCallbacks.cs
+++ b/Libraries/SPTarkov.Server.Core/Callbacks/BundleCallbacks.cs
@@ -2,6 +2,7 @@
using SPTarkov.Server.Core.Loaders;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
+using SPTarkov.Server.Core.Routers.Serializers;
using SPTarkov.Server.Core.Utils;
namespace SPTarkov.Server.Core.Callbacks;
@@ -19,9 +20,10 @@ public class BundleCallbacks(HttpResponseUtil httpResponseUtil, BundleLoader bun
}
///
- /// TODO: what does it do
+ /// Handle requests to /files/bundle
+ ///
+ /// Makes sure the output is set to BUNDLE so that the BundleSerializer's can handle it.
///
- ///
public ValueTask GetBundle(string url, object info, MongoId sessionID)
{
return new ValueTask("BUNDLE");
diff --git a/Libraries/SPTarkov.Server.Core/Loaders/BundleLoader.cs b/Libraries/SPTarkov.Server.Core/Loaders/BundleLoader.cs
index 129abf9e..f5328aa2 100644
--- a/Libraries/SPTarkov.Server.Core/Loaders/BundleLoader.cs
+++ b/Libraries/SPTarkov.Server.Core/Loaders/BundleLoader.cs
@@ -39,6 +39,8 @@ public class BundleLoader(ISptLogger logger, JsonUtil jsonUtil, Bu
public async Task LoadBundlesAsync(SptMod mod)
{
+ await bundleHashCacheService.HydrateCache();
+
var modPath = mod.GetModPath();
var modBundles = await jsonUtil.DeserializeFromFileAsync(
@@ -59,12 +61,7 @@ public class BundleLoader(ISptLogger logger, JsonUtil jsonUtil, Bu
continue;
}
- if (!bundleHashCacheService.CalculateAndMatchHash(bundleLocalPath))
- {
- await bundleHashCacheService.CalculateAndStoreHash(bundleLocalPath);
- }
-
- var bundleHash = bundleHashCacheService.GetStoredValue(bundleLocalPath);
+ var bundleHash = await bundleHashCacheService.CalculateMatchAndStoreHash(bundleLocalPath);
AddBundle(bundleManifest.Key, new BundleInfo(relativeModPath, bundleManifest, bundleHash));
}
diff --git a/Libraries/SPTarkov.Server.Core/Services/BundleHashCacheService.cs b/Libraries/SPTarkov.Server.Core/Services/BundleHashCacheService.cs
index f9f37dd7..34d6f9f2 100644
--- a/Libraries/SPTarkov.Server.Core/Services/BundleHashCacheService.cs
+++ b/Libraries/SPTarkov.Server.Core/Services/BundleHashCacheService.cs
@@ -9,9 +9,27 @@ public class BundleHashCacheService(ISptLogger logger, J
{
protected const string _bundleHashCachePath = "./user/cache/";
protected const string _cacheName = "bundleHashCache.json";
- protected readonly Dictionary _bundleHashes = [];
+ protected Dictionary _bundleHashes = [];
- public uint GetStoredValue(string key)
+ public async Task HydrateCache()
+ {
+ if (!Directory.Exists(_bundleHashCachePath))
+ {
+ Directory.CreateDirectory(_bundleHashCachePath);
+ }
+
+ var fullCachePath = Path.Join(_bundleHashCachePath, _cacheName);
+
+ // File doesn't exist, assume this is the first time we're trying to load in bundles
+ if (!File.Exists(fullCachePath))
+ {
+ return;
+ }
+
+ _bundleHashes = await jsonUtil.DeserializeFromFileAsync>(fullCachePath) ?? [];
+ }
+
+ protected uint GetStoredValue(string key)
{
if (!_bundleHashes.TryGetValue(key, out var value))
{
@@ -21,37 +39,44 @@ public class BundleHashCacheService(ISptLogger logger, J
return value;
}
- public async Task StoreValue(string bundlePath, uint hash)
+ protected async Task StoreValue(string bundlePath, uint hash)
{
_bundleHashes.Add(bundlePath, hash);
- if (!Directory.Exists(_bundleHashCachePath))
+ var bundleHashesSerialized = jsonUtil.Serialize(_bundleHashes);
+
+ if (bundleHashesSerialized is null)
{
- Directory.CreateDirectory(_bundleHashCachePath);
+ return;
}
- await fileUtil.WriteFileAsync(Path.Join(_bundleHashCachePath, _cacheName), jsonUtil.Serialize(_bundleHashes));
+ await fileUtil.WriteFileAsync(Path.Join(_bundleHashCachePath, _cacheName), bundleHashesSerialized);
logger.Debug($"Bundle: {bundlePath} hash stored in: ${_bundleHashCachePath}");
}
- public bool CalculateAndMatchHash(string BundlePath)
+ ///
+ /// Calculate, match the current hash and store the correct hash of the bundle
+ ///
+ /// The path to the bundle
+ public async Task CalculateMatchAndStoreHash(string BundlePath)
{
- return MatchWithStoredHash(BundlePath, CalculateHash(BundlePath));
+ var hash = await CalculateHash(BundlePath);
+
+ if (!MatchWithStoredHash(BundlePath, hash))
+ {
+ await StoreValue(BundlePath, await CalculateHash(BundlePath));
+ }
+
+ return hash;
}
- public async Task CalculateAndStoreHash(string BundlePath)
+ protected async Task CalculateHash(string BundlePath)
{
- await StoreValue(BundlePath, CalculateHash(BundlePath));
+ return hashUtil.GenerateCrc32ForData(await fileUtil.ReadFileAsBytesAsync(BundlePath));
}
- public uint CalculateHash(string BundlePath)
- {
- var fileData = fileUtil.ReadFile(BundlePath);
- return hashUtil.GenerateCrc32ForData(fileData);
- }
-
- public bool MatchWithStoredHash(string BundlePath, uint hash)
+ protected bool MatchWithStoredHash(string BundlePath, uint hash)
{
return GetStoredValue(BundlePath) == hash;
}
diff --git a/Libraries/SPTarkov.Server.Core/Utils/FileUtil.cs b/Libraries/SPTarkov.Server.Core/Utils/FileUtil.cs
index 87eb541d..1842fabe 100644
--- a/Libraries/SPTarkov.Server.Core/Utils/FileUtil.cs
+++ b/Libraries/SPTarkov.Server.Core/Utils/FileUtil.cs
@@ -1,3 +1,4 @@
+using System.Security.AccessControl;
using SPTarkov.DI.Annotations;
namespace SPTarkov.Server.Core.Utils;
@@ -61,8 +62,17 @@ public class FileUtil
public string ReadFile(string path)
{
- using var reader = new StreamReader(path);
- return reader.ReadToEnd();
+ return File.ReadAllText(path);
+ }
+
+ public async Task ReadFileAsync(string path)
+ {
+ return await File.ReadAllTextAsync(path);
+ }
+
+ public async Task ReadFileAsBytesAsync(string path)
+ {
+ return await File.ReadAllBytesAsync(path);
}
public void WriteFile(string filePath, string fileContent)
diff --git a/Libraries/SPTarkov.Server.Core/Utils/HashUtil.cs b/Libraries/SPTarkov.Server.Core/Utils/HashUtil.cs
index 16e4f2e8..d3b46ada 100644
--- a/Libraries/SPTarkov.Server.Core/Utils/HashUtil.cs
+++ b/Libraries/SPTarkov.Server.Core/Utils/HashUtil.cs
@@ -13,6 +13,11 @@ public class HashUtil(RandomUtil _randomUtil)
return Crc32.HashToUInt32(new ArraySegment(Encoding.UTF8.GetBytes(data)));
}
+ public uint GenerateCrc32ForData(ReadOnlySpan data)
+ {
+ return Crc32.HashToUInt32(data);
+ }
+
///
/// Create a hash for the data parameter
///
diff --git a/SPTarkov.Server/Services/SptServerBackgroundService.cs b/SPTarkov.Server/Services/SptServerBackgroundService.cs
index 66bb97c3..1195c4c8 100644
--- a/SPTarkov.Server/Services/SptServerBackgroundService.cs
+++ b/SPTarkov.Server/Services/SptServerBackgroundService.cs
@@ -13,7 +13,7 @@ public class SptServerBackgroundService(IReadOnlyList loadedMods, Bundle
{
foreach (var mod in loadedMods)
{
- if (mod.ModMetadata?.IsBundleMod == true)
+ if (mod.ModMetadata.IsBundleMod == true)
{
await bundleLoader.LoadBundlesAsync(mod);
}