diff --git a/LibMatrix/Helpers/SyncHelper.cs b/LibMatrix/Helpers/SyncHelper.cs
index 6488464..6f2cacc 100644
--- a/LibMatrix/Helpers/SyncHelper.cs
+++ b/LibMatrix/Helpers/SyncHelper.cs
@@ -24,7 +24,7 @@ public class SyncHelper(AuthenticatedHomeserverGeneric homeserver, ILogger? logg
public string? Since { get; set; }
public int Timeout { get; set; } = 30000;
- public string? SetPresence { get; set; } = "online";
+ public string? SetPresence { get; set; }
/// <summary>
/// Disabling this uses a technically slower code path, useful for checking whether delay comes from waiting for server or deserialising responses
@@ -168,9 +168,11 @@ public class SyncHelper(AuthenticatedHomeserverGeneric homeserver, ILogger? logg
var sw = Stopwatch.StartNew();
if (_filterIsDirty) await UpdateFilterAsync();
- var url = $"/_matrix/client/v3/sync?timeout={Timeout}&set_presence={SetPresence}&full_state={(FullState ? "true" : "false")}";
+ var url = $"/_matrix/client/v3/sync?timeout={Timeout}";
+ if (!string.IsNullOrWhiteSpace(SetPresence)) url += $"&set_presence={SetPresence}";
if (!string.IsNullOrWhiteSpace(Since)) url += $"&since={Since}";
if (_filterId is not null) url += $"&filter={_filterId}";
+ if (FullState) url += "&full_state=true";
if (UseMsc4222StateAfter) url += "&org.matrix.msc4222.use_state_after=true&use_state_after=true"; // We use both unstable and stable names for compatibility
// logger?.LogInformation("SyncHelper: Calling: {}", url);
@@ -209,6 +211,7 @@ public class SyncHelper(AuthenticatedHomeserverGeneric homeserver, ILogger? logg
Console.WriteLine(e);
logger?.LogError(e, "Failed to sync!\n{}", e.ToString());
await Task.WhenAll(ExceptionHandlers.Select(x => x.Invoke(e)).ToList());
+ if (e is MatrixException { ErrorCode: MatrixException.ErrorCodes.M_UNKNOWN_TOKEN }) throw;
}
return null;
diff --git a/LibMatrix/RoomTypes/GenericRoom.cs b/LibMatrix/RoomTypes/GenericRoom.cs
index 93736a3..bc1bc90 100644
--- a/LibMatrix/RoomTypes/GenericRoom.cs
+++ b/LibMatrix/RoomTypes/GenericRoom.cs
@@ -232,8 +232,11 @@ public class GenericRoom {
return await res.Content.ReadFromJsonAsync<RoomIdResponse>() ?? throw new Exception("Failed to join room?");
}
- public async IAsyncEnumerable<StateEventResponse> GetMembersEnumerableAsync(bool joinedOnly = true) {
- var res = await Homeserver.ClientHttpClient.GetAsync($"/_matrix/client/v3/rooms/{RoomId}/members");
+ public async IAsyncEnumerable<StateEventResponse> GetMembersEnumerableAsync(string? membership = null) {
+ var url = $"/_matrix/client/v3/rooms/{RoomId}/members";
+ var isMembershipSet = !string.IsNullOrWhiteSpace(membership);
+ if (isMembershipSet) url += $"?membership={membership}";
+ var res = await Homeserver.ClientHttpClient.GetAsync(url);
var result = await JsonSerializer.DeserializeAsync<ChunkedStateEventResponse>(await res.Content.ReadAsStreamAsync(), new JsonSerializerOptions() {
TypeInfoResolver = ChunkedStateEventResponseSerializerContext.Default
});
@@ -242,13 +245,16 @@ public class GenericRoom {
foreach (var resp in result.Chunk ?? []) {
if (resp.Type != "m.room.member") continue;
- if (joinedOnly && resp.RawContent?["membership"]?.GetValue<string>() != "join") continue;
+ if (isMembershipSet && resp.RawContent?["membership"]?.GetValue<string>() != membership) continue;
yield return resp;
}
}
- public async Task<FrozenSet<StateEventResponse>> GetMembersListAsync(bool joinedOnly = true) {
- var res = await Homeserver.ClientHttpClient.GetAsync($"/_matrix/client/v3/rooms/{RoomId}/members");
+ public async Task<FrozenSet<StateEventResponse>> GetMembersListAsync(string? membership = null) {
+ var url = $"/_matrix/client/v3/rooms/{RoomId}/members";
+ var isMembershipSet = !string.IsNullOrWhiteSpace(membership);
+ if (isMembershipSet) url += $"?membership={membership}";
+ var res = await Homeserver.ClientHttpClient.GetAsync(url);
var result = await JsonSerializer.DeserializeAsync<ChunkedStateEventResponse>(await res.Content.ReadAsStreamAsync(), new JsonSerializerOptions() {
TypeInfoResolver = ChunkedStateEventResponseSerializerContext.Default
});
@@ -258,13 +264,23 @@ public class GenericRoom {
var members = new List<StateEventResponse>();
foreach (var resp in result.Chunk ?? []) {
if (resp.Type != "m.room.member") continue;
- if (joinedOnly && resp.RawContent?["membership"]?.GetValue<string>() != "join") continue;
+ if (isMembershipSet && resp.RawContent?["membership"]?.GetValue<string>() != membership) continue;
members.Add(resp);
}
return members.ToFrozenSet();
}
+ public async IAsyncEnumerable<string> GetMemberIdsEnumerableAsync(string? membership = null) {
+ await foreach (var evt in GetMembersEnumerableAsync(membership))
+ yield return evt.StateKey!;
+ }
+
+ public async Task<FrozenSet<string>> GetMemberIdsListAsync(string? membership = null) {
+ var members = await GetMembersListAsync(membership);
+ return members.Select(x => x.StateKey!).ToFrozenSet();
+ }
+
#region Utility shortcuts
public Task<EventIdResponse> SendMessageEventAsync(RoomMessageEventContent content) =>
@@ -393,6 +409,15 @@ public class GenericRoom {
return await res.Content.ReadFromJsonAsync<EventIdResponse>() ?? throw new Exception("Failed to send event");
}
+ public async Task<EventIdResponse> SendReactionAsync(string eventId, string key) =>
+ await SendTimelineEventAsync("m.reaction", new RoomMessageReactionEventContent() {
+ RelatesTo = new() {
+ RelationType = "m.annotation",
+ EventId = eventId,
+ Key = key
+ }
+ });
+
public async Task<EventIdResponse?> SendFileAsync(string fileName, Stream fileStream, string messageType = "m.file", string contentType = "application/octet-stream") {
var url = await Homeserver.UploadFile(fileName, fileStream);
var content = new RoomMessageEventContent() {
@@ -586,4 +611,4 @@ public class GenericRoom {
public class RoomIdResponse {
[JsonPropertyName("room_id")]
public string RoomId { get; set; }
-}
+}
\ No newline at end of file
diff --git a/LibMatrix/RoomTypes/SpaceRoom.cs b/LibMatrix/RoomTypes/SpaceRoom.cs
index 4563ed3..0c74be5 100644
--- a/LibMatrix/RoomTypes/SpaceRoom.cs
+++ b/LibMatrix/RoomTypes/SpaceRoom.cs
@@ -17,7 +17,7 @@ public class SpaceRoom(AuthenticatedHomeserverGeneric homeserver, string roomId)
}
public async Task<EventIdResponse> AddChildAsync(GenericRoom room) {
- var members = room.GetMembersEnumerableAsync(true);
+ var members = room.GetMembersEnumerableAsync("join");
Dictionary<string, int> memberCountByHs = new();
await foreach (var member in members) {
var server = member.StateKey.Split(':')[1];
|