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);
|