about summary refs log tree commit diff
path: root/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2025-04-17 11:26:12 +0200
committerRory& <root@rory.gay>2025-04-17 11:26:12 +0200
commitf82c62fe9d75c3cdc5ed5fe6f5e5ce517e6eafbc (patch)
tree36f45841b0f8b094f591040d533e1d61f683e51d /MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor
parentFix migration from non-keyed sessions (diff)
downloadMatrixUtils-f82c62fe9d75c3cdc5ed5fe6f5e5ce517e6eafbc.tar.xz
Room query cleanup, add start of state resync
Diffstat (limited to 'MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor')
-rw-r--r--MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor218
1 files changed, 99 insertions, 119 deletions
diff --git a/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor b/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor

index 79e7357..5c29909 100644 --- a/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor +++ b/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor
@@ -2,9 +2,10 @@ @using Microsoft.AspNetCore.WebUtilities @using ArcaneLibs.Extensions @using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Filters -@using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Requests @using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Responses @using MatrixUtils.Web.Pages.HSAdmin.Synapse.Components +@using MatrixUtils.Web.Pages.HSAdmin.Synapse.Components.RoomQuery +@inject ILogger<RoomQuery> Logger <h3>Homeserver Administration - Room Query</h3> @@ -21,93 +22,52 @@ <details> <summary> <span>Local filtering (slow)</span> - </summary> - <div style="margin-left: 8px; margin-bottom: 8px;"> - <u style="display: block;">String contains</u> - <span class="tile tile280">Room ID: <FancyTextBox @bind-Value="@Filter.RoomIdContains"></FancyTextBox></span> - <span class="tile tile280">Room name: <FancyTextBox @bind-Value="@Filter.NameContains"></FancyTextBox></span> - <span class="tile tile280">Canonical alias: <FancyTextBox @bind-Value="@Filter.CanonicalAliasContains"></FancyTextBox></span> - <span class="tile tile280">Creator: <FancyTextBox @bind-Value="@Filter.CreatorContains"></FancyTextBox></span> - <span class="tile tile280">Room version: <FancyTextBox @bind-Value="@Filter.VersionContains"></FancyTextBox></span> - <span class="tile tile280">Encryption algorithm: <FancyTextBox @bind-Value="@Filter.EncryptionContains"></FancyTextBox></span> - <span class="tile tile280">Join rules: <FancyTextBox @bind-Value="@Filter.JoinRulesContains"></FancyTextBox></span> - <span class="tile tile280">Guest access: <FancyTextBox @bind-Value="@Filter.GuestAccessContains"></FancyTextBox></span> - <span class="tile tile280">History visibility: <FancyTextBox @bind-Value="@Filter.HistoryVisibilityContains"></FancyTextBox></span> - - <u style="display: block;">Optional checks</u> - <span class="tile tile150"> - <InputCheckbox @bind-Value="@Filter.CheckFederation"></InputCheckbox> Is federated: - @if (Filter.CheckFederation) { - <InputCheckbox @bind-Value="@Filter.Federatable"></InputCheckbox> - } - </span> - <span class="tile tile150"> - <InputCheckbox @bind-Value="@Filter.CheckPublic"></InputCheckbox> Is public: - @if (Filter.CheckPublic) { - <InputCheckbox @bind-Value="@Filter.Public"></InputCheckbox> - } - </span> - - <u style="display: block;">Ranges</u> - <span class="tile center-children"> - <InputNumber max="@int.MaxValue" class="int-input" TValue="int" @bind-Value="@Filter.StateEventsGreaterThan"></InputNumber><span class="range-sep">state events</span><InputNumber - max="@int.MaxValue" class="int-input" TValue="int" @bind-Value="@Filter.StateEventsLessThan"></InputNumber> - </span> - <span class="tile center-children"> - <InputNumber max="@int.MaxValue" class="int-input" TValue="int" @bind-Value="@Filter.JoinedMembersGreaterThan"></InputNumber><span class="range-sep">members</span><InputNumber - max="@int.MaxValue" class="int-input" TValue="int" @bind-Value="@Filter.JoinedMembersLessThan"></InputNumber> - </span> - <span class="tile center-children"> - <InputNumber max="@int.MaxValue" class="int-input" TValue="int" @bind-Value="@Filter.JoinedLocalMembersGreaterThan"></InputNumber><span - class="range-sep">local members</span><InputNumber max="@int.MaxValue" class="int-input" TValue="int" - @bind-Value="@Filter.JoinedLocalMembersLessThan"></InputNumber> - </span> - </div> + <SynapseRoomQueryFilter Filter="@Filter"/> </details> <button class="btn btn-primary" @onclick="Search">Search</button> <br/> @if (Results.Count > 0) { <p>Found @Results.Count rooms</p> - <details> - <summary>TSV data (copy/paste)</summary> - <pre style="font-size: 0.6em;"> - <table> - @foreach (var res in Results) { - <tr> - <td style="padding: 8px;">@res.RoomId@("\t")</td> - <td style="padding: 8px;">@res.CanonicalAlias@("\t")</td> - <td style="padding: 8px;">@res.Creator@("\t")</td> - <td style="padding: 8px;">@res.Name</td> - </tr> - } - </table> - </pre> - </details> + @* <details> *@ + @* <summary>TSV data (copy/paste)</summary> *@ + @* <pre style="font-size: 0.6em;"> *@ + @* <table> *@ + @* @foreach (var res in Results) { *@ + @* <tr> *@ + @* <td style="padding: 8px;">@res.RoomId@("\t")</td> *@ + @* <td style="padding: 8px;">@res.CanonicalAlias@("\t")</td> *@ + @* <td style="padding: 8px;">@res.Creator@("\t")</td> *@ + @* <td style="padding: 8px;">@res.Name</td> *@ + @* </tr> *@ + @* } *@ + @* </table> *@ + @* </pre> *@ + @* </details> *@ } @foreach (var res in Results) { - <div style="background-color: #ffffff11; border-radius: 0.5em; display: block; margin-top: 4px; padding: 4px;"> + <div class="room-list-item"> @* <RoomListItem RoomName="@res.Name" RoomId="@res.RoomId"></RoomListItem> *@ <p> @if (!string.IsNullOrWhiteSpace(res.CanonicalAlias)) { - <span>@res.CanonicalAlias - @res.RoomId (@res.Name)</span> - <br/> + <span>@res.CanonicalAlias - </span> } - else { - <span>@res.RoomId (@res.Name)</span> - <br/> + <span>@res.RoomId</span> + @if (!string.IsNullOrWhiteSpace(res.Name)) { + <span> (@res.Name)</span> } + <br/> + @if (!string.IsNullOrWhiteSpace(res.Creator)) { - @* <span>Created by <InlineUserItem UserId="@res.Creator"></InlineUserItem></span> *@ <span>Created by @res.Creator</span> <br/> } </p> <p> <LinkButton OnClick="@(() => { - DeleteRequests.Add(res.RoomId, new() { + DeleteRequests.TryAdd(res.RoomId, new() { RoomId = res.RoomId, DeleteRequest = new() { Block = true, @@ -115,18 +75,65 @@ ForcePurge = false } }); - + StateHasChanged(); + return Task.CompletedTask; })">Delete room </LinkButton> + <LinkButton target="_blank" href="@($"/HSAdmin/Synapse/ResyncState?roomId={res.RoomId}&via={res.RoomId.Split(':', 2)[1]}")">Resync state</LinkButton> </p> - <span>@res.StateEvents state events</span><br/> - @if (res.LocalMembers is null) { - <span>@res.JoinedMembers members, of which @res.JoinedLocalMembers are on this server</span> + + @{ + List<string?> flags = []; + if (res.JoinedLocalMembers > 0) { + flags.Add(res.JoinRules switch { + "public" => "Public", + "invite" => "Invite only", + "knock" => "Knock", + "restricted" => "Restricted", + "knock_restricted" => "Knock + restricted", + // TODO: default? + null => null, + "" => null, + _ => "unknown join rule: " + res.JoinRules + }); + if (!string.IsNullOrWhiteSpace(res.Encryption)) flags.Add("encrypted"); + if (!res.Federatable) flags.Add("unfederated"); + + flags.Add(res.HistoryVisibility switch { + "world_readable" => "world readable history", + "shared" => "shared history", + "invited" => "history since invite", + "joined" => "history since join", + // TODO: default? + null => null, + "" => null, + _ => "unknown history setting: " + res.HistoryVisibility + }); + + flags.Add(res.GuestAccess switch { + "can_join" => "guests allowed", + "forbidden" => null, + // TODO: default? + null => null, + "" => null, + _ => "unknown guest access: " + res.GuestAccess, + }); + + flags = flags.Where(x => x != null).ToList(); + } } - else { - <span>@res.JoinedMembers members, of which @res.JoinedLocalMembers are on this server: @(string.Join(", ", res.LocalMembers))</span> + <span>@string.Join(", ", flags)</span><br/> + + <span>@res.StateEvents state events, room version @(res.Version ?? "1")</span><br/> + + @{ + var memberSummary = $"{res.JoinedMembers} members, of which {res.JoinedLocalMembers} are on this server"; + if (res.LocalMembers is not null) { + memberSummary += $": {string.Join(", ", res.LocalMembers)}"; + } } + <span>@memberSummary</span> <details> <summary>Full result data</summary> <pre>@res.ToJson(ignoreNull: true)</pre> @@ -146,46 +153,14 @@ @* </ModalWindow> *@ @* } *@ -@foreach(var (roomId, deleteRequest) in DeleteRequests) { - <SynapseRoomShutdownWindowContent Context="deleteRequest" Homeserver="Homeserver"/> +@foreach (var (roomId, deleteRequest) in DeleteRequests) { + <ModalWindow Title="@($"Delete room {roomId}")" OnCloseClicked="@(() => { DeleteRequests.Remove(roomId); StateHasChanged(); })"> + <SynapseRoomShutdownWindowContent Context="deleteRequest" Homeserver="Homeserver"/> + </ModalWindow> } <style> - .int-input { - width: 128px; - } - - .tile { - display: inline-block; - padding: 4px; - border: 1px solid #ffffff22; - } - - .tile280 { - min-width: 280px; - } - .tile150 { - min-width: 150px; - } - - .range-sep { - display: inline-block; - padding: 4px; - width: 150px; - } - - .range-sep::before { - content: "@("<") "; - } - - .range-sep::after { - content: " @("<")"; - } - - .center-children { - text-align: center; - } </style> @code { @@ -200,7 +175,7 @@ [Parameter] [SupplyParameterFromQuery(Name = "ascending")] - public bool Ascending { get; set; } + public bool Ascending { get; set; } = true; private List<RoomInfo> Results { get; set; } = new(); @@ -215,8 +190,6 @@ // private Dictionary<string, SynapseAdminRoomDeleteStatus> DeleteStatuses { get; set; } = new(); protected override Task OnParametersSetAsync() { - if (Ascending == null) - Ascending = true; OrderBy ??= "name"; var execute = false; @@ -300,9 +273,6 @@ while (await searchRooms.MoveNextAsync()) { var room = searchRooms.Current; - if (Results.Count < 100) - Console.WriteLine("Hit: " + room.ToJson(false)); - var roomInfo = new RoomInfo { RoomId = room.RoomId, Name = room.Name, @@ -322,14 +292,24 @@ Results.Add(roomInfo); - if (room.JoinedLocalMembers is > 0 and < 100) - roomInfo.LocalMembers = (await synapse.Admin.GetRoomMembersAsync(room.RoomId)).Members.Where(x => x.EndsWith(":" + synapse.ServerName)).ToList(); - - if (Results.Count < 200 || Results.Count % 1000 == 0) { + 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(); @@ -416,5 +396,5 @@ private class RoomInfo : SynapseAdminRoomListResult.SynapseAdminRoomListResultRoom { public List<string>? LocalMembers { get; set; } } - + }