diff --git a/MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs b/MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs
index a439ea1..c224160 100644
--- a/MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs
+++ b/MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs
@@ -1,6 +1,5 @@
using Blazored.LocalStorage;
using MatrixRoomUtils.Core;
-using MatrixRoomUtils.Core.Extensions;
namespace MatrixRoomUtils.Web.Classes;
@@ -27,7 +26,7 @@ public partial class LocalStorageWrapper
{
Console.WriteLine($"Access token is not null, creating authenticated home server");
Console.WriteLine($"Homeserver cache: {RuntimeCache.HomeserverResolutionCache.Count} entries");
- Console.WriteLine(RuntimeCache.HomeserverResolutionCache.ToJson());
+ // Console.WriteLine(RuntimeCache.HomeserverResolutionCache.ToJson());
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");
}
@@ -47,6 +46,17 @@ public partial class LocalStorageWrapper
.ToDictionary(x => x.Key, x => x.Value));
await localStorage.SetItemAsync("rory.matrixroomutils.generic_cache", RuntimeCache.GenericResponseCache);
}
+ public static async Task SaveFieldToLocalStorage(ILocalStorageService localStorage, string key)
+ {
+ if (key == "rory.matrixroomutils.settings") await localStorage.SetItemAsync(key, Settings);
+ // if (key == "rory.matrixroomutils.token") await localStorage.SetItemAsStringAsync(key, RuntimeCache.AccessToken);
+ // if (key == "rory.matrixroomutils.current_homeserver") await localStorage.SetItemAsync(key, RuntimeCache.CurrentHomeserver);
+ if (key == "rory.matrixroomutils.user_cache") await localStorage.SetItemAsync(key, RuntimeCache.LoginSessions);
+ if (key == "rory.matrixroomutils.last_used_token") await localStorage.SetItemAsync(key, RuntimeCache.LastUsedToken);
+ if (key == "rory.matrixroomutils.homeserver_resolution_cache") await localStorage.SetItemAsync(key, RuntimeCache.HomeserverResolutionCache);
+ if (key == "rory.matrixroomutils.generic_cache") await localStorage.SetItemAsync(key, RuntimeCache.GenericResponseCache);
+
+ }
}
@@ -59,4 +69,6 @@ public class Settings
public class DeveloperSettings
{
public bool EnableLogViewers { get; set; } = false;
+ public bool EnableConsoleLogging { get; set; } = true;
+ public bool EnablePortableDevtools { get; set; } = false;
}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj b/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj
index f167eaa..77a039c 100644
--- a/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj
+++ b/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj
@@ -20,4 +20,8 @@
<_ContentIncludedByDefault Remove="wwwroot\sample-data\weather.json" />
</ItemGroup>
+ <ItemGroup>
+ <None Include="wwwroot\homeservers.txt" />
+ </ItemGroup>
+
</Project>
diff --git a/MatrixRoomUtils.Web/Pages/About.razor b/MatrixRoomUtils.Web/Pages/About.razor
index fc9128e..d47e60b 100644
--- a/MatrixRoomUtils.Web/Pages/About.razor
+++ b/MatrixRoomUtils.Web/Pages/About.razor
@@ -1,5 +1,4 @@
@page "/About"
-@using MatrixRoomUtils.Web.Shared.IndexComponents
@using System.Net
@inject NavigationManager NavigationManager
@inject ILocalStorageService LocalStorage
diff --git a/MatrixRoomUtils.Web/Pages/DevOptions.razor b/MatrixRoomUtils.Web/Pages/DevOptions.razor
index 0cc38d8..e1b6ac0 100644
--- a/MatrixRoomUtils.Web/Pages/DevOptions.razor
+++ b/MatrixRoomUtils.Web/Pages/DevOptions.razor
@@ -1,6 +1,4 @@
@page "/DevOptions"
-@using MatrixRoomUtils.Web.Shared.IndexComponents
-@using System.Net
@using MatrixRoomUtils.Core.Extensions
@inject NavigationManager NavigationManager
@inject ILocalStorageService LocalStorage
@@ -10,8 +8,32 @@
<h3>Rory&::MatrixUtils - Developer options</h3>
<hr/>
-<InputCheckbox @bind-Value="@LocalStorageWrapper.Settings.DeveloperSettings.EnableLogViewers" @oninput="@LogStuff"></InputCheckbox><label> Enable log views</label>
+<InputCheckbox @bind-Value="@LocalStorageWrapper.Settings.DeveloperSettings.EnableLogViewers" @oninput="@LogStuff"></InputCheckbox><label> Enable log views</label><br/>
+<InputCheckbox @bind-Value="@LocalStorageWrapper.Settings.DeveloperSettings.EnableConsoleLogging" @oninput="@LogStuff"></InputCheckbox><label> Enable console logging</label><br/>
+<InputCheckbox @bind-Value="@LocalStorageWrapper.Settings.DeveloperSettings.EnablePortableDevtools" @oninput="@LogStuff"></InputCheckbox><label> Enable portable devtools</label><br/>
+<button @onclick="@DropCaches">Drop caches</button>
+<button @onclick="@RandomiseCacheTimers">Randomise cache timers</button>
+<br/>
+<details open>
+ <summary>View caches</summary>
+ <p>Generic cache:</p>
+ <ul>
+ @foreach (var item in RuntimeCache.GenericResponseCache)
+ {
+ <li>
+ @item.Key: @item.Value.Cache.Count entries<br/>
+ Default expiry: @item.Value.DefaultExpiry<br/>
+ @if (item.Value.Cache.Count > 0)
+ {
+ <p>Earliest expiry: @(item.Value.Cache.Min(x => x.Value.ExpiryTime)) (@string.Format("{0:g}", item.Value.Cache.Min(x => x.Value.ExpiryTime).Value.Subtract(DateTime.Now)) from now)</p>
+ @* <p>Average expiry: @(item.Value.Cache.Average(x => x.Value.ExpiryTime.Value))(@item.Value.Cache.Average(x => x.Value.ExpiryTime).Value.Subtract(DateTime.Now) from now)</p> *@
+ <p>Last expiry: @(item.Value.Cache.Max(x => x.Value.ExpiryTime)) (@string.Format("{0:g}", item.Value.Cache.Max(x => x.Value.ExpiryTime).Value.Subtract(DateTime.Now)) from now)</p>
+ }
+ </li>
+ }
+ </ul>
+</details>
@code {
protected override async Task OnInitializedAsync()
@@ -19,6 +41,14 @@
await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage);
await base.OnInitializedAsync();
await LocalStorageWrapper.SaveToLocalStorage(LocalStorage);
+ Task.Run(async () =>
+ {
+ while (true)
+ {
+ await Task.Delay(100);
+ StateHasChanged();
+ }
+ });
}
protected async Task LogStuff()
@@ -29,4 +59,25 @@
await LocalStorageWrapper.SaveToLocalStorage(LocalStorage);
}
+ protected async Task DropCaches()
+ {
+ RuntimeCache.GenericResponseCache.Clear();
+ RuntimeCache.HomeserverResolutionCache.Clear();
+ await LocalStorageWrapper.SaveToLocalStorage(LocalStorage);
+ }
+
+ protected async Task RandomiseCacheTimers()
+ {
+ foreach (var keyValuePair in RuntimeCache.GenericResponseCache)
+ {
+ Console.WriteLine($"Randomising cache timer for {keyValuePair.Key}");
+ foreach (var cacheItem in keyValuePair.Value.Cache)
+ {
+ cacheItem.Value.ExpiryTime = DateTime.Now.AddSeconds(Random.Shared.Next(15, 120));
+ }
+
+ await LocalStorageWrapper.SaveToLocalStorage(LocalStorage);
+ }
+ }
+
}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/HSAdmin/HSAdmin.razor b/MatrixRoomUtils.Web/Pages/HSAdmin/HSAdmin.razor
new file mode 100644
index 0000000..b77012b
--- /dev/null
+++ b/MatrixRoomUtils.Web/Pages/HSAdmin/HSAdmin.razor
@@ -0,0 +1,7 @@
+@page "/HSAdmin"
+<h3>Homeserver Admininistration</h3>
+<hr/>
+
+@code {
+
+}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor b/MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor
new file mode 100644
index 0000000..f396025
--- /dev/null
+++ b/MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor
@@ -0,0 +1,79 @@
+@page "/KnownHomeserverList"
+@using System.Text.Json
+@using MatrixRoomUtils.Core.Extensions
+<h3>Known Homeserver List</h3>
+<hr/>
+
+@if (!IsFinished)
+{
+ <p>Loading... Please wait...</p>
+}
+else
+{
+ @foreach (var server in HomeServers.OrderByDescending(x => x.KnownUserCount).ThenBy(x => x.Server).ToList())
+ {
+ <p>@server.Server - @server.KnownUserCount</p>
+ }
+}
+<hr/>
+
+@code {
+ List<HomeServerInfo> HomeServers = new();
+ bool IsFinished { get; set; }
+
+ protected override async Task OnInitializedAsync()
+ {
+ await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage);
+
+ HomeServers = await GetHomeservers();
+
+ IsFinished = true;
+ StateHasChanged();
+ Console.WriteLine("Rerendered!");
+ await base.OnInitializedAsync();
+ }
+
+
+ private async Task<List<HomeServerInfo>> GetHomeservers()
+ {
+ List<HomeServerInfo> homeServers = new();
+ var rooms = await RuntimeCache.CurrentHomeServer.GetJoinedRooms();
+ // Dictionary<string, StateEvent> roomMembers = new();
+ //start a task for each room
+ var tasks = rooms.Select(async room =>
+ {
+ Console.WriteLine($"Fetching states for room ({rooms.IndexOf(room)}/{rooms.Count}) ({room.RoomId})");
+ StateHasChanged();
+
+ var states = (await room.GetStateAsync("")).Value.Deserialize<List<StateEvent>>();
+ states.RemoveAll(x => x.type != "m.room.member");
+ Console.WriteLine($"Room {room.RoomId} has {states.Count} members");
+ foreach (var state in states)
+ {
+ if (!homeServers.Any(x => x.Server == state.state_key.Split(':')[1]))
+ {
+ homeServers.Add(new HomeServerInfo() { Server = state.state_key.Split(':')[1] });
+ }
+ var hs = homeServers.First(x => x.Server == state.state_key.Split(':')[1]);
+ if(!hs.KnownUsers.Contains(state.state_key.Split(':')[0]))
+ hs.KnownUsers.Add(state.state_key.Split(':')[0]);
+ }
+ Console.WriteLine("Collected states!");
+ });
+ await Task.WhenAll(tasks);
+
+ Console.WriteLine("Calculating member counts...");
+ homeServers.ForEach(x => x.KnownUserCount = x.KnownUsers.Count);
+ Console.WriteLine(homeServers.First(x=>x.Server=="rory.gay").ToJson());
+ Console.WriteLine("Recalculated!");
+ return homeServers;
+ }
+
+ class HomeServerInfo
+ {
+ public string Server { get; set; }
+ public int? KnownUserCount { get; set; }
+ public List<string> KnownUsers { get; set; } = new();
+ }
+
+}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/MediaLocator.razor b/MatrixRoomUtils.Web/Pages/MediaLocator.razor
index cd244ef..06256f0 100644
--- a/MatrixRoomUtils.Web/Pages/MediaLocator.razor
+++ b/MatrixRoomUtils.Web/Pages/MediaLocator.razor
@@ -1,11 +1,46 @@
@page "/MediaLocator"
-<h3>MediaLocator</h3>
+@inject HttpClient Http
+<h3>Media locator</h3>
<hr/>
+<b>This is going to expose your IP address to all these homeservers!</b>
+<details>
+ <summary>Checked homeserver list (@homeservers.Count entries)</summary>
+ <ul>
+ @foreach (var hs in homeservers)
+ {
+ <li>@hs</li>
+ }
+ </ul>
+</details>
+<button @onclick="addMoreHomeservers">Add more homeservers</button>
+<br/>
<span>MXC URL: </span>
<input type="text" @bind="mxcUrl" />
<button @onclick="executeSearch">Search</button>
+@if (successResults.Count > 0)
+{
+ <h4>Successes</h4>
+ <ul>
+ @foreach (var result in successResults)
+ {
+ <li>@result</li>
+ }
+ </ul>
+}
+
+@if (errorResults.Count > 0)
+{
+ <h4>Errors</h4>
+ <ul>
+ @foreach (var result in errorResults)
+ {
+ <li>@result</li>
+ }
+ </ul>
+}
+
@code {
string mxcUrl { get; set; }
@@ -15,22 +50,82 @@
protected override async Task OnInitializedAsync()
{
- base.OnInitializedAsync();
-
+ await base.OnInitializedAsync();
+ homeservers.AddRange(new []
+ {
+ "matrix.org",
+ "feline.support",
+ "rory.gay",
+ "the-apothecary.club",
+ "envs.net",
+ "projectsegfau.lt"
+ });
}
async Task executeSearch()
{
- var client = new HttpClient();
- var response = await client.GetAsync($"https://matrix.org/_matrix/media/r0/identicon/{mxcUrl}");
- if (response.IsSuccessStatusCode)
+ var sem = new SemaphoreSlim(128, 128);
+ homeservers.ForEach(async hs =>
{
- successResults.Add(mxcUrl);
- }
- else
- {
- errorResults.Add(mxcUrl);
- }
+ await sem.WaitAsync();
+ var httpClient = new HttpClient { BaseAddress = new Uri(hs) };
+ httpClient.Timeout = TimeSpan.FromSeconds(5);
+ var rmu = mxcUrl.Replace("mxc://", $"{hs}/_matrix/media/r0/download/");
+ try
+ {
+ var res = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, rmu));
+ if (res.IsSuccessStatusCode)
+ {
+ successResults.Add($"{hs}: found - {res.Content.Headers.ContentLength} bytes");
+ StateHasChanged();
+ return;
+ }
+ errorResults.Add($"Error: {hs} - {res.StatusCode}\n" + await res.Content.ReadAsStringAsync());
+ }
+ catch (Exception e)
+ {
+ errorResults.Add($"Error: {e}");
+ }
+ finally
+ {
+ sem.Release();
+ }
+ StateHasChanged();
+ });
}
+
+ async Task addMoreHomeservers()
+ {
+ await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage);
+ var res = await Http.GetAsync("/homeservers.txt");
+ var content = await res.Content.ReadAsStringAsync();
+ 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();
+ try
+ {
+ homeservers.Add(await rhs.ResolveHomeserverFromWellKnown(line));
+ StateHasChanged();
+ if(Random.Shared.Next(0,101) == 50)
+ await LocalStorageWrapper.SaveToLocalStorage(LocalStorage);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
+ finally
+ {
+ sem.Release();
+ }
+ });
+
+
+ StateHasChanged();
+ }
}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor
index 5dfb2d6..d0f9b87 100644
--- a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor
+++ b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor
@@ -41,7 +41,8 @@ else
@policyEvent.content.ExpiryDateTime
</td>
<td>
- <button class="btn btn-danger" @* @onclick="async () => await RemovePolicyAsync(policyEvent)" *@>Remove</button>
+ <button class="btn" @* @onclick="async () => await RemovePolicyAsync(policyEvent)" *@>Edit</button>
+ @* <button class="btn btn-danger" $1$ @onclick="async () => await RemovePolicyAsync(policyEvent)" #1#>Remove</button> *@
</td>
</tr>
}
diff --git a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor
index e9d1be4..f25fbae 100644
--- a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor
+++ b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor
@@ -19,8 +19,13 @@ else
}
foreach (var s in PolicyRoomList)
{
- <a href="@(NavigationManager.Uri + "/" + s.RoomId.Replace('.', '~'))">[@s.Shortcode] @s.Name (@s.RoomId)</a>
- <br/>
+
+ <a style="color: unset; text-decoration: unset;" href="/PolicyListEditor/@s.RoomId.Replace('.','~')"><RoomListItem RoomId="@s.RoomId">
+ <br/>
+ <span>Shortcode: @s.Shortcode</span>
+ </RoomListItem></a>
+ @* <a href="@(NavigationManager.Uri + "/" + s.RoomId.Replace('.', '~'))">[@s.Shortcode] @s.Name (@s.RoomId)</a> *@
+ @* <br/> *@
}
}
@@ -74,15 +79,11 @@ else
{
try
{
- //TODO: refactor!!!!!
await semaphore.WaitAsync();
PolicyRoomInfo roomInfo = new()
{
RoomId = room
};
-
-
- // --- //
var r = await RuntimeCache.CurrentHomeServer.GetRoom(room);
var shortcodeState = await r.GetStateAsync("org.matrix.mjolnir.shortcode");
if(!shortcodeState.HasValue) return null;
diff --git a/MatrixRoomUtils.Web/Pages/RoomManager.razor b/MatrixRoomUtils.Web/Pages/RoomManager.razor
deleted file mode 100644
index deb6fd5..0000000
--- a/MatrixRoomUtils.Web/Pages/RoomManager.razor
+++ /dev/null
@@ -1,40 +0,0 @@
-@page "/RoomManager"
-@inject ILocalStorageService LocalStorage
-@inject NavigationManager NavigationManager
-<h3>Room manager</h3>
-<hr/>
-@if (Rooms.Count == 0)
-{
- <p>You are not in any rooms!</p>
- @* <p>Loading progress: @checkedRoomCount/@totalRoomCount</p> *@
-}
-else
-{
- <details open>
- <summary>Room List</summary>
- @foreach (var room in Rooms)
- {
- <a style="color: unset; text-decoration: unset;" href="/RoomStateViewer/@room.Replace('.', '~')"><RoomListItem RoomId="@room" ShowOwnProfile="true"></RoomListItem></a>
- }
- </details>
-
-}
-
-<div style="margin-bottom: 4em;"></div>
-<LogView></LogView>
-
-@code {
- public List<string> Rooms { get; set; } = new();
- protected override async Task OnInitializedAsync()
- {
- if (!RuntimeCache.WasLoaded) await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage);
- await base.OnInitializedAsync();
- if (RuntimeCache.CurrentHomeServer == null)
- {
- NavigationManager.NavigateTo("/Login");
- return;
- }
- Rooms = (await RuntimeCache.CurrentHomeServer.GetJoinedRooms()).Select(x=>x.RoomId).ToList();
- Console.WriteLine("Fetched joined rooms!");
- }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManager.razor b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManager.razor
new file mode 100644
index 0000000..6d27679
--- /dev/null
+++ b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManager.razor
@@ -0,0 +1,96 @@
+@page "/RoomManager"
+@inject ILocalStorageService LocalStorage
+@inject NavigationManager NavigationManager
+<h3>Room manager</h3>
+<hr/>
+@if (Rooms.Count == 0)
+{
+ <p>You are not in any rooms!</p>
+ @* <p>Loading progress: @checkedRoomCount/@totalRoomCount</p> *@
+}
+else
+{
+ <p>You are in @Rooms.Count rooms and @Spaces.Count spaces</p>
+ <details open>
+ <summary>Space List</summary>
+ @foreach (var room in Spaces)
+ {
+ <a style="color: unset; text-decoration: unset;" href="/RoomManager/Space/@room.RoomId.Replace('.', '~')"><RoomListItem Room="@room" ShowOwnProfile="true"></RoomListItem></a>
+ }
+ </details>
+ <details open>
+ <summary>Room List</summary>
+ @foreach (var room in Rooms)
+ {
+ <a style="color: unset; text-decoration: unset;" href="/RoomManager/Room/@room.RoomId.Replace('.', '~')"><RoomListItem Room="@room" ShowOwnProfile="true"></RoomListItem></a>
+ }
+ </details>
+
+}
+
+<div style="margin-bottom: 4em;"></div>
+<LogView></LogView>
+
+@code {
+ public List<Room> Rooms { get; set; } = new();
+ public List<Room> Spaces { get; set; } = new();
+ protected override async Task OnInitializedAsync()
+ {
+ if (!RuntimeCache.WasLoaded) await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage);
+ await base.OnInitializedAsync();
+ if (RuntimeCache.CurrentHomeServer == null)
+ {
+ NavigationManager.NavigateTo("/Login");
+ return;
+ }
+ Rooms = await RuntimeCache.CurrentHomeServer.GetJoinedRooms();
+ StateHasChanged();
+ var semaphore = new SemaphoreSlim(1000);
+ var tasks = new List<Task<Room?>>();
+ foreach (var room in Rooms)
+ {
+ tasks.Add(CheckIfSpace(room, semaphore));
+ }
+ await Task.WhenAll(tasks);
+
+ Console.WriteLine("Fetched joined rooms!");
+ }
+
+ private async Task<Room?> CheckIfSpace(Room room, SemaphoreSlim semaphore)
+ {
+ await semaphore.WaitAsync();
+ try
+ {
+ var state = await room.GetStateAsync("m.room.create");
+ if (state != null)
+ {
+ //Console.WriteLine(state.Value.ToJson());
+ if(state.Value.TryGetProperty("type", out var type))
+ {
+ if(type.ToString() == "m.space")
+ {
+ Spaces.Add(room);
+ Rooms.Remove(room);
+ StateHasChanged();
+ return room;
+ }
+ }
+ else
+ {
+ //this is fine, apprently...
+ //Console.WriteLine($"Room {room.RoomId} has no content.type in m.room.create!");
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ return null;
+ }
+ finally
+ {
+ semaphore.Release();
+ }
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerSpace.razor b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerSpace.razor
new file mode 100644
index 0000000..4a5bddf
--- /dev/null
+++ b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerSpace.razor
@@ -0,0 +1,77 @@
+@page "/RoomManager/Space/{RoomId}"
+@using MatrixRoomUtils.Core.Extensions
+@using System.Text.Json
+<h3>Room manager - Viewing Space</h3>
+
+<button onclick="@JoinAllRooms">Join all rooms</button>
+@foreach (var room in Rooms)
+{
+ <RoomListItem Room="room" ShowOwnProfile="true"></RoomListItem>
+}
+
+
+<br/>
+<details style="background: #0002;">
+ <summary style="background: #fff1;">State list</summary>
+ @foreach (var stateEvent in States.OrderBy(x => x.state_key).ThenBy(x => x.type))
+ {
+ <p>@stateEvent.state_key/@stateEvent.type:</p>
+ <pre>@stateEvent.content.ToJson()</pre>
+ }
+</details>
+
+@code {
+
+ [Parameter]
+ public string RoomId { get; set; } = "invalid!!!!!!";
+
+ private Room? Room { get; set; }
+
+ private StateEvent<object>[] States { get; set; } = Array.Empty<StateEvent<object>>();
+ private List<Room> Rooms { get; set; } = new();
+
+ protected override async Task OnInitializedAsync()
+ {
+ await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage);
+ Room = await RuntimeCache.CurrentHomeServer.GetRoom(RoomId.Replace('~', '.'));
+ var state = await Room.GetStateAsync("");
+ if (state != null)
+ {
+ Console.WriteLine(state.Value.ToJson());
+ States = state.Value.Deserialize<StateEvent<object>[]>()!;
+
+ foreach (var stateEvent in States)
+ {
+ if (stateEvent.type == "m.space.child")
+ {
+ // if (stateEvent.content.ToJson().Length < 5) return;
+ var roomId = stateEvent.state_key;
+ var room = await RuntimeCache.CurrentHomeServer.GetRoom(roomId);
+ if (room != null)
+ {
+ Rooms.Add(room);
+ }
+ }
+ }
+
+ // if(state.Value.TryGetProperty("type", out var type))
+ // {
+ // }
+ // else
+ // {
+ // //this is fine, apprently...
+ // //Console.WriteLine($"Room {room.RoomId} has no content.type in m.room.create!");
+ // }
+ }
+ await base.OnInitializedAsync();
+ }
+
+ private async Task JoinAllRooms()
+ {
+ foreach (var room in Rooms)
+ {
+ room.JoinAsync();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Properties/launchSettings.json b/MatrixRoomUtils.Web/Properties/launchSettings.json
index d5a26f5..aa41dc8 100644
--- a/MatrixRoomUtils.Web/Properties/launchSettings.json
+++ b/MatrixRoomUtils.Web/Properties/launchSettings.json
@@ -11,7 +11,7 @@
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
- "launchBrowser": true,
+ "launchBrowser": false,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"applicationUrl": "http://localhost:5117",
"environmentVariables": {
@@ -21,7 +21,7 @@
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
- "launchBrowser": true,
+ "launchBrowser": false,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"applicationUrl": "https://localhost:7014;http://localhost:5117",
"environmentVariables": {
diff --git a/MatrixRoomUtils.Web/Shared/IndexComponents/IndexUserItem.razor b/MatrixRoomUtils.Web/Shared/IndexComponents/IndexUserItem.razor
index 08161b2..87ef831 100644
--- a/MatrixRoomUtils.Web/Shared/IndexComponents/IndexUserItem.razor
+++ b/MatrixRoomUtils.Web/Shared/IndexComponents/IndexUserItem.razor
@@ -10,22 +10,30 @@
<div style="margin-bottom: 1em;">
<img style="border-radius: 50%; height: 3em; width: 3em;" src="@_avatarUrl"/>
- <span style="margin-left: 1em;"><input type="radio" name="csa" checked="@(RuntimeCache.LastUsedToken == User.AccessToken)" onclick="@SetCurrent" style="text-decoration-line: unset;"/> <b>@User.Profile.DisplayName</b> on <b>@User.LoginResponse.HomeServer</b></span>
- <a href="#" onclick="@RemoveUser">Remove</a>
+ <p style="margin-left: 1em; margin-top: -0.5em; display: inline-block;">
+ <input type="radio" name="csa" checked="@(RuntimeCache.LastUsedToken == User.AccessToken)" onclick="@SetCurrent" style="text-decoration-line: unset;"/>
+ <b>@User.Profile.DisplayName</b> on <b>@User.LoginResponse.HomeServer</b>
+ <a href="#" onclick="@RemoveUser">Remove</a>
+ </p>
+ <p style="margin-top: -1.5em; margin-left: 4em;">Member of @_roomCount rooms</p>
+
</div>
@code {
[Parameter]
public UserInfo User { get; set; } = null!;
-
+
private string _avatarUrl { get; set; }
+ private int _roomCount { get; set; } = 0;
protected override async Task OnInitializedAsync()
{
+ var hs = await new AuthenticatedHomeServer(User.LoginResponse.UserId, User.AccessToken, User.LoginResponse.HomeServer).Configure();
if (User.Profile.AvatarUrl != null && User.Profile.AvatarUrl != "")
- _avatarUrl = await (await new AuthenticatedHomeServer(User.LoginResponse.UserId, User.AccessToken, User.LoginResponse.HomeServer).Configure()).ResolveMediaUri(User.Profile.AvatarUrl);
+ _avatarUrl = await hs.ResolveMediaUri(User.Profile.AvatarUrl);
else _avatarUrl = "https://api.dicebear.com/6.x/identicon/svg?seed=" + User.LoginResponse.UserId;
+ _roomCount = (await hs.GetJoinedRooms()).Count;
await base.OnInitializedAsync();
}
@@ -34,15 +42,17 @@
Console.WriteLine(User.ToJson());
RuntimeCache.LoginSessions.Remove(User.AccessToken);
await LocalStorageWrapper.ReloadLocalStorage(LocalStorage);
-
+
StateHasChanged();
}
+
private async Task SetCurrent()
{
RuntimeCache.LastUsedToken = User.AccessToken;
- //RuntimeCache.CurrentHomeserver = await MatrixAuth.ResolveHomeserverFromWellKnown(LocalStorageWrapper.LoginSessions[Token].LoginResponse.HomeServer);
+ //RuntimeCache.CurrentHomeserver = await MatrixAuth.ResolveHomeserverFromWellKnown(LocalStorageWrapper.LoginSessions[Token].LoginResponse.HomeServer);
await LocalStorageWrapper.ReloadLocalStorage(LocalStorage);
-
+
StateHasChanged();
}
+
}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Shared/LogView.razor b/MatrixRoomUtils.Web/Shared/LogView.razor
index f60f271..80fd355 100644
--- a/MatrixRoomUtils.Web/Shared/LogView.razor
+++ b/MatrixRoomUtils.Web/Shared/LogView.razor
@@ -1,13 +1,27 @@
@using System.Text
-<u>Logs</u><br/>
-<pre>
- @_stringBuilder
-</pre>
+@if (LocalStorageWrapper.Settings.DeveloperSettings.EnableLogViewers)
+{
+ <u>Logs</u>
+ <br/>
+ <pre>
+ @_stringBuilder
+ </pre>
+}
@code {
StringBuilder _stringBuilder = new();
- protected override void OnInitialized()
+ protected override async Task OnInitializedAsync()
{
+ await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage);
+ if (!LocalStorageWrapper.Settings.DeveloperSettings.EnableConsoleLogging)
+ {
+ Console.WriteLine("Console logging disabled!");
+ var _sw = new StringWriter();
+ Console.SetOut(_sw);
+ Console.SetError(_sw);
+ return;
+ }
+ if (!LocalStorageWrapper.Settings.DeveloperSettings.EnableLogViewers) return;
//intecept stdout with textwriter to get logs
var sw = new StringWriter(_stringBuilder);
Console.SetOut(sw);
@@ -27,6 +41,6 @@
}
// ReSharper disable once FunctionNeverReturns - This is intentional behavior
});
- base.OnInitialized();
+ await base.OnInitializedAsync();
}
}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Shared/MainLayout.razor b/MatrixRoomUtils.Web/Shared/MainLayout.razor
index da27978..b1b0b53 100644
--- a/MatrixRoomUtils.Web/Shared/MainLayout.razor
+++ b/MatrixRoomUtils.Web/Shared/MainLayout.razor
@@ -1,5 +1,4 @@
-@using MatrixRoomUtils.Core.Extensions
-@using System.Net
+@using System.Net
@inherits LayoutComponentBase
<div class="page">
@@ -9,6 +8,7 @@
<main>
<div class="top-row px-4">
+ <PortableDevTools></PortableDevTools>
<a href="https://git.rory.gay/MatrixRoomUtils.git/" target="_blank">Git</a>
<a href="https://matrix.to/#/%23mru%3Arory.gay?via=rory.gay&via=matrix.org&via=feline.support" target="_blank">Matrix</a>
@if (showDownload)
@@ -31,6 +31,16 @@
using var hc = new HttpClient();
var hr = await hc.SendAsync(new(HttpMethod.Head, NavigationManager.ToAbsoluteUri("/MRU-BIN.tar.xz").AbsoluteUri));
showDownload = hr.StatusCode == HttpStatusCode.OK;
+
+ await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage);
+ if (!LocalStorageWrapper.Settings.DeveloperSettings.EnableConsoleLogging)
+ {
+ Console.WriteLine("Console logging disabled!");
+ var sw = new StringWriter();
+ Console.SetOut(sw);
+ Console.SetError(sw);
+ }
+
await base.OnInitializedAsync();
}
diff --git a/MatrixRoomUtils.Web/Shared/NavMenu.razor b/MatrixRoomUtils.Web/Shared/NavMenu.razor
index b77935d..8136715 100644
--- a/MatrixRoomUtils.Web/Shared/NavMenu.razor
+++ b/MatrixRoomUtils.Web/Shared/NavMenu.razor
@@ -52,10 +52,15 @@
<hr style="margin-bottom: 0em;"/>
</div>
<div class="nav-item px-3">
- <NavLink class="nav-link" href="MediaLocator">
- <span class="oi oi-plus" aria-hidden="true"></span> Media locator
+ <NavLink class="nav-link" href="KnownHomeserverList">
+ <span class="oi oi-plus" aria-hidden="true"></span> Known homeserver list
</NavLink>
</div>
+ @* <div class="nav-item px-3"> *@
+ @* <NavLink class="nav-link" href="MediaLocator"> *@
+ @* <span class="oi oi-plus" aria-hidden="true"></span> Media locator *@
+ @* </NavLink> *@
+ @* </div> *@
<div class="nav-item px-3">
<h5 style="margin-left: 1em;">MRU</h5>
<hr style="margin-bottom: 0em;"/>
diff --git a/MatrixRoomUtils.Web/Shared/PortableDevTools.razor b/MatrixRoomUtils.Web/Shared/PortableDevTools.razor
new file mode 100644
index 0000000..84e7791
--- /dev/null
+++ b/MatrixRoomUtils.Web/Shared/PortableDevTools.razor
@@ -0,0 +1,31 @@
+
+@if (Enabled)
+{
+ <a href="/DevOptions">Portable devtools (enabled)</a>
+ <div id="PortableDevTools" style="position: fixed; bottom: 0; right: 0; min-width: 200px; min-height: 100px; background: #0002;" draggable>
+ <p>Cache size: @RuntimeCache.GenericResponseCache.Sum(x=>x.Value.Cache.Count)</p>
+ </div>
+}
+else {
+ <a href="/DevOptions">Portable devtools (disabled)</a>
+}
+
+@code {
+ private bool Enabled { get; set; } = LocalStorageWrapper.Settings.DeveloperSettings.EnablePortableDevtools;
+
+ protected override async Task OnInitializedAsync()
+ {
+ // if(!RuntimeCache.WasLoaded)
+ // await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage);
+ // StateHasChanged();
+ Task.Run(async () =>
+ {
+ while (true)
+ {
+ await Task.Delay(100);
+ Enabled = LocalStorageWrapper.Settings.DeveloperSettings.EnablePortableDevtools;
+ StateHasChanged();
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Shared/RoomListItem.razor b/MatrixRoomUtils.Web/Shared/RoomListItem.razor
index 15ca5c0..16ced75 100644
--- a/MatrixRoomUtils.Web/Shared/RoomListItem.razor
+++ b/MatrixRoomUtils.Web/Shared/RoomListItem.razor
@@ -3,17 +3,27 @@
<div style="background-color: #ffffff11; border-radius: 25px; margin: 8px; width: fit-content;">
@if (ShowOwnProfile)
{
- <img style="width: 32px; height: 32px; border-radius: 50%; @(hasCustomProfileAvatar ? "border-color: red; border-width: 3px; border-style: dashed;" : "")" src="@profileAvatar"/>
+ <img style="@(ChildContent != null ? "vertical-align: baseline;":"") width: 32px; height: 32px; border-radius: 50%; @(hasCustomProfileAvatar ? "border-color: red; border-width: 3px; border-style: dashed;" : "")" src="@profileAvatar"/>
<span style="vertical-align: middle; margin-right: 8px; border-radius: 75px; @(hasCustomProfileName ? "background-color: red;" : "")">@profileName</span>
<span style="vertical-align: middle; padding-right: 8px; padding-left: 0px;">-></span>
}
- <img style="width: 32px; height: 32px; border-radius: 50%;" src="@roomIcon"/>
- <span style="vertical-align: middle; padding-right: 8px;">@roomName</span>
+ <img style="@(ChildContent != null ? "vertical-align: baseline;":"") width: 32px; height: 32px; border-radius: 50%;" src="@roomIcon"/>
+ <div style="display: inline-block;">
+ <span style="vertical-align: middle; padding-right: 8px;">@roomName</span>
+ @if (ChildContent != null)
+ {
+ @ChildContent
+ }
+ </div>
+
</div>
@code {
[Parameter]
+ public RenderFragment? ChildContent { get; set; }
+
+ [Parameter]
public Room Room { get; set; }
[Parameter]
@@ -33,8 +43,9 @@
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
-
- if(!RuntimeCache.WasLoaded) {
+
+ if (!RuntimeCache.WasLoaded)
+ {
Console.WriteLine("Loading from local storage");
await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage);
}
@@ -47,6 +58,10 @@
}
Room = await RuntimeCache.CurrentHomeServer.GetRoom(RoomId);
}
+ else
+ {
+ RoomId = Room.RoomId;
+ }
roomName = await Room.GetNameAsync();
if (roomName == null)
@@ -66,8 +81,8 @@
if (ShowOwnProfile)
{
- var profile = await RuntimeCache.CurrentHomeServer.GetProfile(RuntimeCache.CurrentHomeServer.UserId, debounce: true);
-
+ var profile = await RuntimeCache.CurrentHomeServer.GetProfile(RuntimeCache.CurrentHomeServer.UserId, debounce: true);
+
var memberState = await Room.GetStateAsync("m.room.member", RuntimeCache.CurrentHomeServer.UserId);
if (memberState.HasValue)
{
@@ -86,7 +101,7 @@
{
hasCustomProfileName = _name.GetString() != profile.DisplayName;
profileName = _name.GetString();
- // Console.WriteLine($"{profile.DisplayName} - {_name.GetString()}: {hasCustomProfileName}");
+ // Console.WriteLine($"{profile.DisplayName} - {_name.GetString()}: {hasCustomProfileName}");
}
else
{
@@ -94,7 +109,7 @@
}
}
}
- if(Random.Shared.Next(100) == 1)
+ if (Random.Shared.Next(100) == 1)
await LocalStorageWrapper.SaveToLocalStorage(LocalStorage);
}
|