diff options
Diffstat (limited to 'LibMatrix')
38 files changed, 283 insertions, 334 deletions
diff --git a/LibMatrix/EventIdResponse.cs b/LibMatrix/EventIdResponse.cs index a7feeca..6a04229 100644 --- a/LibMatrix/EventIdResponse.cs +++ b/LibMatrix/EventIdResponse.cs @@ -5,4 +5,4 @@ namespace LibMatrix; public class EventIdResponse { [JsonPropertyName("event_id")] public required string EventId { get; set; } -} +} \ No newline at end of file diff --git a/LibMatrix/Extensions/EnumerableExtensions.cs b/LibMatrix/Extensions/EnumerableExtensions.cs index 0c98bfe..42d9491 100644 --- a/LibMatrix/Extensions/EnumerableExtensions.cs +++ b/LibMatrix/Extensions/EnumerableExtensions.cs @@ -8,6 +8,7 @@ public static class EnumerableExtensions { oldState.Add(stateEvent); continue; } + oldState.Remove(old); oldState.Add(stateEvent); } @@ -20,9 +21,9 @@ public static class EnumerableExtensions { oldState.Add(stateEvent); continue; } + oldState.Remove(old); oldState.Add(stateEvent); } } - -} +} \ No newline at end of file diff --git a/LibMatrix/Extensions/HttpClientExtensions.cs b/LibMatrix/Extensions/HttpClientExtensions.cs index a7d49c0..b2f45bd 100644 --- a/LibMatrix/Extensions/HttpClientExtensions.cs +++ b/LibMatrix/Extensions/HttpClientExtensions.cs @@ -41,9 +41,7 @@ public class MatrixHttpClient : HttpClient { if (request.RequestUri is null) throw new NullReferenceException("RequestUri is null"); if (!request.RequestUri.IsAbsoluteUri) request.RequestUri = new Uri(BaseAddress, request.RequestUri); // if (AssertedUserId is not null) request.RequestUri = request.RequestUri.AddQuery("user_id", AssertedUserId); - foreach (var (key, value) in AdditionalQueryParameters) { - request.RequestUri = request.RequestUri.AddQuery(key, value); - } + foreach (var (key, value) in AdditionalQueryParameters) request.RequestUri = request.RequestUri.AddQuery(key, value); // Console.WriteLine($"Sending request to {request.RequestUri}"); @@ -59,16 +57,16 @@ public class MatrixHttpClient : HttpClient { HttpResponseMessage responseMessage; // try { - responseMessage = await base.SendAsync(request, cancellationToken); + responseMessage = await base.SendAsync(request, cancellationToken); // } // catch (Exception e) { - // if (requestSettings is { Retries: 0 }) throw; - // typeof(HttpRequestMessage).GetField("_sendStatus", BindingFlags.NonPublic | BindingFlags.Instance) - // ?.SetValue(request, 0); - // await Task.Delay(requestSettings?.RetryDelay ?? 2500, cancellationToken); - // if(requestSettings is not null) requestSettings.Retries--; - // return await SendAsync(request, cancellationToken); - // throw; + // if (requestSettings is { Retries: 0 }) throw; + // typeof(HttpRequestMessage).GetField("_sendStatus", BindingFlags.NonPublic | BindingFlags.Instance) + // ?.SetValue(request, 0); + // await Task.Delay(requestSettings?.RetryDelay ?? 2500, cancellationToken); + // if(requestSettings is not null) requestSettings.Retries--; + // return await SendAsync(request, cancellationToken); + // throw; // } if (responseMessage.IsSuccessStatusCode) return responseMessage; @@ -95,9 +93,8 @@ public class MatrixHttpClient : HttpClient { } // GetAsync - public Task<HttpResponseMessage> GetAsync([StringSyntax("Uri")] string? requestUri, CancellationToken? cancellationToken = null) { - return SendAsync(new HttpRequestMessage(HttpMethod.Get, requestUri), cancellationToken ?? CancellationToken.None); - } + public Task<HttpResponseMessage> GetAsync([StringSyntax("Uri")] string? requestUri, CancellationToken? cancellationToken = null) => + SendAsync(new HttpRequestMessage(HttpMethod.Get, requestUri), cancellationToken ?? CancellationToken.None); // GetFromJsonAsync public async Task<T> GetFromJsonAsync<T>(string requestUri, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default) { @@ -116,7 +113,7 @@ public class MatrixHttpClient : HttpClient { Console.WriteLine("[!!] Checking sync response failed: " + e); } #endif - return await JsonSerializer.DeserializeAsync<T>(responseStream, options, cancellationToken: cancellationToken) ?? + return await JsonSerializer.DeserializeAsync<T>(responseStream, options, cancellationToken) ?? throw new InvalidOperationException("Failed to deserialize response"); } @@ -144,7 +141,7 @@ public class MatrixHttpClient : HttpClient { public async Task<HttpResponseMessage> PostAsJsonAsync<T>([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, T value, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default) where T : notnull { - options ??= new(); + options ??= new JsonSerializerOptions(); options.Converters.Add(new JsonFloatStringConverter()); options.Converters.Add(new JsonDoubleStringConverter()); options.Converters.Add(new JsonDecimalStringConverter()); @@ -160,9 +157,7 @@ public class MatrixHttpClient : HttpClient { options = GetJsonSerializerOptions(options); var res = await GetAsync(requestUri); var result = JsonSerializer.DeserializeAsyncEnumerable<T>(await res.Content.ReadAsStreamAsync(), options); - await foreach (var resp in result) { - yield return resp; - } + await foreach (var resp in result) yield return resp; } } diff --git a/LibMatrix/Extensions/JsonElementExtensions.cs b/LibMatrix/Extensions/JsonElementExtensions.cs index 0bdf01c..c4ed743 100644 --- a/LibMatrix/Extensions/JsonElementExtensions.cs +++ b/LibMatrix/Extensions/JsonElementExtensions.cs @@ -56,9 +56,7 @@ public static class JsonElementExtensions { private static bool FindExtraJsonPropertyFieldsByValueKind(this JsonProperty field, Type containerType, Type propertyType) { - if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) { - propertyType = propertyType.GetGenericArguments()[0]; - } + if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) propertyType = propertyType.GetGenericArguments()[0]; var switchResult = false; switch (field.Value.ValueKind) { @@ -146,4 +144,4 @@ public static class JsonElementExtensions { current | key.FindExtraJsonElementFields(valueType, field.Name) ); } -} +} \ No newline at end of file diff --git a/LibMatrix/Filters/LocalRoomQueryFilter.cs b/LibMatrix/Filters/LocalRoomQueryFilter.cs index 6673716..b3bd4c0 100644 --- a/LibMatrix/Filters/LocalRoomQueryFilter.cs +++ b/LibMatrix/Filters/LocalRoomQueryFilter.cs @@ -22,7 +22,6 @@ public class LocalRoomQueryFilter { public int StateEventsGreaterThan { get; set; } public int StateEventsLessThan { get; set; } = int.MaxValue; - public bool CheckFederation { get; set; } public bool CheckPublic { get; set; } -} +} \ No newline at end of file diff --git a/LibMatrix/Filters/SyncFilter.cs b/LibMatrix/Filters/SyncFilter.cs index 5ffef4d..787ffa7 100644 --- a/LibMatrix/Filters/SyncFilter.cs +++ b/LibMatrix/Filters/SyncFilter.cs @@ -24,21 +24,30 @@ public class SyncFilter { [JsonPropertyName("timeline")] public StateFilter? Timeline { get; set; } - + [JsonPropertyName("rooms")] public List<string>? Rooms { get; set; } - + [JsonPropertyName("not_rooms")] public List<string>? NotRooms { get; set; } - + [JsonPropertyName("include_leave")] public bool? IncludeLeave { get; set; } - public class StateFilter(bool? containsUrl = null, bool? includeRedundantMembers = null, bool? lazyLoadMembers = null, List<string>? rooms = null, - List<string>? notRooms = null, bool? unreadThreadNotifications = null, + public class StateFilter( + bool? containsUrl = null, + bool? includeRedundantMembers = null, + bool? lazyLoadMembers = null, + List<string>? rooms = null, + List<string>? notRooms = null, + bool? unreadThreadNotifications = null, //base ctor - int? limit = null, List<string>? types = null, List<string>? notTypes = null, List<string>? senders = null, List<string>? notSenders = null - ) : EventFilter(limit: limit, types: types, notTypes: notTypes, senders: senders, notSenders: notSenders) { + int? limit = null, + List<string>? types = null, + List<string>? notTypes = null, + List<string>? senders = null, + List<string>? notSenders = null + ) : EventFilter(limit, types, notTypes, senders, notSenders) { [JsonPropertyName("contains_url")] public bool? ContainsUrl { get; set; } = containsUrl; diff --git a/LibMatrix/Helpers/HomeserverWeightEstimation.cs b/LibMatrix/Helpers/HomeserverWeightEstimation.cs index 02f9185..5735af3 100644 --- a/LibMatrix/Helpers/HomeserverWeightEstimation.cs +++ b/LibMatrix/Helpers/HomeserverWeightEstimation.cs @@ -55,4 +55,4 @@ public class HomeserverWeightEstimation { { "!OGEhHVWSdvArJzumhm:matrix.org", 101457 }, { "!YTvKGNlinIzlkMTVRl:matrix.org", 30164 } }; -} +} \ No newline at end of file diff --git a/LibMatrix/Helpers/MessageBuilder.cs b/LibMatrix/Helpers/MessageBuilder.cs index 250187a..68f6300 100644 --- a/LibMatrix/Helpers/MessageBuilder.cs +++ b/LibMatrix/Helpers/MessageBuilder.cs @@ -8,46 +8,42 @@ public class MessageBuilder(string msgType = "m.text", string format = "org.matr MessageType = msgType, Format = format }; - + public RoomMessageEventContent Build() => Content; - + public MessageBuilder WithBody(string body) { Content.Body += body; Content.FormattedBody += body; return this; } - + public MessageBuilder WithHtmlTag(string tag, string body, Dictionary<string, string>? attributes = null) { Content.Body += body; Content.FormattedBody += $"<{tag}"; - if (attributes != null) { - foreach (var (key, value) in attributes) { + if (attributes != null) + foreach (var (key, value) in attributes) Content.FormattedBody += $" {key}=\"{value}\""; - } - } Content.FormattedBody += $">{body}</{tag}>"; return this; } - + public MessageBuilder WithHtmlTag(string tag, Action<MessageBuilder> bodyBuilder, Dictionary<string, string>? attributes = null) { Content.FormattedBody += $"<{tag}"; - if (attributes != null) { - foreach (var (key, value) in attributes) { + if (attributes != null) + foreach (var (key, value) in attributes) Content.FormattedBody += $" {key}=\"{value}\""; - } - } Content.FormattedBody += ">"; bodyBuilder(this); Content.FormattedBody += $"</{tag}>"; return this; } - + public MessageBuilder WithColoredBody(string color, string body) { Content.Body += body; Content.FormattedBody += $"<font color=\"{color}\">{body}</font>"; return this; } - + public MessageBuilder WithColoredBody(string color, Action<MessageBuilder> bodyBuilder) { Content.FormattedBody += $"<font color=\"{color}\">"; bodyBuilder(this); @@ -55,7 +51,7 @@ public class MessageBuilder(string msgType = "m.text", string format = "org.matr return this; } - public MessageBuilder WithRainbowString(string text, byte skip = 1, int offset = 0, double lengthFactor = 255.0, bool useLength = true) { + public MessageBuilder WithRainbowString(string text, byte skip = 1, int offset = 0, double lengthFactor = 255.0, bool useLength = true) => // if (useLength) { // lengthFactor = text.Length; // } @@ -67,8 +63,5 @@ public class MessageBuilder(string msgType = "m.text", string format = "org.matr // // Console.WriteLine($"RBA: {r} {g} {b} {a}"); // // Content.FormattedBody += $"<font color=\"#{r:X2}{g:X2}{b:X2}\">{text[i]}</font>"; // } - - return this; - } - + this; } \ No newline at end of file diff --git a/LibMatrix/Helpers/MessageFormatter.cs b/LibMatrix/Helpers/MessageFormatter.cs index b7c6975..1b9b4f3 100644 --- a/LibMatrix/Helpers/MessageFormatter.cs +++ b/LibMatrix/Helpers/MessageFormatter.cs @@ -4,73 +4,64 @@ using LibMatrix.EventTypes.Spec; namespace LibMatrix.Helpers; public static class MessageFormatter { - public static RoomMessageEventContent FormatError(string error) { - return new RoomMessageEventContent(body: error, messageType: "m.text") { + public static RoomMessageEventContent FormatError(string error) => + new(body: error, messageType: "m.text") { FormattedBody = $"<font color=\"#EE4444\">{error}</font>", Format = "org.matrix.custom.html" }; - } - public static RoomMessageEventContent FormatException(string error, Exception e) { - return new RoomMessageEventContent(body: $"{error}: {e.Message}", messageType: "m.text") { + public static RoomMessageEventContent FormatException(string error, Exception e) => + new(body: $"{error}: {e.Message}", messageType: "m.text") { FormattedBody = $"<font color=\"#EE4444\">{error}: <pre><code>{e.Message}</code></pre></font>", Format = "org.matrix.custom.html" }; - } - public static RoomMessageEventContent FormatSuccess(string text) { - return new RoomMessageEventContent(body: text, messageType: "m.text") { + public static RoomMessageEventContent FormatSuccess(string text) => + new(body: text, messageType: "m.text") { FormattedBody = $"<font color=\"#00FF00\">{text}</font>", Format = "org.matrix.custom.html" }; - } - public static RoomMessageEventContent FormatSuccessJson(string text, object data) { - return new RoomMessageEventContent(body: text, messageType: "m.text") { + public static RoomMessageEventContent FormatSuccessJson(string text, object data) => + new(body: text, messageType: "m.text") { FormattedBody = $"<font color=\"#00FF00\">{text}: <pre><code>{data.ToJson(ignoreNull: true)}</code></pre></font>", Format = "org.matrix.custom.html" }; - } - public static string HtmlFormatMention(string id, string? displayName = null) { - return $"<a href=\"https://matrix.to/#/{id}\">{displayName ?? id}</a>"; - } + public static string HtmlFormatMention(string id, string? displayName = null) => $"<a href=\"https://matrix.to/#/{id}\">{displayName ?? id}</a>"; public static string HtmlFormatMessageLink(string roomId, string eventId, string[]? servers = null, string? displayName = null) { if (servers is not { Length: > 0 }) servers = new[] { roomId.Split(':', 2)[1] }; return $"<a href=\"https://matrix.to/#/{roomId}/{eventId}?via={string.Join("&via=", servers)}\">{displayName ?? eventId}</a>"; } - #region Extension functions +#region Extension functions public static RoomMessageEventContent ToMatrixMessage(this Exception e, string error) => FormatException(error, e); - #endregion +#endregion - public static RoomMessageEventContent FormatWarning(string warning) { - return new RoomMessageEventContent(body: warning, messageType: "m.text") { + public static RoomMessageEventContent FormatWarning(string warning) => + new(body: warning, messageType: "m.text") { FormattedBody = $"<font color=\"#FFFF00\">{warning}</font>", Format = "org.matrix.custom.html" }; - } - - public static RoomMessageEventContent FormatWarningJson(string warning, object data) { - return new RoomMessageEventContent(body: warning, messageType: "m.text") { + + public static RoomMessageEventContent FormatWarningJson(string warning, object data) => + new(body: warning, messageType: "m.text") { FormattedBody = $"<font color=\"#FFFF00\">{warning}: <pre><code>{data.ToJson(ignoreNull: true)}</code></pre></font>", Format = "org.matrix.custom.html" }; - } - - public static RoomMessageEventContent Concat(this RoomMessageEventContent a, RoomMessageEventContent b) { - return new RoomMessageEventContent(body: $"{a.Body}{b.Body}", messageType: a.MessageType) { + + public static RoomMessageEventContent Concat(this RoomMessageEventContent a, RoomMessageEventContent b) => + new(body: $"{a.Body}{b.Body}", messageType: a.MessageType) { FormattedBody = $"{a.FormattedBody}{b.FormattedBody}", Format = a.Format }; - } - public static RoomMessageEventContent ConcatLine(this RoomMessageEventContent a, RoomMessageEventContent b) { - return new RoomMessageEventContent(body: $"{a.Body}\n{b.Body}", messageType: "m.text") { + + public static RoomMessageEventContent ConcatLine(this RoomMessageEventContent a, RoomMessageEventContent b) => + new(body: $"{a.Body}\n{b.Body}", messageType: "m.text") { FormattedBody = $"{a.FormattedBody}<br/>{b.FormattedBody}", Format = "org.matrix.custom.html" }; - } -} +} \ No newline at end of file diff --git a/LibMatrix/Helpers/SyncHelper.cs b/LibMatrix/Helpers/SyncHelper.cs index 636cfdd..47e5b1e 100644 --- a/LibMatrix/Helpers/SyncHelper.cs +++ b/LibMatrix/Helpers/SyncHelper.cs @@ -28,6 +28,7 @@ public class SyncHelper(AuthenticatedHomeserverGeneric homeserver, ILogger? logg _filter = null; } } + public string? NamedFilterName { get => _namedFilterName; set { @@ -81,11 +82,11 @@ public class SyncHelper(AuthenticatedHomeserverGeneric homeserver, ILogger? logg var url = $"/_matrix/client/v3/sync?timeout={Timeout}&set_presence={SetPresence}&full_state={(FullState ? "true" : "false")}"; if (!string.IsNullOrWhiteSpace(Since)) url += $"&since={Since}"; if (_filterId is not null) url += $"&filter={_filterId}"; - + 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.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); var deserializeSw = Stopwatch.StartNew(); @@ -120,8 +121,8 @@ public class SyncHelper(AuthenticatedHomeserverGeneric homeserver, ILogger? logg public async Task RunSyncLoopAsync(bool skipInitialSyncEvents = true, CancellationToken? cancellationToken = null) { var sw = Stopwatch.StartNew(); - int emptyInitialSyncCount = 0; - int syncCount = 0; + var emptyInitialSyncCount = 0; + var syncCount = 0; var oldTimeout = Timeout; Timeout = 0; await foreach (var sync in EnumerateSyncAsync(cancellationToken)) { @@ -163,27 +164,25 @@ public class SyncHelper(AuthenticatedHomeserverGeneric homeserver, ILogger? logg var tasks = SyncReceivedHandlers.Select(x => x(syncResponse)).ToList(); await Task.WhenAll(tasks); - if (syncResponse.AccountData is { Events.Count: > 0 }) { + if (syncResponse.AccountData is { Events.Count: > 0 }) foreach (var accountDataEvent in syncResponse.AccountData.Events) { tasks = AccountDataReceivedHandlers.Select(x => x(accountDataEvent)).ToList(); await Task.WhenAll(tasks); } - } await RunSyncLoopRoomCallbacksAsync(syncResponse, isInitialSync); } private async Task RunSyncLoopRoomCallbacksAsync(SyncResponse syncResponse, bool isInitialSync) { - if (syncResponse.Rooms is { Invite.Count: > 0 }) { + if (syncResponse.Rooms is { Invite.Count: > 0 }) foreach (var roomInvite in syncResponse.Rooms.Invite) { var tasks = InviteReceivedHandlers.Select(x => x(roomInvite)).ToList(); await Task.WhenAll(tasks); } - } if (isInitialSync) return; - if (syncResponse.Rooms is { Join.Count: > 0 }) { + if (syncResponse.Rooms is { Join.Count: > 0 }) foreach (var updatedRoom in syncResponse.Rooms.Join) { if (updatedRoom.Value.Timeline is null) continue; foreach (var stateEventResponse in updatedRoom.Value.Timeline.Events) { @@ -192,7 +191,6 @@ public class SyncHelper(AuthenticatedHomeserverGeneric homeserver, ILogger? logg await Task.WhenAll(tasks); } } - } } /// <summary> diff --git a/LibMatrix/Helpers/SyncStateResolver.cs b/LibMatrix/Helpers/SyncStateResolver.cs index f380a1f..72d600d 100644 --- a/LibMatrix/Helpers/SyncStateResolver.cs +++ b/LibMatrix/Helpers/SyncStateResolver.cs @@ -15,7 +15,7 @@ public class SyncStateResolver(AuthenticatedHomeserverGeneric homeserver, ILogge public SyncResponse? MergedState { get; set; } - private SyncHelper _syncHelper = new SyncHelper(homeserver, logger); + private SyncHelper _syncHelper = new(homeserver, logger); public async Task<(SyncResponse next, SyncResponse merged)> ContinueAsync(CancellationToken? cancellationToken = null) { // copy properties @@ -36,61 +36,55 @@ public class SyncStateResolver(AuthenticatedHomeserverGeneric homeserver, ILogge private SyncResponse MergeSyncs(SyncResponse oldState, SyncResponse newState) { oldState.NextBatch = newState.NextBatch ?? oldState.NextBatch; - oldState.AccountData ??= new(); - oldState.AccountData.Events ??= new(); + oldState.AccountData ??= new EventList(); + oldState.AccountData.Events ??= new List<StateEventResponse>(); if (newState.AccountData?.Events is not null) - oldState.AccountData.Events.MergeStateEventLists(newState.AccountData?.Events ?? new()); + oldState.AccountData.Events.MergeStateEventLists(newState.AccountData?.Events ?? new List<StateEventResponse>()); - oldState.Presence ??= new(); + oldState.Presence ??= new SyncResponse.PresenceDataStructure(); if (newState.Presence?.Events is not null) - oldState.Presence.Events.MergeStateEventLists(newState.Presence?.Events ?? new()); + oldState.Presence.Events.MergeStateEventLists(newState.Presence?.Events ?? new List<StateEventResponse>()); - oldState.DeviceOneTimeKeysCount ??= new(); + oldState.DeviceOneTimeKeysCount ??= new Dictionary<string, int>(); if (newState.DeviceOneTimeKeysCount is not null) - foreach (var (key, value) in newState.DeviceOneTimeKeysCount) { + foreach (var (key, value) in newState.DeviceOneTimeKeysCount) oldState.DeviceOneTimeKeysCount[key] = value; - } - oldState.Rooms ??= new(); + oldState.Rooms ??= new SyncResponse.RoomsDataStructure(); if (newState.Rooms is not null) oldState.Rooms = MergeRoomsDataStructure(oldState.Rooms, newState.Rooms); - oldState.ToDevice ??= new(); - oldState.ToDevice.Events ??= new(); + oldState.ToDevice ??= new EventList(); + oldState.ToDevice.Events ??= new List<StateEventResponse>(); if (newState.ToDevice?.Events is not null) - oldState.ToDevice.Events.MergeStateEventLists(newState.ToDevice?.Events ?? new()); + oldState.ToDevice.Events.MergeStateEventLists(newState.ToDevice?.Events ?? new List<StateEventResponse>()); - oldState.DeviceLists ??= new(); + oldState.DeviceLists ??= new SyncResponse.DeviceListsDataStructure(); if (newState.DeviceLists?.Changed is not null) - foreach (var s in oldState.DeviceLists.Changed!) { + foreach (var s in oldState.DeviceLists.Changed!) oldState.DeviceLists.Changed.Add(s); - } if (newState.DeviceLists?.Left is not null) - foreach (var s in oldState.DeviceLists.Left!) { + foreach (var s in oldState.DeviceLists.Left!) oldState.DeviceLists.Left.Add(s); - } - return oldState; } - #region Merge rooms +#region Merge rooms private SyncResponse.RoomsDataStructure MergeRoomsDataStructure(SyncResponse.RoomsDataStructure oldState, SyncResponse.RoomsDataStructure newState) { - oldState.Join ??= new(); - foreach (var (key, value) in newState.Join ?? new()) { + oldState.Join ??= new Dictionary<string, SyncResponse.RoomsDataStructure.JoinedRoomDataStructure>(); + foreach (var (key, value) in newState.Join ?? new Dictionary<string, SyncResponse.RoomsDataStructure.JoinedRoomDataStructure>()) if (!oldState.Join.ContainsKey(key)) oldState.Join[key] = value; else oldState.Join[key] = MergeJoinedRoomDataStructure(oldState.Join[key], value); - } - oldState.Invite ??= new(); - foreach (var (key, value) in newState.Invite ?? new()) { + oldState.Invite ??= new Dictionary<string, SyncResponse.RoomsDataStructure.InvitedRoomDataStructure>(); + foreach (var (key, value) in newState.Invite ?? new Dictionary<string, SyncResponse.RoomsDataStructure.InvitedRoomDataStructure>()) if (!oldState.Invite.ContainsKey(key)) oldState.Invite[key] = value; else oldState.Invite[key] = MergeInvitedRoomDataStructure(oldState.Invite[key], value); - } - oldState.Leave ??= new(); - foreach (var (key, value) in newState.Leave ?? new()) { + oldState.Leave ??= new Dictionary<string, SyncResponse.RoomsDataStructure.LeftRoomDataStructure>(); + foreach (var (key, value) in newState.Leave ?? new Dictionary<string, SyncResponse.RoomsDataStructure.LeftRoomDataStructure>()) { if (!oldState.Leave.ContainsKey(key)) oldState.Leave[key] = value; else oldState.Leave[key] = MergeLeftRoomDataStructure(oldState.Leave[key], value); if (oldState.Invite.ContainsKey(key)) oldState.Invite.Remove(key); @@ -102,67 +96,67 @@ public class SyncStateResolver(AuthenticatedHomeserverGeneric homeserver, ILogge private SyncResponse.RoomsDataStructure.LeftRoomDataStructure MergeLeftRoomDataStructure(SyncResponse.RoomsDataStructure.LeftRoomDataStructure oldData, SyncResponse.RoomsDataStructure.LeftRoomDataStructure newData) { - oldData.AccountData ??= new(); - oldData.AccountData.Events ??= new(); - oldData.Timeline ??= new(); - oldData.Timeline.Events ??= new(); - oldData.State ??= new(); - oldData.State.Events ??= new(); + oldData.AccountData ??= new EventList(); + oldData.AccountData.Events ??= new List<StateEventResponse>(); + oldData.Timeline ??= new SyncResponse.RoomsDataStructure.JoinedRoomDataStructure.TimelineDataStructure(); + oldData.Timeline.Events ??= new List<StateEventResponse>(); + oldData.State ??= new EventList(); + oldData.State.Events ??= new List<StateEventResponse>(); if (newData.AccountData?.Events is not null) - oldData.AccountData.Events.MergeStateEventLists(newData.AccountData?.Events ?? new()); + oldData.AccountData.Events.MergeStateEventLists(newData.AccountData?.Events ?? new List<StateEventResponse>()); if (newData.Timeline?.Events is not null) - oldData.Timeline.Events.MergeStateEventLists(newData.Timeline?.Events ?? new()); + oldData.Timeline.Events.MergeStateEventLists(newData.Timeline?.Events ?? new List<StateEventResponse>()); oldData.Timeline.Limited = newData.Timeline?.Limited ?? oldData.Timeline.Limited; oldData.Timeline.PrevBatch = newData.Timeline?.PrevBatch ?? oldData.Timeline.PrevBatch; if (newData.State?.Events is not null) - oldData.State.Events.MergeStateEventLists(newData.State?.Events ?? new()); + oldData.State.Events.MergeStateEventLists(newData.State?.Events ?? new List<StateEventResponse>()); return oldData; } private SyncResponse.RoomsDataStructure.InvitedRoomDataStructure MergeInvitedRoomDataStructure(SyncResponse.RoomsDataStructure.InvitedRoomDataStructure oldData, SyncResponse.RoomsDataStructure.InvitedRoomDataStructure newData) { - oldData.InviteState ??= new(); - oldData.InviteState.Events ??= new(); + oldData.InviteState ??= new EventList(); + oldData.InviteState.Events ??= new List<StateEventResponse>(); if (newData.InviteState?.Events is not null) - oldData.InviteState.Events.MergeStateEventLists(newData.InviteState?.Events ?? new()); + oldData.InviteState.Events.MergeStateEventLists(newData.InviteState?.Events ?? new List<StateEventResponse>()); return oldData; } private SyncResponse.RoomsDataStructure.JoinedRoomDataStructure MergeJoinedRoomDataStructure(SyncResponse.RoomsDataStructure.JoinedRoomDataStructure oldData, SyncResponse.RoomsDataStructure.JoinedRoomDataStructure newData) { - oldData.AccountData ??= new(); - oldData.AccountData.Events ??= new(); - oldData.Timeline ??= new(); - oldData.Timeline.Events ??= new(); - oldData.State ??= new(); - oldData.State.Events ??= new(); - oldData.Ephemeral ??= new(); - oldData.Ephemeral.Events ??= new(); + oldData.AccountData ??= new EventList(); + oldData.AccountData.Events ??= new List<StateEventResponse>(); + oldData.Timeline ??= new SyncResponse.RoomsDataStructure.JoinedRoomDataStructure.TimelineDataStructure(); + oldData.Timeline.Events ??= new List<StateEventResponse>(); + oldData.State ??= new EventList(); + oldData.State.Events ??= new List<StateEventResponse>(); + oldData.Ephemeral ??= new EventList(); + oldData.Ephemeral.Events ??= new List<StateEventResponse>(); if (newData.AccountData?.Events is not null) - oldData.AccountData.Events.MergeStateEventLists(newData.AccountData?.Events ?? new()); + oldData.AccountData.Events.MergeStateEventLists(newData.AccountData?.Events ?? new List<StateEventResponse>()); if (newData.Timeline?.Events is not null) - oldData.Timeline.Events.MergeStateEventLists(newData.Timeline?.Events ?? new()); + oldData.Timeline.Events.MergeStateEventLists(newData.Timeline?.Events ?? new List<StateEventResponse>()); oldData.Timeline.Limited = newData.Timeline?.Limited ?? oldData.Timeline.Limited; oldData.Timeline.PrevBatch = newData.Timeline?.PrevBatch ?? oldData.Timeline.PrevBatch; if (newData.State?.Events is not null) - oldData.State.Events.MergeStateEventLists(newData.State?.Events ?? new()); + oldData.State.Events.MergeStateEventLists(newData.State?.Events ?? new List<StateEventResponse>()); if (newData.Ephemeral?.Events is not null) - oldData.Ephemeral.Events.MergeStateEventLists(newData.Ephemeral?.Events ?? new()); + oldData.Ephemeral.Events.MergeStateEventLists(newData.Ephemeral?.Events ?? new List<StateEventResponse>()); - oldData.UnreadNotifications ??= new(); + oldData.UnreadNotifications ??= new SyncResponse.RoomsDataStructure.JoinedRoomDataStructure.UnreadNotificationsDataStructure(); oldData.UnreadNotifications.HighlightCount = newData.UnreadNotifications?.HighlightCount ?? oldData.UnreadNotifications.HighlightCount; oldData.UnreadNotifications.NotificationCount = newData.UnreadNotifications?.NotificationCount ?? oldData.UnreadNotifications.NotificationCount; - oldData.Summary ??= new() { + oldData.Summary ??= new SyncResponse.RoomsDataStructure.JoinedRoomDataStructure.SummaryDataStructure { Heroes = newData.Summary?.Heroes ?? oldData.Summary.Heroes, JoinedMemberCount = newData.Summary?.JoinedMemberCount ?? oldData.Summary.JoinedMemberCount, InvitedMemberCount = newData.Summary?.InvitedMemberCount ?? oldData.Summary.InvitedMemberCount @@ -174,5 +168,5 @@ public class SyncStateResolver(AuthenticatedHomeserverGeneric homeserver, ILogge return oldData; } - #endregion -} +#endregion +} \ No newline at end of file diff --git a/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs b/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs index 134ec11..6f21e9f 100644 --- a/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs +++ b/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs @@ -7,6 +7,7 @@ using System.Text.Json.Serialization; using System.Web; using ArcaneLibs.Extensions; using LibMatrix.EventTypes.Spec.State; +using LibMatrix.Extensions; using LibMatrix.Filters; using LibMatrix.Helpers; using LibMatrix.Responses; @@ -27,7 +28,7 @@ public class AuthenticatedHomeserverGeneric(string serverName, string accessToke var instance = Activator.CreateInstance(type, serverName, accessToken) as AuthenticatedHomeserverGeneric ?? throw new InvalidOperationException($"Failed to create instance of {type.Name}"); - instance.ClientHttpClient = new() { + instance.ClientHttpClient = new MatrixHttpClient { Timeout = TimeSpan.FromMinutes(15), DefaultRequestHeaders = { Authorization = new AuthenticationHeaderValue("Bearer", accessToken) @@ -36,7 +37,7 @@ public class AuthenticatedHomeserverGeneric(string serverName, string accessToke instance.FederationClient = await FederationClient.TryCreate(serverName, proxy); if (string.IsNullOrWhiteSpace(proxy)) { - HomeserverResolverService.WellKnownUris? urls = await new HomeserverResolverService().ResolveHomeserverFromWellKnown(serverName); + var urls = await new HomeserverResolverService().ResolveHomeserverFromWellKnown(serverName); instance.ClientHttpClient.BaseAddress = new Uri(urls?.Client ?? throw new InvalidOperationException("Failed to resolve homeserver")); } else { @@ -91,13 +92,9 @@ public class AuthenticatedHomeserverGeneric(string serverName, string accessToke var aliasRes = await ResolveRoomAliasAsync($"#{creationEvent.RoomAliasName}:{ServerName}"); if (aliasRes?.RoomId != null) { var existingRoom = GetRoom(aliasRes.RoomId); - if (joinIfAliasExists) { - await existingRoom.JoinAsync(); - } + if (joinIfAliasExists) await existingRoom.JoinAsync(); - if (inviteIfAliasExists) { - await existingRoom.InviteUsersAsync(creationEvent.Invite ?? new()); - } + if (inviteIfAliasExists) await existingRoom.InviteUsersAsync(creationEvent.Invite ?? new List<string>()); return existingRoom; } @@ -115,7 +112,7 @@ public class AuthenticatedHomeserverGeneric(string serverName, string accessToke var room = GetRoom((await res.Content.ReadFromJsonAsync<JsonObject>())!["room_id"]!.ToString()); if (creationEvent.Invite is not null) - await room.InviteUsersAsync(creationEvent.Invite ?? new()); + await room.InviteUsersAsync(creationEvent.Invite ?? new List<string>()); return room; } @@ -134,23 +131,21 @@ public class AuthenticatedHomeserverGeneric(string serverName, string accessToke var rooms = await GetJoinedRooms(); var tasks = rooms.Select(async room => { var roomType = await room.GetRoomType(); - if (roomType == type) { - return room; - } + if (roomType == type) return room; return null; }).ToAsyncEnumerable(); - await foreach (var result in tasks) { - if (result is not null) yield return result; - } + await foreach (var result in tasks) + if (result is not null) + yield return result; } #endregion #region Account Data - public virtual async Task<T> GetAccountDataAsync<T>(string key) { + public virtual async Task<T> GetAccountDataAsync<T>(string key) => // var res = await _httpClient.GetAsync($"/_matrix/client/v3/user/{UserId}/account_data/{key}"); // if (!res.IsSuccessStatusCode) { // Console.WriteLine($"Failed to get account data: {await res.Content.ReadAsStringAsync()}"); @@ -158,8 +153,7 @@ public class AuthenticatedHomeserverGeneric(string serverName, string accessToke // } // // return await res.Content.ReadFromJsonAsync<T>(); - return await ClientHttpClient.GetFromJsonAsync<T>($"/_matrix/client/v3/user/{WhoAmI.UserId}/account_data/{key}"); - } + await ClientHttpClient.GetFromJsonAsync<T>($"/_matrix/client/v3/user/{WhoAmI.UserId}/account_data/{key}"); public virtual async Task<T?> GetAccountDataOrNullAsync<T>(string key) { try { @@ -195,56 +189,46 @@ public class AuthenticatedHomeserverGeneric(string serverName, string accessToke }, Timeout = 250 }; - int targetSyncCount = 0; + var targetSyncCount = 0; if (preserveCustomRoomProfile) { var rooms = await GetJoinedRooms(); var roomProfiles = rooms.Select(GetOwnRoomProfileWithIdAsync).ToAsyncEnumerable(); targetSyncCount = rooms.Count; - await foreach (var (roomId, currentRoomProfile) in roomProfiles) { + await foreach (var (roomId, currentRoomProfile) in roomProfiles) try { // var currentRoomProfile = await room.GetStateAsync<RoomMemberEventContent>("m.room.member", WhoAmI.UserId!); //build new profiles + if (currentRoomProfile.DisplayName == oldProfile.DisplayName) currentRoomProfile.DisplayName = newProfile.DisplayName; - if (currentRoomProfile.DisplayName == oldProfile.DisplayName) { - currentRoomProfile.DisplayName = newProfile.DisplayName; - } - - if (currentRoomProfile.AvatarUrl == oldProfile.AvatarUrl) { - currentRoomProfile.AvatarUrl = newProfile.AvatarUrl; - } + if (currentRoomProfile.AvatarUrl == oldProfile.AvatarUrl) currentRoomProfile.AvatarUrl = newProfile.AvatarUrl; currentRoomProfile.Reason = null; expectedRoomProfiles.Add(roomId, currentRoomProfile); } catch (Exception e) { } - } Console.WriteLine($"Rooms with custom profiles: {string.Join(',', expectedRoomProfiles.Keys)}"); } - if (oldProfile.DisplayName != newProfile.DisplayName) { + if (oldProfile.DisplayName != newProfile.DisplayName) await ClientHttpClient.PutAsJsonAsync($"/_matrix/client/v3/profile/{WhoAmI.UserId}/displayname", new { displayname = newProfile.DisplayName }); - } - else { + else Console.WriteLine($"Not updating display name because {oldProfile.DisplayName} == {newProfile.DisplayName}"); - } - if (oldProfile.AvatarUrl != newProfile.AvatarUrl) { + if (oldProfile.AvatarUrl != newProfile.AvatarUrl) await ClientHttpClient.PutAsJsonAsync($"/_matrix/client/v3/profile/{WhoAmI.UserId}/avatar_url", new { avatar_url = newProfile.AvatarUrl }); - } - else { + else Console.WriteLine($"Not updating avatar URL because {newProfile.AvatarUrl} == {newProfile.AvatarUrl}"); - } if (!preserveCustomRoomProfile) return; - int syncCount = 0; + var syncCount = 0; await foreach (var sync in syncHelper.EnumerateSyncAsync()) { if (sync.Rooms is null) break; List<Task> tasks = new(); - foreach (var (roomId, roomData) in sync.Rooms.Join) { + foreach (var (roomId, roomData) in sync.Rooms.Join) if (roomData.State is { Events.Count: > 0 }) { var incommingRoomProfile = roomData.State?.Events?.FirstOrDefault(x => x.Type == "m.room.member" && x.StateKey == WhoAmI.UserId)?.TypedContent as RoomMemberEventContent; @@ -255,7 +239,6 @@ public class AuthenticatedHomeserverGeneric(string serverName, string accessToke if (incommingRoomProfile.DisplayName != targetRoomProfileOverride.DisplayName || incommingRoomProfile.AvatarUrl != targetRoomProfileOverride.AvatarUrl) tasks.Add(room.SendStateEventAsync("m.room.member", WhoAmI.UserId, targetRoomProfileOverride)); } - } await Task.WhenAll(tasks); await Task.Delay(1000); @@ -263,7 +246,7 @@ public class AuthenticatedHomeserverGeneric(string serverName, string accessToke var differenceFound = false; if (syncCount++ >= targetSyncCount) { var profiles = GetRoomProfilesAsync(); - await foreach ((string roomId, var profile) in profiles) { + await foreach ((var roomId, var profile) in profiles) { if (!expectedRoomProfiles.ContainsKey(roomId)) { Console.WriteLine($"Skipping profile check for {roomId} because its not in override list?"); continue; @@ -284,15 +267,13 @@ public class AuthenticatedHomeserverGeneric(string serverName, string accessToke public async IAsyncEnumerable<KeyValuePair<string, RoomMemberEventContent>> GetRoomProfilesAsync() { var rooms = await GetJoinedRooms(); var results = rooms.Select(GetOwnRoomProfileWithIdAsync).ToAsyncEnumerable(); - await foreach (var res in results) { - yield return res; - } + await foreach (var res in results) yield return res; } public async Task<RoomIdResponse> JoinRoomAsync(string roomId, List<string> homeservers = null, string? reason = null) { 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] }; + if (homeservers == null || homeservers.Count == 0) homeservers = new List<string> { roomId.Split(':')[1] }; var fullJoinUrl = $"{joinUrl}?server_name=" + string.Join("&server_name=", homeservers); var res = await ClientHttpClient.PostAsJsonAsync(fullJoinUrl, new { reason @@ -302,9 +283,8 @@ public class AuthenticatedHomeserverGeneric(string serverName, string accessToke #region Room Profile Utility - private async Task<KeyValuePair<string, RoomMemberEventContent>> GetOwnRoomProfileWithIdAsync(GenericRoom room) { - return new KeyValuePair<string, RoomMemberEventContent>(room.RoomId, await room.GetStateAsync<RoomMemberEventContent>("m.room.member", WhoAmI.UserId!)); - } + private async Task<KeyValuePair<string, RoomMemberEventContent>> GetOwnRoomProfileWithIdAsync(GenericRoom room) => + new(room.RoomId, await room.GetStateAsync<RoomMemberEventContent>("m.room.member", WhoAmI.UserId!)); #endregion @@ -350,7 +330,7 @@ public class AuthenticatedHomeserverGeneric(string serverName, string accessToke var resp = await ClientHttpClient.PostAsJsonAsync("/_matrix/client/v3/user/" + UserId + "/filter", filter); var idResp = await resp.Content.ReadFromJsonAsync<FilterIdResponse>() ?? throw new Exception("Failed to upload filter?"); - var filterList = await GetNamedFilterListOrNullAsync() ?? new(); + var filterList = await GetNamedFilterListOrNullAsync() ?? new Dictionary<string, string>(); filterList[filterName] = idResp.FilterId; await SetAccountDataAsync("gay.rory.libmatrix.named_filters", filterList); @@ -360,7 +340,7 @@ public class AuthenticatedHomeserverGeneric(string serverName, string accessToke } public async Task<string?> GetNamedFilterIdOrNullAsync(string filterName) { - var filterList = await GetNamedFilterListOrNullAsync() ?? new(); + var filterList = await GetNamedFilterListOrNullAsync() ?? new Dictionary<string, string>(); return filterList.GetValueOrDefault(filterName); //todo: validate that filter exists } @@ -395,9 +375,7 @@ public class AuthenticatedHomeserverGeneric(string serverName, string accessToke if (includeGlobal) perRoomAccountData[""] = resp.AccountData; - foreach (var (roomId, room) in resp.Rooms?.Join ?? []) { - perRoomAccountData[roomId] = room.AccountData; - } + foreach (var (roomId, room) in resp.Rooms?.Join ?? []) perRoomAccountData[roomId] = room.AccountData; return perRoomAccountData; } diff --git a/LibMatrix/Homeservers/AuthenticatedHomeserverMxApiExtended.cs b/LibMatrix/Homeservers/AuthenticatedHomeserverMxApiExtended.cs index 494c442..f0b5675 100644 --- a/LibMatrix/Homeservers/AuthenticatedHomeserverMxApiExtended.cs +++ b/LibMatrix/Homeservers/AuthenticatedHomeserverMxApiExtended.cs @@ -1,3 +1,3 @@ namespace LibMatrix.Homeservers; -public class AuthenticatedHomeserverMxApiExtended(string baseUrl, string accessToken) : AuthenticatedHomeserverGeneric(baseUrl, accessToken); +public class AuthenticatedHomeserverMxApiExtended(string baseUrl, string accessToken) : AuthenticatedHomeserverGeneric(baseUrl, accessToken); \ No newline at end of file diff --git a/LibMatrix/Homeservers/AuthenticatedHomeserverSynapse.cs b/LibMatrix/Homeservers/AuthenticatedHomeserverSynapse.cs index 6562686..8df0c5b 100644 --- a/LibMatrix/Homeservers/AuthenticatedHomeserverSynapse.cs +++ b/LibMatrix/Homeservers/AuthenticatedHomeserverSynapse.cs @@ -6,8 +6,10 @@ namespace LibMatrix.Homeservers; public class AuthenticatedHomeserverSynapse : AuthenticatedHomeserverGeneric { public readonly SynapseAdminApi Admin; + public class SynapseAdminApi(AuthenticatedHomeserverSynapse authenticatedHomeserver) { - public async IAsyncEnumerable<AdminRoomListingResult.AdminRoomListingResultRoom> SearchRoomsAsync(int limit = int.MaxValue, string orderBy = "name", string dir = "f", string? searchTerm = null, LocalRoomQueryFilter? localFilter = null) { + public async IAsyncEnumerable<AdminRoomListingResult.AdminRoomListingResultRoom> SearchRoomsAsync(int limit = int.MaxValue, string orderBy = "name", string dir = "f", + string? searchTerm = null, LocalRoomQueryFilter? localFilter = null) { AdminRoomListingResult? res = null; var i = 0; int? totalRooms = null; @@ -28,34 +30,42 @@ public class AuthenticatedHomeserverSynapse : AuthenticatedHomeserverGeneric { totalRooms--; continue; } + if (!room.Name?.Contains(localFilter.NameContains) == true) { totalRooms--; continue; } + if (!room.CanonicalAlias?.Contains(localFilter.CanonicalAliasContains) == true) { totalRooms--; continue; } + if (!room.Version.Contains(localFilter.VersionContains)) { totalRooms--; continue; } + if (!room.Creator.Contains(localFilter.CreatorContains)) { totalRooms--; continue; } + if (!room.Encryption?.Contains(localFilter.EncryptionContains) == true) { totalRooms--; continue; } + if (!room.JoinRules?.Contains(localFilter.JoinRulesContains) == true) { totalRooms--; continue; } + if (!room.GuestAccess?.Contains(localFilter.GuestAccessContains) == true) { totalRooms--; continue; } + if (!room.HistoryVisibility?.Contains(localFilter.HistoryVisibilityContains) == true) { totalRooms--; continue; @@ -65,6 +75,7 @@ public class AuthenticatedHomeserverSynapse : AuthenticatedHomeserverGeneric { totalRooms--; continue; } + if (localFilter.CheckPublic && room.Public != localFilter.Public) { totalRooms--; continue; @@ -74,6 +85,7 @@ public class AuthenticatedHomeserverSynapse : AuthenticatedHomeserverGeneric { totalRooms--; continue; } + if (room.JoinedLocalMembers < localFilter.JoinedLocalMembersGreaterThan || room.JoinedLocalMembers > localFilter.JoinedLocalMembersLessThan) { totalRooms--; continue; @@ -97,7 +109,5 @@ public class AuthenticatedHomeserverSynapse : AuthenticatedHomeserverGeneric { } } - public AuthenticatedHomeserverSynapse(string serverName, string accessToken) : base(serverName, accessToken) { - Admin = new(this); - } -} + public AuthenticatedHomeserverSynapse(string serverName, string accessToken) : base(serverName, accessToken) => Admin = new SynapseAdminApi(this); +} \ No newline at end of file diff --git a/LibMatrix/Homeservers/FederationClient.cs b/LibMatrix/Homeservers/FederationClient.cs index 6001862..288b6b5 100644 --- a/LibMatrix/Homeservers/FederationClient.cs +++ b/LibMatrix/Homeservers/FederationClient.cs @@ -23,33 +23,28 @@ public class FederationClient(string baseUrl) { public static async Task<FederationClient> Create(string baseUrl, string? proxy = null) { var homeserver = new FederationClient(baseUrl); homeserver.WellKnownUris = await new HomeserverResolverService().ResolveHomeserverFromWellKnown(baseUrl); - if(string.IsNullOrWhiteSpace(proxy) && string.IsNullOrWhiteSpace(homeserver.WellKnownUris.Client)) + if (string.IsNullOrWhiteSpace(proxy) && string.IsNullOrWhiteSpace(homeserver.WellKnownUris.Client)) Console.WriteLine($"Failed to resolve homeserver client URI for {baseUrl}"); - if(string.IsNullOrWhiteSpace(proxy) && string.IsNullOrWhiteSpace(homeserver.WellKnownUris.Server)) + if (string.IsNullOrWhiteSpace(proxy) && string.IsNullOrWhiteSpace(homeserver.WellKnownUris.Server)) Console.WriteLine($"Failed to resolve homeserver server URI for {baseUrl}"); if (!string.IsNullOrWhiteSpace(homeserver.WellKnownUris.Server)) - homeserver.HttpClient = new() { + homeserver.HttpClient = new MatrixHttpClient { BaseAddress = new Uri(proxy ?? homeserver.WellKnownUris.Server ?? throw new InvalidOperationException($"Failed to resolve homeserver server URI for {baseUrl}")), Timeout = TimeSpan.FromSeconds(120) }; - if (proxy is not null) { - homeserver.HttpClient.DefaultRequestHeaders.Add("MXAE_UPSTREAM", baseUrl); - } + if (proxy is not null) homeserver.HttpClient.DefaultRequestHeaders.Add("MXAE_UPSTREAM", baseUrl); return homeserver; } - + public string BaseUrl { get; } = baseUrl; public MatrixHttpClient HttpClient { get; set; } = null!; public HomeserverResolverService.WellKnownUris WellKnownUris { get; set; } = null!; - public async Task<ServerVersionResponse> GetServerVersionAsync() { - return await HttpClient.GetFromJsonAsync<ServerVersionResponse>("/_matrix/federation/v1/version"); - } - + public async Task<ServerVersionResponse> GetServerVersionAsync() => await HttpClient.GetFromJsonAsync<ServerVersionResponse>("/_matrix/federation/v1/version"); } public class ServerVersionResponse { diff --git a/LibMatrix/Homeservers/RemoteHomeServer.cs b/LibMatrix/Homeservers/RemoteHomeServer.cs index f47dc4d..5c7d254 100644 --- a/LibMatrix/Homeservers/RemoteHomeServer.cs +++ b/LibMatrix/Homeservers/RemoteHomeServer.cs @@ -26,23 +26,21 @@ public class RemoteHomeserver(string baseUrl) { proxy = null; var homeserver = new RemoteHomeserver(baseUrl); homeserver.WellKnownUris = await new HomeserverResolverService().ResolveHomeserverFromWellKnown(baseUrl); - if(string.IsNullOrWhiteSpace(homeserver.WellKnownUris.Client)) + if (string.IsNullOrWhiteSpace(homeserver.WellKnownUris.Client)) Console.WriteLine($"Failed to resolve homeserver client URI for {baseUrl}"); - if(string.IsNullOrWhiteSpace(homeserver.WellKnownUris.Server)) + if (string.IsNullOrWhiteSpace(homeserver.WellKnownUris.Server)) Console.WriteLine($"Failed to resolve homeserver server URI for {baseUrl}"); - - Console.WriteLine(homeserver.WellKnownUris.ToJson(ignoreNull:false)); - - homeserver.ClientHttpClient = new() { + + Console.WriteLine(homeserver.WellKnownUris.ToJson(ignoreNull: false)); + + homeserver.ClientHttpClient = new MatrixHttpClient { BaseAddress = new Uri(proxy ?? homeserver.WellKnownUris.Client ?? throw new InvalidOperationException($"Failed to resolve homeserver client URI for {baseUrl}")), Timeout = TimeSpan.FromSeconds(120) }; - + homeserver.FederationClient = await FederationClient.TryCreate(baseUrl, proxy); - if (proxy is not null) { - homeserver.ClientHttpClient.DefaultRequestHeaders.Add("MXAE_UPSTREAM", baseUrl); - } + if (proxy is not null) homeserver.ClientHttpClient.DefaultRequestHeaders.Add("MXAE_UPSTREAM", baseUrl); return homeserver; } diff --git a/LibMatrix/Interfaces/Services/IStorageProvider.cs b/LibMatrix/Interfaces/Services/IStorageProvider.cs index 519d8ed..165e7df 100644 --- a/LibMatrix/Interfaces/Services/IStorageProvider.cs +++ b/LibMatrix/Interfaces/Services/IStorageProvider.cs @@ -13,7 +13,6 @@ public interface IStorageProvider { throw new NotImplementedException(); } - public Task SaveObjectAsync<T>(string key, T value) { Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement SaveObject<T>(key, value)!"); throw new NotImplementedException(); @@ -37,7 +36,6 @@ public interface IStorageProvider { throw new NotImplementedException(); } - // delete public Task DeleteObjectAsync(string key) { Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement DeleteObject(key)!"); @@ -55,4 +53,4 @@ public interface IStorageProvider { Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement LoadStream(key)!"); throw new NotImplementedException(); } -} +} \ No newline at end of file diff --git a/LibMatrix/LibMatrix.csproj b/LibMatrix/LibMatrix.csproj index e6b091f..b85df52 100644 --- a/LibMatrix/LibMatrix.csproj +++ b/LibMatrix/LibMatrix.csproj @@ -11,8 +11,8 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" /> - <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" /> + <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0"/> + <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0"/> </ItemGroup> <ItemGroup> @@ -23,11 +23,11 @@ If you want to use a time-appropriate version of the library, recursively clone https://cgit.rory.gay/matrix/MatrixUtils.git instead, since this will be locked by the MatrixUtils project, which contains both LibMatrix and ArcaneLibs as a submodule. --> <PackageReference Condition="!Exists('..\ArcaneLibs\ArcaneLibs\ArcaneLibs.csproj')" Include="ArcaneLibs" Version="*-preview*"/> - <ProjectReference Include="..\LibMatrix.EventTypes\LibMatrix.EventTypes.csproj" /> + <ProjectReference Include="..\LibMatrix.EventTypes\LibMatrix.EventTypes.csproj"/> </ItemGroup> - + <Target Name="ArcaneLibsNugetWarning" AfterTargets="AfterBuild"> <Warning Text="ArcaneLibs is being referenced from NuGet, which is dangerous. Please read the warning in LibMatrix.csproj!" Condition="!Exists('..\ArcaneLibs\ArcaneLibs\ArcaneLibs.csproj')"/> </Target> - + </Project> diff --git a/LibMatrix/MatrixException.cs b/LibMatrix/MatrixException.cs index 6a0f352..86dbce4 100644 --- a/LibMatrix/MatrixException.cs +++ b/LibMatrix/MatrixException.cs @@ -23,7 +23,6 @@ public class MatrixException : Exception { public object GetAsObject() => new { ErrorCode, Error, SoftLogout, RetryAfterMs }; public string GetAsJson() => GetAsObject().ToJson(ignoreNull: true); - public override string Message => $"{ErrorCode}: {ErrorCode switch { // common @@ -62,4 +61,4 @@ public class MatrixException : Exception { "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM" => $"Cannot leave server notice room: {Error}", _ => $"Unknown error: {new { ErrorCode, Error, SoftLogout, RetryAfterMs }.ToJson(ignoreNull: true)}" }}"; -} +} \ No newline at end of file diff --git a/LibMatrix/MessagesResponse.cs b/LibMatrix/MessagesResponse.cs index f1a220c..526da74 100644 --- a/LibMatrix/MessagesResponse.cs +++ b/LibMatrix/MessagesResponse.cs @@ -14,4 +14,4 @@ public class MessagesResponse { [JsonPropertyName("state")] public List<StateEventResponse> State { get; set; } = new(); -} +} \ No newline at end of file diff --git a/LibMatrix/Responses/Admin/AdminRoomDeleteRequest.cs b/LibMatrix/Responses/Admin/AdminRoomDeleteRequest.cs index f22c8d2..ceb1b3f 100644 --- a/LibMatrix/Responses/Admin/AdminRoomDeleteRequest.cs +++ b/LibMatrix/Responses/Admin/AdminRoomDeleteRequest.cs @@ -5,14 +5,19 @@ namespace LibMatrix.Responses.Admin; public class AdminRoomDeleteRequest { [JsonPropertyName("new_room_user_id")] public string? NewRoomUserId { get; set; } + [JsonPropertyName("room_name")] public string? RoomName { get; set; } + [JsonPropertyName("block")] public bool Block { get; set; } + [JsonPropertyName("purge")] public bool Purge { get; set; } + [JsonPropertyName("message")] public string? Message { get; set; } + [JsonPropertyName("force_purge")] public bool ForcePurge { get; set; } -} +} \ No newline at end of file diff --git a/LibMatrix/Responses/Admin/AdminRoomListingResult.cs b/LibMatrix/Responses/Admin/AdminRoomListingResult.cs index a90bc6f..7ab96ac 100644 --- a/LibMatrix/Responses/Admin/AdminRoomListingResult.cs +++ b/LibMatrix/Responses/Admin/AdminRoomListingResult.cs @@ -61,4 +61,4 @@ public class AdminRoomListingResult { [JsonPropertyName("state_events")] public int StateEvents { get; set; } } -} +} \ No newline at end of file diff --git a/LibMatrix/Responses/ClientVersionsResponse.cs b/LibMatrix/Responses/ClientVersionsResponse.cs index 8e0a92a..8965857 100644 --- a/LibMatrix/Responses/ClientVersionsResponse.cs +++ b/LibMatrix/Responses/ClientVersionsResponse.cs @@ -8,4 +8,4 @@ public class ClientVersionsResponse { [JsonPropertyName("unstable_features")] public Dictionary<string, bool> UnstableFeatures { get; set; } = new(); -} +} \ No newline at end of file diff --git a/LibMatrix/Responses/CreateRoomRequest.cs b/LibMatrix/Responses/CreateRoomRequest.cs index 9a797b5..d78f574 100644 --- a/LibMatrix/Responses/CreateRoomRequest.cs +++ b/LibMatrix/Responses/CreateRoomRequest.cs @@ -52,7 +52,7 @@ public class CreateRoomRequest { public StateEvent this[string eventType, string eventKey = ""] { get { var stateEvent = InitialState.FirstOrDefault(x => x.Type == eventType && x.StateKey == eventKey); - if (stateEvent == null) { + if (stateEvent == null) InitialState.Add(stateEvent = new StateEvent { Type = eventType, StateKey = eventKey, @@ -62,7 +62,6 @@ public class CreateRoomRequest { .Any(y => y.EventName == eventType) ?? false) ?? typeof(UnknownEventContent) )! }); - } return stateEvent; } @@ -88,8 +87,8 @@ public class CreateRoomRequest { var request = new CreateRoomRequest { Name = name ?? "New public Room", Visibility = "public", - CreationContent = new(), - PowerLevelContentOverride = new() { + CreationContent = new JsonObject(), + PowerLevelContentOverride = new RoomPowerLevelEventContent { EventsDefault = 0, UsersDefault = 0, Kick = 50, @@ -97,10 +96,10 @@ public class CreateRoomRequest { Invite = 25, StateDefault = 10, Redact = 50, - NotificationsPl = new() { + NotificationsPl = new RoomPowerLevelEventContent.NotificationsPL { Room = 10 }, - Events = new() { + Events = new Dictionary<string, long> { { "m.room.avatar", 50 }, { "m.room.canonical_alias", 50 }, { "m.room.encryption", 100 }, @@ -110,7 +109,7 @@ public class CreateRoomRequest { { "m.room.server_acl", 100 }, { "m.room.tombstone", 100 } }, - Users = new() { + Users = new Dictionary<string, long> { { hs.UserId, 101 @@ -118,17 +117,18 @@ public class CreateRoomRequest { } }, RoomAliasName = roomAliasName, - InitialState = new() + InitialState = new List<StateEvent>() }; return request; } + public static CreateRoomRequest CreatePrivate(AuthenticatedHomeserverGeneric hs, string? name = null, string? roomAliasName = null) { var request = new CreateRoomRequest { Name = name ?? "New private Room", Visibility = "private", - CreationContent = new(), - PowerLevelContentOverride = new() { + CreationContent = new JsonObject(), + PowerLevelContentOverride = new RoomPowerLevelEventContent { EventsDefault = 0, UsersDefault = 0, Kick = 50, @@ -136,10 +136,10 @@ public class CreateRoomRequest { Invite = 25, StateDefault = 10, Redact = 50, - NotificationsPl = new() { + NotificationsPl = new RoomPowerLevelEventContent.NotificationsPL { Room = 10 }, - Events = new() { + Events = new Dictionary<string, long> { { "m.room.avatar", 50 }, { "m.room.canonical_alias", 50 }, { "m.room.encryption", 100 }, @@ -149,7 +149,7 @@ public class CreateRoomRequest { { "m.room.server_acl", 100 }, { "m.room.tombstone", 100 } }, - Users = new() { + Users = new Dictionary<string, long> { { hs.UserId, 101 @@ -157,9 +157,9 @@ public class CreateRoomRequest { } }, RoomAliasName = roomAliasName, - InitialState = new() + InitialState = new List<StateEvent>() }; return request; } -} +} \ No newline at end of file diff --git a/LibMatrix/Responses/CreationContentBaseType.cs b/LibMatrix/Responses/CreationContentBaseType.cs index 073bb60..b4fd849 100644 --- a/LibMatrix/Responses/CreationContentBaseType.cs +++ b/LibMatrix/Responses/CreationContentBaseType.cs @@ -5,7 +5,7 @@ namespace LibMatrix.Responses; public class CreationContentBaseType { private readonly CreateRoomRequest _createRoomRequest; - public CreationContentBaseType(CreateRoomRequest createRoomRequest) => this._createRoomRequest = createRoomRequest; + public CreationContentBaseType(CreateRoomRequest createRoomRequest) => _createRoomRequest = createRoomRequest; [JsonPropertyName("type")] public string Type { @@ -15,4 +15,4 @@ public class CreationContentBaseType { else _createRoomRequest.CreationContent["type"] = value; } } -} +} \ No newline at end of file diff --git a/LibMatrix/Responses/LoginResponse.cs b/LibMatrix/Responses/LoginResponse.cs index c5d4e87..3962fa6 100644 --- a/LibMatrix/Responses/LoginResponse.cs +++ b/LibMatrix/Responses/LoginResponse.cs @@ -21,11 +21,11 @@ public class LoginResponse { [JsonPropertyName("user_id")] public string UserId { get; set; } = null!; - public async Task<AuthenticatedHomeserverGeneric> GetAuthenticatedHomeserver(string? proxy = null) { + public async Task<AuthenticatedHomeserverGeneric> GetAuthenticatedHomeserver(string? proxy = null) => // var urls = await new HomeserverResolverService().ResolveHomeserverFromWellKnown(Homeserver); - return await AuthenticatedHomeserverGeneric.Create<AuthenticatedHomeserverGeneric>(Homeserver, AccessToken, proxy); - } + await AuthenticatedHomeserverGeneric.Create<AuthenticatedHomeserverGeneric>(Homeserver, AccessToken, proxy); } + public class LoginRequest { [JsonPropertyName("type")] public string Type { get; set; } = "m.login.password"; @@ -46,4 +46,4 @@ public class LoginRequest { [JsonPropertyName("user")] public string User { get; set; } = ""; } -} +} \ No newline at end of file diff --git a/LibMatrix/Responses/ModAS/AdminRoomListingResult.cs b/LibMatrix/Responses/ModAS/AdminRoomListingResult.cs index 95e3dcf..2d8d387 100644 --- a/LibMatrix/Responses/ModAS/AdminRoomListingResult.cs +++ b/LibMatrix/Responses/ModAS/AdminRoomListingResult.cs @@ -44,7 +44,7 @@ public class ModASRoomQueryResult { [JsonPropertyName("state_events")] public int StateEvents { get; set; } - + [JsonPropertyName("type")] public string? Type { get; set; } @@ -56,7 +56,7 @@ public class ModASRoomQueryResult { [JsonPropertyName("total_members")] public int TotalMembers { get; set; } - + [JsonPropertyName("total_local_members")] public int TotalLocalMembers { get; set; } } \ No newline at end of file diff --git a/LibMatrix/Responses/UserProfileResponse.cs b/LibMatrix/Responses/UserProfileResponse.cs index 9972a26..6c9380f 100644 --- a/LibMatrix/Responses/UserProfileResponse.cs +++ b/LibMatrix/Responses/UserProfileResponse.cs @@ -8,4 +8,4 @@ public class UserProfileResponse { [JsonPropertyName("displayname")] public string? DisplayName { get; set; } -} +} \ No newline at end of file diff --git a/LibMatrix/RoomTypes/GenericRoom.cs b/LibMatrix/RoomTypes/GenericRoom.cs index ec14ca9..eee6041 100644 --- a/LibMatrix/RoomTypes/GenericRoom.cs +++ b/LibMatrix/RoomTypes/GenericRoom.cs @@ -24,18 +24,14 @@ public class GenericRoom { Homeserver = homeserver; RoomId = roomId; // if (GetType() != typeof(SpaceRoom)) - if (GetType() == typeof(GenericRoom)) { - AsSpace = new SpaceRoom(homeserver, RoomId); - } + if (GetType() == typeof(GenericRoom)) AsSpace = new SpaceRoom(homeserver, RoomId); } public string RoomId { get; set; } public async IAsyncEnumerable<StateEventResponse?> GetFullStateAsync() { var result = Homeserver.ClientHttpClient.GetAsyncEnumerableFromJsonAsync<StateEventResponse>($"/_matrix/client/v3/rooms/{RoomId}/state"); - await foreach (var resp in result) { - yield return resp; - } + await foreach (var resp in result) yield return resp; } public Task<List<StateEventResponse>> GetFullStateAsListAsync() => @@ -76,7 +72,8 @@ public class GenericRoom { url += "?format=event"; try { var resp = await Homeserver.ClientHttpClient.GetFromJsonAsync<JsonObject>(url); - if(resp["type"]?.GetValue<string>() != type) throw new InvalidDataException("Returned event type does not match requested type, or server does not support passing `format`."); + if (resp["type"]?.GetValue<string>() != type) + throw new InvalidDataException("Returned event type does not match requested type, or server does not support passing `format`."); return resp.Deserialize<StateEventResponse>(); } catch (MatrixException e) { @@ -142,7 +139,7 @@ public class GenericRoom { if (limit <= 0) yield break; } } - else { + else while (limit > 0) { var resp = await GetMessagesAsync(from, Math.Min(chunkSize, limit), dir, filter); @@ -158,7 +155,6 @@ public class GenericRoom { from = resp.End; } - } Console.WriteLine("End of GetManyAsync"); } @@ -166,7 +162,7 @@ public class GenericRoom { public async Task<string?> GetNameAsync() => (await GetStateAsync<RoomNameEventContent>("m.room.name"))?.Name; public async Task<RoomIdResponse> JoinAsync(string[]? homeservers = null, string? reason = null, bool checkIfAlreadyMember = true) { - if (checkIfAlreadyMember) { + if (checkIfAlreadyMember) try { _ = await GetCreateEventAsync(); return new RoomIdResponse { @@ -174,7 +170,6 @@ public class GenericRoom { }; } catch { } //ignore - } var joinUrl = $"/_matrix/client/v3/join/{HttpUtility.UrlEncode(RoomId)}"; Console.WriteLine($"Calling {joinUrl} with {homeservers?.Length ?? 0} via's..."); @@ -195,7 +190,7 @@ public class GenericRoom { // var resText = await res.Content.ReadAsStringAsync(); // Console.WriteLine($"Members call response read in {sw.GetElapsedAndRestart()}"); var result = await JsonSerializer.DeserializeAsync<ChunkedStateEventResponse>(await res.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { - TypeInfoResolver = ChunkedStateEventResponseSerializerContext.Default, + TypeInfoResolver = ChunkedStateEventResponseSerializerContext.Default }); if (sw.ElapsedMilliseconds > 100) Console.WriteLine($"Members call deserialised in {sw.GetElapsedAndRestart()}"); @@ -219,7 +214,7 @@ public class GenericRoom { // var resText = await res.Content.ReadAsStringAsync(); // Console.WriteLine($"Members call response read in {sw.GetElapsedAndRestart()}"); var result = await JsonSerializer.DeserializeAsync<ChunkedStateEventResponse>(await res.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { - TypeInfoResolver = ChunkedStateEventResponseSerializerContext.Default, + TypeInfoResolver = ChunkedStateEventResponseSerializerContext.Default }); if (sw.ElapsedMilliseconds > 100) Console.WriteLine($"Members call deserialised in {sw.GetElapsedAndRestart()}"); @@ -280,19 +275,16 @@ public class GenericRoom { return await GetNameAsync(); } catch { - try - { + try { var alias = await GetCanonicalAliasAsync(); if (alias?.Alias is not null) return alias.Alias; throw new Exception("No name or alias"); } - catch - { - try - { + catch { + try { var members = GetMembersEnumerableAsync(); var memberList = new List<string>(); - int memberCount = 0; + var memberCount = 0; await foreach (var member in members) memberList.Add(member.RawContent?["displayname"]?.GetValue<string>() ?? ""); memberCount = memberList.Count; @@ -302,8 +294,7 @@ public class GenericRoom { return string.Join(", ", memberList.Take(maxMemberNames)) + " and " + (memberCount - maxMemberNames) + " others."; return string.Join(", ", memberList); } - catch - { + catch { return RoomId; } } @@ -388,7 +379,7 @@ public class GenericRoom { Url = url, Body = fileName, FileName = fileName, - FileInfo = new() { + FileInfo = new RoomMessageEventContent.FileInfoStruct { Size = fileStream.Length, MimeType = contentType } @@ -414,9 +405,7 @@ public class GenericRoom { } } - public Task<T> GetEventAsync<T>(string eventId) { - return Homeserver.ClientHttpClient.GetFromJsonAsync<T>($"/_matrix/client/v3/rooms/{RoomId}/event/{eventId}"); - } + public Task<T> GetEventAsync<T>(string eventId) => Homeserver.ClientHttpClient.GetFromJsonAsync<T>($"/_matrix/client/v3/rooms/{RoomId}/event/{eventId}"); public async Task<EventIdResponse> RedactEventAsync(string eventToRedact, string reason) { var data = new { reason }; @@ -435,8 +424,8 @@ public class GenericRoom { Dictionary<string, List<string>> roomHomeservers = new(); var members = GetMembersEnumerableAsync(); await foreach (var member in members) { - string memberHs = member.StateKey.Split(':', 2)[1]; - roomHomeservers.TryAdd(memberHs, new()); + var memberHs = member.StateKey.Split(':', 2)[1]; + roomHomeservers.TryAdd(memberHs, new List<string>()); roomHomeservers[memberHs].Add(member.StateKey); } @@ -454,7 +443,7 @@ public class GenericRoom { "m.room.join_rules", "m.room.history_visibility", "m.room.guest_access", - "m.room.member", + "m.room.member" }; await foreach (var state in states) { if (state is null || state.RawContent is not { Count: > 0 }) continue; @@ -467,7 +456,7 @@ public class GenericRoom { } if (stateTypeIgnore.Contains(state.Type)) continue; - await SendStateEventAsync(state.Type, state.StateKey, new()); + await SendStateEventAsync(state.Type, state.StateKey, new object()); } } diff --git a/LibMatrix/RoomTypes/SpaceRoom.cs b/LibMatrix/RoomTypes/SpaceRoom.cs index bf16efb..9bd1173 100644 --- a/LibMatrix/RoomTypes/SpaceRoom.cs +++ b/LibMatrix/RoomTypes/SpaceRoom.cs @@ -31,4 +31,4 @@ public class SpaceRoom(AuthenticatedHomeserverGeneric homeserver, string roomId) }); return resp; } -} +} \ No newline at end of file diff --git a/LibMatrix/Services/HomeserverProviderService.cs b/LibMatrix/Services/HomeserverProviderService.cs index 5ac47f1..7a13816 100644 --- a/LibMatrix/Services/HomeserverProviderService.cs +++ b/LibMatrix/Services/HomeserverProviderService.cs @@ -47,9 +47,9 @@ public class HomeserverProviderService(ILogger<HomeserverProviderService> logger sem.Release(); throw; } - + try { - if (clientVersions.UnstableFeatures.TryGetValue("gay.rory.mxapiextensions.v0", out bool a) && a) + if (clientVersions.UnstableFeatures.TryGetValue("gay.rory.mxapiextensions.v0", out var a) && a) hs = await AuthenticatedHomeserverGeneric.Create<AuthenticatedHomeserverMxApiExtended>(homeserver, accessToken, proxy); else { if (serverVersion is { Server.Name: "Synapse" }) @@ -64,11 +64,13 @@ public class HomeserverProviderService(ILogger<HomeserverProviderService> logger throw; } - if(impersonatedMxid is not null) + if (impersonatedMxid is not null) await hs.SetImpersonate(impersonatedMxid); - - lock (AuthenticatedHomeserverCache) + + lock (AuthenticatedHomeserverCache) { AuthenticatedHomeserverCache[cacheKey] = hs; + } + sem.Release(); return hs; @@ -88,10 +90,12 @@ public class HomeserverProviderService(ILogger<HomeserverProviderService> logger hs = await RemoteHomeserver.Create(homeserver, proxy); - lock (RemoteHomeserverCache) + lock (RemoteHomeserverCache) { RemoteHomeserverCache[cacheKey] = hs; + } + sem.Release(); - + return hs; } diff --git a/LibMatrix/Services/HomeserverResolverService.cs b/LibMatrix/Services/HomeserverResolverService.cs index 9f937c5..a4a18e5 100644 --- a/LibMatrix/Services/HomeserverResolverService.cs +++ b/LibMatrix/Services/HomeserverResolverService.cs @@ -16,7 +16,7 @@ public class HomeserverResolverService(ILogger<HomeserverResolverService>? logge public async Task<WellKnownUris> ResolveHomeserverFromWellKnown(string homeserver) { if (homeserver is null) throw new ArgumentNullException(nameof(homeserver)); - WellKnownSemaphores.TryAdd(homeserver, new(1, 1)); + WellKnownSemaphores.TryAdd(homeserver, new SemaphoreSlim(1, 1)); await WellKnownSemaphores[homeserver].WaitAsync(); if (WellKnownCache.TryGetValue(homeserver, out var known)) { WellKnownSemaphores[homeserver].Release(); @@ -53,7 +53,7 @@ public class HomeserverResolverService(ILogger<HomeserverResolverService>? logge try { var resp = await _httpClient.GetFromJsonAsync<JsonElement>($"{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 is null) throw new InvalidDataException("m.server is null"); if (!hs.StartsWithAnyOf("http://", "https://")) hs = $"https://{hs}"; return hs; @@ -83,4 +83,4 @@ public class HomeserverResolverService(ILogger<HomeserverResolverService>? logge public string? Client { get; set; } public string? Server { get; set; } } -} +} \ No newline at end of file diff --git a/LibMatrix/Services/ServiceInstaller.cs b/LibMatrix/Services/ServiceInstaller.cs index 358dc2a..0f07b61 100644 --- a/LibMatrix/Services/ServiceInstaller.cs +++ b/LibMatrix/Services/ServiceInstaller.cs @@ -3,11 +3,10 @@ using Microsoft.Extensions.DependencyInjection; namespace LibMatrix.Services; public static class ServiceInstaller { - public static IServiceCollection AddRoryLibMatrixServices(this IServiceCollection services, RoryLibMatrixConfiguration? config = null) { //Check required services // if (!services.Any(x => x.ServiceType == typeof(TieredStorageService))) - // throw new Exception("[RMUCore/DI] No TieredStorageService has been registered!"); + // throw new Exception("[RMUCore/DI] No TieredStorageService has been registered!"); //Add config services.AddSingleton(config ?? new RoryLibMatrixConfiguration()); @@ -15,19 +14,17 @@ public static class ServiceInstaller { services.AddSingleton<HomeserverResolverService>(); // if (services.First(x => x.ServiceType == typeof(TieredStorageService)).Lifetime == ServiceLifetime.Singleton) { - services.AddSingleton<HomeserverProviderService>(); + services.AddSingleton<HomeserverProviderService>(); // } // else { - // services.AddScoped<HomeserverProviderService>(); + // services.AddScoped<HomeserverProviderService>(); // } // services.AddScoped<MatrixHttpClient>(); return services; } - - } public class RoryLibMatrixConfiguration { public string AppName { get; set; } = "Rory&::LibMatrix"; -} +} \ No newline at end of file diff --git a/LibMatrix/Services/TieredStorageService.cs b/LibMatrix/Services/TieredStorageService.cs index 280340e..9e411de 100644 --- a/LibMatrix/Services/TieredStorageService.cs +++ b/LibMatrix/Services/TieredStorageService.cs @@ -5,4 +5,4 @@ namespace LibMatrix.Services; public class TieredStorageService(IStorageProvider? cacheStorageProvider, IStorageProvider? dataStorageProvider) { public IStorageProvider? CacheStorageProvider { get; } = cacheStorageProvider; public IStorageProvider? DataStorageProvider { get; } = dataStorageProvider; -} +} \ No newline at end of file diff --git a/LibMatrix/StateEvent.cs b/LibMatrix/StateEvent.cs index d78939e..019c428 100644 --- a/LibMatrix/StateEvent.cs +++ b/LibMatrix/StateEvent.cs @@ -15,14 +15,12 @@ namespace LibMatrix; public class StateEvent { public static FrozenSet<Type> KnownStateEventTypes { get; } = new ClassCollector<EventContent>().ResolveFromAllAccessibleAssemblies().ToFrozenSet(); - + public static FrozenDictionary<string, Type> KnownStateEventTypesByName { get; } = KnownStateEventTypes.Aggregate( new Dictionary<string, Type>(), (dict, type) => { var attrs = type.GetCustomAttributes<MatrixEventAttribute>(); - foreach (var attr in attrs) { - dict[attr.EventName] = type; - } + foreach (var attr in attrs) dict[attr.EventName] = type; return dict; }).ToFrozenDictionary(); @@ -48,7 +46,7 @@ public class StateEvent { new JsonDecimalStringConverter() } }; - + [JsonIgnore] [SuppressMessage("ReSharper", "PropertyCanBeMadeInitOnly.Global")] public EventContent? TypedContent { @@ -57,7 +55,7 @@ public class StateEvent { // return null; // } try { - var c= (EventContent)RawContent.Deserialize(GetStateEventType(Type), TypedContentSerializerOptions)!; + var c = (EventContent)RawContent.Deserialize(GetStateEventType(Type), TypedContentSerializerOptions)!; return c; } catch (JsonException e) { @@ -68,9 +66,8 @@ public class StateEvent { return null; } set { - if (value is null) { + if (value is null) RawContent?.Clear(); - } else RawContent = JsonSerializer.Deserialize<JsonObject>(JsonSerializer.Serialize(value, value.GetType())); } } diff --git a/LibMatrix/UserIdAndReason.cs b/LibMatrix/UserIdAndReason.cs index c76ecc7..99c9eaf 100644 --- a/LibMatrix/UserIdAndReason.cs +++ b/LibMatrix/UserIdAndReason.cs @@ -8,4 +8,4 @@ internal class UserIdAndReason(string userId = null!, string reason = null!) { [JsonPropertyName("reason")] public string? Reason { get; set; } = reason; -} +} \ No newline at end of file diff --git a/LibMatrix/Utilities/CommonSyncFilters.cs b/LibMatrix/Utilities/CommonSyncFilters.cs index 7cf1b41..8e727be 100644 --- a/LibMatrix/Utilities/CommonSyncFilters.cs +++ b/LibMatrix/Utilities/CommonSyncFilters.cs @@ -38,14 +38,14 @@ public static class CommonSyncFilters { "m.room.name", "m.room.avatar", "org.matrix.mjolnir.shortcode", - "m.room.power_levels", + "m.room.power_levels" }, LazyLoadMembers = true, IncludeRedundantMembers = false }, - Timeline = new SyncFilter.RoomFilter.StateFilter(rooms: []), + Timeline = new SyncFilter.RoomFilter.StateFilter(rooms: []) } }; - + public static readonly SyncFilter GetSpaceRelationsFilter = new() { AccountData = new SyncFilter.EventFilter(notTypes: ["*"], limit: 1), Presence = new SyncFilter.EventFilter(notTypes: ["*"], limit: 1), @@ -59,7 +59,7 @@ public static class CommonSyncFilters { }, LazyLoadMembers = true, IncludeRedundantMembers = false }, - Timeline = new SyncFilter.RoomFilter.StateFilter(rooms: []), + Timeline = new SyncFilter.RoomFilter.StateFilter(rooms: []) } }; diff --git a/LibMatrix/WhoAmIResponse.cs b/LibMatrix/WhoAmIResponse.cs index e2ea118..10fff35 100644 --- a/LibMatrix/WhoAmIResponse.cs +++ b/LibMatrix/WhoAmIResponse.cs @@ -8,6 +8,7 @@ public class WhoAmIResponse { [JsonPropertyName("device_id")] public string? DeviceId { get; set; } + [JsonPropertyName("is_guest")] public bool? IsGuest { get; set; } -} +} \ No newline at end of file |