about summary refs log tree commit diff
diff options
context:
space:
mode:
m---------ArcaneLibs0
-rw-r--r--LibMatrix/Extensions/MatrixHttpClient.Single.cs38
-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.cs4
6 files changed, 80 insertions, 56 deletions
diff --git a/ArcaneLibs b/ArcaneLibs
-Subproject 3fb65c126b591ca05e76394d4c40f74cbb70de4
+Subproject 26b02bc5459f33d3b9b6bd2e4dda558cb8ac2e9
diff --git a/LibMatrix/Extensions/MatrixHttpClient.Single.cs b/LibMatrix/Extensions/MatrixHttpClient.Single.cs
index c9cd260..bab3e92 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.Http.Headers;
@@ -26,7 +26,8 @@ public class MatrixHttpClient {
                 EnableMultipleHttp2Connections = true
             };
             Client = new HttpClient(handler) {
-                DefaultRequestVersion = new Version(3, 0)
+                DefaultRequestVersion = new Version(3, 0),
+                Timeout = TimeSpan.FromHours(1)
             };
         }
         catch (PlatformNotSupportedException e) {
@@ -68,26 +69,29 @@ 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
-
-        Console.WriteLine($"Sending {request.Method} {BaseAddress}{request.RequestUri} ({Util.BytesToString(request.Content?.Headers.ContentLength ?? 0)})");
-
-        if (request.RequestUri is null) throw new NullReferenceException("RequestUri is null");
-        if (!request.RequestUri.IsAbsoluteUri) request.RequestUri = new Uri(BaseAddress, request.RequestUri);
+        swWait.Stop();
+        var swExec = Stopwatch.StartNew();
+       
         foreach (var (key, value) in AdditionalQueryParameters) request.RequestUri = request.RequestUri.AddQuery(key, value);
         foreach (var (key, value) in DefaultRequestHeaders) request.Headers.Add(key, value);
-
         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
@@ -96,8 +100,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;
     }
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 81ee3fe..58ae7d2 100644
--- a/LibMatrix/StateEvent.cs
+++ b/LibMatrix/StateEvent.cs
@@ -156,13 +156,13 @@ public class StateEventResponse : StateEvent {
     public string? Sender { get; set; }
 
     [JsonPropertyName("unsigned")]
-    public UnsignedData? Unsigned { get; set; }
+    public JsonObject? Unsigned { get; set; }
 
     [JsonPropertyName("event_id")]
     public string? EventId { get; set; }
 
     public class UnsignedData {
-        [JsonPropertyName("age")]
+        [JsonPropertyName("age"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
         public ulong? Age { get; set; }
 
         [JsonPropertyName("redacted_because")]