From 3ef3e5caa65458e595e2303358322626c7da1dda Mon Sep 17 00:00:00 2001 From: TheArcaneBrony Date: Tue, 23 May 2023 08:51:02 +0200 Subject: Add numerous new things --- MatrixRoomUtils.Core/AuthenticatedHomeServer.cs | 26 ++++- MatrixRoomUtils.Core/Interfaces/IHomeServer.cs | 17 +++ MatrixRoomUtils.Core/RemoteHomeServer.cs | 3 +- MatrixRoomUtils.Core/Room.cs | 70 ++++++++---- MatrixRoomUtils.Core/RuntimeCache.cs | 45 +++++--- MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs | 16 ++- MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj | 4 + MatrixRoomUtils.Web/Pages/About.razor | 1 - MatrixRoomUtils.Web/Pages/DevOptions.razor | 57 +++++++++- MatrixRoomUtils.Web/Pages/HSAdmin/HSAdmin.razor | 7 ++ .../Pages/KnownHomeserverList.razor | 79 ++++++++++++++ MatrixRoomUtils.Web/Pages/MediaLocator.razor | 119 ++++++++++++++++++--- .../Pages/PolicyList/PolicyListEditorPage.razor | 3 +- .../Pages/PolicyList/PolicyListRoomList.razor | 13 +-- MatrixRoomUtils.Web/Pages/RoomManager.razor | 40 ------- .../Pages/RoomManager/RoomManager.razor | 96 +++++++++++++++++ .../Pages/RoomManager/RoomManagerSpace.razor | 77 +++++++++++++ MatrixRoomUtils.Web/Properties/launchSettings.json | 4 +- .../Shared/IndexComponents/IndexUserItem.razor | 24 +++-- MatrixRoomUtils.Web/Shared/LogView.razor | 26 +++-- MatrixRoomUtils.Web/Shared/MainLayout.razor | 14 ++- MatrixRoomUtils.Web/Shared/NavMenu.razor | 9 +- MatrixRoomUtils.Web/Shared/PortableDevTools.razor | 31 ++++++ MatrixRoomUtils.Web/Shared/RoomListItem.razor | 33 ++++-- deploy.sh | 2 +- 25 files changed, 680 insertions(+), 136 deletions(-) create mode 100644 MatrixRoomUtils.Web/Pages/HSAdmin/HSAdmin.razor create mode 100644 MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor delete mode 100644 MatrixRoomUtils.Web/Pages/RoomManager.razor create mode 100644 MatrixRoomUtils.Web/Pages/RoomManager/RoomManager.razor create mode 100644 MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerSpace.razor create mode 100644 MatrixRoomUtils.Web/Shared/PortableDevTools.razor diff --git a/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs b/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs index 6f5df39..7a1f5de 100644 --- a/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs +++ b/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs @@ -9,12 +9,14 @@ public class AuthenticatedHomeServer : IHomeServer { public string UserId { get; set; } public string AccessToken { get; set; } + public readonly HomeserverAdminApi Admin; public AuthenticatedHomeServer(string userId, string accessToken, string canonicalHomeServerDomain) { UserId = userId; AccessToken = accessToken; HomeServerDomain = canonicalHomeServerDomain; + Admin = new HomeserverAdminApi(this); _httpClient = new HttpClient(); } @@ -56,9 +58,25 @@ public class AuthenticatedHomeServer : IHomeServer return rooms; } - - public async Task ResolveMediaUri(string mxc) + + + + + + public class HomeserverAdminApi { - return mxc.Replace("mxc://", $"{FullHomeServerDomain}/_matrix/media/r0/download/"); + private readonly AuthenticatedHomeServer _authenticatedHomeServer; + + public HomeserverAdminApi(AuthenticatedHomeServer authenticatedHomeServer) + { + _authenticatedHomeServer = authenticatedHomeServer; + } + + + + + + + } -} \ No newline at end of file +} diff --git a/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs b/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs index c6d788c..8fb8b2c 100644 --- a/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs +++ b/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs @@ -15,6 +15,18 @@ public class IHomeServer public async Task ResolveHomeserverFromWellKnown(string homeserver) { + var res = await _resolveHomeserverFromWellKnown(homeserver); + if(!res.StartsWith("http")) res = "https://" + res; + if(res.EndsWith(":443")) res = res.Substring(0, res.Length - 4); + return res; + } + private async Task _resolveHomeserverFromWellKnown(string homeserver) + { + if (RuntimeCache.HomeserverResolutionCache.Count == 0) + { + Console.WriteLine("No cached homeservers, resolving..."); + await Task.Delay(Random.Shared.Next(1000, 5000)); + } if (RuntimeCache.HomeserverResolutionCache.ContainsKey(homeserver)) { if (RuntimeCache.HomeserverResolutionCache[homeserver].ResolutionTime < DateTime.Now.AddHours(1)) @@ -22,6 +34,7 @@ public class IHomeServer Console.WriteLine($"Found cached homeserver: {RuntimeCache.HomeserverResolutionCache[homeserver].Result}"); return RuntimeCache.HomeserverResolutionCache[homeserver].Result; } + Console.WriteLine($"Cached homeserver expired, removing: {RuntimeCache.HomeserverResolutionCache[homeserver].Result}"); RuntimeCache.HomeserverResolutionCache.Remove(homeserver); } //throw new NotImplementedException(); @@ -95,4 +108,8 @@ public class IHomeServer _profileCache[mxid] = profile; return profile; } + public async Task ResolveMediaUri(string mxc) + { + return mxc.Replace("mxc://", $"{FullHomeServerDomain}/_matrix/media/r0/download/"); + } } \ No newline at end of file diff --git a/MatrixRoomUtils.Core/RemoteHomeServer.cs b/MatrixRoomUtils.Core/RemoteHomeServer.cs index 9c096c8..942f873 100644 --- a/MatrixRoomUtils.Core/RemoteHomeServer.cs +++ b/MatrixRoomUtils.Core/RemoteHomeServer.cs @@ -1,7 +1,6 @@ using System.Net.Http.Json; using System.Text.Json; using MatrixRoomUtils.Core.Interfaces; -using MatrixRoomUtils.Core.Responses; namespace MatrixRoomUtils.Core; @@ -13,12 +12,14 @@ public class RemoteHomeServer : IHomeServer { HomeServerDomain = canonicalHomeServerDomain; _httpClient = new HttpClient(); + _httpClient.Timeout = TimeSpan.FromSeconds(5); } public async Task Configure() { FullHomeServerDomain = await ResolveHomeserverFromWellKnown(HomeServerDomain); _httpClient.Dispose(); _httpClient = new HttpClient { BaseAddress = new Uri(FullHomeServerDomain) }; + _httpClient.Timeout = TimeSpan.FromSeconds(5); Console.WriteLine("[RHS] Finished setting up http client"); return this; diff --git a/MatrixRoomUtils.Core/Room.cs b/MatrixRoomUtils.Core/Room.cs index 64db03d..6798d5b 100644 --- a/MatrixRoomUtils.Core/Room.cs +++ b/MatrixRoomUtils.Core/Room.cs @@ -1,10 +1,13 @@ using System.Net.Http.Json; using System.Text.Json; +using System.Web; namespace MatrixRoomUtils.Core; public class Room { + private static SemaphoreSlim _semaphore = new SemaphoreSlim(16, 16); + private readonly HttpClient _httpClient; public string RoomId { get; set; } @@ -13,31 +16,34 @@ public class Room _httpClient = httpClient; RoomId = roomId; } - - public async Task GetStateAsync(string type, string state_key="", bool logOnFailure = false) + + public async Task GetStateAsync(string type, string state_key = "", bool logOnFailure = false) { + await _semaphore.WaitAsync(); var url = $"/_matrix/client/v3/rooms/{RoomId}/state"; if (!string.IsNullOrEmpty(state_key)) url += $"/{type}/{state_key}"; else if (!string.IsNullOrEmpty(type)) url += $"/{type}"; - var cache_key = "room_states_"+type; + var cache_key = "room_states:" + type; if (!RuntimeCache.GenericResponseCache.ContainsKey(cache_key)) { Console.WriteLine($"[!!] No cache for {cache_key}, creating..."); - RuntimeCache.GenericResponseCache.Add(cache_key, new ObjectCache() - { - DefaultExpiry = type switch - { - "m.room.name" => TimeSpan.FromMinutes(15), - _ => TimeSpan.FromMinutes(5) - } - }); + RuntimeCache.GenericResponseCache.Add(cache_key, new ObjectCache()); } - if (RuntimeCache.GenericResponseCache[cache_key][url] != null) + RuntimeCache.GenericResponseCache[cache_key].DefaultExpiry = type switch + { + "m.room.name" => TimeSpan.FromMinutes(30), + "org.matrix.mjolnir.shortcode" => TimeSpan.FromHours(4), + "" => TimeSpan.FromSeconds(0), + _ => TimeSpan.FromMinutes(15) + }; + + if (RuntimeCache.GenericResponseCache[cache_key].Cache.ContainsKey(url) && RuntimeCache.GenericResponseCache[cache_key][url] != null) { - if(RuntimeCache.GenericResponseCache[cache_key][url].ExpiryTime > DateTime.Now) + if (RuntimeCache.GenericResponseCache[cache_key][url].ExpiryTime > DateTime.Now) { // Console.WriteLine($"[:3] Found cached state: {RuntimeCache.GenericResponseCache[cache_key][url].Result}"); + _semaphore.Release(); return (JsonElement?)RuntimeCache.GenericResponseCache[cache_key][url].Result; } else @@ -45,35 +51,55 @@ public class Room Console.WriteLine($"[!!] Cached state expired at {RuntimeCache.GenericResponseCache[cache_key][url].ExpiryTime}: {RuntimeCache.GenericResponseCache[cache_key][url].Result}"); } } - else - { - Console.WriteLine($"[!!] No cached state for {url}"); - } + // else + // { + // Console.WriteLine($"[!!] No cached state for {url}"); + // } var res = await _httpClient.GetAsync(url); if (!res.IsSuccessStatusCode) { - if(logOnFailure) Console.WriteLine($"{RoomId}/{state_key}/{type} - got status: {res.StatusCode}"); + if (logOnFailure) Console.WriteLine($"{RoomId}/{state_key}/{type} - got status: {res.StatusCode}"); + _semaphore.Release(); return null; } + var result = await res.Content.ReadFromJsonAsync(); + + if (!RuntimeCache.GenericResponseCache.ContainsKey(cache_key) && type != "") + { + Console.WriteLine($"[!!] No cache for {cache_key}, creating..."); + RuntimeCache.GenericResponseCache.Add(cache_key, new ObjectCache()); + } + RuntimeCache.GenericResponseCache[cache_key][url] = new GenericResult() { Result = result }; + _semaphore.Release(); return result; } - public async Task GetNameAsync() + + public async Task GetNameAsync() { var res = await GetStateAsync("m.room.name"); if (!res.HasValue) { Console.WriteLine($"Room {RoomId} has no name!"); - return null; + return RoomId; } - var resn = res?.TryGetProperty("name", out var name) ?? false ? name.GetString() : null; + + var resn = res?.TryGetProperty("name", out var name) ?? false ? name.GetString() ?? RoomId : RoomId; //Console.WriteLine($"Got name: {resn}"); return resn; } - + + public async Task JoinAsync(string[]? homeservers = null) + { + string join_url = $"/_matrix/client/r0/join/{HttpUtility.UrlEncode(RoomId)}"; + Console.WriteLine($"Calling {join_url} with {(homeservers == null ? 0 : homeservers.Length)} via's..."); + if(homeservers == null || homeservers.Length == 0) homeservers = new[] { RoomId.Split(':')[1] }; + var full_join_url = $"{join_url}?server_name=" + string.Join("&server_name=", homeservers); + var res = await _httpClient.PostAsync(full_join_url, null); + } } \ No newline at end of file diff --git a/MatrixRoomUtils.Core/RuntimeCache.cs b/MatrixRoomUtils.Core/RuntimeCache.cs index affbd94..4a96f50 100644 --- a/MatrixRoomUtils.Core/RuntimeCache.cs +++ b/MatrixRoomUtils.Core/RuntimeCache.cs @@ -1,6 +1,3 @@ -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.JavaScript; -using System.Xml.Schema; using MatrixRoomUtils.Core.Extensions; using MatrixRoomUtils.Core.Responses; @@ -40,17 +37,6 @@ public class ObjectCache where T : class { get { - if (Random.Shared.Next(100) == 1) - { - // Console.WriteLine("Cleaning cache..."); - // foreach (var x in Cache.Where(x => x.Value.ExpiryTime < DateTime.Now).OrderBy(x => x.Value.ExpiryTime).Take(3).ToList()) - // { - // Console.WriteLine($"Removing {x.Key} from cache"); - // Cache.Remove(x.Key); - // } - } - - if (Cache.ContainsKey(key)) { // Console.WriteLine($"Found item in cache: {key} - {Cache[key].Result.ToJson(indent: false)}"); @@ -67,19 +53,48 @@ public class ObjectCache where T : class Console.WriteLine($"Failed to remove {key} from cache: {e.Message}"); } } + Console.WriteLine($"No item in cache: {key}"); return null; } set { Cache[key] = value; if(Cache[key].ExpiryTime == null) Cache[key].ExpiryTime = DateTime.Now.Add(DefaultExpiry); - Console.WriteLine($"New item in cache: {key} - {Cache[key].Result.ToJson(indent: false)}"); + // Console.WriteLine($"New item in cache: {key} - {Cache[key].Result.ToJson(indent: false)}"); // Console.Error.WriteLine("Full cache: " + Cache.ToJson()); } } + + public ObjectCache() + { + //expiry timer + Task.Run(async () => + { + while (true) + { + await Task.Delay(1000); + foreach (var x in Cache.Where(x => x.Value.ExpiryTime < DateTime.Now).OrderBy(x => x.Value.ExpiryTime).Take(15).ToList()) + { + // Console.WriteLine($"Removing {x.Key} from cache"); + Cache.Remove(x.Key); + } + } + }); + } } public class GenericResult { public T? Result { get; set; } public DateTime? ExpiryTime { get; set; } + + public GenericResult() + { + //expiry timer + + } + public GenericResult(T? result, DateTime? expiryTime = null) : this() + { + Result = result; + ExpiryTime = expiryTime; + } } 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" /> + + + + 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 @@

Rory&::MatrixUtils - Developer options


- +
+
+
+ + +
+
+ View caches +

Generic cache:

+
    + @foreach (var item in RuntimeCache.GenericResponseCache) + { +
  • + @item.Key: @item.Value.Cache.Count entries
    + Default expiry: @item.Value.DefaultExpiry
    + @if (item.Value.Cache.Count > 0) + { +

    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)

    + @*

    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)

    *@ +

    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)

    + } +
  • + } +
+
@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" +

Homeserver Admininistration

+
+ +@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 +

Known Homeserver List

+
+ +@if (!IsFinished) +{ +

Loading... Please wait...

+} +else +{ + @foreach (var server in HomeServers.OrderByDescending(x => x.KnownUserCount).ThenBy(x => x.Server).ToList()) + { +

@server.Server - @server.KnownUserCount

+ } +} +
+ +@code { + List 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> GetHomeservers() + { + List homeServers = new(); + var rooms = await RuntimeCache.CurrentHomeServer.GetJoinedRooms(); + // Dictionary 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>(); + 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 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" -

MediaLocator

+@inject HttpClient Http +

Media locator


+This is going to expose your IP address to all these homeservers! +
+ Checked homeserver list (@homeservers.Count entries) +
    + @foreach (var hs in homeservers) + { +
  • @hs
  • + } +
+
+ +
MXC URL: +@if (successResults.Count > 0) +{ +

Successes

+
    + @foreach (var result in successResults) + { +
  • @result
  • + } +
+} + +@if (errorResults.Count > 0) +{ +

Errors

+
    + @foreach (var result in errorResults) + { +
  • @result
  • + } +
+} + @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 - + + @* *@ } 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) { - [@s.Shortcode] @s.Name (@s.RoomId) -
+ + +
+ Shortcode: @s.Shortcode +
+ @* [@s.Shortcode] @s.Name (@s.RoomId) *@ + @*
*@ } } @@ -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 -

Room manager

-
-@if (Rooms.Count == 0) -{ -

You are not in any rooms!

- @*

Loading progress: @checkedRoomCount/@totalRoomCount

*@ -} -else -{ -
- Room List - @foreach (var room in Rooms) - { - - } -
- -} - -
- - -@code { - public List 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 +

Room manager

+
+@if (Rooms.Count == 0) +{ +

You are not in any rooms!

+ @*

Loading progress: @checkedRoomCount/@totalRoomCount

*@ +} +else +{ +

You are in @Rooms.Count rooms and @Spaces.Count spaces

+
+ Space List + @foreach (var room in Spaces) + { + + } +
+
+ Room List + @foreach (var room in Rooms) + { + + } +
+ +} + +
+ + +@code { + public List Rooms { get; set; } = new(); + public List 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>(); + foreach (var room in Rooms) + { + tasks.Add(CheckIfSpace(room, semaphore)); + } + await Task.WhenAll(tasks); + + Console.WriteLine("Fetched joined rooms!"); + } + + private async Task 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 +

Room manager - Viewing Space

+ + +@foreach (var room in Rooms) +{ + +} + + +
+
+ State list + @foreach (var stateEvent in States.OrderBy(x => x.state_key).ThenBy(x => x.type)) + { +

@stateEvent.state_key/@stateEvent.type:

+
@stateEvent.content.ToJson()
+ } +
+ +@code { + + [Parameter] + public string RoomId { get; set; } = "invalid!!!!!!"; + + private Room? Room { get; set; } + + private StateEvent[] States { get; set; } = Array.Empty>(); + private List 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[]>()!; + + 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 @@
- @User.Profile.DisplayName on @User.LoginResponse.HomeServer - Remove +

+ + @User.Profile.DisplayName on @User.LoginResponse.HomeServer + Remove +

+

Member of @_roomCount rooms

+
@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 -Logs
-
-    @_stringBuilder
-
+@if (LocalStorageWrapper.Settings.DeveloperSettings.EnableLogViewers) +{ + Logs +
+
+        @_stringBuilder
+    
+} @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
@@ -9,6 +8,7 @@
+ Git Matrix @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 @@
+ @* *@