diff --git a/.gitignore b/.gitignore
index f1a30ad..340c3ab 100644
--- 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
index be470fa..3ef6ffa 100644
--- 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
index 586cf88..affbd94 100644
--- 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
index 5a13c49..287d1e5 100644
--- 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
index 0027901..a033925 100644
--- 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
index d2c844d..15ca5c0 100644
--- 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
|