From 5affd9f061e75f6575a2fe6715f9e8757cfe87e8 Mon Sep 17 00:00:00 2001 From: "Emma [it/its]@Rory&" Date: Thu, 14 Dec 2023 07:20:46 +0100 Subject: Cleanup --- LibMatrix/EventIdResponse.cs | 2 +- .../Common/MjolnirShortcodeEventContent.cs | 10 --- .../EventTypes/Common/RoomEmotesEventContent.cs | 25 ------- LibMatrix/EventTypes/MatrixEventAttribute.cs | 7 -- .../Spec/Ephemeral/PresenceStateEventContent.cs | 22 ------ .../Spec/Ephemeral/RoomTypingEventContent.cs | 12 ---- .../EventTypes/Spec/RoomMessageEventContent.cs | 47 ------------- .../State/Policy/PolicyRuleStateEventContent.cs | 75 -------------------- .../Spec/State/RoomInfo/RoomAliasEventContent.cs | 12 ---- .../Spec/State/RoomInfo/RoomAvatarEventContent.cs | 29 -------- .../RoomInfo/RoomCanonicalAliasEventContent.cs | 15 ---- .../Spec/State/RoomInfo/RoomCreateEventContent.cs | 32 --------- .../State/RoomInfo/RoomEncryptionEventContent.cs | 14 ---- .../State/RoomInfo/RoomGuestAccessEventContent.cs | 15 ---- .../RoomInfo/RoomHistoryVisibilityEventContent.cs | 10 --- .../State/RoomInfo/RoomJoinRulesEventContent.cs | 29 -------- .../Spec/State/RoomInfo/RoomMemberEventContent.cs | 30 -------- .../Spec/State/RoomInfo/RoomNameEventContent.cs | 12 ---- .../Spec/State/RoomInfo/RoomPinnedEventContent.cs | 10 --- .../State/RoomInfo/RoomPowerLevelEventContent.cs | 79 ---------------------- .../State/RoomInfo/RoomServerACLEventContent.cs | 16 ----- .../Spec/State/RoomInfo/RoomTopicEventContent.cs | 11 --- .../Spec/State/Space/SpaceChildEventContent.cs | 14 ---- .../Spec/State/Space/SpaceParentEventContent.cs | 13 ---- LibMatrix/EventTypes/UnknownStateEventContent.cs | 7 -- LibMatrix/Extensions/HttpClientExtensions.cs | 6 +- LibMatrix/Extensions/JsonElementExtensions.cs | 2 +- LibMatrix/Helpers/MessageFormatter.cs | 9 ++- LibMatrix/Helpers/SyncHelper.cs | 12 ++-- LibMatrix/Helpers/SyncStateResolver.cs | 6 +- .../Homeservers/AuthenticatedHomeserverGeneric.cs | 13 ++-- .../Homeservers/AuthenticatedHomeserverSynapse.cs | 2 +- LibMatrix/Homeservers/RemoteHomeServer.cs | 14 ++-- LibMatrix/Interfaces/EventContent.cs | 48 ------------- LibMatrix/LibMatrix.csproj | 9 ++- LibMatrix/MatrixException.cs | 4 +- .../Responses/Admin/AdminRoomListingResult.cs | 6 +- LibMatrix/Responses/CreateRoomRequest.cs | 26 +++---- LibMatrix/Responses/CreationContentBaseType.cs | 10 +-- LibMatrix/Responses/LoginResponse.cs | 2 - LibMatrix/Responses/SyncResponse.cs | 10 +-- LibMatrix/Responses/UserProfileResponse.cs | 1 - LibMatrix/RoomTypes/GenericRoom.cs | 74 ++++++++++---------- LibMatrix/RoomTypes/SpaceRoom.cs | 4 +- LibMatrix/Services/HomeserverProviderService.cs | 47 ++++++++----- LibMatrix/Services/HomeserverResolverService.cs | 25 ++++--- LibMatrix/StateEvent.cs | 39 ++++------- LibMatrix/UserIdAndReason.cs | 2 +- LibMatrix/WhoAmIResponse.cs | 2 +- 49 files changed, 173 insertions(+), 748 deletions(-) delete mode 100644 LibMatrix/EventTypes/Common/MjolnirShortcodeEventContent.cs delete mode 100644 LibMatrix/EventTypes/Common/RoomEmotesEventContent.cs delete mode 100644 LibMatrix/EventTypes/MatrixEventAttribute.cs delete mode 100644 LibMatrix/EventTypes/Spec/Ephemeral/PresenceStateEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/Ephemeral/RoomTypingEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/RoomMessageEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/Policy/PolicyRuleStateEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/RoomInfo/RoomAliasEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/RoomInfo/RoomAvatarEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/RoomInfo/RoomCanonicalAliasEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/RoomInfo/RoomCreateEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/RoomInfo/RoomEncryptionEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/RoomInfo/RoomGuestAccessEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/RoomInfo/RoomHistoryVisibilityEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/RoomInfo/RoomJoinRulesEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/RoomInfo/RoomMemberEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/RoomInfo/RoomNameEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/RoomInfo/RoomPinnedEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/RoomInfo/RoomPowerLevelEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/RoomInfo/RoomServerACLEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/RoomInfo/RoomTopicEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/Space/SpaceChildEventContent.cs delete mode 100644 LibMatrix/EventTypes/Spec/State/Space/SpaceParentEventContent.cs delete mode 100644 LibMatrix/EventTypes/UnknownStateEventContent.cs delete mode 100644 LibMatrix/Interfaces/EventContent.cs (limited to 'LibMatrix') diff --git a/LibMatrix/EventIdResponse.cs b/LibMatrix/EventIdResponse.cs index 31a95b8..a7feeca 100644 --- a/LibMatrix/EventIdResponse.cs +++ b/LibMatrix/EventIdResponse.cs @@ -4,5 +4,5 @@ namespace LibMatrix; public class EventIdResponse { [JsonPropertyName("event_id")] - public string EventId { get; set; } = null!; + public required string EventId { get; set; } } diff --git a/LibMatrix/EventTypes/Common/MjolnirShortcodeEventContent.cs b/LibMatrix/EventTypes/Common/MjolnirShortcodeEventContent.cs deleted file mode 100644 index a09a393..0000000 --- a/LibMatrix/EventTypes/Common/MjolnirShortcodeEventContent.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Common; - -[MatrixEvent(EventName = "org.matrix.mjolnir.shortcode")] -public class MjolnirShortcodeEventContent : TimelineEventContent { - [JsonPropertyName("shortcode")] - public string? Shortcode { get; set; } -} diff --git a/LibMatrix/EventTypes/Common/RoomEmotesEventContent.cs b/LibMatrix/EventTypes/Common/RoomEmotesEventContent.cs deleted file mode 100644 index 8d05a2e..0000000 --- a/LibMatrix/EventTypes/Common/RoomEmotesEventContent.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Common; - -[MatrixEvent(EventName = "im.ponies.room_emotes")] -public class RoomEmotesEventContent : TimelineEventContent { - [JsonPropertyName("emoticons")] - public Dictionary? Emoticons { get; set; } - - [JsonPropertyName("images")] - public Dictionary? Images { get; set; } - - [JsonPropertyName("pack")] - public PackInfo? Pack { get; set; } - - public class EmoticonData { - [JsonPropertyName("url")] - public string? Url { get; set; } - } - - public class PackInfo { - - } -} diff --git a/LibMatrix/EventTypes/MatrixEventAttribute.cs b/LibMatrix/EventTypes/MatrixEventAttribute.cs deleted file mode 100644 index 92334d0..0000000 --- a/LibMatrix/EventTypes/MatrixEventAttribute.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace LibMatrix.EventTypes; - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class MatrixEventAttribute : Attribute { - public string EventName { get; set; } - public bool Legacy { get; set; } -} diff --git a/LibMatrix/EventTypes/Spec/Ephemeral/PresenceStateEventContent.cs b/LibMatrix/EventTypes/Spec/Ephemeral/PresenceStateEventContent.cs deleted file mode 100644 index 8ffbca5..0000000 --- a/LibMatrix/EventTypes/Spec/Ephemeral/PresenceStateEventContent.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = EventId)] -public class PresenceEventContent : EventContent { - public const string EventId = "m.presence"; - - [JsonPropertyName("presence"), JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string? Presence { get; set; } - [JsonPropertyName("last_active_ago")] - public long LastActiveAgo { get; set; } - [JsonPropertyName("currently_active")] - public bool CurrentlyActive { get; set; } - [JsonPropertyName("status_msg"), JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string? StatusMessage { get; set; } - [JsonPropertyName("avatar_url"), JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string? AvatarUrl { get; set; } - [JsonPropertyName("displayname"), JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string? DisplayName { get; set; } -} diff --git a/LibMatrix/EventTypes/Spec/Ephemeral/RoomTypingEventContent.cs b/LibMatrix/EventTypes/Spec/Ephemeral/RoomTypingEventContent.cs deleted file mode 100644 index b947096..0000000 --- a/LibMatrix/EventTypes/Spec/Ephemeral/RoomTypingEventContent.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = EventId)] -public class RoomTypingEventContent : TimelineEventContent { - public const string EventId = "m.typing"; - - [JsonPropertyName("user_ids")] - public string[]? UserIds { get; set; } -} diff --git a/LibMatrix/EventTypes/Spec/RoomMessageEventContent.cs b/LibMatrix/EventTypes/Spec/RoomMessageEventContent.cs deleted file mode 100644 index 944ed99..0000000 --- a/LibMatrix/EventTypes/Spec/RoomMessageEventContent.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec; - -[MatrixEvent(EventName = EventId)] -public class RoomMessageEventContent : TimelineEventContent { - public const string EventId = "m.room.message"; - - public RoomMessageEventContent(string? messageType = "m.notice", string? body = null) { - MessageType = messageType; - Body = body; - } - - [JsonPropertyName("body")] - public string Body { get; set; } - - [JsonPropertyName("msgtype")] - public string MessageType { get; set; } = "m.notice"; - - [JsonPropertyName("formatted_body")] - public string? FormattedBody { get; set; } - - [JsonPropertyName("format")] - public string? Format { get; set; } - - /// - /// Media URI for this message, if any - /// - [JsonPropertyName("url")] - public string? Url { get; set; } - - public string? FileName { get; set; } - - [JsonPropertyName("info")] - public FileInfoStruct? FileInfo { get; set; } - - public class FileInfoStruct { - [JsonPropertyName("mimetype")] - public string? MimeType { get; set; } - [JsonPropertyName("size")] - public long Size { get; set; } - [JsonPropertyName("thumbnail_url")] - public string? ThumbnailUrl { get; set; } - } - -} diff --git a/LibMatrix/EventTypes/Spec/State/Policy/PolicyRuleStateEventContent.cs b/LibMatrix/EventTypes/Spec/State/Policy/PolicyRuleStateEventContent.cs deleted file mode 100644 index 80d87d6..0000000 --- a/LibMatrix/EventTypes/Spec/State/Policy/PolicyRuleStateEventContent.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -//spec -[MatrixEvent(EventName = EventId)] //spec -[MatrixEvent(EventName = "m.room.rule.server")] //??? -[MatrixEvent(EventName = "org.matrix.mjolnir.rule.server")] //legacy -public class ServerPolicyRuleEventContent : PolicyRuleEventContent { - public const string EventId = "m.policy.rule.server"; -} - -[MatrixEvent(EventName = EventId)] //spec -[MatrixEvent(EventName = "m.room.rule.user")] //??? -[MatrixEvent(EventName = "org.matrix.mjolnir.rule.user")] //legacy -public class UserPolicyRuleEventContent : PolicyRuleEventContent { - public const string EventId = "m.policy.rule.user"; -} - -[MatrixEvent(EventName = EventId)] //spec -[MatrixEvent(EventName = "m.room.rule.room")] //??? -[MatrixEvent(EventName = "org.matrix.mjolnir.rule.room")] //legacy -public class RoomPolicyRuleEventContent : PolicyRuleEventContent { - public const string EventId = "m.policy.rule.room"; -} - -public abstract class PolicyRuleEventContent : EventContent { - /// - /// Entity this ban applies to, can use * and ? as globs. - /// Policy is invalid if entity is null - /// - [JsonPropertyName("entity")] - public string? Entity { get; set; } - - /// - /// Reason this user is banned - /// - [JsonPropertyName("reason")] - public string? Reason { get; set; } - - /// - /// Suggested action to take - /// - [JsonPropertyName("recommendation")] - public string? Recommendation { get; set; } - - /// - /// Expiry time in milliseconds since the unix epoch, or null if the ban has no expiry. - /// - [JsonPropertyName("support.feline.policy.expiry.rev.2")] //stable prefix: expiry, msc pending - public long? Expiry { get; set; } - - //utils - /// - /// Readable expiry time, provided for easy interaction - /// - [JsonPropertyName("gay.rory.matrix_room_utils.readable_expiry_time_utc")] - public DateTime? ExpiryDateTime { - get => Expiry == null ? null : DateTimeOffset.FromUnixTimeMilliseconds(Expiry.Value).DateTime; - set => Expiry = ((DateTimeOffset)value).ToUnixTimeMilliseconds(); - } -} - -public static class PolicyRecommendationTypes { - /// - /// Ban this user - /// - public static string Ban = "m.ban"; - - /// - /// Mute this user - /// - public static string Mute = "support.feline.policy.recommendation_mute"; //stable prefix: m.mute, msc pending -} diff --git a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomAliasEventContent.cs b/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomAliasEventContent.cs deleted file mode 100644 index 830386d..0000000 --- a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomAliasEventContent.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = EventId)] -public class RoomAliasEventContent : TimelineEventContent { - public const string EventId = "m.room.alias"; - - [JsonPropertyName("aliases")] - public List? Aliases { get; set; } -} diff --git a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomAvatarEventContent.cs b/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomAvatarEventContent.cs deleted file mode 100644 index 9c208ba..0000000 --- a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomAvatarEventContent.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = EventId)] -public class RoomAvatarEventContent : TimelineEventContent { - public const string EventId = "m.room.avatar"; - - [JsonPropertyName("url")] - public string? Url { get; set; } - - [JsonPropertyName("info")] - public RoomAvatarInfo? Info { get; set; } - - public class RoomAvatarInfo { - [JsonPropertyName("h")] - public int? Height { get; set; } - - [JsonPropertyName("w")] - public int? Width { get; set; } - - [JsonPropertyName("mimetype")] - public string? MimeType { get; set; } - - [JsonPropertyName("size")] - public int? Size { get; set; } - } -} diff --git a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomCanonicalAliasEventContent.cs b/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomCanonicalAliasEventContent.cs deleted file mode 100644 index 5ba253c..0000000 --- a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomCanonicalAliasEventContent.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = EventId)] -public class RoomCanonicalAliasEventContent : TimelineEventContent { - public const string EventId = "m.room.canonical_alias"; - - [JsonPropertyName("alias")] - public string? Alias { get; set; } - - [JsonPropertyName("alt_aliases")] - public string[]? AltAliases { get; set; } -} diff --git a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomCreateEventContent.cs b/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomCreateEventContent.cs deleted file mode 100644 index 41145de..0000000 --- a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomCreateEventContent.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = EventId)] -public class RoomCreateEventContent : TimelineEventContent { - public const string EventId = "m.room.create"; - - [JsonPropertyName("room_version")] - public string? RoomVersion { get; set; } - - [JsonPropertyName("creator")] - public string? Creator { get; set; } - - [JsonPropertyName("m.federate")] - public bool? Federate { get; set; } - - [JsonPropertyName("predecessor")] - public RoomCreatePredecessor? Predecessor { get; set; } - - [JsonPropertyName("type")] - public string? Type { get; set; } - - public class RoomCreatePredecessor { - [JsonPropertyName("room_id")] - public string? RoomId { get; set; } - - [JsonPropertyName("event_id")] - public string? EventId { get; set; } - } -} diff --git a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomEncryptionEventContent.cs b/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomEncryptionEventContent.cs deleted file mode 100644 index a3627f2..0000000 --- a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomEncryptionEventContent.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = "m.room.encryption")] -public class RoomEncryptionEventContent : TimelineEventContent { - [JsonPropertyName("algorithm")] - public string? Algorithm { get; set; } - [JsonPropertyName("rotation_period_ms")] - public ulong? RotationPeriodMs { get; set; } - [JsonPropertyName("rotation_period_msgs")] - public ulong? RotationPeriodMsgs { get; set; } -} diff --git a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomGuestAccessEventContent.cs b/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomGuestAccessEventContent.cs deleted file mode 100644 index 5bad649..0000000 --- a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomGuestAccessEventContent.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = "m.room.guest_access")] -public class RoomGuestAccessEventContent : TimelineEventContent { - [JsonPropertyName("guest_access")] - public string GuestAccess { get; set; } - - public bool IsGuestAccessEnabled { - get => GuestAccess == "can_join"; - set => GuestAccess = value ? "can_join" : "forbidden"; - } -} diff --git a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomHistoryVisibilityEventContent.cs b/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomHistoryVisibilityEventContent.cs deleted file mode 100644 index 8f5c7f1..0000000 --- a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomHistoryVisibilityEventContent.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = "m.room.history_visibility")] -public class RoomHistoryVisibilityEventContent : TimelineEventContent { - [JsonPropertyName("history_visibility")] - public string HistoryVisibility { get; set; } -} diff --git a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomJoinRulesEventContent.cs b/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomJoinRulesEventContent.cs deleted file mode 100644 index 2db9e60..0000000 --- a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomJoinRulesEventContent.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = "m.room.join_rules")] -public class RoomJoinRulesEventContent : TimelineEventContent { - private static string Public = "public"; - private static string Invite = "invite"; - private static string Knock = "knock"; - - /// - /// one of ["public", "invite", "knock", "restricted", "knock_restricted"] - /// "private" is reserved without implementation! - /// - [JsonPropertyName("join_rule")] - public string JoinRule { get; set; } - - [JsonPropertyName("allow")] - public List Allow { get; set; } - - public class AllowEntry { - [JsonPropertyName("type")] - public string Type { get; set; } - - [JsonPropertyName("room_id")] - public string RoomId { get; set; } - } -} diff --git a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomMemberEventContent.cs b/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomMemberEventContent.cs deleted file mode 100644 index 698315e..0000000 --- a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomMemberEventContent.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = EventId)] -public class RoomMemberEventContent : TimelineEventContent { - public const string EventId = "m.room.member"; - - [JsonPropertyName("reason")] - public string? Reason { get; set; } - - [JsonPropertyName("membership")] - public string Membership { get; set; } = null!; - - [JsonPropertyName("displayname")] - public string? DisplayName { get; set; } - - [JsonPropertyName("is_direct")] - public bool? IsDirect { get; set; } - - [JsonPropertyName("avatar_url")] - public string? AvatarUrl { get; set; } - - [JsonPropertyName("kind")] - public string? Kind { get; set; } - - [JsonPropertyName("join_authorised_via_users_server")] - public string? JoinAuthorisedViaUsersServer { get; set; } -} diff --git a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomNameEventContent.cs b/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomNameEventContent.cs deleted file mode 100644 index 9ad67eb..0000000 --- a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomNameEventContent.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = EventId)] -public class RoomNameEventContent : TimelineEventContent { - public const string EventId = "m.room.name"; - - [JsonPropertyName("name")] - public string? Name { get; set; } -} diff --git a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomPinnedEventContent.cs b/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomPinnedEventContent.cs deleted file mode 100644 index 11fe208..0000000 --- a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomPinnedEventContent.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = "m.room.pinned_events")] -public class RoomPinnedEventContent : TimelineEventContent { - [JsonPropertyName("pinned")] - public string[]? PinnedEvents { get; set; } -} diff --git a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomPowerLevelEventContent.cs b/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomPowerLevelEventContent.cs deleted file mode 100644 index 08f8ad5..0000000 --- a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomPowerLevelEventContent.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = EventId)] -public class RoomPowerLevelEventContent : TimelineEventContent { - public const string EventId = "m.room.power_levels"; - - [JsonPropertyName("ban")] - public long? Ban { get; set; } = 50; - - [JsonPropertyName("events_default")] - public long? EventsDefault { get; set; } = 0; - - [JsonPropertyName("invite")] - public long? Invite { get; set; } = 0; - - [JsonPropertyName("kick")] - public long? Kick { get; set; } = 50; - - [JsonPropertyName("notifications")] - public NotificationsPL? NotificationsPl { get; set; } // = null!; - - [JsonPropertyName("redact")] - public long? Redact { get; set; } = 50; - - [JsonPropertyName("state_default")] - public long? StateDefault { get; set; } = 50; - - [JsonPropertyName("events")] - public Dictionary? Events { get; set; } // = null!; - - [JsonPropertyName("users")] - public Dictionary? Users { get; set; } // = null!; - - [JsonPropertyName("users_default")] - public long? UsersDefault { get; set; } = 0; - - [Obsolete("Historical was a key related to MSC2716, a spec change on backfill that was dropped!", true)] - [JsonIgnore] - [JsonPropertyName("historical")] - public long Historical { get; set; } // = 50; - - public class NotificationsPL { - [JsonPropertyName("room")] - public long Room { get; set; } = 50; - } - - public bool IsUserAdmin(string userId) { - if (userId is null) throw new ArgumentNullException(nameof(userId)); - return Users.TryGetValue(userId, out var level) && level >= Events.Max(x => x.Value); - } - - public bool UserHasTimelinePermission(string userId, string eventType) { - if (userId is null) throw new ArgumentNullException(nameof(userId)); - return Users.TryGetValue(userId, out var level) && level >= Events.GetValueOrDefault(eventType, EventsDefault ?? 0); - } - - public bool UserHasStatePermission(string userId, string eventType) { - if (userId is null) throw new ArgumentNullException(nameof(userId)); - return Users.TryGetValue(userId, out var level) && level >= Events.GetValueOrDefault(eventType, StateDefault ?? 50); - } - - public long GetUserPowerLevel(string userId) { - if (userId is null) throw new ArgumentNullException(nameof(userId)); - return Users.TryGetValue(userId, out var level) ? level : UsersDefault ?? UsersDefault ?? 0; - } - - public long GetEventPowerLevel(string eventType) { - return Events.TryGetValue(eventType, out var level) ? level : EventsDefault ?? EventsDefault ?? 0; - } - - public void SetUserPowerLevel(string userId, long powerLevel) { - if (userId is null) throw new ArgumentNullException(nameof(userId)); - Users ??= new(); - Users[userId] = powerLevel; - } -} diff --git a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomServerACLEventContent.cs b/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomServerACLEventContent.cs deleted file mode 100644 index cbd2241..0000000 --- a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomServerACLEventContent.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = "m.room.server_acl")] -public class RoomServerACLEventContent : TimelineEventContent { - [JsonPropertyName("allow")] - public List Allow { get; set; } // = null!; - - [JsonPropertyName("deny")] - public List Deny { get; set; } // = null!; - - [JsonPropertyName("allow_ip_literals")] - public bool AllowIpLiterals { get; set; } // = false; -} diff --git a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomTopicEventContent.cs b/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomTopicEventContent.cs deleted file mode 100644 index 866eecf..0000000 --- a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomTopicEventContent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = "m.room.topic")] -[MatrixEvent(EventName = "org.matrix.msc3765.topic", Legacy = true)] -public class RoomTopicEventContent : TimelineEventContent { - [JsonPropertyName("topic")] - public string? Topic { get; set; } -} diff --git a/LibMatrix/EventTypes/Spec/State/Space/SpaceChildEventContent.cs b/LibMatrix/EventTypes/Spec/State/Space/SpaceChildEventContent.cs deleted file mode 100644 index 82f4b7f..0000000 --- a/LibMatrix/EventTypes/Spec/State/Space/SpaceChildEventContent.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = "m.space.child")] -public class SpaceChildEventContent : TimelineEventContent { - [JsonPropertyName("auto_join")] - public bool? AutoJoin { get; set; } - [JsonPropertyName("via")] - public List? Via { get; set; } - [JsonPropertyName("suggested")] - public bool? Suggested { get; set; } -} diff --git a/LibMatrix/EventTypes/Spec/State/Space/SpaceParentEventContent.cs b/LibMatrix/EventTypes/Spec/State/Space/SpaceParentEventContent.cs deleted file mode 100644 index 887e91c..0000000 --- a/LibMatrix/EventTypes/Spec/State/Space/SpaceParentEventContent.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Text.Json.Serialization; -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes.Spec.State; - -[MatrixEvent(EventName = "m.space.parent")] -public class SpaceParentEventContent : TimelineEventContent { - [JsonPropertyName("via")] - public string[]? Via { get; set; } - - [JsonPropertyName("canonical")] - public bool? Canonical { get; set; } -} diff --git a/LibMatrix/EventTypes/UnknownStateEventContent.cs b/LibMatrix/EventTypes/UnknownStateEventContent.cs deleted file mode 100644 index c47dc99..0000000 --- a/LibMatrix/EventTypes/UnknownStateEventContent.cs +++ /dev/null @@ -1,7 +0,0 @@ -using LibMatrix.Interfaces; - -namespace LibMatrix.EventTypes; - -public class UnknownEventContent : TimelineEventContent { - -} diff --git a/LibMatrix/Extensions/HttpClientExtensions.cs b/LibMatrix/Extensions/HttpClientExtensions.cs index 6f27f71..93e1441 100644 --- a/LibMatrix/Extensions/HttpClientExtensions.cs +++ b/LibMatrix/Extensions/HttpClientExtensions.cs @@ -116,8 +116,8 @@ public class MatrixHttpClient : HttpClient { return await response.Content.ReadAsStreamAsync(cancellationToken); } - public new async Task PutAsJsonAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, T value, JsonSerializerOptions? options = null, - CancellationToken cancellationToken = default) { + public async Task PutAsJsonAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, T value, JsonSerializerOptions? options = null, + CancellationToken cancellationToken = default) where T : notnull { options = GetJsonSerializerOptions(options); var request = new HttpRequestMessage(HttpMethod.Put, requestUri); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); @@ -130,7 +130,7 @@ public class MatrixHttpClient : HttpClient { } public async Task PostAsJsonAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, T value, JsonSerializerOptions? options = null, - CancellationToken cancellationToken = default) { + CancellationToken cancellationToken = default) where T : notnull { options ??= new(); options.Converters.Add(new JsonFloatStringConverter()); options.Converters.Add(new JsonDoubleStringConverter()); diff --git a/LibMatrix/Extensions/JsonElementExtensions.cs b/LibMatrix/Extensions/JsonElementExtensions.cs index 8c3884e..0bdf01c 100644 --- a/LibMatrix/Extensions/JsonElementExtensions.cs +++ b/LibMatrix/Extensions/JsonElementExtensions.cs @@ -37,7 +37,7 @@ public static class JsonElementExtensions { if (field.Name == "content" && (objectType == typeof(StateEventResponse) || objectType == typeof(StateEvent))) { unknownPropertyFound |= field.FindExtraJsonPropertyFieldsByValueKind( - StateEvent.GetStateEventType(obj.GetProperty("type").GetString()), + StateEvent.GetStateEventType(obj.GetProperty("type").GetString()!), // We expect type to always be present mappedProperty.PropertyType); continue; } diff --git a/LibMatrix/Helpers/MessageFormatter.cs b/LibMatrix/Helpers/MessageFormatter.cs index 03efeec..f275b57 100644 --- a/LibMatrix/Helpers/MessageFormatter.cs +++ b/LibMatrix/Helpers/MessageFormatter.cs @@ -6,7 +6,7 @@ namespace LibMatrix.Helpers; public static class MessageFormatter { public static RoomMessageEventContent FormatError(string error) { return new RoomMessageEventContent(body: error, messageType: "m.text") { - FormattedBody = $"{error}: {error}", + FormattedBody = $"{error}", Format = "org.matrix.custom.html" }; } @@ -46,4 +46,11 @@ public static class MessageFormatter { public static RoomMessageEventContent ToMatrixMessage(this Exception e, string error) => FormatException(error, e); #endregion + + public static RoomMessageEventContent FormatWarning(string warning) { + return new RoomMessageEventContent(body: warning, messageType: "m.text") { + FormattedBody = $"{warning}", + Format = "org.matrix.custom.html" + }; + } } diff --git a/LibMatrix/Helpers/SyncHelper.cs b/LibMatrix/Helpers/SyncHelper.cs index 334c288..ba42735 100644 --- a/LibMatrix/Helpers/SyncHelper.cs +++ b/LibMatrix/Helpers/SyncHelper.cs @@ -38,12 +38,12 @@ public class SyncHelper(AuthenticatedHomeserverGeneric homeserver, ILogger? logg // Console.WriteLine("Calling: " + url); logger?.LogInformation("SyncHelper: Calling: {}", url); try { - var httpResp = await homeserver.ClientHttpClient.GetAsync(url, cancellationToken: cancellationToken ?? CancellationToken.None)!; + var httpResp = await homeserver.ClientHttpClient.GetAsync(url, cancellationToken: cancellationToken ?? CancellationToken.None); if (httpResp is null) throw new NullReferenceException("Failed to send HTTP request"); - logger?.LogInformation("Got sync response: {} bytes, {} elapsed", httpResp?.Content.Headers.ContentLength ?? -1, sw.Elapsed); + logger?.LogInformation("Got sync response: {} bytes, {} elapsed", httpResp.Content.Headers.ContentLength ?? -1, sw.Elapsed); var deserializeSw = Stopwatch.StartNew(); - var resp = await httpResp.Content.ReadFromJsonAsync(cancellationToken: cancellationToken ?? CancellationToken.None)!; - logger?.LogInformation("Deserialized sync response: {} bytes, {} elapsed, {} total", httpResp?.Content.Headers.ContentLength ?? -1, deserializeSw.Elapsed, sw.Elapsed); + var resp = await httpResp.Content.ReadFromJsonAsync(cancellationToken: cancellationToken ?? CancellationToken.None); + logger?.LogInformation("Deserialized sync response: {} bytes, {} elapsed, {} total", httpResp.Content.Headers.ContentLength ?? -1, deserializeSw.Elapsed, sw.Elapsed); var timeToWait = MinimumDelay.Subtract(sw.Elapsed); if (timeToWait.TotalMilliseconds > 0) await Task.Delay(timeToWait); @@ -65,7 +65,7 @@ public class SyncHelper(AuthenticatedHomeserverGeneric homeserver, ILogger? logg while (!cancellationToken?.IsCancellationRequested ?? true) { var sync = await SyncAsync(cancellationToken); if (sync is null) continue; - if (!string.IsNullOrWhiteSpace(sync?.NextBatch)) Since = sync.NextBatch; + if (!string.IsNullOrWhiteSpace(sync.NextBatch)) Since = sync.NextBatch; yield return sync; } } @@ -76,7 +76,7 @@ public class SyncHelper(AuthenticatedHomeserverGeneric homeserver, ILogger? logg var oldTimeout = Timeout; Timeout = 0; await foreach (var sync in EnumerateSyncAsync(cancellationToken)) { - if (sync?.ToJson(ignoreNull: true, indent: false).Length < 250) { + if (sync.ToJson(ignoreNull: true, indent: false).Length < 250) { emptyInitialSyncCount++; if (emptyInitialSyncCount > 5) { IsInitialSync = false; diff --git a/LibMatrix/Helpers/SyncStateResolver.cs b/LibMatrix/Helpers/SyncStateResolver.cs index f40fa22..f380a1f 100644 --- a/LibMatrix/Helpers/SyncStateResolver.cs +++ b/LibMatrix/Helpers/SyncStateResolver.cs @@ -162,7 +162,11 @@ public class SyncStateResolver(AuthenticatedHomeserverGeneric homeserver, ILogge oldData.UnreadNotifications.HighlightCount = newData.UnreadNotifications?.HighlightCount ?? oldData.UnreadNotifications.HighlightCount; oldData.UnreadNotifications.NotificationCount = newData.UnreadNotifications?.NotificationCount ?? oldData.UnreadNotifications.NotificationCount; - oldData.Summary ??= new(); + oldData.Summary ??= new() { + Heroes = newData.Summary?.Heroes ?? oldData.Summary.Heroes, + JoinedMemberCount = newData.Summary?.JoinedMemberCount ?? oldData.Summary.JoinedMemberCount, + InvitedMemberCount = newData.Summary?.InvitedMemberCount ?? oldData.Summary.InvitedMemberCount + }; oldData.Summary.Heroes = newData.Summary?.Heroes ?? oldData.Summary.Heroes; oldData.Summary.JoinedMemberCount = newData.Summary?.JoinedMemberCount ?? oldData.Summary.JoinedMemberCount; oldData.Summary.InvitedMemberCount = newData.Summary?.InvitedMemberCount ?? oldData.Summary.InvitedMemberCount; diff --git a/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs b/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs index e85ecd2..cf85287 100644 --- a/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs +++ b/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Net.Http.Headers; using System.Net.Http.Json; using System.Text.Json; @@ -50,9 +51,9 @@ public class AuthenticatedHomeserverGeneric(string serverName, string accessToke } public WhoAmIResponse WhoAmI { get; set; } - public string? UserId => WhoAmI?.UserId; - public string? UserLocalpart => UserId?.Split(":")[0][1..]; - public string? ServerName => UserId?.Split(":", 2)[1]; + public string UserId => WhoAmI.UserId; + public string UserLocalpart => UserId.Split(":")[0][1..]; + public string ServerName => UserId.Split(":", 2)[1]; // public virtual async Task WhoAmI() { // if (_whoAmI is not null) return _whoAmI; @@ -289,10 +290,10 @@ public class AuthenticatedHomeserverGeneric(string serverName, string accessToke } public async Task JoinRoomAsync(string roomId, List homeservers = null, string? reason = null) { - var join_url = $"/_matrix/client/v3/join/{HttpUtility.UrlEncode(roomId)}"; - Console.WriteLine($"Calling {join_url} with {homeservers?.Count ?? 0} via's..."); + var joinUrl = $"/_matrix/client/v3/join/{HttpUtility.UrlEncode(roomId)}"; + Console.WriteLine($"Calling {joinUrl} with {homeservers?.Count ?? 0} via's..."); if (homeservers == null || homeservers.Count == 0) homeservers = new() { roomId.Split(':')[1] }; - var fullJoinUrl = $"{join_url}?server_name=" + string.Join("&server_name=", homeservers); + var fullJoinUrl = $"{joinUrl}?server_name=" + string.Join("&server_name=", homeservers); var res = await ClientHttpClient.PostAsJsonAsync(fullJoinUrl, new { reason }); diff --git a/LibMatrix/Homeservers/AuthenticatedHomeserverSynapse.cs b/LibMatrix/Homeservers/AuthenticatedHomeserverSynapse.cs index 28ff775..6562686 100644 --- a/LibMatrix/Homeservers/AuthenticatedHomeserverSynapse.cs +++ b/LibMatrix/Homeservers/AuthenticatedHomeserverSynapse.cs @@ -20,7 +20,7 @@ public class AuthenticatedHomeserverSynapse : AuthenticatedHomeserverGeneric { Console.WriteLine($"--- ADMIN Querying Room List with URL: {url} - Already have {i} items... ---"); res = await authenticatedHomeserver.ClientHttpClient.GetFromJsonAsync(url); - totalRooms ??= res?.TotalRooms; + totalRooms ??= res.TotalRooms; Console.WriteLine(res.ToJson(false)); foreach (var room in res.Rooms) { if (localFilter is not null) { diff --git a/LibMatrix/Homeservers/RemoteHomeServer.cs b/LibMatrix/Homeservers/RemoteHomeServer.cs index f8d61fd..a47b731 100644 --- a/LibMatrix/Homeservers/RemoteHomeServer.cs +++ b/LibMatrix/Homeservers/RemoteHomeServer.cs @@ -2,7 +2,6 @@ using System.Net.Http.Json; using System.Text.Json; using System.Text.Json.Serialization; using ArcaneLibs.Extensions; -using LibMatrix.EventTypes.Spec.State; using LibMatrix.Extensions; using LibMatrix.Responses; using LibMatrix.Services; @@ -10,6 +9,7 @@ using LibMatrix.Services; namespace LibMatrix.Homeservers; public class RemoteHomeserver(string baseUrl) { + public static async Task Create(string baseUrl, string? proxy = null) { var homeserver = new RemoteHomeserver(baseUrl); homeserver.WellKnownUris = await new HomeserverResolverService().ResolveHomeserverFromWellKnown(baseUrl); @@ -32,9 +32,10 @@ public class RemoteHomeserver(string baseUrl) { private Dictionary _profileCache { get; set; } = new(); public string BaseUrl { get; } = baseUrl; - public MatrixHttpClient ClientHttpClient { get; set; } - public MatrixHttpClient ServerHttpClient { get; set; } - public HomeserverResolverService.WellKnownUris WellKnownUris { get; set; } + + public MatrixHttpClient ClientHttpClient { get; set; } = null!; + public MatrixHttpClient ServerHttpClient { get; set; } = null!; + public HomeserverResolverService.WellKnownUris WellKnownUris { get; set; } = null!; public async Task GetProfileAsync(string mxid) { if (mxid is null) throw new ArgumentNullException(nameof(mxid)); @@ -63,7 +64,7 @@ public class RemoteHomeserver(string baseUrl) { public async Task ResolveRoomAliasAsync(string alias) { var resp = await ClientHttpClient.GetAsync($"/_matrix/client/v3/directory/room/{alias.Replace("#", "%23")}"); var data = await resp.Content.ReadFromJsonAsync(); - var text = await resp.Content.ReadAsStringAsync(); + //var text = await resp.Content.ReadAsStringAsync(); if (!resp.IsSuccessStatusCode) Console.WriteLine("ResolveAlias: " + data.ToJson()); return data; } @@ -119,8 +120,9 @@ public class RemoteHomeserver(string baseUrl) { public class ServerVersionResponse { [JsonPropertyName("server")] - public ServerInfo Server { get; set; } + public required ServerInfo Server { get; set; } + // ReSharper disable once ClassNeverInstantiated.Global public class ServerInfo { [JsonPropertyName("name")] public string Name { get; set; } diff --git a/LibMatrix/Interfaces/EventContent.cs b/LibMatrix/Interfaces/EventContent.cs deleted file mode 100644 index 76419a6..0000000 --- a/LibMatrix/Interfaces/EventContent.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Nodes; -using System.Text.Json.Serialization; - -namespace LibMatrix.Interfaces; - -public abstract class EventContent { } - -public abstract class TimelineEventContent : EventContent { - [JsonPropertyName("m.relates_to")] - public MessageRelatesTo? RelatesTo { get; set; } - - [JsonPropertyName("m.new_content")] - public JsonObject? NewContent { get; set; } - - public TimelineEventContent SetReplaceRelation(string eventId) { - NewContent = JsonSerializer.SerializeToNode(this, GetType()).AsObject(); - // NewContent = JsonSerializer.Deserialize(jsonText, GetType()); - RelatesTo = new() { - RelationType = "m.replace", - EventId = eventId - }; - return this; - } - - public T SetReplaceRelation(string eventId) where T : TimelineEventContent { - return SetReplaceRelation(eventId) as T ?? throw new InvalidOperationException(); - } - - public class MessageRelatesTo { - [JsonPropertyName("m.in_reply_to")] - public EventInReplyTo? InReplyTo { get; set; } - - [JsonPropertyName("event_id")] - public string? EventId { get; set; } - - [JsonPropertyName("rel_type")] - public string? RelationType { get; set; } - - public class EventInReplyTo { - [JsonPropertyName("event_id")] - public string EventId { get; set; } - - [JsonPropertyName("rel_type")] - public string RelType { get; set; } - } - } -} diff --git a/LibMatrix/LibMatrix.csproj b/LibMatrix/LibMatrix.csproj index afe06d7..07bd831 100644 --- a/LibMatrix/LibMatrix.csproj +++ b/LibMatrix/LibMatrix.csproj @@ -20,13 +20,18 @@ + + + + + - + diff --git a/LibMatrix/MatrixException.cs b/LibMatrix/MatrixException.cs index 863c6d4..10f0433 100644 --- a/LibMatrix/MatrixException.cs +++ b/LibMatrix/MatrixException.cs @@ -5,10 +5,10 @@ namespace LibMatrix; public class MatrixException : Exception { [JsonPropertyName("errcode")] - public string ErrorCode { get; set; } + public required string ErrorCode { get; set; } [JsonPropertyName("error")] - public string Error { get; set; } + public required string Error { get; set; } [JsonPropertyName("soft_logout")] public bool? SoftLogout { get; set; } diff --git a/LibMatrix/Responses/Admin/AdminRoomListingResult.cs b/LibMatrix/Responses/Admin/AdminRoomListingResult.cs index f035184..a90bc6f 100644 --- a/LibMatrix/Responses/Admin/AdminRoomListingResult.cs +++ b/LibMatrix/Responses/Admin/AdminRoomListingResult.cs @@ -20,7 +20,7 @@ public class AdminRoomListingResult { public class AdminRoomListingResultRoom { [JsonPropertyName("room_id")] - public string RoomId { get; set; } + public required string RoomId { get; set; } [JsonPropertyName("name")] public string? Name { get; set; } @@ -35,10 +35,10 @@ public class AdminRoomListingResult { public int JoinedLocalMembers { get; set; } [JsonPropertyName("version")] - public string Version { get; set; } + public string? Version { get; set; } [JsonPropertyName("creator")] - public string Creator { get; set; } + public string? Creator { get; set; } [JsonPropertyName("encryption")] public string? Encryption { get; set; } diff --git a/LibMatrix/Responses/CreateRoomRequest.cs b/LibMatrix/Responses/CreateRoomRequest.cs index 85db517..f8d1d05 100644 --- a/LibMatrix/Responses/CreateRoomRequest.cs +++ b/LibMatrix/Responses/CreateRoomRequest.cs @@ -10,28 +10,28 @@ using LibMatrix.Interfaces; namespace LibMatrix.Responses; public class CreateRoomRequest { - [JsonIgnore] public CreationContentBaseType _creationContentBaseType; + [JsonIgnore] public CreationContentBaseType CreationContentBaseType; - public CreateRoomRequest() => _creationContentBaseType = new CreationContentBaseType(this); + public CreateRoomRequest() => CreationContentBaseType = new CreationContentBaseType(this); [JsonPropertyName("name")] - public string Name { get; set; } = null!; + public string? Name { get; set; } [JsonPropertyName("room_alias_name")] - public string RoomAliasName { get; set; } = null!; + public string? RoomAliasName { get; set; } //we dont want to use this, we want more control // [JsonPropertyName("preset")] // public string Preset { get; set; } = null!; [JsonPropertyName("initial_state")] - public List InitialState { get; set; } = null!; + public List? InitialState { get; set; } /// /// One of: ["public", "private"] /// [JsonPropertyName("visibility")] - public string Visibility { get; set; } = null!; + public string? Visibility { get; set; } [JsonPropertyName("power_level_content_override")] public RoomPowerLevelEventContent PowerLevelContentOverride { get; set; } = null!; @@ -46,25 +46,25 @@ public class CreateRoomRequest { /// For use only when you can't use the CreationContent property /// - public StateEvent this[string event_type, string event_key = ""] { + public StateEvent this[string eventType, string eventKey = ""] { get { - var stateEvent = InitialState.FirstOrDefault(x => x.Type == event_type && x.StateKey == event_key); + var stateEvent = InitialState.FirstOrDefault(x => x.Type == eventType && x.StateKey == eventKey); if (stateEvent == null) { InitialState.Add(stateEvent = new StateEvent { - Type = event_type, - StateKey = event_key, + Type = eventType, + StateKey = eventKey, TypedContent = (EventContent)Activator.CreateInstance( StateEvent.KnownStateEventTypes.FirstOrDefault(x => x.GetCustomAttributes()? - .Any(y => y.EventName == event_type) ?? false) ?? typeof(object) - ) + .Any(y => y.EventName == eventType) ?? false) ?? typeof(object) + )! }); } return stateEvent; } set { - var stateEvent = InitialState.FirstOrDefault(x => x.Type == event_type && x.StateKey == event_key); + var stateEvent = InitialState.FirstOrDefault(x => x.Type == eventType && x.StateKey == eventKey); if (stateEvent == null) InitialState.Add(value); else diff --git a/LibMatrix/Responses/CreationContentBaseType.cs b/LibMatrix/Responses/CreationContentBaseType.cs index ba3ce5e..073bb60 100644 --- a/LibMatrix/Responses/CreationContentBaseType.cs +++ b/LibMatrix/Responses/CreationContentBaseType.cs @@ -3,16 +3,16 @@ using System.Text.Json.Serialization; namespace LibMatrix.Responses; public class CreationContentBaseType { - private readonly CreateRoomRequest createRoomRequest; + private readonly CreateRoomRequest _createRoomRequest; - public CreationContentBaseType(CreateRoomRequest createRoomRequest) => this.createRoomRequest = createRoomRequest; + public CreationContentBaseType(CreateRoomRequest createRoomRequest) => this._createRoomRequest = createRoomRequest; [JsonPropertyName("type")] public string Type { - get => (string)createRoomRequest.CreationContent["type"]; + get => (string)_createRoomRequest.CreationContent["type"]; set { - if (value is "null" or "") createRoomRequest.CreationContent.Remove("type"); - else createRoomRequest.CreationContent["type"] = value; + if (value is "null" or "") _createRoomRequest.CreationContent.Remove("type"); + else _createRoomRequest.CreationContent["type"] = value; } } } diff --git a/LibMatrix/Responses/LoginResponse.cs b/LibMatrix/Responses/LoginResponse.cs index 82004fc..c5d4e87 100644 --- a/LibMatrix/Responses/LoginResponse.cs +++ b/LibMatrix/Responses/LoginResponse.cs @@ -1,7 +1,5 @@ -using System.ComponentModel.DataAnnotations; using System.Text.Json.Serialization; using LibMatrix.Homeservers; -using LibMatrix.Services; namespace LibMatrix.Responses; diff --git a/LibMatrix/Responses/SyncResponse.cs b/LibMatrix/Responses/SyncResponse.cs index d3130bb..42759ff 100644 --- a/LibMatrix/Responses/SyncResponse.cs +++ b/LibMatrix/Responses/SyncResponse.cs @@ -50,13 +50,13 @@ public class SyncResponse { public class LeftRoomDataStructure { [JsonPropertyName("account_data")] - public EventList AccountData { get; set; } + public EventList? AccountData { get; set; } [JsonPropertyName("timeline")] public JoinedRoomDataStructure.TimelineDataStructure? Timeline { get; set; } [JsonPropertyName("state")] - public EventList State { get; set; } + public EventList? State { get; set; } } public class JoinedRoomDataStructure { @@ -99,13 +99,13 @@ public class SyncResponse { public class SummaryDataStructure { [JsonPropertyName("m.heroes")] - public List Heroes { get; set; } + public List? Heroes { get; set; } [JsonPropertyName("m.invited_member_count")] - public int InvitedMemberCount { get; set; } + public int? InvitedMemberCount { get; set; } [JsonPropertyName("m.joined_member_count")] - public int JoinedMemberCount { get; set; } + public int? JoinedMemberCount { get; set; } } } diff --git a/LibMatrix/Responses/UserProfileResponse.cs b/LibMatrix/Responses/UserProfileResponse.cs index e56e87b..9972a26 100644 --- a/LibMatrix/Responses/UserProfileResponse.cs +++ b/LibMatrix/Responses/UserProfileResponse.cs @@ -1,5 +1,4 @@ using System.Text.Json.Serialization; -using LibMatrix.Interfaces; namespace LibMatrix.Responses; diff --git a/LibMatrix/RoomTypes/GenericRoom.cs b/LibMatrix/RoomTypes/GenericRoom.cs index 9804e78..d067f9f 100644 --- a/LibMatrix/RoomTypes/GenericRoom.cs +++ b/LibMatrix/RoomTypes/GenericRoom.cs @@ -4,39 +4,39 @@ using System.Text.Json; using System.Text.Json.Serialization; using System.Web; using ArcaneLibs.Extensions; +using LibMatrix.EventTypes; using LibMatrix.EventTypes.Spec; using LibMatrix.EventTypes.Spec.State; -using LibMatrix.Extensions; +using LibMatrix.EventTypes.Spec.State.RoomInfo; using LibMatrix.Homeservers; -using LibMatrix.Interfaces; namespace LibMatrix.RoomTypes; public class GenericRoom { internal readonly AuthenticatedHomeserverGeneric Homeserver; - internal readonly MatrixHttpClient _httpClient; public GenericRoom(AuthenticatedHomeserverGeneric homeserver, string roomId) { if (string.IsNullOrWhiteSpace(roomId)) throw new ArgumentException("Room ID cannot be null or whitespace", nameof(roomId)); Homeserver = homeserver; - _httpClient = homeserver.ClientHttpClient; RoomId = roomId; - if (GetType() != typeof(SpaceRoom)) + // if (GetType() != typeof(SpaceRoom)) + if (GetType() == typeof(GenericRoom)) { AsSpace = new SpaceRoom(homeserver, RoomId); + } } public string RoomId { get; set; } public async IAsyncEnumerable GetFullStateAsync() { - var result = _httpClient.GetAsyncEnumerableFromJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/state"); + var result = Homeserver.ClientHttpClient.GetAsyncEnumerableFromJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/state"); await foreach (var resp in result) { yield return resp; } } public async Task> GetFullStateAsListAsync() { - return await _httpClient.GetFromJsonAsync>($"/_matrix/client/v3/rooms/{RoomId}/state"); + return await Homeserver.ClientHttpClient.GetFromJsonAsync>($"/_matrix/client/v3/rooms/{RoomId}/state"); } public async Task GetStateAsync(string type, string stateKey = "") { @@ -56,7 +56,7 @@ public class GenericRoom { return resp.Deserialize(); #else - var resp = await _httpClient.GetFromJsonAsync(url); + var resp = await Homeserver.ClientHttpClient.GetFromJsonAsync(url); return resp; #endif } @@ -85,8 +85,8 @@ public class GenericRoom { if (!string.IsNullOrWhiteSpace(from)) url += $"&from={from}"; if (limit is not null) url += $"&limit={limit}"; if (!string.IsNullOrWhiteSpace(filter)) url += $"&filter={filter}"; - var res = await _httpClient.GetFromJsonAsync(url); - return res ?? new MessagesResponse(); + var res = await Homeserver.ClientHttpClient.GetFromJsonAsync(url); + return res; } /// @@ -101,8 +101,8 @@ public class GenericRoom { concat.Add(resp); if (!includeState) resp.State.Clear(); - from = resp.End; if (resp.End is null) break; + from = resp.End; } concat.Reverse(); @@ -131,12 +131,12 @@ public class GenericRoom { resp.State.Clear(); limit -= resp.Chunk.Count + resp.State.Count; - from = resp.End; yield return resp; if (resp.End is null) { Console.WriteLine("End is null"); yield break; } + from = resp.End; } } @@ -148,19 +148,19 @@ public class GenericRoom { public async Task JoinAsync(string[]? homeservers = null, string? reason = null, bool checkIfAlreadyMember = true) { if (checkIfAlreadyMember) { try { - var ce = await GetCreateEventAsync(); - return new() { + _ = await GetCreateEventAsync(); + return new RoomIdResponse { RoomId = RoomId }; } catch { } //ignore } - var join_url = $"/_matrix/client/v3/join/{HttpUtility.UrlEncode(RoomId)}"; - Console.WriteLine($"Calling {join_url} with {homeservers?.Length ?? 0} via's..."); + var joinUrl = $"/_matrix/client/v3/join/{HttpUtility.UrlEncode(RoomId)}"; + Console.WriteLine($"Calling {joinUrl} with {homeservers?.Length ?? 0} via's..."); if (homeservers == null || homeservers.Length == 0) homeservers = new[] { RoomId.Split(':')[1] }; - var fullJoinUrl = $"{join_url}?server_name=" + string.Join("&server_name=", homeservers); - var res = await _httpClient.PostAsJsonAsync(fullJoinUrl, new { + var fullJoinUrl = $"{joinUrl}?server_name=" + string.Join("&server_name=", homeservers); + var res = await Homeserver.ClientHttpClient.PostAsJsonAsync(fullJoinUrl, new { reason }); return await res.Content.ReadFromJsonAsync() ?? throw new Exception("Failed to join room?"); @@ -168,9 +168,9 @@ public class GenericRoom { public async IAsyncEnumerable GetMembersAsync(bool joinedOnly = true) { var sw = Stopwatch.StartNew(); - var res = await _httpClient.GetAsync($"/_matrix/client/v3/rooms/{RoomId}/members"); + var res = await Homeserver.ClientHttpClient.GetAsync($"/_matrix/client/v3/rooms/{RoomId}/members"); Console.WriteLine($"Members call responded in {sw.GetElapsedAndRestart()}"); - var resText = await res.Content.ReadAsStringAsync(); + // var resText = await res.Content.ReadAsStringAsync(); Console.WriteLine($"Members call response read in {sw.GetElapsedAndRestart()}"); var result = await JsonSerializer.DeserializeAsync(await res.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { TypeInfoResolver = ChunkedStateEventResponseSerializerContext.Default, @@ -188,7 +188,7 @@ public class GenericRoom { #region Utility shortcuts - public async Task SendMessageEventAsync(RoomMessageEventContent content) => + public async Task SendMessageEventAsync(RoomMessageEventContent content) => await SendTimelineEventAsync("m.room.message", content); public async Task?> GetAliasesAsync() { @@ -259,29 +259,29 @@ public class GenericRoom { #region Simple calls public async Task ForgetAsync() => - await _httpClient.PostAsync($"/_matrix/client/v3/rooms/{RoomId}/forget", null); + await Homeserver.ClientHttpClient.PostAsync($"/_matrix/client/v3/rooms/{RoomId}/forget", null); public async Task LeaveAsync(string? reason = null) => - await _httpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/leave", new { + await Homeserver.ClientHttpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/leave", new { reason }); public async Task KickAsync(string userId, string? reason = null) => - await _httpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/kick", + await Homeserver.ClientHttpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/kick", new UserIdAndReason { UserId = userId, Reason = reason }); public async Task BanAsync(string userId, string? reason = null) => - await _httpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/ban", + await Homeserver.ClientHttpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/ban", new UserIdAndReason { UserId = userId, Reason = reason }); public async Task UnbanAsync(string userId) => - await _httpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/unban", + await Homeserver.ClientHttpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/unban", new UserIdAndReason { UserId = userId }); public async Task InviteUserAsync(string userId, string? reason = null, bool skipExisting = true) { if (skipExisting && await GetStateAsync("m.room.member", userId) is not null) return; - await _httpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/invite", new UserIdAndReason(userId, reason)); + await Homeserver.ClientHttpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/invite", new UserIdAndReason(userId, reason)); } #endregion @@ -289,19 +289,19 @@ public class GenericRoom { #region Events public async Task SendStateEventAsync(string eventType, object content) => - await (await _httpClient.PutAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/state/{eventType}", content)) + await (await Homeserver.ClientHttpClient.PutAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/state/{eventType}", content)) .Content.ReadFromJsonAsync(); public async Task SendStateEventAsync(string eventType, string stateKey, object content) => - await (await _httpClient.PutAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/state/{eventType}/{stateKey}", content)) + await (await Homeserver.ClientHttpClient.PutAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/state/{eventType}/{stateKey}", content)) .Content.ReadFromJsonAsync(); - public async Task SendTimelineEventAsync(string eventType, TimelineEventContent content) { - var res = await _httpClient.PutAsJsonAsync( + public async Task SendTimelineEventAsync(string eventType, TimelineEventContent content) { + var res = await Homeserver.ClientHttpClient.PutAsJsonAsync( $"/_matrix/client/v3/rooms/{RoomId}/send/{eventType}/" + Guid.NewGuid(), content, new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }); - return await res.Content.ReadFromJsonAsync(); + return await res.Content.ReadFromJsonAsync() ?? throw new Exception("Failed to send event"); } public async Task SendFileAsync(string fileName, Stream fileStream, string messageType = "m.file", string contentType = "application/octet-stream") { @@ -320,7 +320,7 @@ public class GenericRoom { } public async Task GetRoomAccountDataAsync(string key) { - var res = await _httpClient.GetAsync($"/_matrix/client/v3/user/{Homeserver.UserId}/rooms/{RoomId}/account_data/{key}"); + var res = await Homeserver.ClientHttpClient.GetAsync($"/_matrix/client/v3/user/{Homeserver.UserId}/rooms/{RoomId}/account_data/{key}"); if (!res.IsSuccessStatusCode) { Console.WriteLine($"Failed to get room account data: {await res.Content.ReadAsStringAsync()}"); throw new InvalidDataException($"Failed to get room account data: {await res.Content.ReadAsStringAsync()}"); @@ -330,7 +330,7 @@ public class GenericRoom { } public async Task SetRoomAccountDataAsync(string key, object data) { - var res = await _httpClient.PutAsJsonAsync($"/_matrix/client/v3/user/{Homeserver.UserId}/rooms/{RoomId}/account_data/{key}", data); + var res = await Homeserver.ClientHttpClient.PutAsJsonAsync($"/_matrix/client/v3/user/{Homeserver.UserId}/rooms/{RoomId}/account_data/{key}", data); if (!res.IsSuccessStatusCode) { Console.WriteLine($"Failed to set room account data: {await res.Content.ReadAsStringAsync()}"); throw new InvalidDataException($"Failed to set room account data: {await res.Content.ReadAsStringAsync()}"); @@ -338,12 +338,12 @@ public class GenericRoom { } public async Task GetEventAsync(string eventId) { - return await _httpClient.GetFromJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/event/{eventId}"); + return await Homeserver.ClientHttpClient.GetFromJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/event/{eventId}"); } public async Task RedactEventAsync(string eventToRedact, string reason) { var data = new { reason }; - return (await (await _httpClient.PutAsJsonAsync( + return (await (await Homeserver.ClientHttpClient.PutAsJsonAsync( $"/_matrix/client/v3/rooms/{RoomId}/redact/{eventToRedact}/{Guid.NewGuid()}", data)).Content.ReadFromJsonAsync())!; } @@ -353,7 +353,7 @@ public class GenericRoom { public async Task>> GetMembersByHomeserverAsync(bool joinedOnly = true) { if (Homeserver is AuthenticatedHomeserverMxApiExtended mxaeHomeserver) - return await Homeserver.ClientHttpClient.GetFromJsonAsync>>( + return await mxaeHomeserver.ClientHttpClient.GetFromJsonAsync>>( $"/_matrix/client/v3/rooms/{RoomId}/members_by_homeserver?joined_only={joinedOnly}"); Dictionary> roomHomeservers = new(); var members = GetMembersAsync(); diff --git a/LibMatrix/RoomTypes/SpaceRoom.cs b/LibMatrix/RoomTypes/SpaceRoom.cs index da9fcf8..6ebd62f 100644 --- a/LibMatrix/RoomTypes/SpaceRoom.cs +++ b/LibMatrix/RoomTypes/SpaceRoom.cs @@ -4,10 +4,8 @@ using LibMatrix.Homeservers; namespace LibMatrix.RoomTypes; public class SpaceRoom(AuthenticatedHomeserverGeneric homeserver, string roomId) : GenericRoom(homeserver, roomId) { - private readonly GenericRoom _room; - public async IAsyncEnumerable GetChildrenAsync(bool includeRemoved = false) { - var rooms = new List(); + // var rooms = new List(); var state = GetFullStateAsync(); await foreach (var stateEvent in state) { if (stateEvent!.Type != "m.space.child") continue; diff --git a/LibMatrix/Services/HomeserverProviderService.cs b/LibMatrix/Services/HomeserverProviderService.cs index a42077a..983f469 100644 --- a/LibMatrix/Services/HomeserverProviderService.cs +++ b/LibMatrix/Services/HomeserverProviderService.cs @@ -6,20 +6,20 @@ using Microsoft.Extensions.Logging; namespace LibMatrix.Services; -public class HomeserverProviderService(ILogger logger, HomeserverResolverService homeserverResolverService) { - private static Dictionary _authenticatedHomeserverSemaphore = new(); - private static Dictionary _authenticatedHomeserverCache = new(); +public class HomeserverProviderService(ILogger logger) { + private static readonly Dictionary AuthenticatedHomeserverSemaphore = new(); + private static readonly Dictionary AuthenticatedHomeserverCache = new(); - private static Dictionary _remoteHomeserverSemaphore = new(); - private static Dictionary _remoteHomeserverCache = new(); + private static readonly Dictionary RemoteHomeserverSemaphore = new(); + private static readonly Dictionary RemoteHomeserverCache = new(); public async Task GetAuthenticatedWithToken(string homeserver, string accessToken, string? proxy = null) { var cacheKey = homeserver + accessToken + proxy; - var sem = _authenticatedHomeserverSemaphore.GetOrCreate(cacheKey, _ => new SemaphoreSlim(1, 1)); + var sem = AuthenticatedHomeserverSemaphore.GetOrCreate(cacheKey, _ => new SemaphoreSlim(1, 1)); await sem.WaitAsync(); AuthenticatedHomeserverGeneric? hs; - lock (_authenticatedHomeserverCache) { - if (_authenticatedHomeserverCache.TryGetValue(cacheKey, out hs)) { + lock (AuthenticatedHomeserverCache) { + if (AuthenticatedHomeserverCache.TryGetValue(cacheKey, out hs)) { sem.Release(); return hs; } @@ -30,8 +30,8 @@ public class HomeserverProviderService(ILogger logger var rhs = await RemoteHomeserver.Create(homeserver, proxy); var clientVersions = await rhs.GetClientVersionsAsync(); if (proxy is not null) - Console.WriteLine($"Homeserver {homeserver} proxied via {proxy}..."); - Console.WriteLine($"{homeserver}: " + clientVersions.ToJson()); + logger.LogInformation($"Homeserver {homeserver} proxied via {proxy}..."); + logger.LogInformation($"{homeserver}: " + clientVersions.ToJson()); if (clientVersions.UnstableFeatures.TryGetValue("gay.rory.mxapiextensions.v0", out bool a) && a) hs = await AuthenticatedHomeserverGeneric.Create(homeserver, accessToken, proxy); @@ -43,18 +43,31 @@ public class HomeserverProviderService(ILogger logger hs = await AuthenticatedHomeserverGeneric.Create(homeserver, accessToken, proxy); } - lock (_authenticatedHomeserverCache) - _authenticatedHomeserverCache[cacheKey] = hs; + lock (AuthenticatedHomeserverCache) + AuthenticatedHomeserverCache[cacheKey] = hs; sem.Release(); return hs; } public async Task GetRemoteHomeserver(string homeserver, string? proxy = null) { - var hs = await RemoteHomeserver.Create(homeserver, proxy); - // hs._httpClient.Dispose(); - // hs._httpClient = new MatrixHttpClient { BaseAddress = new Uri(hs.ServerName) }; - // hs._httpClient.Timeout = TimeSpan.FromSeconds(120); + var cacheKey = homeserver + proxy; + var sem = RemoteHomeserverSemaphore.GetOrCreate(cacheKey, _ => new SemaphoreSlim(1, 1)); + await sem.WaitAsync(); + RemoteHomeserver? hs; + lock (RemoteHomeserverCache) { + if (RemoteHomeserverCache.TryGetValue(cacheKey, out hs)) { + sem.Release(); + return hs; + } + } + + hs = await RemoteHomeserver.Create(homeserver, proxy); + + lock (RemoteHomeserverCache) + RemoteHomeserverCache[cacheKey] = hs; + sem.Release(); + return hs; } @@ -68,4 +81,4 @@ public class HomeserverProviderService(ILogger logger var data = await resp.Content.ReadFromJsonAsync(); return data!; } -} +} \ No newline at end of file diff --git a/LibMatrix/Services/HomeserverResolverService.cs b/LibMatrix/Services/HomeserverResolverService.cs index f9f92d6..9f937c5 100644 --- a/LibMatrix/Services/HomeserverResolverService.cs +++ b/LibMatrix/Services/HomeserverResolverService.cs @@ -11,15 +11,15 @@ public class HomeserverResolverService(ILogger? logge Timeout = TimeSpan.FromMilliseconds(10000) }; - private static readonly ConcurrentDictionary _wellKnownCache = new(); - private static readonly ConcurrentDictionary _wellKnownSemaphores = new(); + private static readonly ConcurrentDictionary WellKnownCache = new(); + private static readonly ConcurrentDictionary WellKnownSemaphores = new(); public async Task ResolveHomeserverFromWellKnown(string homeserver) { if (homeserver is null) throw new ArgumentNullException(nameof(homeserver)); - _wellKnownSemaphores.TryAdd(homeserver, new(1, 1)); - await _wellKnownSemaphores[homeserver].WaitAsync(); - if (_wellKnownCache.TryGetValue(homeserver, out var known)) { - _wellKnownSemaphores[homeserver].Release(); + WellKnownSemaphores.TryAdd(homeserver, new(1, 1)); + await WellKnownSemaphores[homeserver].WaitAsync(); + if (WellKnownCache.TryGetValue(homeserver, out var known)) { + WellKnownSemaphores[homeserver].Release(); return known; } @@ -28,8 +28,8 @@ public class HomeserverResolverService(ILogger? logge Client = await _tryResolveFromClientWellknown(homeserver), Server = await _tryResolveFromServerWellknown(homeserver) }; - _wellKnownCache.TryAdd(homeserver, res); - _wellKnownSemaphores[homeserver].Release(); + WellKnownCache.TryAdd(homeserver, res); + WellKnownSemaphores[homeserver].Release(); return res; } @@ -40,7 +40,9 @@ public class HomeserverResolverService(ILogger? logge var hs = resp.GetProperty("m.homeserver").GetProperty("base_url").GetString(); return hs; } - catch { } + catch { + // ignored + } logger?.LogInformation("No client well-known..."); return null; @@ -51,11 +53,14 @@ public class HomeserverResolverService(ILogger? logge try { var resp = await _httpClient.GetFromJsonAsync($"{homeserver}/.well-known/matrix/server"); var hs = resp.GetProperty("m.server").GetString(); + if(hs is null) throw new InvalidDataException("m.server is null"); if (!hs.StartsWithAnyOf("http://", "https://")) hs = $"https://{hs}"; return hs; } - catch { } + catch { + // ignored + } // fallback: most servers host these on the same location var clientUrl = await _tryResolveFromClientWellknown(homeserver); diff --git a/LibMatrix/StateEvent.cs b/LibMatrix/StateEvent.cs index 6ca82f4..cfc7011 100644 --- a/LibMatrix/StateEvent.cs +++ b/LibMatrix/StateEvent.cs @@ -1,3 +1,5 @@ +using System.Collections.Frozen; +using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text.Json; @@ -7,31 +9,23 @@ using ArcaneLibs; using ArcaneLibs.Extensions; using LibMatrix.EventTypes; using LibMatrix.Extensions; -using LibMatrix.Interfaces; namespace LibMatrix; public class StateEvent { - public static List KnownStateEventTypes { get; } = new ClassCollector().ResolveFromAllAccessibleAssemblies(); + public static FrozenSet KnownStateEventTypes { get; } = new ClassCollector().ResolveFromAllAccessibleAssemblies().ToFrozenSet(); - public static readonly Dictionary KnownStateEventTypesByName = KnownStateEventTypes.Aggregate( + public static FrozenDictionary KnownStateEventTypesByName { get; } = KnownStateEventTypes.Aggregate( new Dictionary(), (dict, type) => { var attrs = type.GetCustomAttributes(); foreach (var attr in attrs) { dict[attr.EventName] = type; } - return dict; - }); - - public static Type GetStateEventType(string type) { - if (type == "m.receipt") { - return typeof(Dictionary); - } + }).ToFrozenDictionary(); - return KnownStateEventTypesByName.GetValueOrDefault(type) ?? typeof(UnknownEventContent); - } + public static Type GetStateEventType(string type) => KnownStateEventTypesByName.GetValueOrDefault(type) ?? typeof(UnknownEventContent); private static readonly JsonSerializerOptions TypedContentSerializerOptions = new JsonSerializerOptions() { Converters = { @@ -80,13 +74,7 @@ public class StateEvent { [JsonPropertyName("content")] public JsonObject? RawContent { get => _rawContent; - set { - _rawContent = value; - // if (Type is not null && this is StateEventResponse stateEventResponse) { - // if (File.Exists($"unknown_state_events/{Type}/{stateEventResponse.EventId}.json")) return; - // var x = GetType.Name; - // } - } + set => _rawContent = value; } [JsonIgnore] @@ -139,22 +127,22 @@ public class StateEvent { public class StateEventResponse : StateEvent { [JsonPropertyName("origin_server_ts")] - public ulong OriginServerTs { get; set; } + public ulong? OriginServerTs { get; set; } [JsonPropertyName("room_id")] - public string RoomId { get; set; } + public string? RoomId { get; set; } [JsonPropertyName("sender")] - public string Sender { get; set; } + public string? Sender { get; set; } [JsonPropertyName("unsigned")] public UnsignedData? Unsigned { get; set; } [JsonPropertyName("event_id")] - public string EventId { get; set; } + public string? EventId { get; set; } [JsonPropertyName("replaces_state")] - public new string ReplacesState { get; set; } + public new string? ReplacesState { get; set; } public class UnsignedData { [JsonPropertyName("age")] @@ -179,8 +167,7 @@ public class StateEventResponse : StateEvent { [JsonSourceGenerationOptions(WriteIndented = true)] [JsonSerializable(typeof(ChunkedStateEventResponse))] -internal partial class ChunkedStateEventResponseSerializerContext : JsonSerializerContext { -} +internal partial class ChunkedStateEventResponseSerializerContext : JsonSerializerContext; public class EventList { [JsonPropertyName("events")] diff --git a/LibMatrix/UserIdAndReason.cs b/LibMatrix/UserIdAndReason.cs index 09dc461..c76ecc7 100644 --- a/LibMatrix/UserIdAndReason.cs +++ b/LibMatrix/UserIdAndReason.cs @@ -2,7 +2,7 @@ using System.Text.Json.Serialization; namespace LibMatrix; -internal class UserIdAndReason(string? userId = null, string? reason = null) { +internal class UserIdAndReason(string userId = null!, string reason = null!) { [JsonPropertyName("user_id")] public string UserId { get; set; } = userId; diff --git a/LibMatrix/WhoAmIResponse.cs b/LibMatrix/WhoAmIResponse.cs index 4eb5f2e..e2ea118 100644 --- a/LibMatrix/WhoAmIResponse.cs +++ b/LibMatrix/WhoAmIResponse.cs @@ -4,7 +4,7 @@ namespace LibMatrix; public class WhoAmIResponse { [JsonPropertyName("user_id")] - public string? UserId { get; set; } = null!; + public required string UserId { get; set; } [JsonPropertyName("device_id")] public string? DeviceId { get; set; } -- cgit 1.4.1