diff --git a/LibMatrix/Helpers/SyncProcessors/Msc4222EmulationSyncProcessor.cs b/LibMatrix/Helpers/SyncProcessors/Msc4222EmulationSyncProcessor.cs
index e34b5cf..be8aa8d 100644
--- a/LibMatrix/Helpers/SyncProcessors/Msc4222EmulationSyncProcessor.cs
+++ b/LibMatrix/Helpers/SyncProcessors/Msc4222EmulationSyncProcessor.cs
@@ -45,7 +45,7 @@ public class Msc4222EmulationSyncProcessor(AuthenticatedHomeserverGeneric homese
tasks.AddRange(resp.Rooms.Leave.Select(ProcessLeftRooms).ToList());
}
- var tasksEnum = tasks.ToAsyncEnumerable();
+ var tasksEnum = tasks.ToAsyncResultEnumerable();
await foreach (var wasModified in tasksEnum) {
if (wasModified) {
modified = true;
@@ -129,7 +129,7 @@ public class Msc4222EmulationSyncProcessor(AuthenticatedHomeserverGeneric homese
}
});
- var tasksEnum = tasks.ToAsyncEnumerable();
+ var tasksEnum = tasks.ToAsyncResultEnumerable();
await foreach (var evt in tasksEnum) {
data.StateAfter.Events.Add(evt);
}
@@ -198,7 +198,7 @@ public class Msc4222EmulationSyncProcessor(AuthenticatedHomeserverGeneric homese
}
});
- var tasksEnum = tasks.ToAsyncEnumerable();
+ var tasksEnum = tasks.ToAsyncResultEnumerable();
await foreach (var evt in tasksEnum) {
data.StateAfter.Events.Add(evt);
}
diff --git a/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs b/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs
index 47e7039..916780e 100644
--- a/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs
+++ b/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs
@@ -147,7 +147,7 @@ public class AuthenticatedHomeserverGeneric : RemoteHomeserver {
await Task.Delay(1000);
}
}
- }).ToAsyncEnumerable();
+ }).ToAsyncResultEnumerable();
await foreach (var result in tasks)
if (result is not null)
@@ -217,7 +217,7 @@ public class AuthenticatedHomeserverGeneric : RemoteHomeserver {
if (preserveCustomRoomProfile) {
var rooms = await GetJoinedRooms();
- var roomProfiles = rooms.Select(GetOwnRoomProfileWithIdAsync).ToAsyncEnumerable();
+ var roomProfiles = rooms.Select(GetOwnRoomProfileWithIdAsync).ToAsyncResultEnumerable();
targetSyncCount = rooms.Count;
await foreach (var (roomId, currentRoomProfile) in roomProfiles)
try {
@@ -290,7 +290,7 @@ public class AuthenticatedHomeserverGeneric : RemoteHomeserver {
public async IAsyncEnumerable<KeyValuePair<string, RoomMemberEventContent>> GetRoomProfilesAsync() {
var rooms = await GetJoinedRooms();
- var results = rooms.Select(GetOwnRoomProfileWithIdAsync).ToAsyncEnumerable();
+ var results = rooms.Select(GetOwnRoomProfileWithIdAsync).ToAsyncResultEnumerable();
await foreach (var res in results) yield return res;
}
@@ -613,6 +613,9 @@ public class AuthenticatedHomeserverGeneric : RemoteHomeserver {
[JsonPropertyName("gay.rory.bulk_send_events")]
public BooleanCapability? BulkSendEvents { get; set; }
+ [JsonPropertyName("gay.rory.synapse_admin_extensions.room_list.query_events.v2")]
+ public BooleanCapability? SynapseRoomListQueryEventsV2 { get; set; }
+
[JsonExtensionData]
public Dictionary<string, object>? AdditionalCapabilities { get; set; }
}
diff --git a/LibMatrix/Homeservers/ImplementationDetails/Synapse/Models/Filters/SynapseAdminLocalRoomQueryFilter.cs b/LibMatrix/Homeservers/ImplementationDetails/Synapse/Models/Filters/SynapseAdminLocalRoomQueryFilter.cs
index b8929a0..97c4bbf 100644
--- a/LibMatrix/Homeservers/ImplementationDetails/Synapse/Models/Filters/SynapseAdminLocalRoomQueryFilter.cs
+++ b/LibMatrix/Homeservers/ImplementationDetails/Synapse/Models/Filters/SynapseAdminLocalRoomQueryFilter.cs
@@ -1,27 +1,90 @@
namespace LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Filters;
public class SynapseAdminLocalRoomQueryFilter {
- public string RoomIdContains { get; set; } = "";
- public string NameContains { get; set; } = "";
- public string CanonicalAliasContains { get; set; } = "";
- public string VersionContains { get; set; } = "";
- public string CreatorContains { get; set; } = "";
- public string EncryptionContains { get; set; } = "";
- public string JoinRulesContains { get; set; } = "";
- public string GuestAccessContains { get; set; } = "";
- public string HistoryVisibilityContains { get; set; } = "";
-
- public bool Federatable { get; set; } = true;
- public bool Public { get; set; } = true;
-
- public int JoinedMembersGreaterThan { get; set; }
- public int JoinedMembersLessThan { get; set; } = int.MaxValue;
-
- public int JoinedLocalMembersGreaterThan { get; set; }
- public int JoinedLocalMembersLessThan { get; set; } = int.MaxValue;
- public int StateEventsGreaterThan { get; set; }
- public int StateEventsLessThan { get; set; } = int.MaxValue;
-
- public bool CheckFederation { get; set; }
- public bool CheckPublic { get; set; }
+ public StringFilter RoomId { get; set; } = new();
+ public StringFilter Name { get; set; } = new();
+ public StringFilter CanonicalAlias { get; set; } = new();
+ public StringFilter Version { get; set; } = new();
+ public StringFilter Creator { get; set; } = new();
+ public StringFilter Encryption { get; set; } = new();
+ public StringFilter JoinRules { get; set; } = new();
+ public StringFilter GuestAccess { get; set; } = new();
+ public StringFilter HistoryVisibility { get; set; } = new();
+ public StringFilter RoomType { get; set; } = new();
+ public StringFilter Topic { get; set; } = new();
+
+ public IntFilter JoinedMembers { get; set; } = new() {
+ GreaterThan = 0,
+ LessThan = int.MaxValue
+ };
+
+ public IntFilter JoinedLocalMembers { get; set; } = new() {
+ GreaterThan = 0,
+ LessThan = int.MaxValue
+ };
+
+ public IntFilter StateEvents { get; set; } = new() {
+ GreaterThan = 0,
+ LessThan = int.MaxValue
+ };
+
+ public BoolFilter Federation { get; set; } = new();
+ public BoolFilter Public { get; set; } = new();
+ public BoolFilter Tombstone { get; set; } = new();
+}
+
+public class OptionalFilter {
+ public bool Enabled { get; set; }
+}
+
+public class StringFilter : OptionalFilter {
+ public bool CheckValueContains { get; set; }
+ public string? ValueContains { get; set; }
+
+ public bool CheckValueEquals { get; set; }
+ public string? ValueEquals { get; set; }
+
+ public bool Matches(string? value, StringComparison comparison = StringComparison.Ordinal) {
+ if (!Enabled) return true;
+
+ if (CheckValueEquals) {
+ if (!string.Equals(value, ValueEquals, comparison)) return false;
+ }
+
+ if (CheckValueContains && ValueContains != null) {
+ if (value != null && !value.Contains(ValueContains, comparison)) return false;
+ }
+
+ return true;
+ }
+}
+
+public class IntFilter : OptionalFilter {
+ public bool CheckGreaterThan { get; set; }
+ public int GreaterThan { get; set; }
+ public bool CheckLessThan { get; set; }
+ public int LessThan { get; set; }
+
+ public bool Matches(int value) {
+ if (!Enabled) return true;
+
+ if (CheckGreaterThan) {
+ if (value <= GreaterThan) return false;
+ }
+
+ if (CheckLessThan) {
+ if (value >= LessThan) return false;
+ }
+
+ return true;
+ }
+}
+
+public class BoolFilter : OptionalFilter {
+ public bool Value { get; set; }
+
+ public bool Matches(bool value) {
+ if (!Enabled) return true;
+ return value == Value;
+ }
}
\ No newline at end of file
diff --git a/LibMatrix/Homeservers/ImplementationDetails/Synapse/Models/Responses/RoomListResult.cs b/LibMatrix/Homeservers/ImplementationDetails/Synapse/Models/Responses/RoomListResult.cs
index d84c89b..3bc1f47 100644
--- a/LibMatrix/Homeservers/ImplementationDetails/Synapse/Models/Responses/RoomListResult.cs
+++ b/LibMatrix/Homeservers/ImplementationDetails/Synapse/Models/Responses/RoomListResult.cs
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
+using LibMatrix.EventTypes.Spec.State.RoomInfo;
namespace LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Responses;
@@ -60,5 +61,56 @@ public class SynapseAdminRoomListResult {
[JsonPropertyName("state_events")]
public int StateEvents { get; set; }
+
+ [JsonPropertyName("gay.rory.synapse_admin_extensions.tombstone")]
+ public StateEventResponse? TombstoneEvent { get; set; }
+
+ [JsonPropertyName("gay.rory.synapse_admin_extensions.create")]
+ public StateEventResponse? CreateEvent { get; set; }
+
+ [JsonPropertyName("gay.rory.synapse_admin_extensions.topic")]
+ public StateEventResponse? TopicEvent { get; set; }
+
+ public async Task<StateEventResponse?> GetCreateEventAsync(AuthenticatedHomeserverSynapse hs) {
+ if (CreateEvent != null) return CreateEvent;
+
+ try {
+ var events = (await hs.Admin.GetRoomStateAsync(RoomId, RoomCreateEventContent.EventId));
+ CreateEvent = events.Events.SingleOrDefault(x => x.StateKey == "");
+ }
+ catch (Exception e) {
+ Console.WriteLine($"Failed to fetch room create event for {RoomId}: {e}");
+ }
+
+ return null;
+ }
+
+ public async Task<StateEventResponse?> GetTombstoneEventAsync(AuthenticatedHomeserverSynapse hs) {
+ if (TombstoneEvent != null) return TombstoneEvent;
+
+ try {
+ var events = (await hs.Admin.GetRoomStateAsync(RoomId, RoomTombstoneEventContent.EventId));
+ TombstoneEvent = events.Events.SingleOrDefault(x => x.StateKey == "");
+ }
+ catch (Exception e) {
+ Console.WriteLine($"Failed to fetch room tombstone event for {RoomId}: {e}");
+ }
+
+ return null;
+ }
+
+ public async Task<StateEventResponse?> GetTopicEventAsync(AuthenticatedHomeserverSynapse hs) {
+ if (TopicEvent != null) return TopicEvent;
+
+ try {
+ var events = await hs.Admin.GetRoomStateAsync(RoomId, RoomTopicEventContent.EventId);
+ TopicEvent = events.Events.SingleOrDefault(x => x.StateKey == "");
+ }
+ catch (Exception e) {
+ Console.WriteLine($"Failed to fetch room topic event for {RoomId}: {e}");
+ }
+
+ return null;
+ }
}
}
\ No newline at end of file
diff --git a/LibMatrix/Homeservers/ImplementationDetails/Synapse/SynapseAdminApiClient.cs b/LibMatrix/Homeservers/ImplementationDetails/Synapse/SynapseAdminApiClient.cs
index 4da0013..6d09006 100644
--- a/LibMatrix/Homeservers/ImplementationDetails/Synapse/SynapseAdminApiClient.cs
+++ b/LibMatrix/Homeservers/ImplementationDetails/Synapse/SynapseAdminApiClient.cs
@@ -1,21 +1,15 @@
// #define LOG_SKIP
+using System.CodeDom.Compiler;
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Nodes;
-using System.Net.Http.Json;
-using System.Text.Json;
-using System.Text.Json.Nodes;
-using System.Text.Json.Serialization;
using ArcaneLibs.Extensions;
+using LibMatrix.EventTypes.Spec.State.RoomInfo;
using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Filters;
using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Requests;
using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Responses;
using LibMatrix.Responses;
-using LibMatrix.Filters;
-using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Filters;
-using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Responses;
-using LibMatrix.Responses;
using LibMatrix.StructuredData;
namespace LibMatrix.Homeservers.ImplementationDetails.Synapse;
@@ -28,24 +22,41 @@ public class SynapseAdminApiClient(AuthenticatedHomeserverSynapse authenticatedH
#region Rooms
public async IAsyncEnumerable<SynapseAdminRoomListResult.SynapseAdminRoomListResultRoom> SearchRoomsAsync(int limit = int.MaxValue, int chunkLimit = 250,
- string orderBy = "name", string dir = "f", string? searchTerm = null, SynapseAdminLocalRoomQueryFilter? localFilter = null) {
+ string orderBy = "name", string dir = "f", string? searchTerm = null, SynapseAdminLocalRoomQueryFilter? localFilter = null,
+ bool fetchTombstones = false, bool fetchTopics = false, bool fetchCreateEvents = false) {
+ if (localFilter != null) {
+ fetchTombstones |= localFilter.Tombstone.Enabled;
+ fetchTopics |= localFilter.Topic.Enabled;
+ fetchCreateEvents |= localFilter.RoomType.Enabled;
+ }
+
+ var serverCaps = await authenticatedHomeserver.GetCapabilitiesAsync();
+ var serverSupportsQueryEventsV2 = serverCaps.Capabilities.SynapseRoomListQueryEventsV2?.Enabled ?? false;
+
SynapseAdminRoomListResult? res = null;
var i = 0;
int? totalRooms = null;
do {
var url = $"/_synapse/admin/v1/rooms?limit={Math.Min(limit, chunkLimit)}&dir={dir}&order_by={orderBy}";
- if (!string.IsNullOrEmpty(searchTerm)) url += $"&search_term={searchTerm}";
+ if (!string.IsNullOrEmpty(searchTerm)) url += $"&search_term={searchTerm}";
if (res?.NextBatch is not null) url += $"&from={res.NextBatch}";
+ // nonstandard stuff
+ if (fetchTombstones) url += "&gay.rory.synapse_admin_extensions.include_tombstone=true&emma_include_tombstone=true";
+ if (fetchTopics) url += "&gay.rory.synapse_admin_extensions.include_topic=true";
+ if (fetchCreateEvents) url += "&gay.rory.synapse_admin_extensions.include_create_event=true";
+
Console.WriteLine($"--- ADMIN Querying Room List with URL: {url} - Already have {i} items... ---");
res = await authenticatedHomeserver.ClientHttpClient.GetFromJsonAsync<SynapseAdminRoomListResult>(url);
totalRooms ??= res.TotalRooms;
// Console.WriteLine(res.ToJson(false));
+
+ List<SynapseAdminRoomListResult.SynapseAdminRoomListResultRoom> keep = [];
foreach (var room in res.Rooms) {
if (localFilter is not null) {
- if (!string.IsNullOrWhiteSpace(localFilter.RoomIdContains) && !room.RoomId.Contains(localFilter.RoomIdContains, StringComparison.OrdinalIgnoreCase)) {
+ if (!localFilter.RoomId.Matches(room.RoomId, StringComparison.OrdinalIgnoreCase)) {
totalRooms--;
#if LOG_SKIP
Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule roomid.");
@@ -53,7 +64,7 @@ public class SynapseAdminApiClient(AuthenticatedHomeserverSynapse authenticatedH
continue;
}
- if (!string.IsNullOrWhiteSpace(localFilter.NameContains) && room.Name?.Contains(localFilter.NameContains, StringComparison.OrdinalIgnoreCase) != true) {
+ if (!localFilter.Name.Matches(room.Name ?? "", StringComparison.OrdinalIgnoreCase)) {
totalRooms--;
#if LOG_SKIP
Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule roomname.");
@@ -61,8 +72,7 @@ public class SynapseAdminApiClient(AuthenticatedHomeserverSynapse authenticatedH
continue;
}
- if (!string.IsNullOrWhiteSpace(localFilter.CanonicalAliasContains) &&
- room.CanonicalAlias?.Contains(localFilter.CanonicalAliasContains, StringComparison.OrdinalIgnoreCase) != true) {
+ if (!localFilter.CanonicalAlias.Matches(room.CanonicalAlias ?? "", StringComparison.OrdinalIgnoreCase)) {
totalRooms--;
#if LOG_SKIP
Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule alias.");
@@ -70,7 +80,7 @@ public class SynapseAdminApiClient(AuthenticatedHomeserverSynapse authenticatedH
continue;
}
- if (!string.IsNullOrWhiteSpace(localFilter.VersionContains) && !room.Version.Contains(localFilter.VersionContains, StringComparison.OrdinalIgnoreCase)) {
+ if (!localFilter.Version.Matches(room.Version ?? "")) {
totalRooms--;
#if LOG_SKIP
Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule version.");
@@ -78,7 +88,7 @@ public class SynapseAdminApiClient(AuthenticatedHomeserverSynapse authenticatedH
continue;
}
- if (!string.IsNullOrWhiteSpace(localFilter.CreatorContains) && !room.Creator.Contains(localFilter.CreatorContains, StringComparison.OrdinalIgnoreCase)) {
+ if (!localFilter.Creator.Matches(room.Creator ?? "", StringComparison.OrdinalIgnoreCase)) {
totalRooms--;
#if LOG_SKIP
Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule creator.");
@@ -86,8 +96,7 @@ public class SynapseAdminApiClient(AuthenticatedHomeserverSynapse authenticatedH
continue;
}
- if (!string.IsNullOrWhiteSpace(localFilter.EncryptionContains) &&
- room.Encryption?.Contains(localFilter.EncryptionContains, StringComparison.OrdinalIgnoreCase) != true) {
+ if (!localFilter.Encryption.Matches(room.Encryption ?? "", StringComparison.OrdinalIgnoreCase)) {
totalRooms--;
#if LOG_SKIP
Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule encryption.");
@@ -95,8 +104,7 @@ public class SynapseAdminApiClient(AuthenticatedHomeserverSynapse authenticatedH
continue;
}
- if (!string.IsNullOrWhiteSpace(localFilter.JoinRulesContains) &&
- room.JoinRules?.Contains(localFilter.JoinRulesContains, StringComparison.OrdinalIgnoreCase) != true) {
+ if (!localFilter.JoinRules.Matches(room.JoinRules ?? "", StringComparison.OrdinalIgnoreCase)) {
totalRooms--;
#if LOG_SKIP
Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule joinrules.");
@@ -104,8 +112,7 @@ public class SynapseAdminApiClient(AuthenticatedHomeserverSynapse authenticatedH
continue;
}
- if (!string.IsNullOrWhiteSpace(localFilter.GuestAccessContains) &&
- room.GuestAccess?.Contains(localFilter.GuestAccessContains, StringComparison.OrdinalIgnoreCase) != true) {
+ if (!localFilter.GuestAccess.Matches(room.GuestAccess ?? "", StringComparison.OrdinalIgnoreCase)) {
totalRooms--;
#if LOG_SKIP
Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule guestaccess.");
@@ -113,8 +120,7 @@ public class SynapseAdminApiClient(AuthenticatedHomeserverSynapse authenticatedH
continue;
}
- if (!string.IsNullOrWhiteSpace(localFilter.HistoryVisibilityContains) &&
- room.HistoryVisibility?.Contains(localFilter.HistoryVisibilityContains, StringComparison.OrdinalIgnoreCase) != true) {
+ if (!localFilter.HistoryVisibility.Matches(room.HistoryVisibility ?? "", StringComparison.OrdinalIgnoreCase)) {
totalRooms--;
#if LOG_SKIP
Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule history visibility.");
@@ -122,7 +128,7 @@ public class SynapseAdminApiClient(AuthenticatedHomeserverSynapse authenticatedH
continue;
}
- if (localFilter.CheckFederation && room.Federatable != localFilter.Federatable) {
+ if (!localFilter.Federation.Matches(room.Federatable)) {
totalRooms--;
#if LOG_SKIP
Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule federation.");
@@ -130,7 +136,7 @@ public class SynapseAdminApiClient(AuthenticatedHomeserverSynapse authenticatedH
continue;
}
- if (localFilter.CheckPublic && room.Public != localFilter.Public) {
+ if (!localFilter.Public.Matches(room.Public)) {
totalRooms--;
#if LOG_SKIP
Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule public.");
@@ -138,15 +144,15 @@ public class SynapseAdminApiClient(AuthenticatedHomeserverSynapse authenticatedH
continue;
}
- if (room.StateEvents < localFilter.StateEventsGreaterThan || room.StateEvents > localFilter.StateEventsLessThan) {
+ if (!localFilter.StateEvents.Matches(room.StateEvents)) {
totalRooms--;
#if LOG_SKIP
- Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule joined local members.");
+ Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule state events.");
#endif
continue;
}
- if (room.JoinedMembers < localFilter.JoinedMembersGreaterThan || room.JoinedMembers > localFilter.JoinedMembersLessThan) {
+ if (!localFilter.JoinedMembers.Matches(room.JoinedMembers)) {
totalRooms--;
#if LOG_SKIP
Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule joined members: {localFilter.JoinedMembersGreaterThan} < {room.JoinedLocalMembers} < {localFilter.JoinedMembersLessThan}.");
@@ -154,7 +160,7 @@ public class SynapseAdminApiClient(AuthenticatedHomeserverSynapse authenticatedH
continue;
}
- if (room.JoinedLocalMembers < localFilter.JoinedLocalMembersGreaterThan || room.JoinedLocalMembers > localFilter.JoinedLocalMembersLessThan) {
+ if (!localFilter.JoinedLocalMembers.Matches(room.JoinedLocalMembers)) {
totalRooms--;
#if LOG_SKIP
Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule joined local members: {localFilter.JoinedLocalMembersGreaterThan} < {room.JoinedLocalMembers} < {localFilter.JoinedLocalMembersLessThan}.");
@@ -162,23 +168,93 @@ public class SynapseAdminApiClient(AuthenticatedHomeserverSynapse authenticatedH
continue;
}
}
- // if (contentSearch is not null && !string.IsNullOrEmpty(contentSearch) &&
- // !(
- // room.Name?.Contains(contentSearch, StringComparison.InvariantCultureIgnoreCase) == true ||
- // room.CanonicalAlias?.Contains(contentSearch, StringComparison.InvariantCultureIgnoreCase) == true ||
- // room.Creator?.Contains(contentSearch, StringComparison.InvariantCultureIgnoreCase) == true
- // )
- // ) {
- // totalRooms--;
- // continue;
- // }
i++;
+ keep.Add(room);
+ }
+
+ var parallelisationLimit = new SemaphoreSlim(32, 32);
+ List<Task<(SynapseAdminRoomListResult.SynapseAdminRoomListResultRoom room, StateEventResponse?[] tasks)>> tasks = [];
+
+ async Task<(SynapseAdminRoomListResult.SynapseAdminRoomListResultRoom room, StateEventResponse?[] tasks)> fillTask(
+ SynapseAdminRoomListResult.SynapseAdminRoomListResultRoom room) {
+ if (serverSupportsQueryEventsV2) return (room, []);
+
+ var fillTasks = await Task.WhenAll(((Task<StateEventResponse?>?[]) [
+ fetchTombstones && room.TombstoneEvent is null
+ ? parallelisationLimit.RunWithLockAsync(() => room.GetTombstoneEventAsync(authenticatedHomeserver))
+ : null!,
+ fetchTopics && room.TopicEvent is null
+ ? parallelisationLimit.RunWithLockAsync(() => room.GetTopicEventAsync(authenticatedHomeserver))
+ : null!,
+ fetchCreateEvents && room.CreateEvent is null
+ ? parallelisationLimit.RunWithLockAsync(() => room.GetCreateEventAsync(authenticatedHomeserver))
+ : null!,
+ ])
+ .Where(t => t != null)!
+ );
+ return (
+ room,
+ fillTasks
+ );
+ }
+
+ tasks.AddRange(
+ serverSupportsQueryEventsV2
+ ? keep.Select(x => Task.FromResult((x, (StateEventResponse?[])[])))
+ : keep.Select(fillTask)
+ );
+
+ // await Task.WhenAll(tasks);
+
+ foreach (var taskRes in tasks) {
+ var (room, _) = await taskRes;
+ if (localFilter is not null) {
+ if (!localFilter.Tombstone.Matches(room.TombstoneEvent != null)) {
+ totalRooms--;
+#if LOG_SKIP
+ Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule tombstone.");
+#endif
+ continue;
+ }
+
+ if (!localFilter.RoomType.Matches(room.CreateEvent?.ContentAs<RoomCreateEventContent>()?.Type)) {
+ totalRooms--;
+#if LOG_SKIP
+ Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule room type.");
+#endif
+ continue;
+ }
+
+ if (!localFilter.Topic.Matches(room.TopicEvent?.ContentAs<RoomTopicEventContent>()?.Topic, StringComparison.OrdinalIgnoreCase)) {
+ totalRooms--;
+#if LOG_SKIP
+ Console.WriteLine($"Skipped room {room.ToJson(indent: false)} on rule topic.");
+#endif
+ continue;
+ }
+ }
+
yield return room;
}
} while (i < Math.Min(limit, totalRooms ?? limit));
}
+ public async Task<bool> CheckRoomKnownAsync(string roomId) {
+ try {
+ var createEvt = await GetRoomStateAsync(roomId, RoomCreateEventContent.EventId);
+ if (createEvt.Events.FirstOrDefault(e => e.StateKey == "") is null)
+ return false;
+ var members = await GetRoomMembersAsync(roomId, localOnly: true);
+ return members.Members.Count > 0;
+ }
+ catch (Exception e) {
+ if (e is HttpRequestException { StatusCode: System.Net.HttpStatusCode.NotFound }) return false;
+ if (e is MatrixException { ErrorCode: MatrixException.ErrorCodes.M_NOT_FOUND }) return false;
+ throw;
+ }
+ }
+
#endregion
#region Users
@@ -194,7 +270,7 @@ public class SynapseAdminApiClient(AuthenticatedHomeserverSynapse authenticatedH
if (!string.IsNullOrWhiteSpace(from)) url = url.AddQuery("from", from);
if (!string.IsNullOrWhiteSpace(orderBy)) url = url.AddQuery("order_by", orderBy);
if (!string.IsNullOrWhiteSpace(dir)) url = url.AddQuery("dir", dir);
-
+
Console.WriteLine($"--- ADMIN Querying User List with URL: {url} ---");
// TODO: implement URI methods in http client
var res = await authenticatedHomeserver.ClientHttpClient.GetFromJsonAsync<SynapseAdminUserListResult>(url.ToString());
@@ -527,8 +603,13 @@ public class SynapseAdminApiClient(AuthenticatedHomeserverSynapse authenticatedH
$"/_synapse/admin/v2/rooms/delete_status/{deleteId}");
}
- public async Task<SynapseAdminRoomMemberListResult> GetRoomMembersAsync(string roomId) {
- return await authenticatedHomeserver.ClientHttpClient.GetFromJsonAsync<SynapseAdminRoomMemberListResult>($"/_synapse/admin/v1/rooms/{roomId.UrlEncode()}/members");
+ public async Task<SynapseAdminRoomMemberListResult> GetRoomMembersAsync(string roomId, bool localOnly = false) {
+ var res = await authenticatedHomeserver.ClientHttpClient.GetFromJsonAsync<SynapseAdminRoomMemberListResult>($"/_synapse/admin/v1/rooms/{roomId.UrlEncode()}/members");
+ if (localOnly) {
+ res.Members = res.Members.Where(m => m.EndsWith($":{authenticatedHomeserver.ServerName}")).ToList();
+ }
+
+ return res;
}
public async Task<SynapseAdminRoomStateResult> GetRoomStateAsync(string roomId, string? type = null) {
diff --git a/LibMatrix/Homeservers/RemoteHomeServer.cs b/LibMatrix/Homeservers/RemoteHomeServer.cs
index 3e41075..af84be2 100644
--- a/LibMatrix/Homeservers/RemoteHomeServer.cs
+++ b/LibMatrix/Homeservers/RemoteHomeServer.cs
@@ -118,9 +118,6 @@ public class RemoteHomeserver {
#endregion
- [Obsolete("This call uses the deprecated unauthenticated media endpoints, please switch to the relevant AuthenticatedHomeserver methods instead.", true)]
- public virtual string? ResolveMediaUri(string? mxcUri) => null;
-
public UserInteractiveAuthClient Auth;
}
diff --git a/LibMatrix/LibMatrix.csproj b/LibMatrix/LibMatrix.csproj
index c6c1dce..61810a3 100644
--- a/LibMatrix/LibMatrix.csproj
+++ b/LibMatrix/LibMatrix.csproj
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <TargetFramework>net9.0</TargetFramework>
+ <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>preview</LangVersion>
@@ -12,8 +12,8 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.9" />
- <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.9" />
+ <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0-rc.2.25502.107"/>
+ <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0-rc.2.25502.107"/>
<ProjectReference Include="..\LibMatrix.EventTypes\LibMatrix.EventTypes.csproj"/>
</ItemGroup>
diff --git a/LibMatrix/Services/HomeserverResolverService.cs b/LibMatrix/Services/HomeserverResolverService.cs
index 7d30b7b..ed1d2e3 100644
--- a/LibMatrix/Services/HomeserverResolverService.cs
+++ b/LibMatrix/Services/HomeserverResolverService.cs
@@ -133,15 +133,6 @@ public class HomeserverResolverService {
_logger.LogInformation("No server well-known for {server}...", homeserver);
return null;
}
-
- [Obsolete("Use authenticated media, available on AuthenticatedHomeserverGeneric", true)]
- public async Task<string?> ResolveMediaUri(string homeserver, string mxc) {
- if (homeserver is null) throw new ArgumentNullException(nameof(homeserver));
- if (mxc is null) throw new ArgumentNullException(nameof(mxc));
- if (!mxc.StartsWith("mxc://")) throw new InvalidDataException("mxc must start with mxc://");
- homeserver = (await ResolveHomeserverFromWellKnown(homeserver)).Client;
- return mxc.Replace("mxc://", $"{homeserver}/_matrix/media/v3/download/");
- }
public class WellKnownUris {
public string? Client { get; set; }
|