commit 383f7b633471dedf515907cb8a8752bc5885ae64
parent dc3201d641a03e051c6f0db07612eb6b0bb506c3
Author: TheArcaneBrony <myrainbowdash949@gmail.com>
Date: Thu, 4 May 2023 20:34:16 +0200
Add room manager, profile caching
Diffstat:
15 files changed, 247 insertions(+), 53 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,4 +1,4 @@
**/bin/
**/obj/
MatrixRoomUtils/
-
+MatrixRoomUtils.Web/wwwroot/MRU.tar.xz
diff --git a/.idea/.idea.MatrixRoomUtils/.idea/vcs.xml b/.idea/.idea.MatrixRoomUtils/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="VcsDirectoryMappings">
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
+ </component>
+</project>
+\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Authentication/MatrixAuth.cs b/MatrixRoomUtils.Core/Authentication/MatrixAuth.cs
@@ -39,6 +39,7 @@ public class MatrixAuth
//return token;
}
+ [Obsolete("Migrate to IHomeServer instance")]
public static async Task<ProfileResponse> GetProfile(string homeserver, string mxid) =>
await (await new RemoteHomeServer(homeserver).Configure()).GetProfile(mxid);
diff --git a/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs b/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs
@@ -1,11 +1,13 @@
using System.Net.Http.Json;
using System.Text.Json;
using MatrixRoomUtils.Core.Extensions;
+using MatrixRoomUtils.Core.Responses;
namespace MatrixRoomUtils.Core.Interfaces;
public class IHomeServer
{
+ private Dictionary<string, ProfileResponse?> _profileCache = new();
public string HomeServerDomain { get; set; }
public string FullHomeServerDomain { get; set; }
@@ -69,4 +71,28 @@ public class IHomeServer
}
throw new InvalidDataException($"Failed to resolve homeserver, not on {homeserver}, nor do client or server well-knowns exist!");
}
+ public async Task<ProfileResponse> GetProfile(string mxid, bool debounce = false, bool cache = true)
+ {
+ if (cache)
+ {
+ if(debounce) await Task.Delay(Random.Shared.Next(100, 500));
+ if (_profileCache.ContainsKey(mxid))
+ {
+ while (_profileCache[mxid] == null)
+ {
+ Console.WriteLine($"Waiting for profile cache for {mxid}, currently {_profileCache[mxid]?.ToJson()} within {_profileCache.Count} profiles...");
+ await Task.Delay(Random.Shared.Next(50, 500));
+ }
+ return _profileCache[mxid];
+ }
+ }
+
+ _profileCache.Add(mxid, null);
+ var resp = await _httpClient.GetAsync($"/_matrix/client/r0/profile/{mxid}");
+ var data = await resp.Content.ReadFromJsonAsync<JsonElement>();
+ if(!resp.IsSuccessStatusCode) Console.WriteLine("Profile: " + data.ToString());
+ var profile = data.Deserialize<ProfileResponse>();
+ _profileCache[mxid] = profile;
+ return profile;
+ }
}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/RemoteHomeServer.cs b/MatrixRoomUtils.Core/RemoteHomeServer.cs
@@ -7,6 +7,8 @@ namespace MatrixRoomUtils.Core;
public class RemoteHomeServer : IHomeServer
{
+
+
public RemoteHomeServer(string canonicalHomeServerDomain)
{
HomeServerDomain = canonicalHomeServerDomain;
@@ -21,13 +23,6 @@ public class RemoteHomeServer : IHomeServer
return this;
}
- public async Task<ProfileResponse> GetProfile(string mxid)
- {
- var resp = await _httpClient.GetAsync($"/_matrix/client/r0/profile/{mxid}");
- var data = await resp.Content.ReadFromJsonAsync<JsonElement>();
- if(!resp.IsSuccessStatusCode) Console.WriteLine("Profile: " + data.ToString());
- return data.Deserialize<ProfileResponse>();
- }
public async Task<Room> GetRoom(string roomId)
{
diff --git a/MatrixRoomUtils.Core/Room.cs b/MatrixRoomUtils.Core/Room.cs
@@ -33,10 +33,11 @@ public class Room
var res = await GetStateAsync("m.room.name");
if (!res.HasValue)
{
+ Console.WriteLine($"Room {RoomId} has no name!");
return null;
}
var resn = res?.TryGetProperty("name", out var name) ?? false ? name.GetString() : null;
- Console.WriteLine($"Got name: {resn}");
+ //Console.WriteLine($"Got name: {resn}");
return resn;
}
diff --git a/MatrixRoomUtils.Web/Pages/DataExportPage.razor b/MatrixRoomUtils.Web/Pages/DataExportPage.razor
@@ -1,4 +1,4 @@
-@page "/export"
+@page "/Export"
@using MatrixRoomUtils.Web.Shared.IndexComponents
@using System.Text.Json
@inject NavigationManager NavigationManager
@@ -6,7 +6,7 @@
<PageTitle>Export</PageTitle>
-<h1>Data export</h1>
+<h3>Data export</h3>
<br/><br/>
<h5>Signed in accounts - <a href="/Login">Add new account</a> or <a href="/ImportUsers">Import from TSV</a></h5>
diff --git a/MatrixRoomUtils.Web/Pages/DebugTools.razor b/MatrixRoomUtils.Web/Pages/DebugTools.razor
@@ -0,0 +1,87 @@
+@page "/Debug"
+@using MatrixRoomUtils.Core.Interfaces
+@using MatrixRoomUtils.Core.Extensions
+@using System.Reflection
+@inject ILocalStorageService LocalStorage
+@inject NavigationManager NavigationManager
+<h3>Debug Tools</h3>
+<hr/>
+@if (Rooms.Count == 0)
+{
+ <p>You are not in any rooms!</p>
+ @* <p>Loading progress: @checkedRoomCount/@totalRoomCount</p> *@
+}
+else
+{
+ <details>
+ <summary>Room List</summary>
+ @foreach (var room in Rooms)
+ {
+ <a style="color: unset; text-decoration: unset;" href="/RoomStateViewer/@room.Replace('.', '~')"><RoomListItem RoomId="@room"></RoomListItem></a>
+ }
+ </details>
+
+}
+
+<details open>
+ <summary>Send GET request to URL</summary>
+ <div class="input-group">
+ <input type="text" class="form-control" @bind-value="get_request_url" placeholder="URL">
+ <button class="btn btn-outline-secondary" type="button" @onclick="SendGetRequest">Send</button>
+ </div>
+ <br/>
+ <pre>@get_request_result</pre>
+</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!");
+ }
+
+
+ //send req
+ string get_request_url { get; set; } = "";
+ string get_request_result { get; set; } = "";
+ private async Task SendGetRequest()
+ {
+ var field = typeof(IHomeServer).GetRuntimeFields().First(x => x.ToString().Contains("<_httpClient>k__BackingField"));
+ var httpClient = field.GetValue(RuntimeCache.CurrentHomeServer) as HttpClient;
+ try
+ {
+ var res = await httpClient.GetAsync(get_request_url);
+ if (res.IsSuccessStatusCode)
+ {
+ if(res.Content.Headers.ContentType.MediaType == "application/json")
+ get_request_result = (await res.Content.ReadFromJsonAsync<object>()).ToJson();
+ else
+ get_request_result = await res.Content.ReadAsStringAsync();
+ StateHasChanged();
+ return;
+ }
+ if(res.Content.Headers.ContentType.MediaType == "application/json")
+ get_request_result = $"Error: {res.StatusCode}\n" + (await res.Content.ReadFromJsonAsync<object>()).ToJson();
+ else
+ get_request_result = $"Error: {res.StatusCode}\n" + await res.Content.ReadAsStringAsync();
+
+ }
+ catch (Exception e)
+ {
+ get_request_result = $"Error: {e}";
+ }
+ StateHasChanged();
+ }
+
+}
+\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/Index.razor b/MatrixRoomUtils.Web/Pages/Index.razor
@@ -5,7 +5,7 @@
<PageTitle>Index</PageTitle>
-<h1>Rory&::MatrixUtils</h1>
+<h3>Rory&::MatrixUtils</h3>
Small collection of tools to do not-so-everyday things.
<br/><br/>
diff --git a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor
@@ -57,7 +57,7 @@ else
totalRoomCount = xxxrooms.Count;
StateHasChanged();
- var xxxsemaphore = new SemaphoreSlim(256);
+ var xxxsemaphore = new SemaphoreSlim(1000);
var xxxtasks = new List<Task<PolicyRoomInfo?>>();
foreach (var room in xxxrooms)
{
@@ -68,44 +68,6 @@ else
Console.WriteLine($"Detected policy lists: {PolicyRoomList.ToJson()}");
return;
- /*
- using HttpClient wc = new();
- wc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", LocalStorageWrapper.AccessToken);
-
-
-
- //get room list
- //temporary hack until rooms get enumerated...
- string[] rooms = { "!fTjMjIzNKEsFlUIiru:neko.dev" };
- var _rooms = await wc.GetAsync($"{LocalStorageWrapper.CurrentHomeserver}/_matrix/client/v3/joined_rooms");
- Console.WriteLine($"Got {_rooms.StatusCode}...");
- if (!_rooms.IsSuccessStatusCode)
- {
- Console.WriteLine($"Failed to get rooms: {await _rooms.Content.ReadAsStringAsync()}");
- return;
- }
- var _rooms_o = await _rooms.Content.ReadFromJsonAsync<JsonElement>();
- if (_rooms_o.TryGetProperty("joined_rooms", out JsonElement _rooms_j))
- {
- rooms = _rooms_j.EnumerateArray().Select(x => x.GetString()).ToArray();
- }
-
- totalRoomCount = rooms.Length;
- StateHasChanged();
-
- var semaphore = new SemaphoreSlim(256);
- var tasks = new List<Task<PolicyRoomInfo?>>();
- foreach (string room in rooms)
- {
- tasks.Add(GetPolicyRoomInfo(room, semaphore));
- }
- var results = await Task.WhenAll(tasks);
- PolicyRoomList.AddRange(results.Where(x => x != null).Select(x => x.Value));
-
-
- //print to console
- Console.WriteLine($"Detected policy lists: {PolicyRoomList.ToJson()}");
- */
}
private async Task<PolicyRoomInfo?> GetPolicyRoomInfo(string room, SemaphoreSlim semaphore)
diff --git a/MatrixRoomUtils.Web/Pages/RoomManager.razor b/MatrixRoomUtils.Web/Pages/RoomManager.razor
@@ -0,0 +1,40 @@
+@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/Shared/MainLayout.razor b/MatrixRoomUtils.Web/Shared/MainLayout.razor
@@ -1,4 +1,6 @@
-@inherits LayoutComponentBase
+@using MatrixRoomUtils.Core.Extensions
+@using System.Net
+@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
@@ -9,6 +11,10 @@
<div class="top-row px-4">
<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)
+ {
+ <a href="/MRU.tar.xz" target="_blank">Download</a>
+ }
</div>
<article class="content px-4">
@@ -18,6 +24,14 @@
</div>
@code {
+ private bool showDownload { get; set; } = false;
+ protected override async Task OnInitializedAsync()
+ {
+ using var hc = new HttpClient();
+ var hr = await hc.SendAsync(new(HttpMethod.Head, NavigationManager.ToAbsoluteUri("/MRU.tar.xz").AbsoluteUri));
+ showDownload = hr.StatusCode == HttpStatusCode.OK;
+ await base.OnInitializedAsync();
+ }
}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Shared/NavMenu.razor b/MatrixRoomUtils.Web/Shared/NavMenu.razor
@@ -15,11 +15,16 @@
</NavLink>
</div>
<div class="nav-item px-3">
- <NavLink class="nav-link" href="export">
+ <NavLink class="nav-link" href="Export">
<span class="oi oi-plus" aria-hidden="true"></span> Export data
</NavLink>
</div>
<div class="nav-item px-3">
+ <NavLink class="nav-link" href="RoomManager">
+ <span class="oi oi-plus" aria-hidden="true"></span> Manage Rooms
+ </NavLink>
+ </div>
+ <div class="nav-item px-3">
<NavLink class="nav-link" href="PolicyListEditor">
<span class="oi oi-plus" aria-hidden="true"></span> Policy list editor
</NavLink>
diff --git a/MatrixRoomUtils.Web/Shared/RoomListItem.razor b/MatrixRoomUtils.Web/Shared/RoomListItem.razor
@@ -1,17 +1,35 @@
+@using MatrixRoomUtils.Core.Authentication
+@using System.Text.Json
<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"/>
+ <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>
</div>
@code {
+
[Parameter]
public Room Room { get; set; }
+
[Parameter]
public string RoomId { get; set; }
+ [Parameter]
+ public bool ShowOwnProfile { get; set; } = false;
+
private string roomName { get; set; } = "Loading...";
private string roomIcon { get; set; } = "/icon-192.png";
+ private string profileAvatar { get; set; } = "/icon-192.png";
+ private string profileName { get; set; } = "Loading...";
+ private bool hasCustomProfileAvatar { get; set; } = false;
+ private bool hasCustomProfileName { get; set; } = false;
+
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
@@ -40,6 +58,36 @@
}
}
+ if (ShowOwnProfile)
+ {
+ 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)
+ {
+ memberState.Value.TryGetProperty("avatar_url", out var _avatar);
+ if (_avatar.ValueKind == JsonValueKind.String)
+ {
+ hasCustomProfileAvatar = _avatar.GetString() != profile.AvatarUrl;
+ profileAvatar = await RuntimeCache.CurrentHomeServer.ResolveMediaUri(_avatar.GetString());
+ }
+ else
+ {
+ profileAvatar = "/icon-192.png";
+ }
+ memberState.Value.TryGetProperty("displayname", out var _name);
+ if (_name.ValueKind == JsonValueKind.String)
+ {
+ hasCustomProfileName = _name.GetString() != profile.DisplayName;
+ profileName = _name.GetString();
+ Console.WriteLine($"{profile.DisplayName} - {_name.GetString()}: {hasCustomProfileName}");
+ }
+ else
+ {
+ profileName = "Unnamed user";
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/deploy.sh b/deploy.sh
@@ -1,4 +1,10 @@
#!/bin/sh
+BASE_DIR=`pwd`
+rm -rf **/bin/Release
cd MatrixRoomUtils.Web
dotnet publish -c Release
rsync -raP bin/Release/net7.0/publish/wwwroot/ rory.gay:/data/nginx/html_mru/
+cd bin/Release/net7.0/publish/wwwroot
+tar cf - ./ | xz -z -9 - > $BASE_DIR/MRU.tar.xz
+rsync -raP $BASE_DIR/MRU.tar.xz rory.gay:/data/nginx/html_mru/MRU.tar.xz
+rm -rf $BASE_DIR/MRU.tar.xz