about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--LibMatrix/Extensions/MatrixHttpClient.Single.cs34
-rw-r--r--LibMatrix/Helpers/SyncStateResolver.cs10
-rw-r--r--LibMatrix/MatrixException.cs78
-rw-r--r--LibMatrix/Services/HomeserverProviderService.cs6
-rw-r--r--LibMatrix/StateEvent.cs2
5 files changed, 78 insertions, 52 deletions
diff --git a/LibMatrix/Extensions/MatrixHttpClient.Single.cs b/LibMatrix/Extensions/MatrixHttpClient.Single.cs

index 4145a16..b15804d 100644 --- a/LibMatrix/Extensions/MatrixHttpClient.Single.cs +++ b/LibMatrix/Extensions/MatrixHttpClient.Single.cs
@@ -1,5 +1,5 @@ #define SINGLE_HTTPCLIENT // Use a single HttpClient instance for all MatrixHttpClient instances -// #define SYNC_HTTPCLIENT // Only allow one request as a time, for debugging +// #define SYNC_HTTPCLIENT // Only allow one request as a time, for debugging using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Net; @@ -15,7 +15,7 @@ using ArcaneLibs.Extensions; namespace LibMatrix.Extensions; #if SINGLE_HTTPCLIENT -// TODO: Add URI wrapper for +// TODO: Add URI wrapper for public class MatrixHttpClient { private static readonly HttpClient Client; @@ -70,6 +70,10 @@ public class MatrixHttpClient { } public async Task<HttpResponseMessage> SendUnhandledAsync(HttpRequestMessage request, CancellationToken cancellationToken) { + if (request.RequestUri is null) throw new NullReferenceException("RequestUri is null"); + // if (!request.RequestUri.IsAbsoluteUri) + request.RequestUri = request.RequestUri.EnsureAbsolute(BaseAddress!); + var swWait = Stopwatch.StartNew(); #if SYNC_HTTPCLIENT await _rateLimitSemaphore.WaitAsync(cancellationToken); #endif @@ -86,13 +90,15 @@ public class MatrixHttpClient { request.Options.Set(new HttpRequestOptionsKey<bool>("WebAssemblyEnableStreamingResponse"), true); + Console.WriteLine("Sending " + request.Summarise(includeHeaders:true, includeQuery: true, includeContentIfText: true)); + HttpResponseMessage? responseMessage; try { responseMessage = await Client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken); } catch (Exception e) { Console.WriteLine( - $"Failed to send request {request.Method} {BaseAddress}{request.RequestUri} ({Util.BytesToString(request.Content?.Headers.ContentLength ?? 0)}):\n{e}"); + $"Failed to send request {request.Method} {request.RequestUri} ({Util.BytesToString(request.GetContentLength())}):\n{e}"); throw; } #if SYNC_HTTPCLIENT @@ -101,8 +107,20 @@ public class MatrixHttpClient { } #endif - Console.WriteLine( - $"Sending {request.Method} {request.RequestUri} ({Util.BytesToString(request.Content?.Headers.ContentLength ?? 0)}) -> {(int)responseMessage.StatusCode} {responseMessage.StatusCode} ({Util.BytesToString(responseMessage.Content.Headers.ContentLength ?? 0)})"); + // Console.WriteLine($"Sending {request.Method} {request.RequestUri} ({Util.BytesToString(request.Content?.Headers.ContentLength ?? 0)}) -> {(int)responseMessage.StatusCode} {responseMessage.StatusCode} ({Util.BytesToString(responseMessage.GetContentLength())}, WAIT={swWait.ElapsedMilliseconds}ms, EXEC={swExec.ElapsedMilliseconds}ms)"); + Console.WriteLine("Received " + responseMessage.Summarise(includeHeaders: true, includeContentIfText: false, hideHeaders: [ + "Server", + "Date", + "Transfer-Encoding", + "Connection", + "Vary", + "Content-Length", + "Access-Control-Allow-Origin", + "Access-Control-Allow-Methods", + "Access-Control-Allow-Headers", + "Access-Control-Expose-Headers", + "Cache-Control" + ])); return responseMessage; } @@ -110,13 +128,13 @@ public class MatrixHttpClient { public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken = default) { var responseMessage = await SendUnhandledAsync(request, cancellationToken); if (responseMessage.IsSuccessStatusCode) return responseMessage; - + //retry on gateway timeout if (responseMessage.StatusCode == HttpStatusCode.GatewayTimeout) { request.ResetSendStatus(); return await SendAsync(request, cancellationToken); } - + //error handling var content = await responseMessage.Content.ReadAsStringAsync(cancellationToken); if (content.Length == 0) @@ -238,4 +256,4 @@ public class MatrixHttpClient { return await SendAsync(request, cancellationToken); } } -#endif \ No newline at end of file +#endif diff --git a/LibMatrix/Helpers/SyncStateResolver.cs b/LibMatrix/Helpers/SyncStateResolver.cs
index 72d600d..0529e50 100644 --- a/LibMatrix/Helpers/SyncStateResolver.cs +++ b/LibMatrix/Helpers/SyncStateResolver.cs
@@ -37,7 +37,7 @@ public class SyncStateResolver(AuthenticatedHomeserverGeneric homeserver, ILogge oldState.NextBatch = newState.NextBatch ?? oldState.NextBatch; oldState.AccountData ??= new EventList(); - oldState.AccountData.Events ??= new List<StateEventResponse>(); + oldState.AccountData.Events ??= []; if (newState.AccountData?.Events is not null) oldState.AccountData.Events.MergeStateEventLists(newState.AccountData?.Events ?? new List<StateEventResponse>()); @@ -55,16 +55,18 @@ public class SyncStateResolver(AuthenticatedHomeserverGeneric homeserver, ILogge oldState.Rooms = MergeRoomsDataStructure(oldState.Rooms, newState.Rooms); oldState.ToDevice ??= new EventList(); - oldState.ToDevice.Events ??= new List<StateEventResponse>(); + oldState.ToDevice.Events ??= []; if (newState.ToDevice?.Events is not null) oldState.ToDevice.Events.MergeStateEventLists(newState.ToDevice?.Events ?? new List<StateEventResponse>()); oldState.DeviceLists ??= new SyncResponse.DeviceListsDataStructure(); + oldState.DeviceLists.Changed ??= []; + oldState.DeviceLists.Left ??= []; if (newState.DeviceLists?.Changed is not null) - foreach (var s in oldState.DeviceLists.Changed!) + foreach (var s in newState.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 newState.DeviceLists.Left!) oldState.DeviceLists.Left.Add(s); return oldState; diff --git a/LibMatrix/MatrixException.cs b/LibMatrix/MatrixException.cs
index eb207da..afdeefe 100644 --- a/LibMatrix/MatrixException.cs +++ b/LibMatrix/MatrixException.cs
@@ -24,43 +24,47 @@ public class MatrixException : Exception { public string GetAsJson() => GetAsObject().ToJson(ignoreNull: true); public override string Message => - $"{ErrorCode}: {ErrorCode switch { - // common - "M_FORBIDDEN" => $"You do not have permission to perform this action: {Error}", - "M_UNKNOWN_TOKEN" => $"The access token specified was not recognised: {Error}{(SoftLogout == true ? " (soft logout)" : "")}", - "M_MISSING_TOKEN" => $"No access token was specified: {Error}", - "M_BAD_JSON" => $"Request contained valid JSON, but it was malformed in some way: {Error}", - "M_NOT_JSON" => $"Request did not contain valid JSON: {Error}", - "M_NOT_FOUND" => $"The requested resource was not found: {Error}", - "M_LIMIT_EXCEEDED" => $"Too many requests have been sent in a short period of time. Wait a while then try again: {Error}", - "M_UNRECOGNISED" => $"The server did not recognise the request: {Error}", - "M_UNKOWN" => $"The server encountered an unexpected error: {Error}", - // endpoint specific - "M_UNAUTHORIZED" => $"The request did not contain valid authentication information for the target of the request: {Error}", - "M_USER_DEACTIVATED" => $"The user ID associated with the request has been deactivated: {Error}", - "M_USER_IN_USE" => $"The user ID associated with the request is already in use: {Error}", - "M_INVALID_USERNAME" => $"The requested user ID is not valid: {Error}", - "M_ROOM_IN_USE" => $"The room alias requested is already taken: {Error}", - "M_INVALID_ROOM_STATE" => $"The room associated with the request is not in a valid state to perform the request: {Error}", - "M_THREEPID_IN_USE" => $"The threepid requested is already associated with a user ID on this server: {Error}", - "M_THREEPID_NOT_FOUND" => $"The threepid requested is not associated with any user ID: {Error}", - "M_THREEPID_AUTH_FAILED" => $"The provided threepid and/or token was invalid: {Error}", - "M_THREEPID_DENIED" => $"The homeserver does not permit the third party identifier in question: {Error}", - "M_SERVER_NOT_TRUSTED" => $"The homeserver does not trust the identity server: {Error}", - "M_UNSUPPORTED_ROOM_VERSION" => $"The room version is not supported: {Error}", - "M_INCOMPATIBLE_ROOM_VERSION" => $"The room version is incompatible: {Error}", - "M_BAD_STATE" => $"The request was invalid because the state was invalid: {Error}", - "M_GUEST_ACCESS_FORBIDDEN" => $"Guest access is forbidden: {Error}", - "M_CAPTCHA_NEEDED" => $"Captcha needed: {Error}", - "M_CAPTCHA_INVALID" => $"Captcha invalid: {Error}", - "M_MISSING_PARAM" => $"Missing parameter: {Error}", - "M_INVALID_PARAM" => $"Invalid parameter: {Error}", - "M_TOO_LARGE" => $"The request or entity was too large: {Error}", - "M_EXCLUSIVE" => $"The resource being requested is reserved by an application service, or the application service making the request has not created the resource: {Error}", - "M_RESOURCE_LIMIT_EXCEEDED" => $"Exceeded resource limit: {Error}", - "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM" => $"Cannot leave server notice room: {Error}", - _ => $"Unknown error: {new { ErrorCode, Error, SoftLogout, RetryAfterMs }.ToJson(ignoreNull: true)}" - }}"; + $"{ErrorCode}: " + + (!string.IsNullOrWhiteSpace(Error) + ? Error + : ErrorCode switch { + // common + "M_FORBIDDEN" => $"You do not have permission to perform this action: {Error}", + "M_UNKNOWN_TOKEN" => $"The access token specified was not recognised: {Error}{(SoftLogout == true ? " (soft logout)" : "")}", + "M_MISSING_TOKEN" => $"No access token was specified: {Error}", + "M_BAD_JSON" => $"Request contained valid JSON, but it was malformed in some way: {Error}", + "M_NOT_JSON" => $"Request did not contain valid JSON: {Error}", + "M_NOT_FOUND" => $"The requested resource was not found: {Error}", + "M_LIMIT_EXCEEDED" => $"Too many requests have been sent in a short period of time. Wait a while then try again: {Error}", + "M_UNRECOGNISED" => $"The server did not recognise the request: {Error}", + "M_UNKOWN" => $"The server encountered an unexpected error: {Error}", + // endpoint specific + "M_UNAUTHORIZED" => $"The request did not contain valid authentication information for the target of the request: {Error}", + "M_USER_DEACTIVATED" => $"The user ID associated with the request has been deactivated: {Error}", + "M_USER_IN_USE" => $"The user ID associated with the request is already in use: {Error}", + "M_INVALID_USERNAME" => $"The requested user ID is not valid: {Error}", + "M_ROOM_IN_USE" => $"The room alias requested is already taken: {Error}", + "M_INVALID_ROOM_STATE" => $"The room associated with the request is not in a valid state to perform the request: {Error}", + "M_THREEPID_IN_USE" => $"The threepid requested is already associated with a user ID on this server: {Error}", + "M_THREEPID_NOT_FOUND" => $"The threepid requested is not associated with any user ID: {Error}", + "M_THREEPID_AUTH_FAILED" => $"The provided threepid and/or token was invalid: {Error}", + "M_THREEPID_DENIED" => $"The homeserver does not permit the third party identifier in question: {Error}", + "M_SERVER_NOT_TRUSTED" => $"The homeserver does not trust the identity server: {Error}", + "M_UNSUPPORTED_ROOM_VERSION" => $"The room version is not supported: {Error}", + "M_INCOMPATIBLE_ROOM_VERSION" => $"The room version is incompatible: {Error}", + "M_BAD_STATE" => $"The request was invalid because the state was invalid: {Error}", + "M_GUEST_ACCESS_FORBIDDEN" => $"Guest access is forbidden: {Error}", + "M_CAPTCHA_NEEDED" => $"Captcha needed: {Error}", + "M_CAPTCHA_INVALID" => $"Captcha invalid: {Error}", + "M_MISSING_PARAM" => $"Missing parameter: {Error}", + "M_INVALID_PARAM" => $"Invalid parameter: {Error}", + "M_TOO_LARGE" => $"The request or entity was too large: {Error}", + "M_EXCLUSIVE" => + $"The resource being requested is reserved by an application service, or the application service making the request has not created the resource: {Error}", + "M_RESOURCE_LIMIT_EXCEEDED" => $"Exceeded resource limit: {Error}", + "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM" => $"Cannot leave server notice room: {Error}", + _ => $"Unknown error: {new { ErrorCode, Error, SoftLogout, RetryAfterMs }.ToJson(ignoreNull: true)}" + }); public static class ErrorCodes { public const string M_FORBIDDEN = "M_FORBIDDEN"; diff --git a/LibMatrix/Services/HomeserverProviderService.cs b/LibMatrix/Services/HomeserverProviderService.cs
index 3e42c21..a674549 100644 --- a/LibMatrix/Services/HomeserverProviderService.cs +++ b/LibMatrix/Services/HomeserverProviderService.cs
@@ -23,9 +23,11 @@ public class HomeserverProviderService(ILogger<HomeserverProviderService> logger AuthenticatedHomeserverGeneric? hs = null; if (!useGeneric) { + var clientVersionsTask = rhs.GetClientVersionsAsync(); + var serverVersionTask = rhs.FederationClient?.GetServerVersionAsync() ?? Task.FromResult<ServerVersionResponse?>(null)!; ClientVersionsResponse? clientVersions = new(); try { - clientVersions = await rhs.GetClientVersionsAsync(); + clientVersions = await clientVersionsTask; } catch (Exception e) { logger.LogError(e, "Failed to get client versions for {homeserver}", homeserver); @@ -33,7 +35,7 @@ public class HomeserverProviderService(ILogger<HomeserverProviderService> logger ServerVersionResponse? serverVersion; try { - serverVersion = await (rhs.FederationClient?.GetServerVersionAsync() ?? Task.FromResult<ServerVersionResponse?>(null)!); + serverVersion = await serverVersionTask; } catch (Exception e) { logger.LogWarning(e, "Failed to get server version for {homeserver}", homeserver); diff --git a/LibMatrix/StateEvent.cs b/LibMatrix/StateEvent.cs
index cc870e4..0cd5662 100644 --- a/LibMatrix/StateEvent.cs +++ b/LibMatrix/StateEvent.cs
@@ -172,7 +172,7 @@ public class StateEventResponse : StateEvent { public string? EventId { get; set; } public class UnsignedData { - [JsonPropertyName("age")] + [JsonPropertyName("age"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)] public ulong? Age { get; set; } [JsonPropertyName("redacted_because")]