about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2024-04-05 19:01:39 +0200
committerRory& <root@rory.gay>2024-04-05 19:02:00 +0200
commit9319fe76c56b79e0933c09280fe32658c2f176c7 (patch)
treeafc31b8b8b2a683b549e352237e2260efe97fba6
parentChanges (diff)
downloadMatrixUtils-9319fe76c56b79e0933c09280fe32658c2f176c7.tar.xz
Cleanup, work on index2, some tooling updates
m---------LibMatrix0
-rw-r--r--MatrixRoomUtils.sln7
-rw-r--r--MatrixUtils.Desktop/Components/NavigationStack.axaml.cs13
-rw-r--r--MatrixUtils.Web/Classes/RMUStorageWrapper.cs17
-rw-r--r--MatrixUtils.Web/MatrixUtils.Web.csproj6
-rw-r--r--MatrixUtils.Web/Pages/HSEInit.razor5
-rw-r--r--MatrixUtils.Web/Pages/Index.razor25
-rw-r--r--MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor37
-rw-r--r--MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor.css6
-rw-r--r--MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2MainTab.razor90
-rw-r--r--MatrixUtils.Web/Pages/Tools/MediaLocator.razor1
-rw-r--r--MatrixUtils.Web/Program.cs13
-rw-r--r--MatrixUtils.Web/appsettings.Development.json2
-rw-r--r--MatrixUtils.Web/appsettings.json2
-rw-r--r--MatrixUtils.Web/wwwroot/appsettings.json9
m---------MxApiExtensions0
16 files changed, 165 insertions, 68 deletions
diff --git a/LibMatrix b/LibMatrix
-Subproject fc3d89ad7422dedb8763783c6ebb5d70fcc2c53
+Subproject 37b97d65c0a5262539a5de560e911048166b8bb
diff --git a/MatrixRoomUtils.sln b/MatrixRoomUtils.sln
index 924697b..08f236d 100644
--- a/MatrixRoomUtils.sln
+++ b/MatrixRoomUtils.sln
@@ -55,10 +55,13 @@ EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibMatrix.DevTestBot", "LibMatrix\Utilities\LibMatrix.DevTestBot\LibMatrix.DevTestBot.csproj", "{5CE239F8-C124-4A96-A0F8-B56B9AE27434}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibMatrix.HomeserverEmulator", "LibMatrix\Tests\LibMatrix.HomeserverEmulator\LibMatrix.HomeserverEmulator.csproj", "{6D93DA72-69D8-43BD-BC19-7FFF8A313971}"
+EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArcaneLibs.UsageTest", "LibMatrix\ArcaneLibs\ArcaneLibs.UsageTest\ArcaneLibs.UsageTest.csproj", "{EDFC9BA8-CAA9-4B51-AFAF-834C1D74DCF0}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixUtils.DmSpaced", "MatrixUtils.DmSpaced\MatrixUtils.DmSpaced.csproj", "{B3FEA1EF-6CFE-49C5-A0B2-11DB58D4CD1C}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlazorApp1", "tmp\BlazorApp1\BlazorApp1.csproj", "{2057E543-84D9-483A-9A14-6399E7062419}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -161,6 +164,10 @@ Global
 		{B3FEA1EF-6CFE-49C5-A0B2-11DB58D4CD1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{B3FEA1EF-6CFE-49C5-A0B2-11DB58D4CD1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{B3FEA1EF-6CFE-49C5-A0B2-11DB58D4CD1C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{2057E543-84D9-483A-9A14-6399E7062419}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{2057E543-84D9-483A-9A14-6399E7062419}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2057E543-84D9-483A-9A14-6399E7062419}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{2057E543-84D9-483A-9A14-6399E7062419}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(NestedProjects) = preSolution
 		{F4E241C3-0300-4B87-8707-BCBDEF1F0185} = {8F4F6BEC-0C66-486B-A21A-1C35B2EDAD33}
diff --git a/MatrixUtils.Desktop/Components/NavigationStack.axaml.cs b/MatrixUtils.Desktop/Components/NavigationStack.axaml.cs
index 632ae3c..4e962a7 100644
--- a/MatrixUtils.Desktop/Components/NavigationStack.axaml.cs
+++ b/MatrixUtils.Desktop/Components/NavigationStack.axaml.cs
@@ -10,23 +10,24 @@ public partial class NavigationStack : UserControl {
     }
 
     // private void InitializeComponent() {
-        // AvaloniaXamlLoader.Load(this);
-        // buildView();
+    // AvaloniaXamlLoader.Load(this);
+    // buildView();
     // }
 
     protected override void OnLoaded(RoutedEventArgs e) {
         base.OnLoaded(e);
         buildView();
     }
-    
+
     private void buildView() {
         if (navPanel is null) {
             Console.WriteLine("NavigationStack buildView called while navpanel is null!");
             // await Task.Delay(100);
             // if (navPanel is null)
-                // await buildView();
+            // await buildView();
             // else Console.WriteLine("navpanel is not null!");
         }
+
         navPanel.Children.Clear();
         foreach (var item in _stack) {
             Button btn = new() {
@@ -38,10 +39,10 @@ public partial class NavigationStack : UserControl {
             };
             navPanel.Children.Add(btn);
         }
+
         content.Content = Current?.View ?? new UserControl();
     }
 
-
     public class NavigationStackItem {
         public string Name { get; set; }
         public string Description { get; set; } = "";
@@ -69,4 +70,4 @@ public partial class NavigationStack : UserControl {
         _stack.RemoveRange(index, _stack.Count - index);
         buildView();
     }
-}
+}
\ No newline at end of file
diff --git a/MatrixUtils.Web/Classes/RMUStorageWrapper.cs b/MatrixUtils.Web/Classes/RMUStorageWrapper.cs
index fa79268..45028ba 100644
--- a/MatrixUtils.Web/Classes/RMUStorageWrapper.cs
+++ b/MatrixUtils.Web/Classes/RMUStorageWrapper.cs
@@ -5,13 +5,15 @@ using Microsoft.AspNetCore.Components;
 
 namespace MatrixUtils.Web.Classes;
 
-public class RMUStorageWrapper(TieredStorageService storageService, HomeserverProviderService homeserverProviderService, NavigationManager navigationManager) {
+public class RMUStorageWrapper(ILogger<RMUStorageWrapper> logger, TieredStorageService storageService, HomeserverProviderService homeserverProviderService, NavigationManager navigationManager) {
     public async Task<List<UserAuth>?> GetAllTokens() {
+        logger.LogTrace("Getting all tokens.");
         return await storageService.DataStorageProvider.LoadObjectAsync<List<UserAuth>>("rmu.tokens") ??
                new List<UserAuth>();
     }
 
     public async Task<UserAuth?> GetCurrentToken() {
+        logger.LogTrace("Getting current token.");
         var currentToken = await storageService.DataStorageProvider.LoadObjectAsync<UserAuth>("rmu.token");
         var allTokens = await GetAllTokens();
         if (allTokens is null or { Count: 0 }) {
@@ -31,6 +33,7 @@ public class RMUStorageWrapper(TieredStorageService storageService, HomeserverPr
     }
 
     public async Task AddToken(UserAuth UserAuth) {
+        logger.LogTrace("Adding token.");
         var tokens = await GetAllTokens() ?? new List<UserAuth>();
 
         tokens.Add(UserAuth);
@@ -38,6 +41,7 @@ public class RMUStorageWrapper(TieredStorageService storageService, HomeserverPr
     }
 
     private async Task<AuthenticatedHomeserverGeneric?> GetCurrentSession() {
+        logger.LogTrace("Getting current session.");
         var token = await GetCurrentToken();
         if (token == null) {
             return null;
@@ -47,10 +51,12 @@ public class RMUStorageWrapper(TieredStorageService storageService, HomeserverPr
     }
 
     public async Task<AuthenticatedHomeserverGeneric?> GetSession(UserAuth userAuth) {
+        logger.LogTrace("Getting session.");
         return await homeserverProviderService.GetAuthenticatedWithToken(userAuth.Homeserver, userAuth.AccessToken, userAuth.Proxy);
     }
 
     public async Task<AuthenticatedHomeserverGeneric?> GetCurrentSessionOrNavigate() {
+        logger.LogTrace("Getting current session or navigating.");
         AuthenticatedHomeserverGeneric? session = null;
 
         try {
@@ -60,6 +66,7 @@ public class RMUStorageWrapper(TieredStorageService storageService, HomeserverPr
         catch (MatrixException e) {
             if (e.ErrorCode == "M_UNKNOWN_TOKEN") {
                 var token = await GetCurrentToken();
+                logger.LogWarning("Encountered invalid token for {user} on {homeserver}", token.UserId, token.Homeserver);
                 navigationManager.NavigateTo("/InvalidSession?ctx=" + token.AccessToken);
                 return null;
             }
@@ -68,6 +75,7 @@ public class RMUStorageWrapper(TieredStorageService storageService, HomeserverPr
         }
 
         if (session is null) {
+            logger.LogInformation("No session found. Navigating to login.");
             navigationManager.NavigateTo("/Login");
         }
 
@@ -85,6 +93,7 @@ public class RMUStorageWrapper(TieredStorageService storageService, HomeserverPr
     }
 
     public async Task RemoveToken(UserAuth auth) {
+        logger.LogTrace("Removing token.");
         var tokens = await GetAllTokens();
         if (tokens == null) {
             return;
@@ -94,9 +103,13 @@ public class RMUStorageWrapper(TieredStorageService storageService, HomeserverPr
         await storageService.DataStorageProvider.SaveObjectAsync("rmu.tokens", tokens);
     }
 
-    public async Task SetCurrentToken(UserAuth? auth) => await storageService.DataStorageProvider.SaveObjectAsync("rmu.token", auth);
+    public async Task SetCurrentToken(UserAuth? auth) {
+        logger.LogTrace("Setting current token.");
+        await storageService.DataStorageProvider.SaveObjectAsync("rmu.token", auth);
+    }
 
     public async Task MigrateFromMRU() {
+        logger.LogInformation("Migrating from MRU token namespace!");
         var dsp = storageService.DataStorageProvider!;
         if(await dsp.ObjectExistsAsync("token")) {
             var oldToken = await dsp.LoadObjectAsync<UserAuth>("token");
diff --git a/MatrixUtils.Web/MatrixUtils.Web.csproj b/MatrixUtils.Web/MatrixUtils.Web.csproj
index dfb4713..53c056a 100644
--- a/MatrixUtils.Web/MatrixUtils.Web.csproj
+++ b/MatrixUtils.Web/MatrixUtils.Web.csproj
@@ -20,6 +20,7 @@
         <PackageReference Include="Blazored.SessionStorage" Version="2.4.0" />
         <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.0" />
         <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.0" PrivateAssets="all" />
+        <PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="8.0.0" />
     </ItemGroup>
 
     <ItemGroup>
@@ -37,10 +38,13 @@
       <Content Update="appsettings.json">
         <CopyToOutputDirectory>Always</CopyToOutputDirectory>
       </Content>
+      <Content Update="wwwroot\appsettings.json">
+        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+      </Content>
     </ItemGroup>
 
     <ItemGroup>
         <ServiceWorker Include="wwwroot\service-worker.js" PublishedContent="wwwroot\service-worker.published.js" />
     </ItemGroup>
-
+    
 </Project>
diff --git a/MatrixUtils.Web/Pages/HSEInit.razor b/MatrixUtils.Web/Pages/HSEInit.razor
index b2fc0db..b76dfe6 100644
--- a/MatrixUtils.Web/Pages/HSEInit.razor
+++ b/MatrixUtils.Web/Pages/HSEInit.razor
@@ -3,7 +3,9 @@
 @inject IJSRuntime JsRuntime
 <h3>HSE Initialising...</h3>
 <hr/>
+
 @code {
+
     protected override async Task OnInitializedAsync() {
         await base.OnInitializedAsync();
         var tasks = Enumerable.Range(0, 50).Select(i => Login()).ToList();
@@ -16,7 +18,7 @@
 
     async Task<UserAuth?> Login() {
         try {
-            var result = new UserAuth(await hsProvider.Login("http://localhost:5298", "", ""));
+            var result = new UserAuth(await hsProvider.Login("http://localhost:5298", $"{Guid.NewGuid().ToString()}", ""));
             if (result == null) {
                 Console.WriteLine($"Failed to login!");
                 return null;
@@ -34,4 +36,5 @@
 
         return null;
     }
+
 }
\ No newline at end of file
diff --git a/MatrixUtils.Web/Pages/Index.razor b/MatrixUtils.Web/Pages/Index.razor
index 7c0a9f2..b3dc7d4 100644
--- a/MatrixUtils.Web/Pages/Index.razor
+++ b/MatrixUtils.Web/Pages/Index.razor
@@ -2,7 +2,6 @@
 @inject ILogger<Index> logger
 @using LibMatrix.Responses
 @using LibMatrix
-@using ArcaneLibs.Extensions
 @using ArcaneLibs
 @using System.Diagnostics
 
@@ -34,7 +33,7 @@ Small collection of tools to do not-so-everyday things.
                         <b>@session.UserInfo.DisplayName</b> on <b>@_auth.Homeserver</b><br/>
                     </p>
                     <span style="display: inline-block; width: 128px;">@session.UserInfo.RoomCount rooms</span>
-                    <a style="color: #888888" href="@("/ServerInfo/" + session.Homeserver.ServerName + "/")">@session.ServerVersion.Server.Name @session.ServerVersion.Server.Version</a>
+                    <a style="color: #888888" href="@("/ServerInfo/" + session.Homeserver?.ServerName + "/")">@session.ServerVersion?.Server.Name @session.ServerVersion?.Server.Version</a>
                     @if (_auth.Proxy != null) {
                         <span class="badge badge-info"> (proxied via @_auth.Proxy)</span>
                     }
@@ -132,7 +131,6 @@ Small collection of tools to do not-so-everyday things.
         public AuthenticatedHomeserverGeneric? Homeserver { get; set; }
     }
 
-    // private Dictionary<UserAuth, UserInfo> _users = new();
     private readonly List<AuthInfo> _sessions = [];
     private readonly List<UserAuth> _offlineSessions = [];
     private readonly List<UserAuth> _invalidSessions = [];
@@ -142,12 +140,14 @@ Small collection of tools to do not-so-everyday things.
 
     protected override async Task OnInitializedAsync() {
         Console.WriteLine("Index.OnInitializedAsync");
+        logger.LogDebug("Initialising index page");
         _currentSession = await RMUStorage.GetCurrentToken();
         _sessions.Clear();
         _offlineSessions.Clear();
         var tokens = await RMUStorage.GetAllTokens();
         scannedSessions = 0;
         totalSessions = tokens.Count;
+        logger.LogDebug("Found {0} tokens", totalSessions);
         if (tokens is not { Count: > 0 }) {
             Console.WriteLine("No tokens found, trying migration from MRU...");
             await RMUStorage.MigrateFromMRU();
@@ -166,7 +166,7 @@ Small collection of tools to do not-so-everyday things.
             if ((!string.IsNullOrWhiteSpace(token.Proxy) && offlineServers.Contains(token.Proxy)) || offlineServers.Contains(token.Homeserver)) {
                 _offlineSessions.Add(token);
                 sema.Release();
-            scannedSessions++;
+                scannedSessions++;
                 return;
             }
 
@@ -192,10 +192,17 @@ Small collection of tools to do not-so-everyday things.
                 }
             }
             catch (MatrixException e) {
-                if (e is { ErrorCode: "M_UNKNOWN_TOKEN" }) _invalidSessions.Add(token);
-                else throw;
+                if (e is { ErrorCode: "M_UNKNOWN_TOKEN" }) {
+                    logger.LogWarning("Got unknown token error for {0} via {1}", token.UserId, token.Homeserver);
+                    _invalidSessions.Add(token);
+                }
+                else {
+                    logger.LogError("Failed to get info for {0} via {1}: {2}", token.UserId, token.Homeserver, e);
+                    throw;
+                }
             }
-            catch {
+            catch (Exception e) {
+                logger.LogError("Failed to get info for {0} via {1}: {2}", token.UserId, token.Homeserver, e);
                 if (!string.IsNullOrWhiteSpace(token.Proxy)) {
                     offlineServers.Add(token.Proxy);
 
@@ -211,7 +218,7 @@ Small collection of tools to do not-so-everyday things.
         }).ToList();
         await Task.WhenAll(tasks);
         scannedSessions = totalSessions;
-        
+
         await base.OnInitializedAsync();
     }
 
@@ -239,7 +246,6 @@ Small collection of tools to do not-so-everyday things.
         await RMUStorage.RemoveToken(auth);
         if ((await RMUStorage.GetCurrentToken())?.AccessToken == auth.AccessToken)
             await RMUStorage.SetCurrentToken((await RMUStorage.GetAllTokens() ?? throw new InvalidOperationException()).FirstOrDefault());
-        // await OnInitializedAsync();
         StateHasChanged();
     }
 
@@ -247,7 +253,6 @@ Small collection of tools to do not-so-everyday things.
         Console.WriteLine($"Switching to {auth.Homeserver} {auth.UserId} via {auth.Proxy}");
         await RMUStorage.SetCurrentToken(auth);
         _currentSession = auth;
-        // await OnInitializedAsync();
         StateHasChanged();
     }
 
diff --git a/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor b/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor
index 4216824..7a3b27b 100644
--- a/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor
+++ b/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor
@@ -1,17 +1,34 @@
 @using MatrixUtils.Abstractions
-<div class="spaceListItem" onclick="@ToggleSpace">
+<div class="spaceListItem" style="@(SelectedSpace == Space ? "background-color: #FFFFFF33;" : "")" onclick="@SelectSpace">
+    @if (IsSpaceOpened()) {
+        <span onclick="@ToggleSpace">▼ </span>
+    }
+    else {
+        <span onclick="@ToggleSpace">▶ </span>
+    }
+
     <MxcImage Circular="true" Height="32" Width="32" Homeserver="Space.Room.Homeserver" MxcUri="@Space.RoomIcon"></MxcImage>
     <span class="spaceNameEllipsis">@Space.RoomName</span>
+
+    @if (IsSpaceOpened()) {
+        <span>meow</span>
+    }
 </div>
 
 @code {
 
     [Parameter]
     public RoomInfo Space { get; set; }
+    
+    [Parameter]
+    public RoomInfo SelectedSpace { get; set; }
+    
+    [Parameter]
+    public EventCallback<RoomInfo> SelectedSpaceChanged { get; set; }
 
     [Parameter]
     public List<RoomInfo> OpenedSpaces { get; set; }
-    
+
     protected override Task OnInitializedAsync() {
         Space.PropertyChanged += (sender, args) => { StateHasChanged(); };
         return base.OnInitializedAsync();
@@ -20,8 +37,20 @@
     public void ToggleSpace() {
         if (OpenedSpaces.Contains(Space)) {
             OpenedSpaces.Remove(Space);
-        } else {
+        }
+        else {
             OpenedSpaces.Add(Space);
         }
     }
-}
\ No newline at end of file
+
+    public void SelectSpace() {
+        SelectedSpace = Space;
+        SelectedSpaceChanged.InvokeAsync(Space);
+    }
+
+    public bool IsSpaceOpened() {
+        return OpenedSpaces.Contains(Space);
+    }
+
+}
+
diff --git a/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor.css b/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor.css
index c174567..a88975b 100644
--- a/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor.css
+++ b/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor.css
@@ -5,11 +5,15 @@
     text-overflow: ellipsis;
     white-space: nowrap;
     vertical-align: middle;
-    width: calc(100% - 38px);
+    width: calc(100% - 64px);
 }
 
 .spaceListItem {
     display: block;
     width: 100%;
     height: 50px;
+}
+
+.spaceListItem > img {
+    display: inline-block;
 }
\ No newline at end of file
diff --git a/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2MainTab.razor b/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2MainTab.razor
index 2b7c5ac..b163a52 100644
--- a/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2MainTab.razor
+++ b/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2MainTab.razor
@@ -31,11 +31,17 @@
         <div class="col-3" style="background-color: #ffffff22;">
             <LinkButton>Uncategorised rooms</LinkButton>
             @foreach (var space in GetTopLevelSpaces()) {
-                @RecursingSpaceChildren(space)
+                @* @RecursingSpaceChildren(space) *@
+                <MainTabSpaceItem Space="space" OpenedSpaces="OpenedSpaces" @bind-SelectedSpace="SelectedSpace" />
             }
         </div>
         <div class="col-9" style="background-color: #ff00ff66;">
             <p>Placeholder for rooms list...</p>
+            @if (SelectedSpace != null) {
+                foreach (var room in GetSpaceChildRooms(SelectedSpace)) {
+                    <p>@room.RoomName</p>
+                }
+            }
         </div>
     </div>
 </div>
@@ -116,48 +122,54 @@
         var childSpaces = children.Where(x => x.RoomType == "m.space").ToList();
         return childSpaces;
     }
+    
+    private List<RoomInfo> GetSpaceChildRooms(RoomInfo space) {
+        var children = GetSpaceChildren(space);
+        var childRooms = children.Where(x => x.RoomType != "m.space").ToList();
+        return childRooms;
+    }
 
     private RoomInfo? SelectedSpace { get; set; }
     private List<RoomInfo> OpenedSpaces { get; set; } = new List<RoomInfo>();
 
-    private RenderFragment RecursingSpaceChildren(RoomInfo space, List<RoomInfo>? parents = null, int depth = 0) {
-        parents ??= [];
-        var totalSw = Stopwatch.StartNew();
-        var children = GetSpaceChildSpaces(space);
-
-        var randomColor = RandomNumberGenerator.GetBytes(3).Append((byte)0x33).ToArray().AsHexString().Replace(" ", "");
-        var isExpanded = OpenedSpaces.Contains(space);
-
-        // Console.WriteLine($"RecursingSpaceChildren::FetchData - Depth: {depth}, Space: {space.RoomName}, Children: {children.Count} - {totalSw.Elapsed}");
-
-        // var renderSw = Stopwatch.StartNew();
-        var rf = new RenderFragment(builder => {
-            builder.OpenElement(0, "div");
-            //space list entry render fragment
-            // builder.AddContent(1, SpaceListEntry(space));
-            builder.OpenComponent<MainTabSpaceItem>(1);
-            builder.AddAttribute(2, "Space", space);
-            builder.AddAttribute(2, "OpenedSpaces", OpenedSpaces);
-            builder.CloseComponent();
-            builder.CloseElement();
-            //space children render fragment
-            if (isExpanded) {
-                builder.OpenElement(2, "div");
-                builder.AddAttribute(3, "style", "padding-left: 10px;");
-                foreach (var child in children) {
-                    builder.AddContent(4, RecursingSpaceChildren(child, parents.Append(space).ToList(), depth + 1));
-                }
-
-                builder.CloseElement();
-            }
-        });
-
-        // Console.WriteLine($"RecursingSpaceChildren::Render - Depth: {depth}, Space: {space.RoomName}, Children: {children.Count} - {renderSw.Elapsed}");
-        if (totalSw.ElapsedMilliseconds > 20)
-            Console.WriteLine($"RecursingSpaceChildren::Total - Depth: {depth}, Space: {space.RoomName}, Children: {children.Count} - {totalSw.Elapsed}");
-        // Console.WriteLine($"RecursingSpaceChildren::Total - Depth: {depth}, Space: {space.RoomName}, Children: {children.Count} - {totalSw.Elapsed}");
-        return rf;
-    }
+    // private RenderFragment RecursingSpaceChildren(RoomInfo space, List<RoomInfo>? parents = null, int depth = 0) {
+    //     parents ??= [];
+    //     var totalSw = Stopwatch.StartNew();
+    //     var children = GetSpaceChildSpaces(space);
+    //
+    //     var randomColor = RandomNumberGenerator.GetBytes(3).Append((byte)0x33).ToArray().AsHexString().Replace(" ", "");
+    //     var isExpanded = OpenedSpaces.Contains(space);
+    //
+    //     // Console.WriteLine($"RecursingSpaceChildren::FetchData - Depth: {depth}, Space: {space.RoomName}, Children: {children.Count} - {totalSw.Elapsed}");
+    //
+    //     // var renderSw = Stopwatch.StartNew();
+    //     var rf = new RenderFragment(builder => {
+    //         builder.OpenElement(0, "div");
+    //         //space list entry render fragment
+    //         // builder.AddContent(1, SpaceListEntry(space));
+    //         builder.OpenComponent<MainTabSpaceItem>(1);
+    //         builder.AddAttribute(2, "Space", space);
+    //         builder.AddAttribute(2, "OpenedSpaces", OpenedSpaces);
+    //         builder.CloseComponent();
+    //         builder.CloseElement();
+    //         //space children render fragment
+    //         if (isExpanded) {
+    //             builder.OpenElement(2, "div");
+    //             builder.AddAttribute(3, "style", "padding-left: 10px;");
+    //             foreach (var child in children) {
+    //                 builder.AddContent(4, RecursingSpaceChildren(child, parents.Append(space).ToList(), depth + 1));
+    //             }
+    //
+    //             builder.CloseElement();
+    //         }
+    //     });
+    //
+    //     // Console.WriteLine($"RecursingSpaceChildren::Render - Depth: {depth}, Space: {space.RoomName}, Children: {children.Count} - {renderSw.Elapsed}");
+    //     if (totalSw.ElapsedMilliseconds > 20)
+    //         Console.WriteLine($"RecursingSpaceChildren::Total - Depth: {depth}, Space: {space.RoomName}, Children: {children.Count} - {totalSw.Elapsed}");
+    //     // Console.WriteLine($"RecursingSpaceChildren::Total - Depth: {depth}, Space: {space.RoomName}, Children: {children.Count} - {totalSw.Elapsed}");
+    //     return rf;
+    // }
 
     // private RenderFragment SpaceListEntry(RoomInfo space) {
     //     return builder => {
diff --git a/MatrixUtils.Web/Pages/Tools/MediaLocator.razor b/MatrixUtils.Web/Pages/Tools/MediaLocator.razor
index 0818d6d..6e87926 100644
--- a/MatrixUtils.Web/Pages/Tools/MediaLocator.razor
+++ b/MatrixUtils.Web/Pages/Tools/MediaLocator.razor
@@ -88,7 +88,6 @@
         homeservers.Clear();
         var lines = content.Split("\n");
 
-        var rhs = new RemoteHomeserver("rory.gay");
         var sem = new SemaphoreSlim(128, 128);
         lines.ToList().ForEach(async line => {
             await sem.WaitAsync();
diff --git a/MatrixUtils.Web/Program.cs b/MatrixUtils.Web/Program.cs
index e63d191..1b8960c 100644
--- a/MatrixUtils.Web/Program.cs
+++ b/MatrixUtils.Web/Program.cs
@@ -1,3 +1,4 @@
+using System.Net;
 using System.Text.Json;
 using System.Text.Json.Serialization;
 using Blazored.LocalStorage;
@@ -22,10 +23,19 @@ try {
     builder.Configuration.AddJsonStream(await new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }.GetStreamAsync("/appsettings.Development.json"));
 #endif
 }
+catch (HttpRequestException e) {
+    if (e.StatusCode == HttpStatusCode.NotFound)
+        Console.WriteLine("Could not load appsettings, server returned 404.");
+    else
+        Console.WriteLine("Could not load appsettings: " + e);
+}
 catch (Exception e) {
     Console.WriteLine("Could not load appsettings: " + e);
 }
 
+builder.Logging.AddConfiguration(
+    builder.Configuration.GetSection("Logging"));
+
 builder.Services.AddBlazoredLocalStorage(config => {
     config.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
     config.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
@@ -35,6 +45,7 @@ builder.Services.AddBlazoredLocalStorage(config => {
     config.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip;
     config.JsonSerializerOptions.WriteIndented = false;
 });
+
 builder.Services.AddBlazoredSessionStorage(config => {
     config.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
     config.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
@@ -54,4 +65,4 @@ builder.Services.AddScoped<TieredStorageService>(x =>
 
 builder.Services.AddRoryLibMatrixServices();
 builder.Services.AddScoped<RMUStorageWrapper>();
-await builder.Build().RunAsync();
+await builder.Build().RunAsync();
\ No newline at end of file
diff --git a/MatrixUtils.Web/appsettings.Development.json b/MatrixUtils.Web/appsettings.Development.json
index e203e94..1ca99ed 100644
--- a/MatrixUtils.Web/appsettings.Development.json
+++ b/MatrixUtils.Web/appsettings.Development.json
@@ -1,7 +1,7 @@
 {
   "Logging": {
     "LogLevel": {
-      "Default": "Debug",
+      "Default": "Trace",
       "System": "Information",
       "Microsoft": "Information"
     }
diff --git a/MatrixUtils.Web/appsettings.json b/MatrixUtils.Web/appsettings.json
index e203e94..29d3614 100644
--- a/MatrixUtils.Web/appsettings.json
+++ b/MatrixUtils.Web/appsettings.json
@@ -1,7 +1,7 @@
 {
   "Logging": {
     "LogLevel": {
-      "Default": "Debug",
+      "Default": "Trace", //debug
       "System": "Information",
       "Microsoft": "Information"
     }
diff --git a/MatrixUtils.Web/wwwroot/appsettings.json b/MatrixUtils.Web/wwwroot/appsettings.json
new file mode 100644
index 0000000..1ca99ed
--- /dev/null
+++ b/MatrixUtils.Web/wwwroot/appsettings.json
@@ -0,0 +1,9 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Trace",
+      "System": "Information",
+      "Microsoft": "Information"
+    }
+  }
+}
diff --git a/MxApiExtensions b/MxApiExtensions
-Subproject 2d21596eec41cf1669f8064278b3273dc4f4c36
+Subproject c673f705cd62346f5995415414e309bb56b18c6