about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTheArcaneBrony <myrainbowdash949@gmail.com>2023-05-11 20:56:16 +0200
committerTheArcaneBrony <myrainbowdash949@gmail.com>2023-05-11 20:56:16 +0200
commita069cfd6a0f7c53b902607e79037ffd90681a7b9 (patch)
tree0cfc47619d35e2d89568f5d1c151ba8e1906ec85
parentAdd license, deploy src (diff)
downloadMatrixUtils-a069cfd6a0f7c53b902607e79037ffd90681a7b9.tar.xz
Add state cache
-rw-r--r--.gitignore1
-rw-r--r--MatrixRoomUtils.Core/Room.cs41
-rw-r--r--MatrixRoomUtils.Core/RuntimeCache.cs57
-rw-r--r--MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs2
-rw-r--r--MatrixRoomUtils.Web/Shared/NavMenu.razor9
-rw-r--r--MatrixRoomUtils.Web/Shared/RoomListItem.razor10
6 files changed, 116 insertions, 4 deletions
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