mirror of
https://github.com/sp-tarkov/modules.git
synced 2025-02-13 09:50:43 -05:00

This patch contains the following: - Initial async VFS code (for reading / writing files) - Simplified Http Client code - Added async support to Http Client, RequestHandler - Improved RequestHandler logging - Deferred bundle loading to EasyAssetPatch - Make GetManifestJson run async This comes with a number of benefits: - When downloading bundles, it will mention which files succeeded or failed to download - Bundle loading happens in the initial screen, not the white screen - Fixed the issue where bundle loading could break bepinex loading (too long load time) - Modders can now make async http request and read/write files async I removed logging of sessionid inside the RequestHandler for each request, sessionid is already visible from bepinex log startup parameters. At last, sorry for the amount of commits it took. I initially wanted to target the 3.9.0 branch, but decided to use 3.8.1 instead as async request can really help out some mods. Reviewed-on: SPT-AKI/Modules#117 Co-authored-by: Merijn Hendriks <merijn.d.hendriks@gmail.com> Co-committed-by: Merijn Hendriks <merijn.d.hendriks@gmail.com>
110 lines
3.4 KiB
C#
110 lines
3.4 KiB
C#
using System.Collections.Concurrent;
|
|
using System.Threading.Tasks;
|
|
using BepInEx.Logging;
|
|
using Newtonsoft.Json;
|
|
using Aki.Common.Http;
|
|
using Aki.Common.Utils;
|
|
using Aki.Custom.Models;
|
|
|
|
namespace Aki.Custom.Utils
|
|
{
|
|
public static class BundleManager
|
|
{
|
|
private static readonly ManualLogSource _logger;
|
|
public static readonly ConcurrentDictionary<string, BundleItem> Bundles;
|
|
public static string CachePath;
|
|
|
|
static BundleManager()
|
|
{
|
|
_logger = Logger.CreateLogSource(nameof(BundleManager));
|
|
Bundles = new ConcurrentDictionary<string, BundleItem>();
|
|
CachePath = "user/cache/bundles/";
|
|
}
|
|
|
|
public static string GetBundlePath(BundleItem bundle)
|
|
{
|
|
return RequestHandler.IsLocal
|
|
? $"{bundle.ModPath}/bundles/{bundle.FileName}"
|
|
: CachePath + bundle.FileName;
|
|
}
|
|
|
|
public static async Task GetBundles()
|
|
{
|
|
// get bundles
|
|
var json = RequestHandler.GetJson("/singleplayer/bundles");
|
|
var bundles = JsonConvert.DeserializeObject<BundleItem[]>(json);
|
|
|
|
// register bundles
|
|
var toDownload = new ConcurrentBag<BundleItem>();
|
|
|
|
foreach (var bundle in bundles)
|
|
{
|
|
Bundles.TryAdd(bundle.FileName, bundle);
|
|
|
|
if (await ShouldReaquire(bundle))
|
|
{
|
|
// mark for download
|
|
toDownload.Add(bundle);
|
|
}
|
|
}
|
|
|
|
if (RequestHandler.IsLocal)
|
|
{
|
|
// loading from local mods
|
|
_logger.LogInfo("CACHE: Loading all bundles from mods on disk.");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// download bundles
|
|
// NOTE: assumes bundle keys to be unique
|
|
foreach (var bundle in toDownload)
|
|
{
|
|
// download bundle
|
|
var filepath = GetBundlePath(bundle);
|
|
var data = await RequestHandler.GetDataAsync($"/files/bundle/{bundle.FileName}");
|
|
await VFS.WriteFileAsync(filepath, data);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static async Task<bool> ShouldReaquire(BundleItem bundle)
|
|
{
|
|
if (RequestHandler.IsLocal)
|
|
{
|
|
// only handle remote bundles
|
|
return false;
|
|
}
|
|
|
|
// read cache
|
|
var filepath = CachePath + bundle.FileName;
|
|
|
|
if (VFS.Exists(filepath))
|
|
{
|
|
// calculate hash
|
|
var data = await VFS.ReadFileAsync(filepath);
|
|
var crc = Crc32.Compute(data);
|
|
|
|
if (crc == bundle.Crc)
|
|
{
|
|
// file is up-to-date
|
|
_logger.LogInfo($"CACHE: Loading locally {bundle.FileName}");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// crc doesn't match, reaquire the file
|
|
_logger.LogInfo($"CACHE: Bundle is invalid, (re-)acquiring {bundle.FileName}");
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// file doesn't exist in cache
|
|
_logger.LogInfo($"CACHE: Bundle is missing, (re-)acquiring {bundle.FileName}");
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|