From ede3857084bc7c6e65b7d36cbf913b09596e2787 Mon Sep 17 00:00:00 2001 From: Rory& Date: Mon, 8 Jan 2024 13:55:15 +0100 Subject: Internal changes to policy list viewer (extensibility), fix duplicating change handler for room list page (performance), use /state in room list page before sync --- MatrixRoomUtils.Web/Pages/Dev/DevUtilities.razor | 1 + MatrixRoomUtils.Web/Pages/Index.razor | 89 ++++-- .../ModerationUtilities/UserRoomHistory.razor | 1 + MatrixRoomUtils.Web/Pages/Rooms/Index.razor | 102 ++++--- MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor | 336 ++++++++++++--------- MatrixRoomUtils.Web/Pages/User/DMManager.razor | 2 +- .../Pages/User/DMSpaceStages/DMSpaceStage2.razor | 5 +- .../Pages/User/DMSpaceStages/DMSpaceStage3.razor | 6 +- MatrixRoomUtils.Web/Pages/User/Profile.razor | 78 ++--- 9 files changed, 364 insertions(+), 256 deletions(-) (limited to 'MatrixRoomUtils.Web/Pages') diff --git a/MatrixRoomUtils.Web/Pages/Dev/DevUtilities.razor b/MatrixRoomUtils.Web/Pages/Dev/DevUtilities.razor index 94c51b2..27fe35e 100644 --- a/MatrixRoomUtils.Web/Pages/Dev/DevUtilities.razor +++ b/MatrixRoomUtils.Web/Pages/Dev/DevUtilities.razor @@ -3,6 +3,7 @@ @using ArcaneLibs.Extensions @using LibMatrix.Extensions @using LibMatrix.Homeservers +@using MatrixRoomUtils.Abstractions @inject ILocalStorageService LocalStorage @inject NavigationManager NavigationManager

Debug Tools

diff --git a/MatrixRoomUtils.Web/Pages/Index.razor b/MatrixRoomUtils.Web/Pages/Index.razor index 2d1d6c0..ebb0ebb 100644 --- a/MatrixRoomUtils.Web/Pages/Index.razor +++ b/MatrixRoomUtils.Web/Pages/Index.razor @@ -16,30 +16,29 @@ Small collection of tools to do not-so-everyday things.
- @foreach (var __auth in _auth.OrderByDescending(x => x.UserInfo.RoomCount)) { - var _auth = __auth.UserAuth; + @foreach (var session in _sessions.OrderByDescending(x => x.UserInfo.RoomCount)) { + var _auth = session.UserAuth; - @* *@ }
- + @@ -49,18 +48,46 @@ Small collection of tools to do not-so-everyday things. Log out

+@if (_offlineSessions.Count > 0) { +
+
+
Sessions on unreachable servers
+
+
+ + @foreach (var session in _offlineSessions) { + + + + + } +
+

+ @{ + string[] parts = session.UserId.Split(':'); + } + @parts[0][1..] on @parts[1] + @if (!string.IsNullOrWhiteSpace(session.Proxy)) { + (proxied via @session.Proxy) + } +

+
+ Remove +
+
+} + @code { #if DEBUG - bool DEBUG = true; + private const bool _debug = true; #else - bool DEBUG = false; + private const bool _debug = false; #endif private class AuthInfo { @@ -71,35 +98,42 @@ Small collection of tools to do not-so-everyday things. } // private Dictionary _users = new(); - private List _auth = new(); + private readonly List _sessions = []; + private readonly List _offlineSessions = []; + private LoginResponse? _currentSession; protected override async Task OnInitializedAsync() { + Console.WriteLine("Index.OnInitializedAsync"); _currentSession = await MRUStorage.GetCurrentToken(); - // _users.Clear(); - _auth.Clear(); + _sessions.Clear(); + _offlineSessions.Clear(); var tokens = await MRUStorage.GetAllTokens(); var profileTasks = tokens.Select(async token => { UserInfo userInfo = new(); AuthenticatedHomeserverGeneric hs; + Console.WriteLine($"Getting hs for {token.ToJson()}"); try { hs = await hsProvider.GetAuthenticatedWithToken(token.Homeserver, token.AccessToken, token.Proxy); } catch (MatrixException e) { - if (e.ErrorCode == "M_UNKNOWN_TOKEN") { - NavigationManager.NavigateTo("/InvalidSession?ctx=" + token.AccessToken); - return; - } - throw; + if (e.ErrorCode != "M_UNKNOWN_TOKEN") throw; + NavigationManager.NavigateTo("/InvalidSession?ctx=" + token.AccessToken); + return; + } catch (HttpRequestException e) { logger.LogError(e, $"Failed to instantiate AuthenticatedHomeserver for {token.ToJson()}, homeserver may be offline?", token.UserId); + _offlineSessions.Add(token); return; } + + Console.WriteLine($"Got hs for {token.ToJson()}"); + var roomCountTask = hs.GetJoinedRooms(); var profile = await hs.GetProfileAsync(hs.WhoAmI.UserId); userInfo.DisplayName = profile.DisplayName ?? hs.WhoAmI.UserId; Console.WriteLine(profile.ToJson()); - _auth.Add(new() { + _sessions.Add(new() { UserInfo = new() { AvatarUrl = string.IsNullOrWhiteSpace(profile.AvatarUrl) ? "https://api.dicebear.com/6.x/identicon/svg?seed=" + hs.WhoAmI.UserId : hs.ResolveMediaUri(profile.AvatarUrl), RoomCount = (await roomCountTask).Count, @@ -110,7 +144,9 @@ Small collection of tools to do not-so-everyday things. Homeserver = hs }); }); + Console.WriteLine("Waiting for profile tasks"); await Task.WhenAll(profileTasks); + Console.WriteLine("Done waiting for profile tasks"); await base.OnInitializedAsync(); } @@ -127,19 +163,20 @@ Small collection of tools to do not-so-everyday things. } } catch (Exception e) { - if (e is MatrixException {ErrorCode: "M_UNKNOWN_TOKEN" }) { - //todo: handle this + if (e is MatrixException { ErrorCode: "M_UNKNOWN_TOKEN" }) { + //todo: handle this return; } + Console.WriteLine(e); } + await MRUStorage.RemoveToken(auth); if ((await MRUStorage.GetCurrentToken())?.AccessToken == auth.AccessToken) await MRUStorage.SetCurrentToken((await MRUStorage.GetAllTokens() ?? throw new InvalidOperationException()).FirstOrDefault()); await OnInitializedAsync(); } - private LoginResponse _currentSession; private async Task SwitchSession(UserAuth auth) { Console.WriteLine($"Switching to {auth.Homeserver} {auth.UserId} via {auth.Proxy}"); diff --git a/MatrixRoomUtils.Web/Pages/ModerationUtilities/UserRoomHistory.razor b/MatrixRoomUtils.Web/Pages/ModerationUtilities/UserRoomHistory.razor index d33756b..506a8a1 100644 --- a/MatrixRoomUtils.Web/Pages/ModerationUtilities/UserRoomHistory.razor +++ b/MatrixRoomUtils.Web/Pages/ModerationUtilities/UserRoomHistory.razor @@ -4,6 +4,7 @@ @using LibMatrix.EventTypes.Spec.State @using LibMatrix.RoomTypes @using ArcaneLibs.Extensions +@using MatrixRoomUtils.Abstractions

UserRoomHistory

Enter mxid: diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor index 2ac4bcb..6cabe82 100644 --- a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor +++ b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor @@ -1,25 +1,21 @@ @page "/Rooms" @using LibMatrix.Filters @using LibMatrix.Helpers -@using LibMatrix.EventTypes.Spec.State -@using LibMatrix -@using LibMatrix.Homeservers -@using ArcaneLibs.Extensions @using LibMatrix.Extensions @using LibMatrix.Responses @using System.Collections.ObjectModel @using System.Diagnostics +@using ArcaneLibs.Extensions +@using MatrixRoomUtils.Abstractions @inject ILogger logger

Room list

@Status

@Status2

-@* @if (RenderContents) { *@ + +Create new room + -@* } *@ -@* else { *@ -@* *@ -@* } *@ @code { private ObservableCollection Rooms { get; } = new(); @@ -47,9 +43,9 @@ }, State = new SyncFilter.RoomFilter.StateFilter { Types = new List { + "m.room.create", "m.room.name", "m.room.avatar", - "m.room.create", "org.matrix.mjolnir.shortcode", "m.room.power_levels", } @@ -92,49 +88,72 @@ // } // }; + private SyncHelper syncHelper; + + // SyncHelper profileSyncHelper; + protected override async Task OnInitializedAsync() { Homeserver = await MRUStorage.GetCurrentSessionOrNavigate(); if (Homeserver is null) return; var rooms = await Homeserver.GetJoinedRooms(); - foreach (var room in rooms) { - Rooms.Add(new(){Room = room}); + // SemaphoreSlim _semaphore = new(160, 160); + + var roomTasks = rooms.Select(async room => { + RoomInfo ri; + // await _semaphore.WaitAsync(); + ri = new() { Room = room }; + await Task.WhenAll((filter.Room?.State?.Types ?? []).Select(x => ri.GetStateEvent(x))); + return ri; + }).ToAsyncEnumerable(); + + await foreach (var room in roomTasks) { + Rooms.Add(room); + StateHasChanged(); + // await Task.Delay(50); + // _semaphore.Release(); } - - GlobalProfile = await Homeserver.GetProfileAsync(Homeserver.WhoAmI.UserId); - var syncHelper = new SyncHelper(Homeserver, logger) { - Timeout = 10000, + if (rooms.Count >= 150) RenderContents = true; + + GlobalProfile = await Homeserver.GetProfileAsync(Homeserver.WhoAmI.UserId); + syncHelper = new SyncHelper(Homeserver, logger) { + Timeout = 30000, Filter = filter, MinimumDelay = TimeSpan.FromMilliseconds(5000) }; - // profileUpdateFilter.Room.State.Senders.Add(Homeserver.WhoAmI.UserId); - // var profileSyncHelper = new SyncHelper(Homeserver, logger) { + // profileSyncHelper = new SyncHelper(Homeserver, logger) { // Timeout = 10000, // Filter = profileUpdateFilter, // MinimumDelay = TimeSpan.FromMilliseconds(5000) - // }; + // }; + // profileUpdateFilter.Room.State.Senders.Add(Homeserver.WhoAmI.UserId); + RunSyncLoop(syncHelper); // RunSyncLoop(profileSyncHelper); RunQueueProcessor(); + await base.OnInitializedAsync(); } - + private async Task RunQueueProcessor() { var renderTimeSw = Stopwatch.StartNew(); + var isInitialSync = true; while (true) { try { - if (queue.Count == 0) { - while (queue.Count == 0) { - Console.WriteLine("Queue is empty, waiting..."); - await Task.Delay(2500); - } - Console.WriteLine("Queue no longer empty!"); + while (queue.Count == 0) { + Console.WriteLine("Queue is empty, waiting..."); + await Task.Delay(isInitialSync ? 100 : 2500); } - while (queue.TryDequeue(out var queueEntry)) { + + Console.WriteLine($"Queue no longer empty after {renderTimeSw.Elapsed}!"); + + int maxUpdates = 10; + isInitialSync = false; + while (maxUpdates-- > 0 && queue.TryDequeue(out var queueEntry)) { var (roomId, roomData) = queueEntry; Console.WriteLine($"Dequeued room {roomId}"); RoomInfo room; - + if (Rooms.Any(x => x.Room.RoomId == roomId)) { room = Rooms.First(x => x.Room.RoomId == roomId); Console.WriteLine($"QueueWorker: {roomId} already known with {room.StateEvents?.Count ?? 0} state events"); @@ -146,26 +165,23 @@ }; Rooms.Add(room); } - + if (room.StateEvents is null) { Console.WriteLine($"QueueWorker: {roomId} does not have state events on record?"); throw new InvalidDataException("Somehow this is null???"); } - if (roomData.State?.Events is {Count: >0 }) + + if (roomData.State?.Events is { Count: > 0 }) room.StateEvents.MergeStateEventLists(roomData.State.Events); else { Console.WriteLine($"QueueWorker: could not merge state for {room.Room.RoomId} as new data contains no state events!"); } - if (Random.Shared.Next(101) < 20 || true) { - Status = $"Got {Rooms.Count} rooms so far! {queue.Count} entries in processing queue..."; - } - RenderContents |= queue.Count == 0; - if (queue.Count > 10) RenderContents = false; - await Task.Delay(RenderContents ? 25 : 6); } - // else { - // Console.WriteLine("Failed to dequeue item"); - // } + Console.WriteLine($"QueueWorker: {queue.Count} entries left in queue, {maxUpdates} maxUpdates left, RenderContents: {RenderContents}"); + Status = $"Got {Rooms.Count} rooms so far! {queue.Count} entries in processing queue..."; + + RenderContents |= queue.Count == 0; + await Task.Delay(Rooms.Count); } catch (Exception e) { Console.WriteLine("QueueWorker exception: " + e); @@ -214,11 +230,15 @@ // We can't trust servers to give us what we ask for, and this ruins performance // Thanks, Conduit. joinedRoom.Value.State.Events.RemoveAll(x => filter.Room?.State?.Types?.Contains(x.Type) == false); - if(filter.Room?.State?.NotSenders?.Any() ?? false) + if (filter.Room?.State?.NotSenders?.Any() ?? false) joinedRoom.Value.State.Events.RemoveAll(x => filter.Room?.State?.NotSenders?.Contains(x.Sender) ?? false); - + queue.Enqueue(joinedRoom); } + if (sync.Rooms.Leave is {Count: > 0}) + foreach (var leftRoom in sync.Rooms.Leave) + if (Rooms.Any(x => x.Room.RoomId == leftRoom.Key)) + Rooms.Remove(Rooms.First(x => x.Room.RoomId == leftRoom.Key)); Status = $"Got {Rooms.Count} rooms so far! {queue.Count} entries in processing queue... " + $"{sync?.Rooms?.Join?.Count ?? 0} new updates!"; diff --git a/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor b/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor index 846d1cb..dbe0648 100644 --- a/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor +++ b/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor @@ -4,184 +4,199 @@ @using ArcaneLibs.Extensions @using LibMatrix.EventTypes.Spec.State @using LibMatrix.EventTypes.Spec.State.Policy +@using System.Diagnostics +@using System.Diagnostics.CodeAnalysis +@using LibMatrix.Extensions +@using LibMatrix.Responses

Policy list editor - Editing @RoomId


- This policy list contains @PolicyEvents.Count(x => x.Type == "m.policy.rule.server") server bans, - @PolicyEvents.Count(x => x.Type == "m.policy.rule.room") room bans and - @PolicyEvents.Count(x => x.Type == "m.policy.rule.user") user bans. + This policy list contains @GetPolicyCount(typeof(ServerPolicyRuleEventContent)) server bans, + @GetPolicyCount(typeof(RoomPolicyRuleEventContent)) room bans and + @GetPolicyCount(typeof(UserPolicyRuleEventContent)) user bans. + @foreach (var (key, value) in PolicyEventsByType) { +

@key.Name: @value.Count

+ }

- - + -@if (!PolicyEvents.Any(x => x.Type == "m.policy.rule.server")) { +

Server policies

+
+@if (!GetPolicyEventsByType(typeof(ServerPolicyRuleEventContent)).Any()) {

No server policies

} else { -

Server policies

-
- +
- - - - - - - - - @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.server" && (x.TypedContent as PolicyRuleEventContent).Entity is not null)) { - var policyData = policyEvent.TypedContent as PolicyRuleEventContent; - - - - + + + + - } + + + @foreach (var policyEvent in GetValidPolicyEventsByType(typeof(ServerPolicyRuleEventContent))) { + var policyData = policyEvent.TypedContent as PolicyRuleEventContent; + + + + + + + }
ServerReasonExpiresActions
Entity: @policyData.Entity
State: @policyEvent.StateKey
@policyData.Reason - @policyData.ExpiryDateTime - - - @* *@ - ServerReasonExpiresActions
+ Entity: @policyData.Entity +
State: @policyEvent.StateKey
+
@policyData.Reason + @policyData.ExpiryDateTime + + + @* *@ +
- Redacted events - + Redacted or invalid events +
- - - - - - - @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.server" && (x.TypedContent as PolicyRuleEventContent).Entity == null)) { - var policyData = policyEvent.TypedContent as PolicyRuleEventContent; - - + + - } + + + @foreach (var policyEvent in GetInvalidPolicyEventsByType(typeof(ServerPolicyRuleEventContent))) { + + + + + }
State keySerialised Contents
@policyEvent.StateKey@policyEvent.RawContent.ToJson(false, true)State keySerialised Contents
@policyEvent.StateKey@policyEvent.RawContent.ToJson(false, true)
} -@if (!PolicyEvents.Any(x => x.Type == "m.policy.rule.room")) { +

Room policies

+
+@if (!GetPolicyEventsByType(typeof(RoomPolicyRuleEventContent)).Any()) {

No room policies

} else { -

Room policies

-
- +
- - - - - - - - - @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.room" && (x.TypedContent as PolicyRuleEventContent).Entity is not null)) { - var policyData = policyEvent.TypedContent as PolicyRuleEventContent; - - - - + + + + - } + + + @foreach (var policyEvent in GetValidPolicyEventsByType(typeof(RoomPolicyRuleEventContent))) { + var policyData = policyEvent.TypedContent as PolicyRuleEventContent; + + + + + + + }
RoomReasonExpiresActions
Entity: @policyData.Entity
State: @policyEvent.StateKey
@policyData.Reason - @policyData.ExpiryDateTime - - - RoomReasonExpiresActions
Entity: @policyData.Entity
State: @policyEvent.StateKey
@policyData.Reason + @policyData.ExpiryDateTime + + +
- Redacted events - + Redacted or invalid events +
- - - - - - - @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.room" && (x.TypedContent as PolicyRuleEventContent).Entity == null)) { - - + + - } + + + @foreach (var policyEvent in GetInvalidPolicyEventsByType(typeof(RoomPolicyRuleEventContent))) { + + + + + }
State keySerialised Contents
@policyEvent.StateKey@policyEvent.RawContent!.ToJson(false, true)State keySerialised Contents
@policyEvent.StateKey@policyEvent.RawContent!.ToJson(false, true)
} -@if (!PolicyEvents.Any(x => x.Type == "m.policy.rule.user")) { +

User policies

+
+@if (!GetPolicyEventsByType(typeof(UserPolicyRuleEventContent)).Any()) {

No user policies

} else { -

User policies

-
- +
- - @if (_enableAvatars) { - - } - - - - - - - - @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.user" && (x.TypedContent as PolicyRuleEventContent).Entity is not null)) { - var policyData = policyEvent.TypedContent as PolicyRuleEventContent; - @if (_enableAvatars) { - + @if (EnableAvatars) { + } - - - - + + + + - } + + + @foreach (var policyEvent in GetValidPolicyEventsByType(typeof(UserPolicyRuleEventContent))) { + var policyData = policyEvent.TypedContent as PolicyRuleEventContent; + + @if (EnableAvatars) { + + } + + + + + + }
UserReasonExpiresActions
- - Entity: @string.Join("", policyData.Entity.Take(64))
State: @string.Join("", policyEvent.StateKey.Take(64))
@policyData.Reason - @policyData.ExpiryDateTime - - - UserReasonExpiresActions
+ @if (Avatars.ContainsKey(policyData.Entity)) { + + } + Entity: @string.Join("", policyData.Entity.Take(64))
State: @string.Join("", policyEvent.StateKey.Take(64))
@policyData.Reason + @policyData.ExpiryDateTime + + +
- Redacted events - + Redacted or invalid events +
- - - - - - - @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.user" && (x.TypedContent as PolicyRuleEventContent).Entity == null)) { - - + + - } + + + @foreach (var policyEvent in GetInvalidPolicyEventsByType(typeof(UserPolicyRuleEventContent))) { + + + + + }
State keySerialised Contents
@policyEvent.StateKey@policyEvent.RawContent.ToJson(false, true)State keySerialised Contents
@policyEvent.StateKey@policyEvent.RawContent.ToJson(false, true)
} - - @code { + +#if DEBUG + private const bool Debug = true; +#else + private const bool Debug = false; +#endif + //get room list // - sync withroom list filter // Type = support.feline.msc3784 @@ -192,18 +207,28 @@ else { private bool _enableAvatars; - static readonly Dictionary avatars = new(); - static readonly Dictionary servers = new(); + static readonly Dictionary Avatars = new(); + // static readonly Dictionary Servers = new(); - public static List PolicyEvents { get; set; } = new(); + // private static List PolicyEvents { get; set; } = new(); + private Dictionary> PolicyEventsByType { get; set; } = new(); + + public bool EnableAvatars { + get => _enableAvatars; + set { + _enableAvatars = value; + if (value) GetAllAvatars(); + } + } protected override async Task OnInitializedAsync() { + var sw = Stopwatch.StartNew(); await base.OnInitializedAsync(); var hs = await MRUStorage.GetCurrentSessionOrNavigate(); if (hs is null) return; RoomId = RoomId.Replace('~', '.'); await LoadStatesAsync(); - Console.WriteLine("Policy list editor initialized!"); + Console.WriteLine($"Policy list editor initialized in {sw.Elapsed}!"); } private async Task LoadStatesAsync() { @@ -214,39 +239,52 @@ else { var states = room.GetFullStateAsync(); await foreach (var state in states) { - if (!state.Type.StartsWith("m.policy.rule")) continue; - PolicyEvents.Add(state); + if (state is null) continue; + if (!state.MappedType.IsAssignableTo(typeof(PolicyRuleEventContent))) continue; + if (!PolicyEventsByType.ContainsKey(state.MappedType)) PolicyEventsByType.Add(state.MappedType, new()); + PolicyEventsByType[state.MappedType].Add(state); } - - // var stateEventsQuery = await room.GetStateAsync(""); - // var stateEvents = stateEventsQuery.Value.Deserialize>(); - // PolicyEvents = stateEvents.Where(x => x.Type.StartsWith("m.policy.rule")) - // .Select(x => JsonSerializer.Deserialize(JsonSerializer.Serialize(x))).ToList(); StateHasChanged(); } - private async Task GetAvatar(string userId) { - try { - if (avatars.ContainsKey(userId)) return; - var hs = userId.Split(':')[1]; - var server = servers.ContainsKey(hs) ? servers[hs] : new RemoteHomeserver(userId.Split(':')[1]); - if (!servers.ContainsKey(hs)) servers.Add(hs, server); - var profile = await server.GetProfileAsync(userId); - avatars.Add(userId, await hsResolver.ResolveMediaUri(server.BaseUrl, profile.AvatarUrl)); - servers.Add(userId, server); + private async Task GetAllAvatars() { + // if (!_enableAvatars) return; + Console.WriteLine("Getting avatars..."); + var users = GetValidPolicyEventsByType(typeof(UserPolicyRuleEventContent)).Select(x => x.RawContent!["entity"]!.GetValue()).Where(x => x.Contains(':') && !x.Contains("*")).ToList(); + Console.WriteLine($"Got {users.Count} users!"); + var usersByHomeServer = users.GroupBy(x => x!.Split(':')[1]).ToDictionary(x => x.Key!, x => x.ToList()); + Console.WriteLine($"Got {usersByHomeServer.Count} homeservers!"); + var homeserverTasks = usersByHomeServer.Keys.Select(x => RemoteHomeserver.TryCreate(x)).ToAsyncEnumerable(); + await foreach (var server in homeserverTasks) { + if (server is null) continue; + var profileTasks = usersByHomeServer[server.BaseUrl].Select(x => TryGetProfile(server, x)).ToList(); + await Task.WhenAll(profileTasks); + profileTasks.RemoveAll(x => x.Result is not { Value: { AvatarUrl: not null } }); + foreach (var profile in profileTasks.Select(x => x.Result!.Value)) { + // if (profile is null) continue; + if (!string.IsNullOrWhiteSpace(profile.Value.AvatarUrl)) { + var url = await hsResolver.ResolveMediaUri(server.BaseUrl, profile.Value.AvatarUrl); + Avatars.TryAdd(profile.Key, url); + } + else Avatars.TryAdd(profile.Key, null); + } StateHasChanged(); } - catch { - // ignored - } } - private async Task GetAllAvatars() { - foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.user" && (x.TypedContent as PolicyRuleEventContent).Entity is not null)) { - await GetAvatar((policyEvent.TypedContent as PolicyRuleEventContent).Entity); + private async Task?> TryGetProfile(RemoteHomeserver server, string mxid) { + try { + return new KeyValuePair(mxid, await server.GetProfileAsync(mxid)); + } + catch { + return null; } - StateHasChanged(); } -} + private List GetPolicyEventsByType(Type type) => PolicyEventsByType.ContainsKey(type) ? PolicyEventsByType[type] : []; + private List GetValidPolicyEventsByType(Type type) => GetPolicyEventsByType(type).Where(x => !string.IsNullOrWhiteSpace(x.RawContent?["entity"]?.GetValue())).ToList(); + private List GetInvalidPolicyEventsByType(Type type) => GetPolicyEventsByType(type).Where(x => string.IsNullOrWhiteSpace(x.RawContent?["entity"]?.GetValue())).ToList(); + private int GetPolicyCount(Type type) => PolicyEventsByType.ContainsKey(type) ? PolicyEventsByType[type].Count : 0; + +} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/User/DMManager.razor b/MatrixRoomUtils.Web/Pages/User/DMManager.razor index 1b28516..a327793 100644 --- a/MatrixRoomUtils.Web/Pages/User/DMManager.razor +++ b/MatrixRoomUtils.Web/Pages/User/DMManager.razor @@ -1,7 +1,7 @@ @page "/User/DirectMessages" -@using LibMatrix.Homeservers @using LibMatrix.EventTypes.Spec.State @using LibMatrix.Responses +@using MatrixRoomUtils.Abstractions

Direct Messages


diff --git a/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage2.razor b/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage2.razor index 553f46d..60c68ac 100644 --- a/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage2.razor +++ b/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage2.razor @@ -7,6 +7,7 @@ @using MatrixRoomUtils.LibDMSpace.StateEvents @using ArcaneLibs.Extensions @using System.Text.Json.Serialization +@using MatrixRoomUtils.Abstractions DM Space setup tool - stage 2: Fix DM room attribution @@ -185,9 +186,9 @@ else { } catch { } - var membersEnum = room.GetMembersAsync(); + var membersEnum = room.GetMembersEnumerableAsync(true); await foreach (var member in membersEnum) - if (member.TypedContent is RoomMemberEventContent memberEvent && !string.IsNullOrWhiteSpace(memberEvent.Membership) && memberEvent.Membership == "join") + if (member.TypedContent is RoomMemberEventContent memberEvent) roomMembers[roomInfo].Add(new() { DisplayName = memberEvent.DisplayName, AvatarUrl = memberEvent.AvatarUrl, Id = member.StateKey }); if (string.IsNullOrWhiteSpace(roomInfo.RoomName) || roomInfo.RoomName == room.RoomId) { diff --git a/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage3.razor b/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage3.razor index 854b09c..42573e6 100644 --- a/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage3.razor +++ b/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage3.razor @@ -7,6 +7,8 @@ @using MatrixRoomUtils.LibDMSpace.StateEvents @using ArcaneLibs.Extensions @using System.Text.Json.Serialization +@using MatrixRoomUtils.Abstractions + DM Space setup tool - stage 3: Preview space layout @@ -154,9 +156,9 @@ else { } catch { } - var membersEnum = room.GetMembersAsync(); + var membersEnum = room.GetMembersEnumerableAsync(true); await foreach (var member in membersEnum) - if (member.TypedContent is RoomMemberEventContent memberEvent && !string.IsNullOrWhiteSpace(memberEvent.Membership) && memberEvent.Membership == "join") + if (member.TypedContent is RoomMemberEventContent memberEvent) roomMembers.Add(new() { DisplayName = memberEvent.DisplayName, AvatarUrl = memberEvent.AvatarUrl, Id = member.StateKey }); if (string.IsNullOrWhiteSpace(roomInfo.RoomName) || roomInfo.RoomName == room.RoomId) { diff --git a/MatrixRoomUtils.Web/Pages/User/Profile.razor b/MatrixRoomUtils.Web/Pages/User/Profile.razor index ae3fb76..73d7c6e 100644 --- a/MatrixRoomUtils.Web/Pages/User/Profile.razor +++ b/MatrixRoomUtils.Web/Pages/User/Profile.razor @@ -9,40 +9,43 @@ @if (NewProfile is not null) {

Profile


- - -
- Display name:
- Avatar URL: -
- Update profile - Update profile (restore room overrides) +
+ +
+ Display name:
+ Avatar URL: +
+ Update profile + Update profile (restore room overrides) +
@if (!string.IsNullOrWhiteSpace(Status)) {

@Status

} -
- Room profiles
- - @foreach (var (roomId, roomProfile) in RoomProfiles.OrderBy(x=>RoomNames.TryGetValue(x.Key, out var _name) ? _name : x.Key)) { -
- @(RoomNames.TryGetValue(roomId, out var name) ? name : roomId) - -
- Display name:
- Avatar URL: -
- Update profile -
-
- @if (!string.IsNullOrWhiteSpace(Status)) { -

@Status

- } -
+
+ + @*
*@ +

Room profiles

+ + @foreach (var (roomId, roomProfile) in RoomProfiles.OrderBy(x => RoomNames.TryGetValue(x.Key, out var _name) ? _name : x.Key)) { +
+ @(RoomNames.TryGetValue(roomId, out var name) ? name : roomId) + +
+ Display name:
+ Avatar URL: +
+ Update profile +

- } -
+ @if (!string.IsNullOrWhiteSpace(Status)) { +

@Status

+ } +
+
+ } + //
} @code { @@ -54,7 +57,10 @@ private string? Status { get => _status; - set { _status = value; StateHasChanged(); } + set { + _status = value; + StateHasChanged(); + } } private Dictionary RoomProfiles { get; set; } = new(); @@ -65,14 +71,15 @@ if (Homeserver is null) return; Status = "Loading global profile..."; if (Homeserver.WhoAmI?.UserId is null) return; - NewProfile = (await Homeserver.GetProfileAsync(Homeserver.WhoAmI.UserId)).DeepClone(); - OldProfile = (await Homeserver.GetProfileAsync(Homeserver.WhoAmI.UserId)).DeepClone(); + NewProfile = (await Homeserver.GetProfileAsync(Homeserver.WhoAmI.UserId)); //.DeepClone(); + OldProfile = (await Homeserver.GetProfileAsync(Homeserver.WhoAmI.UserId)); //.DeepClone(); Status = "Loading room profiles..."; var roomProfiles = Homeserver.GetRoomProfilesAsync(); await foreach (var (roomId, roomProfile) in roomProfiles) { // Status = $"Got profile for {roomId}..."; - RoomProfiles[roomId] = roomProfile.DeepClone(); + RoomProfiles[roomId] = roomProfile; //.DeepClone(); } + StateHasChanged(); Status = "Room profiles loaded, loading room names..."; @@ -80,6 +87,7 @@ var name = await x.GetNameOrFallbackAsync(); return new KeyValuePair(x.RoomId, name); }).ToAsyncEnumerable(); + await foreach (var (roomId, roomName) in roomNameTasks) { // Status = $"Got room name for {roomId}: {roomName}"; RoomNames[roomId] = roomName; @@ -106,13 +114,14 @@ StateHasChanged(); await OnInitializedAsync(); } + private async Task RoomAvatarChanged(InputFileChangeEventArgs arg, string roomId) { var res = await Homeserver.UploadFile(arg.File.Name, arg.File.OpenReadStream(Int64.MaxValue), arg.File.ContentType); Console.WriteLine(res); RoomProfiles[roomId].AvatarUrl = res; StateHasChanged(); } - + private async Task UpdateRoomProfile(string roomId) { Status = "Busy processing room profile update, please do not leave this page..."; StateHasChanged(); @@ -122,5 +131,4 @@ StateHasChanged(); } -} - +} \ No newline at end of file -- cgit 1.5.1