MatrixRoomUtils

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | LICENSE

commit b933f7ed1189c7e14d82b4fcf5c98fb3ef4b9cf1
parent b02fb81a56bd94b38fdb26771c3e591419f0f49c
Author: TheArcaneBrony <myrainbowdash949@gmail.com>
Date:   Thu,  4 May 2023 00:13:25 +0200

Refactoring

Diffstat:
MMatrixRoomUtils.Core/AuthenticatedHomeServer.cs | 44++++++++++++++++++++++++++++----------------
MMatrixRoomUtils.Core/Authentication/MatrixAuth.cs | 44+++++---------------------------------------
MMatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs | 2+-
MMatrixRoomUtils.Core/Extensions/ObjectExtensions.cs | 2+-
MMatrixRoomUtils.Core/Extensions/StringExtensions.cs | 22+++++++++++-----------
MMatrixRoomUtils.Core/Interfaces/IHomeServer.cs | 57++++++++++++++++++++++++++++++++++++++++++++++-----------
MMatrixRoomUtils.Core/RatelimitedHttpClient.cs | 2+-
AMatrixRoomUtils.Core/RemoteHomeServer.cs | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MMatrixRoomUtils.Core/Responses/LoginResponse.cs | 6+++---
MMatrixRoomUtils.Core/Responses/ProfileResponse.cs | 2+-
MMatrixRoomUtils.Core/Room.cs | 2+-
MMatrixRoomUtils.Core/RuntimeCache.cs | 12+++++-------
MMatrixRoomUtils.Core/StateEvent.cs | 2+-
MMatrixRoomUtils.Core/StateEventStruct.cs | 2+-
MMatrixRoomUtils.Core/StateEventTypes/PolicyRuleStateEventData.cs | 2+-
MMatrixRoomUtils.Web.Server/Pages/Error.cshtml | 2+-
MMatrixRoomUtils.Web.Server/Pages/Error.cshtml.cs | 2+-
MMatrixRoomUtils.Web/App.razor | 3++-
MMatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs | 22++++++++++++++--------
MMatrixRoomUtils.Web/Pages/DataExportPage.razor | 5+++--
MMatrixRoomUtils.Web/Pages/Index.razor | 36++++++++++++++++++++----------------
MMatrixRoomUtils.Web/Pages/LoginPage.razor | 10++++------
MMatrixRoomUtils.Web/Pages/PolicyListEditorPage.razor | 5+++--
MMatrixRoomUtils.Web/Pages/PolicyListRoomList.razor | 68+++++++++++++++++++++++++-------------------------------------------
MMatrixRoomUtils.Web/Pages/RoomStateEditorPage.razor | 6++++--
MMatrixRoomUtils.Web/Pages/RoomStateRoomList.razor | 46++++++----------------------------------------
MMatrixRoomUtils.Web/Pages/RoomStateViewerPage.razor | 10++++++----
MMatrixRoomUtils.Web/Pages/UserImportPage.razor | 12+++++++-----
MMatrixRoomUtils.Web/Program.cs | 1-
MMatrixRoomUtils.Web/Shared/IndexComponents/IndexUserItem.razor | 19++++++++++---------
MMatrixRoomUtils.Web/Shared/LogView.razor | 11++++++-----
MMatrixRoomUtils.Web/Shared/MainLayout.razor | 5++---
MMatrixRoomUtils.Web/_Imports.razor | 2++
33 files changed, 280 insertions(+), 244 deletions(-)

diff --git a/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs b/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs @@ -1,8 +1,10 @@ using System.Net.Http.Headers; using System.Net.Http.Json; using System.Text.Json; +using MatrixRoomUtils.Core.Extensions; +using MatrixRoomUtils.Core.Interfaces; -namespace MatrixRoomUtils; +namespace MatrixRoomUtils.Core; public class AuthenticatedHomeServer : IHomeServer { @@ -15,18 +17,20 @@ public class AuthenticatedHomeServer : IHomeServer AccessToken = accessToken; HomeServerDomain = canonicalHomeServerDomain; _httpClient = new HttpClient(); - - var rhsfwt = ResolveHomeserverFromWellKnown(canonicalHomeServerDomain); - rhsfwt.ContinueWith(_ => - { - FullHomeServerDomain = rhsfwt.Result; - _httpClient.Dispose(); - _httpClient = new HttpClient {BaseAddress = new Uri(FullHomeServerDomain)}; - _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken); - Console.WriteLine("[AHS] Finished setting up http client :)"); - }); } + public async Task<AuthenticatedHomeServer> Configure() + { + FullHomeServerDomain = await ResolveHomeserverFromWellKnown(HomeServerDomain); + _httpClient.Dispose(); + _httpClient = new HttpClient { BaseAddress = new Uri(FullHomeServerDomain) }; + _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken); + Console.WriteLine("[AHS] Finished setting up http client"); + + return this; + } + + public async Task<Room> GetRoom(string roomId) { return new Room(_httpClient, roomId); @@ -35,19 +39,27 @@ public class AuthenticatedHomeServer : IHomeServer public async Task<List<Room>> GetJoinedRooms() { var rooms = new List<Room>(); - var _rooms = await _httpClient.GetAsync("/_matrix/client/v3/joined_rooms"); - if (!_rooms.IsSuccessStatusCode) + var roomQuery = await _httpClient.GetAsync("/_matrix/client/v3/joined_rooms"); + if (!roomQuery.IsSuccessStatusCode) { - Console.WriteLine($"Failed to get rooms: {await _rooms.Content.ReadAsStringAsync()}"); - throw new InvalidDataException($"Failed to get rooms: {await _rooms.Content.ReadAsStringAsync()}"); + Console.WriteLine($"Failed to get rooms: {await roomQuery.Content.ReadAsStringAsync()}"); + throw new InvalidDataException($"Failed to get rooms: {await roomQuery.Content.ReadAsStringAsync()}"); } + - var roomsJson = await _rooms.Content.ReadFromJsonAsync<JsonElement>(); + var roomsJson = await roomQuery.Content.ReadFromJsonAsync<JsonElement>(); foreach (var room in roomsJson.GetProperty("joined_rooms").EnumerateArray()) { rooms.Add(new Room(_httpClient, room.GetString())); } + + Console.WriteLine($"Fetched {rooms.Count} rooms"); return rooms; } + + public async Task<string> ResolveMediaUri(string mxc) + { + return mxc.Replace("mxc://", $"{FullHomeServerDomain}/_matrix/media/r0/download/"); + } } \ No newline at end of file diff --git a/MatrixRoomUtils.Core/Authentication/MatrixAuth.cs b/MatrixRoomUtils.Core/Authentication/MatrixAuth.cs @@ -1,15 +1,15 @@ using System.Net.Http.Json; using System.Text.Json; -using MatrixRoomUtils.Responses; +using MatrixRoomUtils.Core.Responses; -namespace MatrixRoomUtils.Authentication; +namespace MatrixRoomUtils.Core.Authentication; public class MatrixAuth { public static async Task<LoginResponse> Login(string homeserver, string username, string password) { Console.WriteLine($"Logging in to {homeserver} as {username}..."); - homeserver = await ResolveHomeserverFromWellKnown(homeserver); + homeserver = (await new RemoteHomeServer(homeserver).Configure()).FullHomeServerDomain; var hc = new HttpClient(); var payload = new { @@ -39,42 +39,8 @@ public class MatrixAuth //return token; } - public static async Task<ProfileResponse> GetProfile(string homeserver, string mxid) - { - Console.WriteLine($"Fetching profile for {mxid} on {homeserver}..."); - homeserver = await ResolveHomeserverFromWellKnown(homeserver); - using var hc = new HttpClient(); - var resp = await hc.GetAsync($"{homeserver}/_matrix/client/r0/profile/{mxid}"); - var data = await resp.Content.ReadFromJsonAsync<JsonElement>(); - if (!resp.IsSuccessStatusCode) Console.WriteLine("Profile: " + data.ToString()); - return data.Deserialize<ProfileResponse>(); - } - - [Obsolete("Use IHomeServer")] - public static async Task<string> ResolveHomeserverFromWellKnown(string homeserver) - { - using var hc = new HttpClient(); - Console.WriteLine($"Resolving homeserver: {homeserver}"); - if (!homeserver.StartsWith("http")) homeserver = "https://" + homeserver; - - if (await CheckSuccessStatus($"{homeserver}/.well-known/matrix/client")) - { - var resp = await hc.GetFromJsonAsync<JsonElement>($"{homeserver}/.well-known/matrix/client"); - var hs = resp.GetProperty("m.homeserver").GetProperty("base_url").GetString(); - return hs; - } - Console.WriteLine($"No client well-known..."); - if (await CheckSuccessStatus($"{homeserver}/.well-known/matrix/server")) - { - var resp = await hc.GetFromJsonAsync<JsonElement>($"{homeserver}/.well-known/matrix/server"); - var hs = resp.GetProperty("m.server").GetString(); - return hs; - } - Console.WriteLine($"No server well-known..."); - if (await CheckSuccessStatus($"{homeserver}/_matrix/client/versions")) return homeserver; - Console.WriteLine($"Failed to resolve homeserver, not on {homeserver}, nor do client or server well-knowns exist!"); - throw new InvalidDataException($"Failed to resolve homeserver, not on {homeserver}, nor do client or server well-knowns exist!"); - } + public static async Task<ProfileResponse> GetProfile(string homeserver, string mxid) => + await (await new RemoteHomeServer(homeserver).Configure()).GetProfile(mxid); private static async Task<bool> CheckSuccessStatus(string url) { diff --git a/MatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs b/MatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs @@ -1,4 +1,4 @@ -namespace MatrixRoomUtils.Extensions; +namespace MatrixRoomUtils.Core.Extensions; public static class HttpClientExtensions { diff --git a/MatrixRoomUtils.Core/Extensions/ObjectExtensions.cs b/MatrixRoomUtils.Core/Extensions/ObjectExtensions.cs @@ -1,6 +1,6 @@ using System.Text.Json; -namespace MatrixRoomUtils.Extensions; +namespace MatrixRoomUtils.Core.Extensions; public static class ObjectExtensions { diff --git a/MatrixRoomUtils.Core/Extensions/StringExtensions.cs b/MatrixRoomUtils.Core/Extensions/StringExtensions.cs @@ -1,17 +1,17 @@ -using MatrixRoomUtils.Authentication; +using MatrixRoomUtils.Core.Authentication; -namespace MatrixRoomUtils.Extensions; +namespace MatrixRoomUtils.Core.Extensions; public static class StringExtensions { - public static async Task<string> GetMediaUrl(this string MxcUrl) - { - //MxcUrl: mxc://rory.gay/ocRVanZoUTCcifcVNwXgbtTg - //target: https://matrix.rory.gay/_matrix/media/v3/download/rory.gay/ocRVanZoUTCcifcVNwXgbtTg - - var server = MxcUrl.Split('/')[2]; - var mediaId = MxcUrl.Split('/')[3]; - return $"{await MatrixAuth.ResolveHomeserverFromWellKnown(server)}/_matrix/media/v3/download/{server}/{mediaId}"; - } + // public static async Task<string> GetMediaUrl(this string MxcUrl) + // { + // //MxcUrl: mxc://rory.gay/ocRVanZoUTCcifcVNwXgbtTg + // //target: https://matrix.rory.gay/_matrix/media/v3/download/rory.gay/ocRVanZoUTCcifcVNwXgbtTg + // + // var server = MxcUrl.Split('/')[2]; + // var mediaId = MxcUrl.Split('/')[3]; + // return $"{(await new RemoteHomeServer(server).Configure()).FullHomeServerDomain}/_matrix/media/v3/download/{server}/{mediaId}"; + // } } \ No newline at end of file diff --git a/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs b/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs @@ -1,8 +1,8 @@ using System.Net.Http.Json; using System.Text.Json; -using MatrixRoomUtils.Extensions; +using MatrixRoomUtils.Core.Extensions; -namespace MatrixRoomUtils; +namespace MatrixRoomUtils.Core.Interfaces; public class IHomeServer { @@ -10,8 +10,21 @@ public class IHomeServer public string FullHomeServerDomain { get; set; } private protected HttpClient _httpClient { get; set; } = new(); + public async Task<string> ResolveHomeserverFromWellKnown(string homeserver) { + if (RuntimeCache.HomeserverResolutionCache.ContainsKey(homeserver)) + { + if (RuntimeCache.HomeserverResolutionCache[homeserver].ResolutionTime < DateTime.Now.AddHours(1)) + { + Console.WriteLine($"Found cached homeserver: {RuntimeCache.HomeserverResolutionCache[homeserver].Result}"); + return RuntimeCache.HomeserverResolutionCache[homeserver].Result; + } + RuntimeCache.HomeserverResolutionCache.Remove(homeserver); + } + //throw new NotImplementedException(); + + string result = null; Console.WriteLine($"Resolving homeserver: {homeserver}"); if (!homeserver.StartsWith("http")) homeserver = "https://" + homeserver; if (await _httpClient.CheckSuccessStatus($"{homeserver}/.well-known/matrix/client")) @@ -20,18 +33,40 @@ public class IHomeServer var resp = await _httpClient.GetFromJsonAsync<JsonElement>($"{homeserver}/.well-known/matrix/client"); Console.WriteLine($"Response: {resp.ToString()}"); var hs = resp.GetProperty("m.homeserver").GetProperty("base_url").GetString(); - return hs; + result = hs; } - Console.WriteLine($"No client well-known..."); - if (await _httpClient.CheckSuccessStatus($"{homeserver}/.well-known/matrix/server")) + else + { + Console.WriteLine($"No client well-known..."); + if (await _httpClient.CheckSuccessStatus($"{homeserver}/.well-known/matrix/server")) + { + var resp = await _httpClient.GetFromJsonAsync<JsonElement>($"{homeserver}/.well-known/matrix/server"); + var hs = resp.GetProperty("m.server").GetString(); + result = hs; + } + else + { + Console.WriteLine($"No server well-known..."); + if (await _httpClient.CheckSuccessStatus($"{homeserver}/_matrix/client/versions")) result = homeserver; + else + { + Console.WriteLine("No homeserver on shortname..."); + if (await _httpClient.CheckSuccessStatus($"{homeserver.Replace("//", "//matrix.")}/_matrix/client/versions")) result = homeserver.Replace("//", "//matrix."); + else Console.WriteLine($"Failed to resolve homeserver, not on {homeserver}, nor do client or server well-knowns exist!"); + } + } + } + + if (result != null) { - var resp = await _httpClient.GetFromJsonAsync<JsonElement>($"{homeserver}/.well-known/matrix/server"); - var hs = resp.GetProperty("m.server").GetString(); - return hs; + Console.WriteLine($"Resolved homeserver: {homeserver} -> {result}"); + RuntimeCache.HomeserverResolutionCache.TryAdd(homeserver, new() + { + Result = result, + ResolutionTime = DateTime.Now + }); + return result; } - Console.WriteLine($"No server well-known..."); - if (await _httpClient.CheckSuccessStatus($"{homeserver}/_matrix/client/versions")) return homeserver; - Console.WriteLine($"Failed to resolve homeserver, not on {homeserver}, nor do client or server well-knowns exist!"); throw new InvalidDataException($"Failed to resolve homeserver, not on {homeserver}, nor do client or server well-knowns exist!"); } } \ No newline at end of file diff --git a/MatrixRoomUtils.Core/RatelimitedHttpClient.cs b/MatrixRoomUtils.Core/RatelimitedHttpClient.cs @@ -1,4 +1,4 @@ -namespace MatrixRoomUtils; +namespace MatrixRoomUtils.Core; public class RatelimitedHttpClient : HttpClient { diff --git a/MatrixRoomUtils.Core/RemoteHomeServer.cs b/MatrixRoomUtils.Core/RemoteHomeServer.cs @@ -0,0 +1,57 @@ +using System.Net.Http.Headers; +using System.Net.Http.Json; +using System.Text.Json; +using MatrixRoomUtils.Core.Extensions; +using MatrixRoomUtils.Core.Interfaces; +using MatrixRoomUtils.Core.Responses; + +namespace MatrixRoomUtils.Core; + +public class RemoteHomeServer : IHomeServer +{ + public RemoteHomeServer(string canonicalHomeServerDomain) + { + HomeServerDomain = canonicalHomeServerDomain; + _httpClient = new HttpClient(); + } + public async Task<RemoteHomeServer> Configure() + { + FullHomeServerDomain = await ResolveHomeserverFromWellKnown(HomeServerDomain); + _httpClient.Dispose(); + _httpClient = new HttpClient { BaseAddress = new Uri(FullHomeServerDomain) }; + Console.WriteLine("[RHS] Finished setting up http client"); + + 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) + { + return new Room(_httpClient, roomId); + } + + public async Task<List<Room>> GetJoinedRooms() + { + var rooms = new List<Room>(); + var roomQuery = await _httpClient.GetAsync("/_matrix/client/v3/joined_rooms"); + if (!roomQuery.IsSuccessStatusCode) + { + Console.WriteLine($"Failed to get rooms: {await roomQuery.Content.ReadAsStringAsync()}"); + throw new InvalidDataException($"Failed to get rooms: {await roomQuery.Content.ReadAsStringAsync()}"); + } + + var roomsJson = await roomQuery.Content.ReadFromJsonAsync<JsonElement>(); + foreach (var room in roomsJson.GetProperty("joined_rooms").EnumerateArray()) + { + rooms.Add(new Room(_httpClient, room.GetString())); + } + + return rooms; + } +} +\ No newline at end of file diff --git a/MatrixRoomUtils.Core/Responses/LoginResponse.cs b/MatrixRoomUtils.Core/Responses/LoginResponse.cs @@ -1,9 +1,9 @@ using System.Net.Http.Json; using System.Text.Json; using System.Text.Json.Serialization; -using MatrixRoomUtils.Authentication; +using MatrixRoomUtils.Core.Authentication; -namespace MatrixRoomUtils.Responses; +namespace MatrixRoomUtils.Core.Responses; public class LoginResponse { @@ -26,6 +26,6 @@ public class LoginResponse } public async Task<string> GetCanonicalHomeserverUrl() { - return await MatrixAuth.ResolveHomeserverFromWellKnown(HomeServer); + return (await new RemoteHomeServer(HomeServer).Configure()).FullHomeServerDomain; } } \ No newline at end of file diff --git a/MatrixRoomUtils.Core/Responses/ProfileResponse.cs b/MatrixRoomUtils.Core/Responses/ProfileResponse.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace MatrixRoomUtils.Authentication; +namespace MatrixRoomUtils.Core.Responses; public class ProfileResponse { diff --git a/MatrixRoomUtils.Core/Room.cs b/MatrixRoomUtils.Core/Room.cs @@ -1,7 +1,7 @@ using System.Net.Http.Json; using System.Text.Json; -namespace MatrixRoomUtils; +namespace MatrixRoomUtils.Core; public class Room { diff --git a/MatrixRoomUtils.Core/RuntimeCache.cs b/MatrixRoomUtils.Core/RuntimeCache.cs @@ -1,18 +1,16 @@ -using MatrixRoomUtils.Authentication; -using MatrixRoomUtils.Responses; +using MatrixRoomUtils.Core.Responses; -namespace MatrixRoomUtils; +namespace MatrixRoomUtils.Core; public class RuntimeCache { public static bool WasLoaded = false; - public static string AccessToken { get; set; } - public static string? CurrentHomeserver { get; set; } + public static string? LastUsedToken { get; set; } public static AuthenticatedHomeServer CurrentHomeServer { get; set; } public static Dictionary<string, UserInfo> LoginSessions { get; set; } = new(); 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, (DateTime cachedAt, ProfileResponse response)> ProfileCache { get; set; } = new(); } @@ -20,7 +18,7 @@ public class UserInfo { public ProfileResponse Profile { get; set; } = new(); public LoginResponse LoginResponse { get; set; } - public string AccessToken { get; set; } + public string AccessToken { get => LoginResponse.AccessToken; } } public class HomeServerResolutionResult diff --git a/MatrixRoomUtils.Core/StateEvent.cs b/MatrixRoomUtils.Core/StateEvent.cs @@ -1,4 +1,4 @@ -namespace MatrixRoomUtils; +namespace MatrixRoomUtils.Core; public class StateEvent { diff --git a/MatrixRoomUtils.Core/StateEventStruct.cs b/MatrixRoomUtils.Core/StateEventStruct.cs @@ -1,4 +1,4 @@ -namespace MatrixRoomUtils; +namespace MatrixRoomUtils.Core; public struct StateEventStruct { diff --git a/MatrixRoomUtils.Core/StateEventTypes/PolicyRuleStateEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/PolicyRuleStateEventData.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace MatrixRoomUtils.StateEventTypes; +namespace MatrixRoomUtils.Core.StateEventTypes; public class PolicyRuleStateEventData { diff --git a/MatrixRoomUtils.Web.Server/Pages/Error.cshtml b/MatrixRoomUtils.Web.Server/Pages/Error.cshtml @@ -1,5 +1,5 @@ @page -@model tmp.Server.Pages.ErrorModel +@model MatrixRoomUtils.Web.Server.Pages.ErrorModel <!DOCTYPE html> <html lang="en"> diff --git a/MatrixRoomUtils.Web.Server/Pages/Error.cshtml.cs b/MatrixRoomUtils.Web.Server/Pages/Error.cshtml.cs @@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; -namespace tmp.Server.Pages; +namespace MatrixRoomUtils.Web.Server.Pages; [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] diff --git a/MatrixRoomUtils.Web/App.razor b/MatrixRoomUtils.Web/App.razor @@ -1,4 +1,5 @@ -<Router AppAssembly="@typeof(App).Assembly"> +@using MatrixRoomUtils.Core +<Router AppAssembly="@typeof(App).Assembly"> <Found Context="routeData"> <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/> <FocusOnNavigate RouteData="@routeData" Selector="h1"/> diff --git a/MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs b/MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs @@ -1,4 +1,6 @@ using Blazored.LocalStorage; +using MatrixRoomUtils.Core; +using MatrixRoomUtils.Core.Extensions; namespace MatrixRoomUtils.Web.Classes; @@ -12,15 +14,18 @@ public partial class LocalStorageWrapper } public static async Task LoadFromLocalStorage(ILocalStorageService localStorage) { - RuntimeCache.AccessToken = await localStorage.GetItemAsync<string>("rory.matrixroomutils.token"); - RuntimeCache.CurrentHomeserver = await localStorage.GetItemAsync<string>("rory.matrixroomutils.current_homeserver"); + // RuntimeCache.AccessToken = await localStorage.GetItemAsync<string>("rory.matrixroomutils.token"); + RuntimeCache.LastUsedToken = await localStorage.GetItemAsync<string>("rory.matrixroomutils.last_used_token"); + // RuntimeCache.CurrentHomeserver = await localStorage.GetItemAsync<string>("rory.matrixroomutils.current_homeserver"); RuntimeCache.LoginSessions = await localStorage.GetItemAsync<Dictionary<string, UserInfo>>("rory.matrixroomutils.user_cache") ?? new(); RuntimeCache.HomeserverResolutionCache = await localStorage.GetItemAsync<Dictionary<string, HomeServerResolutionResult>>("rory.matrixroomutils.homeserver_resolution_cache") ?? new(); Console.WriteLine($"[LocalStorageWrapper] Loaded {RuntimeCache.LoginSessions.Count} login sessions, {RuntimeCache.HomeserverResolutionCache.Count} homeserver resolution cache entries"); - if (RuntimeCache.AccessToken != null && RuntimeCache.CurrentHomeserver != null) + if (RuntimeCache.LastUsedToken != null) { - Console.WriteLine($"Access token and current homeserver are not null, creating authenticated home server"); - RuntimeCache.CurrentHomeServer = new AuthenticatedHomeServer(RuntimeCache.LoginSessions[RuntimeCache.AccessToken].LoginResponse.UserId, RuntimeCache.AccessToken, RuntimeCache.LoginSessions[RuntimeCache.AccessToken].LoginResponse.HomeServer); + Console.WriteLine($"Access token is not null, creating authenticated home server"); + Console.WriteLine($"Homeserver cache: {RuntimeCache.HomeserverResolutionCache.Count} entries"); + 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"); } RuntimeCache.WasLoaded = true; @@ -28,9 +33,10 @@ public partial class LocalStorageWrapper public static async Task SaveToLocalStorage(ILocalStorageService localStorage) { - await localStorage.SetItemAsStringAsync("rory.matrixroomutils.token", RuntimeCache.AccessToken); - await localStorage.SetItemAsync("rory.matrixroomutils.current_homeserver", RuntimeCache.CurrentHomeserver); - await localStorage.SetItemAsync("rory.matrixroomutils.user_cache", RuntimeCache.LoginSessions); + // if(RuntimeCache.AccessToken != null) await localStorage.SetItemAsStringAsync("rory.matrixroomutils.token", RuntimeCache.AccessToken); + // if(RuntimeCache.CurrentHomeserver != null) await localStorage.SetItemAsync("rory.matrixroomutils.current_homeserver", RuntimeCache.CurrentHomeserver); + if(RuntimeCache.LoginSessions != null) await localStorage.SetItemAsync("rory.matrixroomutils.user_cache", RuntimeCache.LoginSessions); + if(RuntimeCache.LastUsedToken != null) await localStorage.SetItemAsync("rory.matrixroomutils.last_used_token", RuntimeCache.LastUsedToken); await localStorage.SetItemAsync("rory.matrixroomutils.homeserver_resolution_cache", RuntimeCache.HomeserverResolutionCache.DistinctBy(x => x.Key) .ToDictionary(x => x.Key, x => x.Value)); diff --git a/MatrixRoomUtils.Web/Pages/DataExportPage.razor b/MatrixRoomUtils.Web/Pages/DataExportPage.razor @@ -1,7 +1,8 @@ @page "/export" @using MatrixRoomUtils.Web.Shared.IndexComponents -@using MatrixRoomUtils.Authentication @using System.Text.Json +@using MatrixRoomUtils.Core +@using MatrixRoomUtils.Core.Authentication @inject NavigationManager NavigationManager @inject ILocalStorageService LocalStorage @@ -57,7 +58,7 @@ else resolvedHomeservers++; continue; } - var resolvedHomeserver = await MatrixAuth.ResolveHomeserverFromWellKnown(hs); + var resolvedHomeserver = (await new RemoteHomeServer(hs).Configure()).FullHomeServerDomain; RuntimeCache.HomeserverResolutionCache.Add(hs, new() { Result = resolvedHomeserver, ResolutionTime = DateTime.Now }); await LocalStorageWrapper.SaveToLocalStorage(LocalStorage); diff --git a/MatrixRoomUtils.Web/Pages/Index.razor b/MatrixRoomUtils.Web/Pages/Index.razor @@ -1,6 +1,7 @@ - @page "/" - @using MatrixRoomUtils.Web.Shared.IndexComponents - @inject NavigationManager NavigationManager +@page "/" +@using MatrixRoomUtils.Web.Shared.IndexComponents +@using MatrixRoomUtils.Core +@inject NavigationManager NavigationManager @inject ILocalStorageService LocalStorage <PageTitle>Index</PageTitle> @@ -11,20 +12,23 @@ Small collection of tools to do not-so-everyday things. <br/><br/> <h5>Signed in accounts - <a href="/Login">Add new account</a> or <a href="/ImportUsers">Import from TSV</a></h5> <hr/> -@{ - if (!RuntimeCache.WasLoaded) - { - Console.WriteLine("[INDEX] !!! LOCALSTORAGE WAS NOT LOADED !!!"); - LocalStorageWrapper.LoadFromLocalStorage(LocalStorage).GetAwaiter().OnCompleted(() => - { - Console.WriteLine("Users in cache: " + RuntimeCache .LoginSessions.Count); - StateHasChanged(); - }); - } -} <form> @foreach (var (token, user) in RuntimeCache.LoginSessions) { <IndexUserItem User="@user"/> } -</form> -\ No newline at end of file +</form> + +@code +{ + protected override async Task OnInitializedAsync() + { + if (!RuntimeCache.WasLoaded) + { + Console.WriteLine("[INDEX] !!! LOCALSTORAGE WAS NOT LOADED !!!"); + await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); + } + await base.OnInitializedAsync(); + await LocalStorageWrapper.ReloadLocalStorage(LocalStorage); + } +} +\ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/LoginPage.razor b/MatrixRoomUtils.Web/Pages/LoginPage.razor @@ -1,5 +1,6 @@ @page "/Login" -@using MatrixRoomUtils.Authentication +@using MatrixRoomUtils.Core +@using MatrixRoomUtils.Core.Authentication @inject ILocalStorageService LocalStorage <h3>Login</h3> @@ -27,17 +28,14 @@ var result = await MatrixAuth.Login(homeserver, username, password); Console.WriteLine($"Obtained access token for {result.UserId}!"); - RuntimeCache.AccessToken = result.AccessToken; + RuntimeCache.LastUsedToken = result.AccessToken; var userinfo = new UserInfo() { LoginResponse = result, - AccessToken = result.AccessToken, - Profile = await MatrixAuth.GetProfile(result.HomeServer, result.UserId) + Profile = await (await new RemoteHomeServer(result.HomeServer).Configure()).GetProfile(result.UserId) }; - //TODO: refactor RuntimeCache.LoginSessions.Add(userinfo.AccessToken, userinfo); - RuntimeCache.CurrentHomeserver = await MatrixAuth.ResolveHomeserverFromWellKnown(result.HomeServer); await LocalStorageWrapper.SaveToLocalStorage(LocalStorage); } diff --git a/MatrixRoomUtils.Web/Pages/PolicyListEditorPage.razor b/MatrixRoomUtils.Web/Pages/PolicyListEditorPage.razor @@ -1,8 +1,9 @@ @page "/PolicyListEditor/{RoomId}" @using System.Net.Http.Headers @using System.Text.Json -@using MatrixRoomUtils.Extensions -@using MatrixRoomUtils.StateEventTypes +@using MatrixRoomUtils.Core +@using MatrixRoomUtils.Core.Extensions +@using MatrixRoomUtils.Core.StateEventTypes @inject ILocalStorageService LocalStorage @inject NavigationManager NavigationManager <h3>Policy list editor</h3> diff --git a/MatrixRoomUtils.Web/Pages/PolicyListRoomList.razor b/MatrixRoomUtils.Web/Pages/PolicyListRoomList.razor @@ -1,7 +1,8 @@ @page "/PolicyListEditor" @using System.Net.Http.Headers @using System.Text.Json -@using MatrixRoomUtils.Extensions +@using MatrixRoomUtils.Core +@using MatrixRoomUtils.Core.Extensions @inject ILocalStorageService LocalStorage @inject NavigationManager NavigationManager <h3>Policy list editor</h3> @@ -44,7 +45,7 @@ else { if (!RuntimeCache.WasLoaded) await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); await base.OnInitializedAsync(); - if (RuntimeCache.CurrentHomeServer != null) + if (RuntimeCache.CurrentHomeServer == null) { NavigationManager.NavigateTo("/Login"); return; @@ -70,7 +71,7 @@ else Console.WriteLine($"Detected policy lists: {PolicyRoomList.ToJson()}"); return; - /* + /* using HttpClient wc = new(); wc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", LocalStorageWrapper.AccessToken); @@ -114,53 +115,28 @@ else { try { - //TODO: refactor!!!!! + //TODO: refactor!!!!! await semaphore.WaitAsync(); PolicyRoomInfo roomInfo = new() { RoomId = room }; - using HttpClient wc = new(); - wc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeCache.AccessToken); - var sk = await wc.GetAsync($"{RuntimeCache.CurrentHomeserver}/_matrix/client/v3/rooms/{room}/state/org.matrix.mjolnir.shortcode"); - if (sk.IsSuccessStatusCode) - { - var sko = await sk.Content.ReadFromJsonAsync<JsonElement>(); - if (sko.TryGetProperty("shortcode", out JsonElement shortcode)) - { - Console.WriteLine($"Room {room} has a shortcode: {shortcode.GetString()}!"); - roomInfo.Shortcode = shortcode.GetString(); - // sk = await wc.GetAsync($"{LocalStorageWrapper.CurrentHomeserver}/_matrix/client/v3/rooms/{room}/state/m.room.name"); - // if (sk.IsSuccessStatusCode) - // { - // Console.WriteLine($"Got content: {await sk.Content.ReadAsStringAsync()}"); - // sko = await sk.Content.ReadFromJsonAsync<JsonElement>(); - // if (sko.TryGetProperty("name", out JsonElement roomname)) - // { - // Console.WriteLine($"Room {room} has a name: {roomname.GetString()}!"); - // roomInfo.Name = roomname.GetString(); - // } - // else Console.WriteLine("No record found..."); - // } - // else if (sk.StatusCode == System.Net.HttpStatusCode.NotFound) - // { - // } - // else Console.WriteLine($"Got failure while checking {room}: {sk.StatusCode} ({await sk.Content.ReadAsStringAsync()})..."); - var r = await RuntimeCache.CurrentHomeServer.GetRoom(room); - roomInfo.Shortcode = (await r.GetStateAsync("org.matrix.mjolnir.shortcode")).Value.GetProperty("shortcode").GetString(); - roomInfo.Name = await r.GetNameAsync(); - return roomInfo; - } - else Console.WriteLine("No record found..."); - } - else if (sk.StatusCode == System.Net.HttpStatusCode.NotFound) + + + // --- // + var r = await RuntimeCache.CurrentHomeServer.GetRoom(room); + roomInfo.Shortcode = (await r.GetStateAsync("org.matrix.mjolnir.shortcode")).Value.GetProperty("shortcode").GetString(); + + if (roomInfo.Shortcode != null) { + roomInfo.Name = await r.GetNameAsync(); + return roomInfo; } - else Console.WriteLine($"Got failure while checking {room}: {sk.StatusCode} ({await sk.Content.ReadAsStringAsync()})..."); - + return null; } finally + { checkedRoomCount++; StateHasChanged(); @@ -169,9 +145,15 @@ else } public struct PolicyRoomInfo + { - public string RoomId { get; set; } - public string? Shortcode { get; set; } - public string? Name { get; set; } + public + string RoomId { get; set; } + + public + string? Shortcode { get; set; } + + public + string? Name { get; set; } } } \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/RoomStateEditorPage.razor b/MatrixRoomUtils.Web/Pages/RoomStateEditorPage.razor @@ -1,6 +1,7 @@ @page "/RoomStateViewer/{RoomId}/Edit" @using System.Net.Http.Headers @using System.Text.Json +@using MatrixRoomUtils.Core @inject ILocalStorageService LocalStorage @inject NavigationManager NavigationManager <h3>Room state editor</h3> @@ -65,8 +66,9 @@ { int StateLoaded = 0; using var client = new HttpClient(); - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeCache.AccessToken); - var response = await client.GetAsync($"{RuntimeCache.CurrentHomeserver}/_matrix/client/r0/rooms/{RoomId}/state"); + //TODO: can this be improved? + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeCache.CurrentHomeServer.AccessToken); + var response = await client.GetAsync($"{RuntimeCache.CurrentHomeServer.FullHomeServerDomain}/_matrix/client/r0/rooms/{RoomId}/state"); // var response = await client.GetAsync($"http://localhost:5117/matrix-hq-state.json"); //var _events = await response.Content.ReadFromJsonAsync<Queue<StateEventStruct>>(); var _data = await response.Content.ReadAsStreamAsync(); diff --git a/MatrixRoomUtils.Web/Pages/RoomStateRoomList.razor b/MatrixRoomUtils.Web/Pages/RoomStateRoomList.razor @@ -1,6 +1,7 @@ @page "/RoomStateViewer" @using System.Net.Http.Headers @using System.Text.Json +@using MatrixRoomUtils.Core @inject ILocalStorageService LocalStorage @inject NavigationManager NavigationManager <h3>Room state viewer</h3> @@ -50,26 +51,9 @@ else private async Task EnumeratePolicyRooms() { - using HttpClient wc = new(); - wc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeCache.AccessToken); + var rooms = (await RuntimeCache.CurrentHomeServer.GetJoinedRooms()).Select(x=>x.RoomId).ToList(); - //get room list - //temporary hack until rooms get enumerated... - string[] rooms = { "!fTjMjIzNKEsFlUIiru:neko.dev" }; - var _rooms = await wc.GetAsync($"{RuntimeCache.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; + totalRoomCount = rooms.Count; StateHasChanged(); var semaphore = new SemaphoreSlim(128); @@ -89,29 +73,11 @@ else try { await semaphore.WaitAsync(); - var roomInfo = new PolicyRoomInfo() + return new PolicyRoomInfo() { - RoomId = room + RoomId = room, + Name = await (await RuntimeCache.CurrentHomeServer.GetRoom(room)).GetNameAsync() }; - using HttpClient wc = new(); - wc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeCache.AccessToken); - var sk = await wc.GetAsync($"{RuntimeCache.CurrentHomeserver}/_matrix/client/v3/rooms/{room}/state/m.room.name"); - if (sk.IsSuccessStatusCode) - { - Console.WriteLine($"Got content: {await sk.Content.ReadAsStringAsync()}"); - var sko = await sk.Content.ReadFromJsonAsync<JsonElement>(); - if (sko.TryGetProperty("name", out JsonElement shortcode)) - { - Console.WriteLine($"Room {room} has a name: {shortcode.GetString()}!"); - roomInfo.Name = shortcode.GetString(); - } - else Console.WriteLine("No record found..."); - } - else if (sk.StatusCode == System.Net.HttpStatusCode.NotFound) - { - } - else Console.WriteLine($"Got failure while checking {room}: {sk.StatusCode} ({await sk.Content.ReadAsStringAsync()})..."); - return roomInfo; } finally { diff --git a/MatrixRoomUtils.Web/Pages/RoomStateViewerPage.razor b/MatrixRoomUtils.Web/Pages/RoomStateViewerPage.razor @@ -1,7 +1,8 @@ @page "/RoomStateViewer/{RoomId}" @using System.Net.Http.Headers @using System.Text.Json -@using MatrixRoomUtils.Extensions +@using MatrixRoomUtils.Core +@using MatrixRoomUtils.Core.Extensions @inject ILocalStorageService LocalStorage @inject NavigationManager NavigationManager <h3>Room state viewer</h3> @@ -76,7 +77,7 @@ { if (!RuntimeCache.WasLoaded) await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); await base.OnInitializedAsync(); - if (RuntimeCache.AccessToken == null || RuntimeCache.CurrentHomeserver == null) + if (RuntimeCache.CurrentHomeServer == null) { NavigationManager.NavigateTo("/Login"); return; @@ -90,9 +91,10 @@ private async Task LoadStatesAsync() { int StateLoaded = 0; + //TODO: can we improve this? using var client = new HttpClient(); - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeCache.AccessToken); - var response = await client.GetAsync($"{RuntimeCache.CurrentHomeserver}/_matrix/client/r0/rooms/{RoomId}/state"); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeCache.CurrentHomeServer.AccessToken); + var response = await client.GetAsync($"{RuntimeCache.CurrentHomeServer.FullHomeServerDomain}/_matrix/client/r0/rooms/{RoomId}/state"); // var response = await client.GetAsync($"http://localhost:5117/matrix-hq-state.json"); //var _events = await response.Content.ReadFromJsonAsync<Queue<StateEventStruct>>(); var _data = await response.Content.ReadAsStreamAsync(); diff --git a/MatrixRoomUtils.Web/Pages/UserImportPage.razor b/MatrixRoomUtils.Web/Pages/UserImportPage.razor @@ -1,10 +1,11 @@ @page "/ImportUsers" -@using MatrixRoomUtils.Authentication @using System.Text.Json +@using MatrixRoomUtils.Core +@using MatrixRoomUtils.Core.Authentication @inject ILocalStorageService LocalStorage <h3>Login</h3> -<InputFile OnChange="@FileChanged"></InputFile> +<InputFile OnChange="@FileChanged" accept=".tsv"></InputFile> <br/> <button @onclick="Login">Login</button> <br/><br/> @@ -13,7 +14,7 @@ <table border="1"> @foreach (var (homeserver, username, password) in records) { - <tr style="background-color: @(LocalStorageWrapper.LoginSessions.Any(x => x.Value.LoginResponse.UserId == $"@{username}:{homeserver}") ? "green" : "unset")"> + <tr style="background-color: @(RuntimeCache.LoginSessions.Any(x => x.Value.LoginResponse.UserId == $"@{username}:{homeserver}") ? "green" : "unset")"> <td style="border-width: 1px;">@username</td> <td style="border-width: 1px;">@homeserver</td> <td style="border-width: 1px;">@password.Length chars</td> @@ -31,7 +32,7 @@ { foreach (var (homeserver, username, password) in records) { - if(LocalStorageWrapper.LoginSessions.Any(x => x.Value.LoginResponse.UserId == $"@{username}:{homeserver}")) continue; + if(RuntimeCache.LoginSessions.Any(x => x.Value.LoginResponse.UserId == $"@{username}:{homeserver}")) continue; var result = await MatrixAuth.Login(homeserver, username, password); Console.WriteLine($"Obtained access token for {result.UserId}!"); @@ -40,8 +41,9 @@ LoginResponse = result }; userinfo.Profile = await MatrixAuth.GetProfile(result.HomeServer, result.UserId); + RuntimeCache.LastUsedToken = result.AccessToken; - LocalStorageWrapper.LoginSessions.Add(result.AccessToken, userinfo); + RuntimeCache.LoginSessions.Add(result.AccessToken, userinfo); StateHasChanged(); } diff --git a/MatrixRoomUtils.Web/Program.cs b/MatrixRoomUtils.Web/Program.cs @@ -1,7 +1,6 @@ using System.Text.Json; using System.Text.Json.Serialization; using Blazored.LocalStorage;using MatrixRoomUtils; -using MatrixRoomUtils.StateEventTypes; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using MatrixRoomUtils.Web; diff --git a/MatrixRoomUtils.Web/Shared/IndexComponents/IndexUserItem.razor b/MatrixRoomUtils.Web/Shared/IndexComponents/IndexUserItem.razor @@ -1,44 +1,45 @@ -@using MatrixRoomUtils.Authentication @using MatrixRoomUtils.Web.Classes @using System.Text.Json @using Blazored.LocalStorage -@using MatrixRoomUtils.Extensions +@using MatrixRoomUtils.Core +@using MatrixRoomUtils.Core.Extensions @using Index = MatrixRoomUtils.Web.Pages.Index +@using System.ComponentModel.DataAnnotations @inject ILocalStorageService LocalStorage @inject NavigationManager NavigationManager <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.AccessToken == User.AccessToken)" onclick="@SetCurrent" style="text-decoration-line: unset;"/> <b>@User.Profile.DisplayName</b> on <b>@User.LoginResponse.HomeServer</b></span> + <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> </div> @code { + [Parameter] - public UserInfo User { get; set; } + public UserInfo User { get; set; } = null!; private string _avatarUrl { get; set; } - private bool _removed { get; set; } = false; protected override async Task OnInitializedAsync() { - if(User.Profile.AvatarUrl != null && User.Profile.AvatarUrl != "") - _avatarUrl = await User.Profile.AvatarUrl.GetMediaUrl(); + 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); else _avatarUrl = "https://api.dicebear.com/6.x/identicon/svg?seed=" + User.LoginResponse.UserId; await base.OnInitializedAsync(); } private async Task RemoveUser() { + Console.WriteLine(User.ToJson()); RuntimeCache.LoginSessions.Remove(User.AccessToken); await LocalStorageWrapper.ReloadLocalStorage(LocalStorage); - _removed = true; StateHasChanged(); } private async Task SetCurrent() { - RuntimeCache.AccessToken = User.AccessToken; + RuntimeCache.LastUsedToken = User.AccessToken; //RuntimeCache.CurrentHomeserver = await MatrixAuth.ResolveHomeserverFromWellKnown(LocalStorageWrapper.LoginSessions[Token].LoginResponse.HomeServer); await LocalStorageWrapper.ReloadLocalStorage(LocalStorage); diff --git a/MatrixRoomUtils.Web/Shared/LogView.razor b/MatrixRoomUtils.Web/Shared/LogView.razor @@ -1,15 +1,15 @@ @using System.Text <u>Logs</u><br/> <pre> - @sb + @_stringBuilder </pre> @code { - StringBuilder sb = new(); + StringBuilder _stringBuilder = new(); protected override void OnInitialized() { //intecept stdout with textwriter to get logs - var sw = new StringWriter(sb); + var sw = new StringWriter(_stringBuilder); Console.SetOut(sw); Console.SetError(sw); //keep updated @@ -19,12 +19,13 @@ while (true) { await Task.Delay(100); - if (sb.Length != length) + if (_stringBuilder.Length != length) { StateHasChanged(); - length = sb.Length; + length = _stringBuilder.Length; } } + // ReSharper disable once FunctionNeverReturns - This is intentional behavior }); base.OnInitialized(); } diff --git a/MatrixRoomUtils.Web/Shared/MainLayout.razor b/MatrixRoomUtils.Web/Shared/MainLayout.razor @@ -1,6 +1,4 @@ @inherits LayoutComponentBase -@inject ILocalStorageService LocalStorage -@inject NavigationManager NavigationManager <div class="page"> <div class="sidebar"> @@ -9,7 +7,8 @@ <main> <div class="top-row px-4"> - <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a> + <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> </div> <article class="content px-4"> diff --git a/MatrixRoomUtils.Web/_Imports.razor b/MatrixRoomUtils.Web/_Imports.razor @@ -1,6 +1,7 @@ @using System.Net.Http @using System.Net.Http.Json @using Blazored.LocalStorage +@using MatrixRoomUtils.Core @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web @@ -12,6 +13,7 @@ @using MatrixRoomUtils.Web.Shared @inject ILocalStorageService LocalStorage +@inject NavigationManager NavigationManager @code {