From 14c3cb3ebf8826742e2957fc22b7ae99b645c40c Mon Sep 17 00:00:00 2001 From: Rory& Date: Tue, 22 Apr 2025 17:04:26 +0200 Subject: Fix room shutdown, room query (WIP) --- LibMatrix | 2 +- .../SynapseRoomShutdownWindowContent.razor | 3 + .../Pages/HSAdmin/Synapse/RoomQuery.razor | 205 ++++++++++++--------- MatrixUtils.Web/Pages/Index.razor | 1 + 4 files changed, 124 insertions(+), 87 deletions(-) diff --git a/LibMatrix b/LibMatrix index 4b508fa..ae19915 160000 --- a/LibMatrix +++ b/LibMatrix @@ -1 +1 @@ -Subproject commit 4b508fa6216c6682925a42b67936b068e6db8e64 +Subproject commit ae199156caae9384d575d384daae5690e0b28aae diff --git a/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/SynapseRoomShutdownWindowContent.razor b/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/SynapseRoomShutdownWindowContent.razor index 124d073..3b3acac 100644 --- a/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/SynapseRoomShutdownWindowContent.razor +++ b/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/SynapseRoomShutdownWindowContent.razor @@ -1,5 +1,6 @@ @using LibMatrix.Homeservers.Extensions.NamedCaches @using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Requests +@using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Responses @if (string.IsNullOrWhiteSpace(Context.DeleteId)) { Block room: @@ -77,6 +78,8 @@ ForcePurge = false }; + public SynapseAdminRoomListResult.SynapseAdminRoomListResultRoom? RoomDetails { get; set; } + public class ExtraDeleteOptions { // room options public bool QuarantineLocalMedia { get; set; } diff --git a/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor b/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor index 5c29909..3e38ee2 100644 --- a/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor +++ b/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor @@ -1,6 +1,10 @@ @page "/HSAdmin/Synapse/RoomQuery" +@using System.Diagnostics.CodeAnalysis @using Microsoft.AspNetCore.WebUtilities @using ArcaneLibs.Extensions +@using LibMatrix +@using LibMatrix.EventTypes.Spec.State.RoomInfo +@using LibMatrix.Homeservers.Extensions.NamedCaches @using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Filters @using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Responses @using MatrixUtils.Web.Pages.HSAdmin.Synapse.Components @@ -47,46 +51,33 @@ @* *@ } -@foreach (var res in Results) { +@foreach (var room in Results) {
@* *@

- @if (!string.IsNullOrWhiteSpace(res.CanonicalAlias)) { - @res.CanonicalAlias - + @if (!string.IsNullOrWhiteSpace(room.CanonicalAlias)) { + @room.CanonicalAlias - } - @res.RoomId - @if (!string.IsNullOrWhiteSpace(res.Name)) { - (@res.Name) + @room.RoomId + @if (!string.IsNullOrWhiteSpace(room.Name)) { + (@room.Name) }
- @if (!string.IsNullOrWhiteSpace(res.Creator)) { - Created by @res.Creator + @if (!string.IsNullOrWhiteSpace(room.Creator)) { + Created by @room.Creator
}

- Delete room - - Resync state + Delete room + Resync state

@{ List flags = []; - if (res.JoinedLocalMembers > 0) { - flags.Add(res.JoinRules switch { + if (true || room.JoinedLocalMembers > 0) { + flags.Add(room.JoinRules switch { "public" => "Public", "invite" => "Invite only", "knock" => "Knock", @@ -95,12 +86,13 @@ // TODO: default? null => null, "" => null, - _ => "unknown join rule: " + res.JoinRules + _ => "unknown join rule: " + room.JoinRules }); - if (!string.IsNullOrWhiteSpace(res.Encryption)) flags.Add("encrypted"); - if (!res.Federatable) flags.Add("unfederated"); + + if (!string.IsNullOrWhiteSpace(room.Encryption)) flags.Add("encrypted"); + if (!room.Federatable) flags.Add("unfederated"); - flags.Add(res.HistoryVisibility switch { + flags.Add(room.HistoryVisibility switch { "world_readable" => "world readable history", "shared" => "shared history", "invited" => "history since invite", @@ -108,35 +100,43 @@ // TODO: default? null => null, "" => null, - _ => "unknown history setting: " + res.HistoryVisibility + _ => "unknown history setting: " + room.HistoryVisibility }); - flags.Add(res.GuestAccess switch { + flags.Add(room.GuestAccess switch { "can_join" => "guests allowed", "forbidden" => null, // TODO: default? null => null, "" => null, - _ => "unknown guest access: " + res.GuestAccess, + _ => "unknown guest access: " + room.GuestAccess, }); flags = flags.Where(x => x != null).ToList(); } } - @string.Join(", ", flags)
+ @string.Join(", ", flags) + @if (room.JoinedLocalMembers == 0 && flags.Count > 0) { + at the time of leaving + } +
- @res.StateEvents state events, room version @(res.Version ?? "1")
+ @room.StateEvents state events, room version @(room.Version ?? "1")
+ @if (room.TombstoneEvent is not null) { + var tombstoneContent = room.TombstoneEvent.ContentAs()!; + Room is tombstoned! Target room: @tombstoneContent.ReplacementRoom, message: @tombstoneContent.Body
+ } @{ - var memberSummary = $"{res.JoinedMembers} members, of which {res.JoinedLocalMembers} are on this server"; - if (res.LocalMembers is not null) { - memberSummary += $": {string.Join(", ", res.LocalMembers)}"; + var memberSummary = room.MemberSummary; + if (room.LocalMembers is not null) { + memberSummary += $": {string.Join(", ", room.LocalMembers)}"; } } @memberSummary
Full result data -
@res.ToJson(ignoreNull: true)
+
@room.ToJson(ignoreNull: true)
} @@ -154,7 +154,10 @@ @* } *@ @foreach (var (roomId, deleteRequest) in DeleteRequests) { - + } @@ -171,7 +174,7 @@ [Parameter] [SupplyParameterFromQuery(Name = "name_search")] - public string SearchTerm { get; set; } + public string? SearchTerm { get; set; } [Parameter] [SupplyParameterFromQuery(Name = "ascending")] @@ -181,14 +184,27 @@ private AuthenticatedHomeserverSynapse Homeserver { get; set; } = null!; - private string Status { get; set; } - - public SynapseAdminLocalRoomQueryFilter Filter { get; set; } = new(); + private SynapseAdminLocalRoomQueryFilter Filter { get; set; } = new(); private Dictionary DeleteRequests { get; set; } = []; // private Dictionary DeleteStatuses { get; set; } = new(); + private NamedCache TaskMap { get; set; } = null!; + + protected override async Task OnInitializedAsync() { + var hs = await sessionStore.GetCurrentHomeserver(navigateOnFailure: true); + if (hs is not AuthenticatedHomeserverSynapse synapse) { + NavigationManager.NavigateTo("/"); + return; + } + + Homeserver = synapse; + TaskMap = new NamedCache(Homeserver, "gay.rory.matrixutils.synapse_room_shutdown_tasks"); + DeleteRequests = (await TaskMap.ReadCacheMapAsync()).Where(x => x.Value.DeleteId is not null).ToDictionary(); + StateHasChanged(); + } + protected override Task OnParametersSetAsync() { OrderBy ??= "name"; @@ -266,54 +282,67 @@ private async Task Search() { Results.Clear(); - var hs = await sessionStore.GetCurrentHomeserver(navigateOnFailure: true); - if (hs is AuthenticatedHomeserverSynapse synapse) { - Homeserver = synapse; - var searchRooms = synapse.Admin.SearchRoomsAsync(orderBy: OrderBy!, dir: Ascending ? "f" : "b", searchTerm: SearchTerm, localFilter: Filter).GetAsyncEnumerator(); - while (await searchRooms.MoveNextAsync()) { - var room = searchRooms.Current; - - var roomInfo = new RoomInfo { - RoomId = room.RoomId, - Name = room.Name, - CanonicalAlias = room.CanonicalAlias, - Creator = room.Creator, - Version = room.Version, - Encryption = room.Encryption, - Federatable = room.Federatable, - Public = room.Public, - JoinRules = room.JoinRules, - GuestAccess = room.GuestAccess, - HistoryVisibility = room.HistoryVisibility, - StateEvents = room.StateEvents, - JoinedMembers = room.JoinedMembers, - JoinedLocalMembers = room.JoinedLocalMembers - }; - - Results.Add(roomInfo); - - if ((Results.Count <= 200 && Results.Count % 10 == 0) || Results.Count % 1000 == 0) { - StateHasChanged(); - await Task.Yield(); - await Task.Delay(1); - } + var searchRooms = Homeserver.Admin.SearchRoomsAsync(orderBy: OrderBy!, dir: Ascending ? "f" : "b", searchTerm: SearchTerm, localFilter: Filter).GetAsyncEnumerator(); + while (await searchRooms.MoveNextAsync()) { + var room = searchRooms.Current; + + var roomInfo = new RoomInfo { + RoomId = room.RoomId, + Name = room.Name, + CanonicalAlias = room.CanonicalAlias, + Creator = room.Creator, + Version = room.Version, + Encryption = room.Encryption, + Federatable = room.Federatable, + Public = room.Public, + JoinRules = room.JoinRules, + GuestAccess = room.GuestAccess, + HistoryVisibility = room.HistoryVisibility, + StateEvents = room.StateEvents, + JoinedMembers = room.JoinedMembers, + JoinedLocalMembers = room.JoinedLocalMembers + }; + + Results.Add(roomInfo); + + if ((Results.Count <= 200 && Results.Count % 10 == 0) || Results.Count % 1000 == 0) { + StateHasChanged(); + await Task.Yield(); + await Task.Delay(1); } - - StateHasChanged(); - - var tasks = Results - .Where(x => x.JoinedLocalMembers is > 0 and < 100) - .Select(async r => { - var members = (await synapse.Admin.GetRoomMembersAsync(r.RoomId)).Members.Where(x => x.EndsWith(":" + synapse.ServerName)).ToList(); - r.LocalMembers = members; - } - ); - await Task.WhenAll(tasks); - //Logger.LogWarning($"Found {tasks.Count} rooms with >0, <100 local members"); } StateHasChanged(); + + var getLocalMembersTasks = Results + .Where(x => x.JoinedLocalMembers is > 0 and < 100) + .Select(async r => { + var members = (await Homeserver.Admin.GetRoomMembersAsync(r.RoomId)).Members.Where(x => x.EndsWith(":" + Homeserver.ServerName)).ToList(); + r.LocalMembers = members; + } + ); + await Task.WhenAll(getLocalMembersTasks); + + var getTombstoneTasks = Results + .Select(async r => { + var state = await Homeserver.Admin.GetRoomStateAsync(r.RoomId, type: "m.room.tombstone"); + var tombstone = state.Events.FirstOrDefault(x => x is { StateKey: "", Type: "m.room.tombstone" }); + if (tombstone is { } tombstoneEvent) { + r.TombstoneEvent = tombstoneEvent; + } + }); + await Task.WhenAll(getTombstoneTasks); + + StateHasChanged(); + } + + Task DeleteRoom(RoomInfo room) { + DeleteRequests.TryAdd(room.RoomId, new() { RoomId = room.RoomId, RoomDetails = room, DeleteRequest = new() { Block = true, Purge = true, ForcePurge = false } }); + StateHasChanged(); + + return Task.CompletedTask; } + // // private async Task DeleteRoom() { // if (DeleteRequest is { } deleteRequest) { @@ -395,6 +424,10 @@ private class RoomInfo : SynapseAdminRoomListResult.SynapseAdminRoomListResultRoom { public List? LocalMembers { get; set; } + public StateEventResponse? TombstoneEvent { get; set; } + + [field: AllowNull, MaybeNull] + public string MemberSummary => field ??= $"{JoinedMembers} members, of which {JoinedLocalMembers} are on this server"; } } diff --git a/MatrixUtils.Web/Pages/Index.razor b/MatrixUtils.Web/Pages/Index.razor index fd38f28..509c634 100644 --- a/MatrixUtils.Web/Pages/Index.razor +++ b/MatrixUtils.Web/Pages/Index.razor @@ -245,6 +245,7 @@ Small collection of tools to do not-so-everyday things. Busy = false; StateHasChanged(); + Console.WriteLine("Index.OnInitializedAsync finished"); } private class UserInfo { -- cgit 1.5.1