diff --git a/LibMatrix/Responses/CreateRoomRequest.cs b/LibMatrix/Responses/CreateRoomRequest.cs
index d9a6acd..b4dcc78 100644
--- a/LibMatrix/Responses/CreateRoomRequest.cs
+++ b/LibMatrix/Responses/CreateRoomRequest.cs
@@ -29,7 +29,7 @@ public class CreateRoomRequest {
// public string Preset { get; set; }
[JsonPropertyName("initial_state")]
- public List<StateEvent>? InitialState { get; set; }
+ public List<MatrixEvent>? InitialState { get; set; }
/// <summary>
/// One of: ["public", "private"]
@@ -42,24 +42,27 @@ public class CreateRoomRequest {
public RoomPowerLevelEventContent? PowerLevelContentOverride { get; set; }
[JsonPropertyName("creation_content")]
- public JsonObject CreationContent { get; set; } = new();
+ public Dictionary<string, object> CreationContent { get; set; } = new();
[JsonPropertyName("invite")]
public List<string>? Invite { get; set; }
+ [JsonPropertyName("room_version")]
+ 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 MatrixEvent? this[string eventType, string eventKey = ""] {
get {
var stateEvent = InitialState?.FirstOrDefault(x => x.Type == eventType && x.StateKey == eventKey);
if (stateEvent == null)
- InitialState?.Add(stateEvent = new StateEvent {
+ InitialState?.Add(stateEvent = new MatrixEvent {
Type = eventType,
StateKey = eventKey,
TypedContent = (EventContent)Activator.CreateInstance(
- StateEvent.KnownStateEventTypes.FirstOrDefault(x =>
+ MatrixEvent.KnownEventTypes.FirstOrDefault(x =>
x.GetCustomAttributes<MatrixEventAttribute>()?
.Any(y => y.EventName == eventType) ?? false) ?? typeof(UnknownEventContent)
)!
@@ -89,7 +92,7 @@ public class CreateRoomRequest {
var request = new CreateRoomRequest {
Name = name ?? "New public Room",
Visibility = "public",
- CreationContent = new JsonObject(),
+ CreationContent = new(),
PowerLevelContentOverride = new RoomPowerLevelEventContent {
EventsDefault = 0,
UsersDefault = 0,
@@ -119,7 +122,7 @@ public class CreateRoomRequest {
}
},
RoomAliasName = roomAliasName,
- InitialState = new List<StateEvent>()
+ InitialState = new List<MatrixEvent>()
};
return request;
@@ -129,7 +132,7 @@ public class CreateRoomRequest {
var request = new CreateRoomRequest {
Name = name ?? "New private Room",
Visibility = "private",
- CreationContent = new JsonObject(),
+ CreationContent = new(),
PowerLevelContentOverride = new RoomPowerLevelEventContent {
EventsDefault = 0,
UsersDefault = 0,
@@ -159,7 +162,7 @@ public class CreateRoomRequest {
}
},
RoomAliasName = roomAliasName,
- InitialState = new List<StateEvent>()
+ InitialState = new List<MatrixEvent>()
};
return request;
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/Federation/ServerKeysResponse.cs b/LibMatrix/Responses/Federation/ServerKeysResponse.cs
new file mode 100644
index 0000000..cb62e34
--- /dev/null
+++ b/LibMatrix/Responses/Federation/ServerKeysResponse.cs
@@ -0,0 +1,55 @@
+using System.Diagnostics;
+using System.Text.Json.Serialization;
+using LibMatrix.Abstractions;
+
+namespace LibMatrix.Responses.Federation;
+
+public class ServerKeysResponse {
+ [JsonPropertyName("server_name")]
+ public string ServerName { get; set; }
+
+ [JsonPropertyName("valid_until_ts")]
+ public ulong ValidUntilTs { get; set; }
+
+ [JsonIgnore]
+ public DateTime ValidUntil {
+ get => DateTimeOffset.FromUnixTimeMilliseconds((long)ValidUntilTs).DateTime;
+ set => ValidUntilTs = (ulong)new DateTimeOffset(value).ToUnixTimeMilliseconds();
+ }
+
+ [JsonPropertyName("verify_keys")]
+ public Dictionary<string, CurrentVerifyKey> VerifyKeys { get; set; } = new();
+
+ [JsonIgnore]
+ public Dictionary<VersionedKeyId, CurrentVerifyKey> VerifyKeysById {
+ get => VerifyKeys.ToDictionary(key => (VersionedKeyId)key.Key, key => key.Value);
+ set => VerifyKeys = value.ToDictionary(key => (string)key.Key, key => key.Value);
+ }
+
+ [JsonPropertyName("old_verify_keys")]
+ public Dictionary<string, ExpiredVerifyKey> OldVerifyKeys { get; set; } = new();
+
+ [JsonIgnore]
+ public Dictionary<VersionedKeyId, ExpiredVerifyKey> OldVerifyKeysById {
+ get => OldVerifyKeys.ToDictionary(key => (VersionedKeyId)key.Key, key => key.Value);
+ set => OldVerifyKeys = value.ToDictionary(key => (string)key.Key, key => key.Value);
+ }
+
+ [DebuggerDisplay("{Key}")]
+ public class CurrentVerifyKey {
+ [JsonPropertyName("key")]
+ public string Key { get; set; }
+ }
+
+ [DebuggerDisplay("{Key} (expired {Expired})")]
+ public class ExpiredVerifyKey : CurrentVerifyKey {
+ [JsonPropertyName("expired_ts")]
+ public ulong ExpiredTs { get; set; }
+
+ [JsonIgnore]
+ public DateTime Expired {
+ get => DateTimeOffset.FromUnixTimeMilliseconds((long)ExpiredTs).DateTime;
+ set => ExpiredTs = (ulong)new DateTimeOffset(value).ToUnixTimeMilliseconds();
+ }
+ }
+}
diff --git a/LibMatrix/Responses/Federation/ServerVersionResponse.cs b/LibMatrix/Responses/Federation/ServerVersionResponse.cs
new file mode 100644
index 0000000..b09bdd0
--- /dev/null
+++ b/LibMatrix/Responses/Federation/ServerVersionResponse.cs
@@ -0,0 +1,16 @@
+using System.Text.Json.Serialization;
+
+namespace LibMatrix.Responses.Federation;
+
+public class ServerVersionResponse {
+ [JsonPropertyName("server")]
+ public required ServerInfo Server { get; set; }
+
+ public class ServerInfo {
+ [JsonPropertyName("name")]
+ public string Name { get; set; }
+
+ [JsonPropertyName("version")]
+ public string Version { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/LibMatrix/Responses/Federation/SignedObject.cs b/LibMatrix/Responses/Federation/SignedObject.cs
new file mode 100644
index 0000000..3f6ffd6
--- /dev/null
+++ b/LibMatrix/Responses/Federation/SignedObject.cs
@@ -0,0 +1,68 @@
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using System.Text.Json.Serialization;
+using ArcaneLibs.Extensions;
+using LibMatrix.Abstractions;
+using LibMatrix.Homeservers;
+
+namespace LibMatrix.Responses.Federation;
+
+[JsonConverter(typeof(SignedObjectConverterFactory))]
+public class SignedObject<T> {
+ [JsonPropertyName("signatures")]
+ public Dictionary<string, Dictionary<string, string>> Signatures { get; set; } = new();
+
+ [JsonIgnore]
+ public Dictionary<string, Dictionary<VersionedKeyId, string>> SignaturesById {
+ get => Signatures.ToDictionary(server => server.Key, server => server.Value.ToDictionary(key => (VersionedKeyId)key.Key, key => key.Value));
+ set => Signatures = value.ToDictionary(server => server.Key, server => server.Value.ToDictionary(key => (string)key.Key, key => key.Value));
+ }
+
+ [JsonExtensionData]
+ public required JsonObject Content { get; set; }
+
+ [JsonIgnore]
+ public T TypedContent {
+ get => Content.Deserialize<T>() ?? throw new JsonException("Failed to deserialize TypedContent from Content.");
+ set => Content = JsonSerializer.Deserialize<JsonObject>(JsonSerializer.Serialize(value)) ?? new JsonObject();
+ }
+}
+
+public class SignedObjectConverter<T> : JsonConverter<SignedObject<T>> {
+ public override SignedObject<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
+ var jsonObject = JsonSerializer.Deserialize<JsonObject>(ref reader, options);
+ if (jsonObject == null) {
+ throw new JsonException("Failed to deserialize SignedObject, JSON object is null.");
+ }
+
+ var signatures = jsonObject["signatures"] ?? throw new JsonException("Failed to find 'signatures' property in JSON object.");
+ jsonObject.Remove("signatures");
+
+ var signedObject = new SignedObject<T> {
+ Content = jsonObject,
+ Signatures = signatures.Deserialize<Dictionary<string, Dictionary<string, string>>>()
+ ?? throw new JsonException("Failed to deserialize 'signatures' property into Dictionary<string, Dictionary<string, string>>.")
+ };
+
+ return signedObject;
+ }
+
+ public override void Write(Utf8JsonWriter writer, SignedObject<T> value, JsonSerializerOptions options) {
+ var targetObj = value.Content.DeepClone();
+ targetObj["signatures"] = value.Signatures.ToJsonNode();
+ JsonSerializer.Serialize(writer, targetObj, options);
+ }
+}
+
+internal class SignedObjectConverterFactory : JsonConverterFactory {
+ public override bool CanConvert(Type typeToConvert) {
+ if (!typeToConvert.IsGenericType) return false;
+ return typeToConvert.GetGenericTypeDefinition() == typeof(SignedObject<>);
+ }
+
+ public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) {
+ var wrappedType = typeToConvert.GetGenericArguments()[0];
+ var converter = (JsonConverter)Activator.CreateInstance(typeof(SignedObjectConverter<>).MakeGenericType(wrappedType))!;
+ return converter;
+ }
+}
\ No newline at end of file
diff --git a/LibMatrix/Responses/LoginResponse.cs b/LibMatrix/Responses/LoginResponse.cs
index 2f78932..1944276 100644
--- a/LibMatrix/Responses/LoginResponse.cs
+++ b/LibMatrix/Responses/LoginResponse.cs
@@ -19,11 +19,6 @@ public class LoginResponse {
[JsonPropertyName("user_id")]
public string UserId { get; set; }
-
- // public async Task<AuthenticatedHomeserverGeneric> GetAuthenticatedHomeserver(string? proxy = null) {
- // var urls = await new HomeserverResolverService().ResolveHomeserverFromWellKnown(Homeserver);
- // await AuthenticatedHomeserverGeneric.Create<AuthenticatedHomeserverGeneric>(Homeserver, AccessToken, proxy);
- // }
}
public class LoginRequest {
diff --git a/LibMatrix/Responses/MessagesResponse.cs b/LibMatrix/Responses/MessagesResponse.cs
new file mode 100644
index 0000000..1b412fe
--- /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<MatrixEventResponse> Chunk { get; set; } = new();
+
+ [JsonPropertyName("state")]
+ public List<MatrixEventResponse> State { get; set; } = new();
+}
\ No newline at end of file
diff --git a/LibMatrix/Responses/SyncResponse.cs b/LibMatrix/Responses/SyncResponse.cs
index d79e820..362ccc4 100644
--- a/LibMatrix/Responses/SyncResponse.cs
+++ b/LibMatrix/Responses/SyncResponse.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics;
using System.Text.Json.Serialization;
using LibMatrix.EventTypes.Spec.State.RoomInfo;
@@ -43,7 +44,7 @@ public class SyncResponse {
// supporting classes
public class PresenceDataStructure {
[JsonPropertyName("events")]
- public List<StateEventResponse>? Events { get; set; }
+ public List<MatrixEventResponse>? Events { get; set; }
}
public class RoomsDataStructure {
@@ -115,13 +116,13 @@ public class SyncResponse {
public class TimelineDataStructure : EventList {
public TimelineDataStructure() { }
- public TimelineDataStructure(List<StateEventResponse>? events, bool? limited) {
+ public TimelineDataStructure(List<MatrixEventResponse>? events, bool? limited) {
Events = events;
Limited = limited;
}
// [JsonPropertyName("events")]
- // public List<StateEventResponse>? Events { get; set; }
+ // public List<MatrixEventResponse>? Events { get; set; }
[JsonPropertyName("prev_batch")]
public string? PrevBatch { get; set; }
@@ -138,6 +139,7 @@ public class SyncResponse {
public int HighlightCount { get; set; }
}
+ [DebuggerDisplay("{JoinedMemberCount} joined, {InvitedMemberCount} invited, Heroes: {string.Join(\", \", Heroes ?? [])}")]
public class SummaryDataStructure {
[JsonPropertyName("m.heroes")]
public List<string>? Heroes { get; set; }
@@ -161,9 +163,9 @@ public class SyncResponse {
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
+ 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();
}
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/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
|