using Blazored.SessionStorage; using LibGit.Extensions; using LibGit.Interfaces; using Microsoft.AspNetCore.Components.WebAssembly.Http; namespace GitRepoViewer; public class WebRepoSource : IRepoSource { private const bool _debug = false; public WebRepoSource(string basePath) { BasePath = basePath; } public string BasePath { get; set; } public ISessionStorageService? SessionStorage { private get; set; } public async Task GetFileStream(string path) { if(_debug)Console.WriteLine("Fetching file: " + Path.Join(BasePath, path)); var _path = Path.Join(BasePath, path); if (SessionStorage != null && await SessionStorage.ContainKeyAsync(_path)) { //Console.WriteLine("Found file in session storage: " + _path); return new MemoryStream((await SessionStorage.GetItemAsync>(_path)).ToArray()); } var request = new HttpRequestMessage(HttpMethod.Get, _path); // request.SetBrowserRequestMode(BrowserRequestMode.NoCors); var client = new HttpClient(); var response = await client.SendAsync(request); if(!response.IsSuccessStatusCode) throw new Exception("Failed to fetch file: " + _path); if(SessionStorage != null && response.Content.Headers.ContentLength.HasValue && response.Content.Headers.ContentLength.Value < 1_000_000 && !noCachePathPrefixes.Any(prefix => path.StartsWith(prefix))) { Console.WriteLine($"Liberally caching file: {_path} ({response.Content.Headers.ContentLength.Value} bytes)"); var stream = await response.Content.ReadAsStreamAsync(); await SessionStorage.SetItemAsync(_path, stream.Peek(response.Content.Headers.ContentLength.Value)); return stream; } if(!noCachePathPrefixes.Any(prefix => path.StartsWith(prefix))) Console.WriteLine($"Not caching file: {_path} ({response.Content.Headers.ContentLength.Value} bytes): blacklisted prefix"); return await response.Content.ReadAsStreamAsync(); } public Task GetObjectStreamById(string objectId) { Console.WriteLine("Fetching object: " + objectId + " from " + BasePath + "objects/" + objectId[..2] + "/" + objectId[2..] + ""); return GetFileStream(Path.Join("objects", objectId[..2], objectId[2..])); } public async Task HasObjectCached(string objectId) { var _path = Path.Join(BasePath, "objects/", objectId[..2], "/", objectId[2..]); return SessionStorage != null && await SessionStorage.ContainKeyAsync(_path); } private static readonly string[] noCachePathPrefixes = { "HEAD", "info", "refs" }; }