diff --git a/LibMatrix/Responses/CreateRoomRequest.cs b/LibMatrix/Responses/CreateRoomRequest.cs
index 6f47183..6933622 100644
--- a/LibMatrix/Responses/CreateRoomRequest.cs
+++ b/LibMatrix/Responses/CreateRoomRequest.cs
@@ -3,7 +3,7 @@ using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using LibMatrix.EventTypes;
-using LibMatrix.EventTypes.Spec.State;
+using LibMatrix.EventTypes.Spec.State.RoomInfo;
using LibMatrix.Homeservers;
namespace LibMatrix.Responses;
@@ -26,7 +26,7 @@ public class CreateRoomRequest {
//we dont want to use this, we want more control
// [JsonPropertyName("preset")]
- // public string Preset { get; set; } = null!;
+ // public string Preset { get; set; }
[JsonPropertyName("initial_state")]
public List<StateEvent>? InitialState { get; set; }
@@ -35,10 +35,11 @@ public class CreateRoomRequest {
/// One of: ["public", "private"]
/// </summary>
[JsonPropertyName("visibility")]
+ // ReSharper disable once UnusedAutoPropertyAccessor.Global
public string? Visibility { get; set; }
[JsonPropertyName("power_level_content_override")]
- public RoomPowerLevelEventContent? PowerLevelContentOverride { get; set; } = null!;
+ public RoomPowerLevelEventContent? PowerLevelContentOverride { get; set; }
[JsonPropertyName("creation_content")]
public JsonObject CreationContent { get; set; } = new();
@@ -46,15 +47,17 @@ public class CreateRoomRequest {
[JsonPropertyName("invite")]
public List<string>? Invite { get; set; }
+ public string? RoomVersion { get; set; }
+
/// <summary>
/// For use only when you can't use the CreationContent property
/// </summary>
- public StateEvent this[string eventType, string eventKey = ""] {
+ public StateEvent? this[string eventType, string eventKey = ""] {
get {
- var stateEvent = InitialState.FirstOrDefault(x => x.Type == eventType && x.StateKey == eventKey);
+ var stateEvent = InitialState?.FirstOrDefault(x => x.Type == eventType && x.StateKey == eventKey);
if (stateEvent == null)
- InitialState.Add(stateEvent = new StateEvent {
+ InitialState?.Add(stateEvent = new StateEvent {
Type = eventType,
StateKey = eventKey,
TypedContent = (EventContent)Activator.CreateInstance(
@@ -77,7 +80,7 @@ public class CreateRoomRequest {
public Dictionary<string, string> Validate() {
Dictionary<string, string> errors = new();
- if (!Regex.IsMatch(RoomAliasName, @"[a-zA-Z0-9_\-]+$"))
+ if (!string.IsNullOrWhiteSpace(RoomAliasName) && !Regex.IsMatch(RoomAliasName, @"[a-zA-Z0-9_\-]+$"))
errors.Add("room_alias_name",
"Room alias name must only contain letters, numbers, underscores, and hyphens.");
@@ -97,7 +100,7 @@ public class CreateRoomRequest {
Invite = 25,
StateDefault = 10,
Redact = 50,
- NotificationsPl = new RoomPowerLevelEventContent.NotificationsPL {
+ NotificationsPl = new RoomPowerLevelEventContent.NotificationsPowerLevels {
Room = 10
},
Events = new Dictionary<string, long> {
@@ -137,7 +140,7 @@ public class CreateRoomRequest {
Invite = 25,
StateDefault = 10,
Redact = 50,
- NotificationsPl = new RoomPowerLevelEventContent.NotificationsPL {
+ NotificationsPl = new RoomPowerLevelEventContent.NotificationsPowerLevels {
Room = 10
},
Events = new Dictionary<string, long> {
diff --git a/LibMatrix/Responses/DeviceKeysUploadRequest.cs b/LibMatrix/Responses/DeviceKeysUploadRequest.cs
new file mode 100644
index 0000000..c93c4c6
--- /dev/null
+++ b/LibMatrix/Responses/DeviceKeysUploadRequest.cs
@@ -0,0 +1,24 @@
+using System.Text.Json.Serialization;
+
+namespace LibMatrix.Responses;
+
+public class DeviceKeysUploadRequest {
+ [JsonPropertyName("device_keys")]
+ public DeviceKeysSchema DeviceKeys { get; set; }
+
+
+ [JsonPropertyName("one_time_keys")]
+ public Dictionary<string, OneTimeKey> OneTimeKeys { get; set; }
+
+ public class DeviceKeysSchema {
+ [JsonPropertyName("algorithms")]
+ public List<string> Algorithms { get; set; }
+ }
+ public class OneTimeKey {
+ [JsonPropertyName("key")]
+ public string Key { get; set; }
+
+ [JsonPropertyName("signatures")]
+ public Dictionary<string, Dictionary<string, string>> Signatures { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/LibMatrix/Responses/EventIdResponse.cs b/LibMatrix/Responses/EventIdResponse.cs
new file mode 100644
index 0000000..9e23210
--- /dev/null
+++ b/LibMatrix/Responses/EventIdResponse.cs
@@ -0,0 +1,8 @@
+using System.Text.Json.Serialization;
+
+namespace LibMatrix.Responses;
+
+public class EventIdResponse {
+ [JsonPropertyName("event_id")]
+ public required string EventId { get; set; }
+}
\ No newline at end of file
diff --git a/LibMatrix/Responses/LoginResponse.cs b/LibMatrix/Responses/LoginResponse.cs
index 28fb245..1944276 100644
--- a/LibMatrix/Responses/LoginResponse.cs
+++ b/LibMatrix/Responses/LoginResponse.cs
@@ -1,30 +1,24 @@
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-using LibMatrix.Homeservers;
namespace LibMatrix.Responses;
public class LoginResponse {
[JsonPropertyName("access_token")]
- public string AccessToken { get; set; } = null!;
+ public string AccessToken { get; set; }
[JsonPropertyName("device_id")]
- public string DeviceId { get; set; } = null!;
-
- private string? _homeserver;
+ public string DeviceId { get; set; }
[JsonPropertyName("home_server")]
+ [field: AllowNull, MaybeNull]
public string Homeserver {
- get => _homeserver ?? UserId.Split(':', 2).Last();
- protected init => _homeserver = value;
+ get => field ?? UserId.Split(':', 2).Last();
+ set;
}
[JsonPropertyName("user_id")]
- public string UserId { get; set; } = null!;
-
- // public async Task<AuthenticatedHomeserverGeneric> GetAuthenticatedHomeserver(string? proxy = null) {
- // var urls = await new HomeserverResolverService().ResolveHomeserverFromWellKnown(Homeserver);
- // await AuthenticatedHomeserverGeneric.Create<AuthenticatedHomeserverGeneric>(Homeserver, AccessToken, proxy);
- // }
+ public string UserId { get; set; }
}
public class LoginRequest {
diff --git a/LibMatrix/Responses/MessagesResponse.cs b/LibMatrix/Responses/MessagesResponse.cs
new file mode 100644
index 0000000..4912add
--- /dev/null
+++ b/LibMatrix/Responses/MessagesResponse.cs
@@ -0,0 +1,17 @@
+using System.Text.Json.Serialization;
+
+namespace LibMatrix.Responses;
+
+public class MessagesResponse {
+ [JsonPropertyName("start")]
+ public string Start { get; set; }
+
+ [JsonPropertyName("end")]
+ public string? End { get; set; }
+
+ [JsonPropertyName("chunk")]
+ public List<StateEventResponse> Chunk { get; set; } = new();
+
+ [JsonPropertyName("state")]
+ public List<StateEventResponse> State { get; set; } = new();
+}
\ No newline at end of file
diff --git a/LibMatrix/Responses/SyncResponse.cs b/LibMatrix/Responses/SyncResponse.cs
index e4addb6..d79e820 100644
--- a/LibMatrix/Responses/SyncResponse.cs
+++ b/LibMatrix/Responses/SyncResponse.cs
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
+using LibMatrix.EventTypes.Spec.State.RoomInfo;
namespace LibMatrix.Responses;
@@ -8,16 +9,16 @@ internal partial class SyncResponseSerializerContext : JsonSerializerContext { }
public class SyncResponse {
[JsonPropertyName("next_batch")]
- public string NextBatch { get; set; } = null!;
+ public string NextBatch { get; set; }
[JsonPropertyName("account_data")]
public EventList? AccountData { get; set; }
[JsonPropertyName("presence")]
- public PresenceDataStructure? Presence { get; set; }
+ public EventList? Presence { get; set; }
[JsonPropertyName("device_one_time_keys_count")]
- public Dictionary<string, int>? DeviceOneTimeKeysCount { get; set; } = null!;
+ public Dictionary<string, int>? DeviceOneTimeKeysCount { get; set; }
[JsonPropertyName("rooms")]
public RoomsDataStructure? Rooms { get; set; }
@@ -28,6 +29,9 @@ public class SyncResponse {
[JsonPropertyName("device_lists")]
public DeviceListsDataStructure? DeviceLists { get; set; }
+ [JsonPropertyName("gay.rory.libmatrix.msc4222_sync_type")]
+ public Msc4222SyncType Msc4222Method { get; set; } = Msc4222SyncType.None;
+
public class DeviceListsDataStructure {
[JsonPropertyName("changed")]
public List<string>? Changed { get; set; }
@@ -39,7 +43,7 @@ public class SyncResponse {
// supporting classes
public class PresenceDataStructure {
[JsonPropertyName("events")]
- public List<StateEventResponse> Events { get; set; } = new();
+ public List<StateEventResponse>? Events { get; set; }
}
public class RoomsDataStructure {
@@ -61,6 +65,22 @@ public class SyncResponse {
[JsonPropertyName("state")]
public EventList? State { get; set; }
+
+ [JsonPropertyName("state_after")]
+ public EventList? StateAfter { get; set; }
+
+ [Obsolete("This property is only used for de/serialisation")]
+ [JsonPropertyName("org.matrix.msc4222.state_after")]
+ public EventList? StateAfterUnstable {
+ get => StateAfter;
+ set => StateAfter = value;
+ }
+
+ public override string ToString() {
+ var lastEvent = Timeline?.Events?.LastOrDefault(x => x.Type == "m.room.member");
+ var membership = (lastEvent?.TypedContent as RoomMemberEventContent);
+ return $"LeftRoomDataStructure: {lastEvent?.Sender} {membership?.Membership} ({membership?.Reason})";
+ }
}
public class JoinedRoomDataStructure {
@@ -70,6 +90,16 @@ public class SyncResponse {
[JsonPropertyName("state")]
public EventList? State { get; set; }
+ [JsonPropertyName("state_after")]
+ public EventList? StateAfter { get; set; }
+
+ [Obsolete("This property is only used for de/serialisation")]
+ [JsonPropertyName("org.matrix.msc4222.state_after")]
+ public EventList? StateAfterUnstable {
+ get => StateAfter;
+ set => StateAfter = value;
+ }
+
[JsonPropertyName("account_data")]
public EventList? AccountData { get; set; }
@@ -82,7 +112,7 @@ public class SyncResponse {
[JsonPropertyName("summary")]
public SummaryDataStructure? Summary { get; set; }
- public class TimelineDataStructure {
+ public class TimelineDataStructure : EventList {
public TimelineDataStructure() { }
public TimelineDataStructure(List<StateEventResponse>? events, bool? limited) {
@@ -90,8 +120,8 @@ public class SyncResponse {
Limited = limited;
}
- [JsonPropertyName("events")]
- public List<StateEventResponse>? Events { get; set; }
+ // [JsonPropertyName("events")]
+ // public List<StateEventResponse>? Events { get; set; }
[JsonPropertyName("prev_batch")]
public string? PrevBatch { get; set; }
@@ -125,4 +155,22 @@ public class SyncResponse {
public EventList? InviteState { get; set; }
}
}
+
+ public long GetDerivedSyncTime() {
+ return ((long[]) [
+ AccountData?.Events?.Max(x => x.OriginServerTs) ?? 0,
+ Presence?.Events?.Max(x => x.OriginServerTs) ?? 0,
+ ToDevice?.Events?.Max(x => x.OriginServerTs) ?? 0,
+ Rooms?.Join?.Values?.Max(x => x.Timeline?.Events?.Max(y => y.OriginServerTs)) ?? 0,
+ Rooms?.Invite?.Values?.Max(x => x.InviteState?.Events?.Max(y => y.OriginServerTs)) ?? 0,
+ Rooms?.Leave?.Values?.Max(x => x.Timeline?.Events?.Max(y => y.OriginServerTs)) ?? 0
+ ]).Max();
+ }
+
+ [JsonConverter(typeof(JsonStringEnumConverter<Msc4222SyncType>))]
+ public enum Msc4222SyncType {
+ None,
+ Server,
+ Emulated
+ }
}
\ No newline at end of file
diff --git a/LibMatrix/Responses/UserDirectoryResponse.cs b/LibMatrix/Responses/UserDirectoryResponse.cs
new file mode 100644
index 0000000..13235d9
--- /dev/null
+++ b/LibMatrix/Responses/UserDirectoryResponse.cs
@@ -0,0 +1,30 @@
+using System.Text.Json.Serialization;
+
+namespace LibMatrix.Responses;
+
+public class UserDirectoryResponse {
+ [JsonPropertyName("limited")]
+ public bool Limited { get; set; }
+
+ [JsonPropertyName("results")]
+ public List<UserDirectoryResult> Results { get; set; }
+
+ public class UserDirectoryResult {
+ [JsonPropertyName("avatar_url")]
+ public string? AvatarUrl { get; set; }
+
+ [JsonPropertyName("display_name")]
+ public string? DisplayName { get; set; }
+
+ [JsonPropertyName("user_id")]
+ public string UserId { get; set; }
+ }
+}
+
+public class UserDirectoryRequest {
+ [JsonPropertyName("search_term")]
+ public string SearchTerm { get; set; }
+
+ [JsonPropertyName("limit")]
+ public int? Limit { get; set; }
+}
\ No newline at end of file
diff --git a/LibMatrix/Responses/UserIdAndReason.cs b/LibMatrix/Responses/UserIdAndReason.cs
new file mode 100644
index 0000000..176cf7c
--- /dev/null
+++ b/LibMatrix/Responses/UserIdAndReason.cs
@@ -0,0 +1,11 @@
+using System.Text.Json.Serialization;
+
+namespace LibMatrix.Responses;
+
+internal class UserIdAndReason(string userId = null!, string reason = null!) {
+ [JsonPropertyName("user_id")]
+ public string UserId { get; set; } = userId;
+
+ [JsonPropertyName("reason")]
+ public string? Reason { get; set; } = reason;
+}
\ No newline at end of file
diff --git a/LibMatrix/Responses/UserProfileResponse.cs b/LibMatrix/Responses/UserProfileResponse.cs
index 6c9380f..30e4c32 100644
--- a/LibMatrix/Responses/UserProfileResponse.cs
+++ b/LibMatrix/Responses/UserProfileResponse.cs
@@ -1,3 +1,4 @@
+using System.Text.Json;
using System.Text.Json.Serialization;
namespace LibMatrix.Responses;
@@ -8,4 +9,18 @@ public class UserProfileResponse {
[JsonPropertyName("displayname")]
public string? DisplayName { get; set; }
+
+ // MSC 4133 - Extending User Profile API with Key:Value pairs
+ [JsonExtensionData]
+ public Dictionary<string, JsonElement>? CustomKeys { get; set; }
+
+ public JsonElement? this[string key] {
+ get => CustomKeys?[key];
+ set {
+ if (value is null)
+ CustomKeys?.Remove(key);
+ else
+ (CustomKeys ??= [])[key] = value.Value;
+ }
+ }
}
\ No newline at end of file
diff --git a/LibMatrix/Responses/WhoAmIResponse.cs b/LibMatrix/Responses/WhoAmIResponse.cs
new file mode 100644
index 0000000..db47152
--- /dev/null
+++ b/LibMatrix/Responses/WhoAmIResponse.cs
@@ -0,0 +1,14 @@
+using System.Text.Json.Serialization;
+
+namespace LibMatrix.Responses;
+
+public class WhoAmIResponse {
+ [JsonPropertyName("user_id")]
+ public required string UserId { get; set; }
+
+ [JsonPropertyName("device_id")]
+ public string? DeviceId { get; set; }
+
+ [JsonPropertyName("is_guest")]
+ public bool? IsGuest { get; set; }
+}
\ No newline at end of file
|