about summary refs log tree commit diff
diff options
context:
space:
mode:
Diffstat (limited to '')
m---------LibMatrix0
-rw-r--r--MatrixUtils.Web/Pages/Rooms/Index.razor41
-rw-r--r--MatrixUtils.Web/Pages/Rooms/PolicyList.razor126
3 files changed, 116 insertions, 51 deletions
diff --git a/LibMatrix b/LibMatrix
-Subproject ae199156caae9384d575d384daae5690e0b28aa
+Subproject a2b318f6f52dfec7f217643273e5b4e0855fe9e
diff --git a/MatrixUtils.Web/Pages/Rooms/Index.razor b/MatrixUtils.Web/Pages/Rooms/Index.razor

index 0373a46..611bf56 100644 --- a/MatrixUtils.Web/Pages/Rooms/Index.razor +++ b/MatrixUtils.Web/Pages/Rooms/Index.razor
@@ -73,7 +73,7 @@ GlobalProfile = await Homeserver.GetProfileAsync(Homeserver.WhoAmI.UserId); var filter = await Homeserver.NamedCaches.FilterCache.GetOrSetValueAsync(CommonSyncFilters.GetBasicRoomInfo); - var filterData = await Homeserver.GetFilterAsync(filter); + // var filterData = await Homeserver.GetFilterAsync(filter); // Rooms = new ObservableCollection<RoomInfo>(rooms.Select(room => new RoomInfo(room))); // foreach (var stateType in filterData.Room?.State?.Types ?? []) { @@ -97,7 +97,8 @@ syncHelper = new SyncHelper(Homeserver, logger) { Timeout = 30000, FilterId = filter, - MinimumDelay = TimeSpan.FromMilliseconds(5000) + MinimumDelay = TimeSpan.FromMilliseconds(5000), + UseMsc4222StateAfter = true }; // profileSyncHelper = new SyncHelper(Homeserver, logger) { // Timeout = 10000, @@ -106,9 +107,9 @@ // }; // profileUpdateFilter.Room.State.Senders.Add(Homeserver.WhoAmI.UserId); - RunSyncLoop(syncHelper); + _ = RunSyncLoop(syncHelper); // RunSyncLoop(profileSyncHelper); - RunQueueProcessor(); + _ = RunQueueProcessor(); await base.OnInitializedAsync(); } @@ -138,7 +139,7 @@ } else { // Console.WriteLine($"QueueWorker: encountered new room {roomId}!"); - room = new RoomInfo(Homeserver.GetRoom(roomId), roomData.State?.Events); + room = new RoomInfo(Homeserver.GetRoom(roomId), roomData.StateAfter?.Events); Rooms.Add(room); } @@ -147,11 +148,10 @@ throw new InvalidDataException("Somehow this is null???"); } - if (roomData.State?.Events is { Count: > 0 }) - room.StateEvents.MergeStateEventLists(roomData.State.Events); - else { + if (roomData is { StateAfter.Events.Count: > 0 }) + room.StateEvents!.MergeStateEventLists(roomData.StateAfter.Events); + else Console.WriteLine($"QueueWorker: could not merge state for {room.Room.RoomId} as new data contains no state events!"); - } if (maxUpdates % 100 == 0) { Console.WriteLine($"QueueWorker: {queue.Count} entries left in queue, {maxUpdates} maxUpdates left, RenderContents: {RenderContents}"); @@ -181,7 +181,8 @@ get => _status; set { _status = value; - StateHasChanged(); + // StateHasChanged(); + Console.WriteLine(value); } } @@ -191,7 +192,8 @@ get => _status2; set { _status2 = value; - StateHasChanged(); + // StateHasChanged(); + Console.WriteLine(value); } } @@ -203,26 +205,24 @@ var syncs = syncHelper.EnumerateSyncAsync(); await foreach (var sync in syncs) { - Console.WriteLine("trying sync"); - if (sync is null) continue; - var filter = await Homeserver.GetFilterAsync(syncHelper.FilterId); Status = $"Got sync with {sync.Rooms?.Join?.Count ?? 0} room updates, next batch: {sync.NextBatch}!"; - if (sync?.Rooms?.Join != null) + if (sync.Rooms?.Join != null) foreach (var joinedRoom in sync.Rooms.Join) if ( /*joinedRoom.Value.AccountData?.Events?.Count > 0 ||*/ joinedRoom.Value.State?.Events?.Count > 0) { - joinedRoom.Value.State.Events.RemoveAll(x => x.Type == "m.room.member" && x.StateKey != Homeserver.WhoAmI?.UserId); + joinedRoom.Value.StateAfter?.Events?.RemoveAll(x => x.Type == "m.room.member" && x.StateKey != Homeserver.WhoAmI.UserId); // 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) - joinedRoom.Value.State.Events.RemoveAll(x => filter.Room?.State?.NotSenders?.Contains(x.Sender) ?? false); + if (filter is { Room.State.Types.Count: > 0 }) + joinedRoom.Value.StateAfter?.Events?.RemoveAll(x => filter.Room?.State?.Types?.Contains(x.Type) == false); + if (filter is { Room.State.NotSenders.Count: > 0 }) + joinedRoom.Value.StateAfter?.Events?.RemoveAll(x => filter.Room?.State?.NotSenders?.Contains(x.Sender!) ?? false); queue.Enqueue(joinedRoom); } - if (sync.Rooms.Leave is { Count: > 0 }) + 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)); @@ -231,6 +231,7 @@ $"{sync.Rooms?.Join?.Count ?? 0} new updates!"; Status2 = $"Next batch: {sync?.NextBatch}"; + StateHasChanged(); await Task.Yield(); } } diff --git a/MatrixUtils.Web/Pages/Rooms/PolicyList.razor b/MatrixUtils.Web/Pages/Rooms/PolicyList.razor
index 9c35673..b908e57 100644 --- a/MatrixUtils.Web/Pages/Rooms/PolicyList.razor +++ b/MatrixUtils.Web/Pages/Rooms/PolicyList.razor
@@ -25,8 +25,17 @@ } <hr/> @* <InputCheckbox @bind-Value="EnableAvatars"></InputCheckbox><label>Enable avatars (WILL EXPOSE YOUR IP TO TARGET HOMESERVERS!)</label> *@ -<LinkButton OnClick="@(() => { CurrentlyEditingEvent = new() { Type = "", RawContent = new() }; return Task.CompletedTask; })">Create new policy</LinkButton> -<LinkButton OnClick="@(() => { MassCreatePolicies = true; return Task.CompletedTask; })">Create many new policies</LinkButton> +<LinkButton OnClick="@(() => { + CurrentlyEditingEvent = new() { Type = "", RawContent = new() }; + return Task.CompletedTask; + })">Create new policy +</LinkButton> +<LinkButton OnClick="@(() => { + MassCreatePolicies = true; + return Task.CompletedTask; + })">Create many new policies +</LinkButton> +<LinkButton OnClick="@LoadStatesAsync">Refresh</LinkButton> @if (Loading) { <p>Loading...</p> @@ -40,15 +49,16 @@ else { @foreach (var (type, value) in PolicyEventsByType) { <p> @(GetValidPolicyEventsByType(type).Count) active, - @(GetInvalidPolicyEventsByType(type).Count) invalid + @(GetInvalidPolicyEventsByType(type).Count) invalid, + @(GetRemovedPolicyEventsByType(type).Count) removed (@value.Count total) @(GetPolicyTypeName(type).ToLower()) </p> } - Console.WriteLine($"Rendered hearder in {renderSw.GetElapsedAndRestart()}"); + Console.WriteLine($"Rendered header in {renderSw.GetElapsedAndRestart()}"); - @foreach (var type in KnownPolicyTypes.OrderByDescending(t => GetPolicyEventsByType(t).Count)) { + @foreach (var type in KnownPolicyTypes.Where(t => GetPolicyEventsByType(t).Count > 0).OrderByDescending(t => GetPolicyEventsByType(t).Count)) { <details> <summary> <span> @@ -87,21 +97,35 @@ else { var typedContent = policy.TypedContent!; } @foreach (var prop in proxySafeProps ?? Enumerable.Empty<PropertyInfo>()) { - <td>@prop.GetGetMethod()?.Invoke(typedContent, null)</td> + if (prop.Name == "Entity") { + <td>@TruncateMxid((string)prop.GetGetMethod()?.Invoke(typedContent, null)!)</td> + } + else { + <td>@prop.GetGetMethod()?.Invoke(typedContent, null)</td> + } } <td> <div style="display: ruby;"> @if (PowerLevels.UserHasStatePermission(Homeserver.WhoAmI.UserId, policy.Type)) { - <LinkButton OnClick="@(() => { CurrentlyEditingEvent = policy; return Task.CompletedTask; })">Edit</LinkButton> + <LinkButton OnClick="@(() => { + CurrentlyEditingEvent = policy; + return Task.CompletedTask; + })">Edit + </LinkButton> <LinkButton OnClick="@(() => RemovePolicyAsync(policy))">Remove</LinkButton> @if (policy.IsLegacyType) { <LinkButton OnClick="@(() => RemovePolicyAsync(policy))">Update policy type</LinkButton> } @if (PolicyTypeIds[typeof(ServerPolicyRuleEventContent)].Contains(policy.Type)) { - <LinkButton OnClick="@(() => { ServerPolicyToMakePermanent = policy; return Task.CompletedTask; })">Make permanent</LinkButton> + <LinkButton OnClick="@(() => { + ServerPolicyToMakePermanent = policy; + return Task.CompletedTask; + })">Make permanent + </LinkButton> @if (CurrentUserIsDraupnir) { - <LinkButton Color="@(ActiveKicks.ContainsKey(policy) ? "#FF0000" : null)" OnClick="@(() => DraupnirKickMatching(policy))">Kick users @(ActiveKicks.ContainsKey(policy) ? $"({ActiveKicks[policy]})" : null)</LinkButton> + <LinkButton Color="@(ActiveKicks.ContainsKey(policy) ? "#FF0000" : null)" OnClick="@(() => DraupnirKickMatching(policy))">Kick + users @(ActiveKicks.ContainsKey(policy) ? $"({ActiveKicks[policy]})" : null)</LinkButton> } } } @@ -157,7 +181,10 @@ else { } @if (MassCreatePolicies) { - <MassPolicyEditorModal Room="@Room" OnClose="@(() => MassCreatePolicies = false)" OnSaved="@(() => { MassCreatePolicies = false; LoadStatesAsync(); })"></MassPolicyEditorModal> + <MassPolicyEditorModal Room="@Room" OnClose="@(() => MassCreatePolicies = false)" OnSaved="@(() => { + MassCreatePolicies = false; + _ = LoadStatesAsync(); + })"></MassPolicyEditorModal> } @code { @@ -171,27 +198,22 @@ else { private bool Loading { get; set; } = true; [Parameter] - public string RoomId { get; set; } - - private bool _enableAvatars; - private StateEventResponse? _currentlyEditingEvent; - private bool _massCreatePolicies; - private StateEventResponse? _serverPolicyToMakePermanent; + public required string RoomId { get; set; } private Dictionary<Type, List<StateEventResponse>> PolicyEventsByType { get; set; } = new(); private StateEventResponse? CurrentlyEditingEvent { - get => _currentlyEditingEvent; + get; set { - _currentlyEditingEvent = value; + field = value; StateHasChanged(); } } public StateEventResponse? ServerPolicyToMakePermanent { - get => _serverPolicyToMakePermanent; + get; set { - _serverPolicyToMakePermanent = value; + field = value; StateHasChanged(); } } @@ -206,9 +228,9 @@ else { public Dictionary<StateEventResponse, int> ActiveKicks { get; set; } = []; public bool MassCreatePolicies { - get => _massCreatePolicies; + get; set { - _massCreatePolicies = value; + field = value; StateHasChanged(); } } @@ -219,39 +241,64 @@ else { Homeserver = (await sessionStore.GetCurrentHomeserver(navigateOnFailure: true))!; if (Homeserver is null) return; Room = Homeserver.GetRoom(RoomId!); - await Task.WhenAll([ + await Task.WhenAll( Task.Run(async () => { PowerLevels = (await Room.GetPowerLevelsAsync())!; }), Task.Run(async () => { DraupnirShortcode = (await Room.GetStateOrNullAsync<MjolnirShortcodeEventContent>(MjolnirShortcodeEventContent.EventId))?.Shortcode; }), Task.Run(async () => { RoomAlias = (await Room.GetCanonicalAliasAsync())?.Alias; }), Task.Run(async () => { RoomName = await Room.GetNameOrFallbackAsync(); }), - Task.Run(async () => { CurrentUserIsDraupnir = (await Homeserver.GetAccountDataOrNullAsync<object>("org.matrix.mjolnir.protected_rooms")) is not null; }), - ]); + Task.Run(async () => { CurrentUserIsDraupnir = (await Homeserver.GetAccountDataOrNullAsync<object>(DraupnirProtectedRoomsData.EventId)) is not null; }) + ); + StateHasChanged(); await LoadStatesAsync(); Console.WriteLine($"Policy list editor initialized in {sw.Elapsed}!"); } private async Task LoadStatesAsync() { + var sw = Stopwatch.StartNew(); Loading = true; - var states = Room.GetFullStateAsync(); - PolicyEventsByType.Clear(); - await foreach (var state in states) { + // var states = Room.GetFullStateAsync(); + var states = await Room.GetFullStateAsListAsync(); + // PolicyEventsByType.Clear(); + + Console.WriteLine($"LoadStatesAsync: Loaded state in {sw.Elapsed}"); + + foreach (var state in states) { 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 targetPolicies = PolicyEventsByType[state.MappedType]; + + if (targetPolicies.FirstOrDefault(x => StateEvent.TypeKeyPairMatches(x, state)) is { } evt) { + if (StateEvent.Equals(evt, state)) continue; + targetPolicies.Remove(evt); + targetPolicies.Add(state); + } + else targetPolicies.Add(state); } + Console.WriteLine($"LoadStatesAsync: Processed state in {sw.Elapsed}"); + Loading = false; StateHasChanged(); + await Task.Delay(10); + await Task.Yield(); + Console.WriteLine($"LoadStatesAsync: yield finished in {sw.Elapsed}"); } + // private List<StateEventResponse> AllPolicies { get; set; } = []; + private List<StateEventResponse> GetPolicyEventsByType(Type type) => PolicyEventsByType.ContainsKey(type) ? PolicyEventsByType[type] : []; private List<StateEventResponse> GetValidPolicyEventsByType(Type type) => GetPolicyEventsByType(type) .Where(x => !string.IsNullOrWhiteSpace(x.RawContent?["recommendation"]?.GetValue<string>())).ToList(); private List<StateEventResponse> GetInvalidPolicyEventsByType(Type type) => GetPolicyEventsByType(type) - .Where(x => string.IsNullOrWhiteSpace(x.RawContent?["recommendation"]?.GetValue<string>())).ToList(); + .Where(x => x.RawContent is { Count: > 0 } && string.IsNullOrWhiteSpace(x.RawContent?["recommendation"]?.GetValue<string>())).ToList(); + + private List<StateEventResponse> GetRemovedPolicyEventsByType(Type type) => GetPolicyEventsByType(type) + .Where(x => x.RawContent is null or { Count: 0 }).ToList(); private string? GetPolicyTypeNameOrNull(Type type) => type.GetFriendlyNamePluralOrNull() ?? type.GetCustomAttributes<MatrixEventAttribute>() @@ -272,7 +319,7 @@ else { } private async Task UpgradePolicyAsync(StateEventResponse policyEvent) { - policyEvent.RawContent["upgraded_from_type"] = policyEvent.Type; + policyEvent.RawContent["gay.rory.matrixutils.upgraded_from_type"] = policyEvent.Type; await LoadStatesAsync(); } @@ -285,6 +332,23 @@ else { private static Dictionary<Type, string[]> PolicyTypeIds = KnownPolicyTypes .ToDictionary(x => x, x => x.GetCustomAttributes<MatrixEventAttribute>().Select(y => y.EventName).ToArray()); + private static string TruncateMxid(string mxid) { + var parts = mxid.Split(':', 2); + if (parts[0].Length > 50) + parts[0] = parts[0][..50] + "[...]"; + + if (parts is [_, { Length: > 50 }]) + parts[1] = parts[1][..50] + "[...]"; + + return parts.Length == 1 ? parts[0] : $"{parts[0]}:{parts[1]}"; + } + + private struct PolicyStats { + public int Active { get; set; } + public int Invalid { get; set; } + public int Removed { get; set; } + } + #region Draupnir interop private SemaphoreSlim ss = new(16, 16);