MatrixRoomUtils

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | LICENSE

commit a069cfd6a0f7c53b902607e79037ffd90681a7b9
parent 50d6afe5f9931c3c19a3038f5b638c4e505a3364
Author: TheArcaneBrony <myrainbowdash949@gmail.com>
Date:   Thu, 11 May 2023 20:56:16 +0200

Add state cache

Diffstat:
M.gitignore | 1+
MMatrixRoomUtils.Core/Room.cs | 41++++++++++++++++++++++++++++++++++++++---
MMatrixRoomUtils.Core/RuntimeCache.cs | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MMatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs | 2++
MMatrixRoomUtils.Web/Shared/NavMenu.razor | 9+++++++++
MMatrixRoomUtils.Web/Shared/RoomListItem.razor | 10+++++++++-
6 files changed, 116 insertions(+), 4 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -4,3 +4,4 @@ MatrixRoomUtils/ MatrixRoomUtils.Web/wwwroot/MRU.tar.xz /src/ *.tar.xz +matrix-sync.json diff --git a/MatrixRoomUtils.Core/Room.cs b/MatrixRoomUtils.Core/Room.cs @@ -16,17 +16,52 @@ public class Room public async Task<JsonElement?> GetStateAsync(string type, string state_key="", bool logOnFailure = false) { - var url = $"/_matrix/client/r0/rooms/{RoomId}/state"; + var url = $"/_matrix/client/v3/rooms/{RoomId}/state"; if (!string.IsNullOrEmpty(state_key)) url += $"/{type}/{state_key}"; else if (!string.IsNullOrEmpty(type)) url += $"/{type}"; - + var cache_key = "room_states_"+type; + if (!RuntimeCache.GenericResponseCache.ContainsKey(cache_key)) + { + Console.WriteLine($"[!!] No cache for {cache_key}, creating..."); + RuntimeCache.GenericResponseCache.Add(cache_key, new ObjectCache<object?>() + { + DefaultExpiry = type switch + { + "m.room.name" => TimeSpan.FromMinutes(15), + _ => TimeSpan.FromMinutes(5) + } + }); + } + + if (RuntimeCache.GenericResponseCache[cache_key][url] != null) + { + if(RuntimeCache.GenericResponseCache[cache_key][url].ExpiryTime > DateTime.Now) + { + Console.WriteLine($"[:3] Found cached state: {RuntimeCache.GenericResponseCache[cache_key][url].Result}"); + return (JsonElement?)RuntimeCache.GenericResponseCache[cache_key][url].Result; + } + else + { + Console.WriteLine($"[!!] Cached state expired at {RuntimeCache.GenericResponseCache[cache_key][url].ExpiryTime}: {RuntimeCache.GenericResponseCache[cache_key][url].Result}"); + } + } + else + { + Console.WriteLine($"[!!] No cached state for {url}"); + } + var res = await _httpClient.GetAsync(url); if (!res.IsSuccessStatusCode) { if(logOnFailure) Console.WriteLine($"{RoomId}/{state_key}/{type} - got status: {res.StatusCode}"); return null; } - return await res.Content.ReadFromJsonAsync<JsonElement>(); + var result = await res.Content.ReadFromJsonAsync<JsonElement>(); + RuntimeCache.GenericResponseCache[cache_key][url] = new GenericResult<object>() + { + Result = result + }; + return result; } public async Task<string?> GetNameAsync() { diff --git a/MatrixRoomUtils.Core/RuntimeCache.cs b/MatrixRoomUtils.Core/RuntimeCache.cs @@ -1,3 +1,7 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.JavaScript; +using System.Xml.Schema; +using MatrixRoomUtils.Core.Extensions; using MatrixRoomUtils.Core.Responses; namespace MatrixRoomUtils.Core; @@ -11,6 +15,8 @@ public class RuntimeCache public static Dictionary<string, HomeServerResolutionResult> HomeserverResolutionCache { get; set; } = new(); // public static Dictionary<string, (DateTime cachedAt, ProfileResponse response)> ProfileCache { get; set; } = new(); + + public static Dictionary<string, ObjectCache<object>> GenericResponseCache { get; set; } = new(); } @@ -26,3 +32,54 @@ public class HomeServerResolutionResult public string Result { get; set; } public DateTime ResolutionTime { get; set; } } +public class ObjectCache<T> where T : class +{ + public Dictionary<string, GenericResult<T>> Cache { get; set; } = new(); + public TimeSpan DefaultExpiry { get; set; } = new(0, 5, 0); + public GenericResult<T> this[string key] + { + get + { + if (Random.Shared.Next(100) == 1) + { + // Console.WriteLine("Cleaning cache..."); + // foreach (var x in Cache.Where(x => x.Value.ExpiryTime < DateTime.Now).OrderBy(x => x.Value.ExpiryTime).Take(3).ToList()) + // { + // Console.WriteLine($"Removing {x.Key} from cache"); + // Cache.Remove(x.Key); + // } + } + + + if (Cache.ContainsKey(key)) + { + // Console.WriteLine($"Found item in cache: {key} - {Cache[key].Result.ToJson(indent: false)}"); + if(Cache[key].ExpiryTime > DateTime.Now) + return Cache[key]; + + Console.WriteLine($"Expired item in cache: {key} - {Cache[key].Result.ToJson(indent: false)}"); + try + { + Cache.Remove(key); + } + catch (Exception e) + { + Console.WriteLine($"Failed to remove {key} from cache: {e.Message}"); + } + } + return null; + } + set + { + Cache[key] = value; + if(Cache[key].ExpiryTime == null) Cache[key].ExpiryTime = DateTime.Now.Add(DefaultExpiry); + Console.WriteLine($"New item in cache: {key} - {Cache[key].Result.ToJson(indent: false)}"); + // Console.Error.WriteLine("Full cache: " + Cache.ToJson()); + } + } +} +public class GenericResult<T> +{ + public T? Result { get; set; } + public DateTime? ExpiryTime { get; set; } +} diff --git a/MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs b/MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs @@ -28,6 +28,7 @@ public partial class LocalStorageWrapper RuntimeCache.CurrentHomeServer = await new AuthenticatedHomeServer(RuntimeCache.LoginSessions[RuntimeCache.LastUsedToken].LoginResponse.UserId, RuntimeCache.LastUsedToken, RuntimeCache.LoginSessions[RuntimeCache.LastUsedToken].LoginResponse.HomeServer).Configure(); Console.WriteLine("Created authenticated home server"); } + RuntimeCache.GenericResponseCache = await localStorage.GetItemAsync<Dictionary<string, ObjectCache<object>>>("rory.matrixroomutils.generic_cache") ?? new(); RuntimeCache.WasLoaded = true; } @@ -40,5 +41,6 @@ public partial class LocalStorageWrapper await localStorage.SetItemAsync("rory.matrixroomutils.homeserver_resolution_cache", RuntimeCache.HomeserverResolutionCache.DistinctBy(x => x.Key) .ToDictionary(x => x.Key, x => x.Value)); + await localStorage.SetItemAsync("rory.matrixroomutils.generic_cache", RuntimeCache.GenericResponseCache); } } \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Shared/NavMenu.razor b/MatrixRoomUtils.Web/Shared/NavMenu.razor @@ -15,6 +15,10 @@ </NavLink> </div> <div class="nav-item px-3"> + <h5 style="margin-left: 1em;">Main tools</h5> + <hr style="margin-bottom: 0em;"/> + </div> + <div class="nav-item px-3"> <NavLink class="nav-link" href="About"> <span class="oi oi-plus" aria-hidden="true"></span> About MRU </NavLink> @@ -39,6 +43,11 @@ <span class="oi oi-plus" aria-hidden="true"></span> Room state viewer </NavLink> </div> + <div class="nav-item px-3"> + <h5 style="margin-left: 1em;">Plural tools</h5> + <hr style="margin-bottom: 0em;"/> + </div> + </nav> </div> diff --git a/MatrixRoomUtils.Web/Shared/RoomListItem.razor b/MatrixRoomUtils.Web/Shared/RoomListItem.razor @@ -33,6 +33,12 @@ protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); + + if(!RuntimeCache.WasLoaded) { + Console.WriteLine("Loading from local storage"); + await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); + } + if (Room == null) { if (RoomId == null) @@ -80,7 +86,7 @@ { hasCustomProfileName = _name.GetString() != profile.DisplayName; profileName = _name.GetString(); - Console.WriteLine($"{profile.DisplayName} - {_name.GetString()}: {hasCustomProfileName}"); + // Console.WriteLine($"{profile.DisplayName} - {_name.GetString()}: {hasCustomProfileName}"); } else { @@ -88,6 +94,8 @@ } } } + if(Random.Shared.Next(100) == 1) + await LocalStorageWrapper.SaveToLocalStorage(LocalStorage); } } \ No newline at end of file