about summary refs log tree commit diff
path: root/MatrixRoomUtils.Core
diff options
context:
space:
mode:
Diffstat (limited to 'MatrixRoomUtils.Core')
-rw-r--r--MatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs13
-rw-r--r--MatrixRoomUtils.Core/MatrixException.cs70
-rw-r--r--MatrixRoomUtils.Core/RoomTypes/GenericRoom.cs21
-rw-r--r--MatrixRoomUtils.Core/RoomTypes/SpaceRoom.cs17
-rw-r--r--MatrixRoomUtils.Core/Services/HomeserverProviderService.cs6
5 files changed, 77 insertions, 50 deletions
diff --git a/MatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs b/MatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs
index 852e1d8..060867d 100644
--- a/MatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs
+++ b/MatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs
@@ -1,3 +1,4 @@
+using System.Net.Http.Headers;
 using System.Reflection;
 using System.Text.Json;
 
@@ -19,6 +20,7 @@ public static class HttpClientExtensions {
 
 public class MatrixHttpClient : HttpClient {
     public override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
+    Console.WriteLine($"Sending request to {request.RequestUri}");
         try
         {
             HttpRequestOptionsKey<bool> WebAssemblyEnableStreamingResponseKey = new HttpRequestOptionsKey<bool>("WebAssemblyEnableStreamingResponse");
@@ -35,10 +37,10 @@ public class MatrixHttpClient : HttpClient {
         }
         var a = await base.SendAsync(request, cancellationToken);
         if (!a.IsSuccessStatusCode) {
-            Console.WriteLine($"Failed to send request: {a.StatusCode}");
             var content = await a.Content.ReadAsStringAsync(cancellationToken);
             if (content.StartsWith('{')) {
                 var ex = JsonSerializer.Deserialize<MatrixException>(content);
+            Console.WriteLine($"Failed to send request: {ex}");
                 if (ex?.RetryAfterMs is not null) {
                     await Task.Delay(ex.RetryAfterMs.Value, cancellationToken);
                     typeof(HttpRequestMessage).GetField("_sendStatus", BindingFlags.NonPublic | BindingFlags.Instance)?.SetValue(request, 0);
@@ -50,4 +52,13 @@ public class MatrixHttpClient : HttpClient {
         }
         return a;
     }
+    // GetFromJsonAsync
+    public async Task<T> GetFromJsonAsync<T>(string requestUri, CancellationToken cancellationToken = default) {
+        var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
+        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+        var response = await SendAsync(request, cancellationToken);
+        response.EnsureSuccessStatusCode();
+        await using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken);
+        return await JsonSerializer.DeserializeAsync<T>(responseStream, cancellationToken: cancellationToken);
+    }
 }
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/MatrixException.cs b/MatrixRoomUtils.Core/MatrixException.cs
index 50fae20..4795d6d 100644
--- a/MatrixRoomUtils.Core/MatrixException.cs
+++ b/MatrixRoomUtils.Core/MatrixException.cs
@@ -17,41 +17,41 @@ public class MatrixException : Exception {
     public int? RetryAfterMs { get; set; }
 
     public override string Message =>
-        ErrorCode switch {
+        $"{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,
+            "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)
-        };
+            "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)}"
+        }}";
 }
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/RoomTypes/GenericRoom.cs b/MatrixRoomUtils.Core/RoomTypes/GenericRoom.cs
index f57c855..879ae6b 100644
--- a/MatrixRoomUtils.Core/RoomTypes/GenericRoom.cs
+++ b/MatrixRoomUtils.Core/RoomTypes/GenericRoom.cs
@@ -44,7 +44,17 @@ public class GenericRoom {
         var url = $"/_matrix/client/v3/rooms/{RoomId}/state";
         if (!string.IsNullOrEmpty(type)) url += $"/{type}";
         if (!string.IsNullOrEmpty(stateKey)) url += $"/{stateKey}";
-        return await _httpClient.GetFromJsonAsync<T>(url);
+        try {
+            var resp = await _httpClient.GetFromJsonAsync<T>(url);
+            return resp;
+        }
+        catch (MatrixException e) {
+            if (e is not { ErrorCode: "M_NOT_FOUND" }) {
+                throw;
+            }
+            Console.WriteLine(e);
+            return default;
+        }
     }
 
     public async Task<MessagesResponse> GetMessagesAsync(string from = "", int limit = 10, string dir = "b",
@@ -56,8 +66,13 @@ public class GenericRoom {
     }
 
     public async Task<string> GetNameAsync() {
-        var res = await GetStateAsync<RoomNameEventData>("m.room.name");
-        return res.Name ?? RoomId;
+        try {
+            var res = await GetStateAsync<RoomNameEventData>("m.room.name");
+            return res?.Name ?? RoomId;
+        }
+        catch (MatrixException e) {
+            return $"{RoomId} ({e.ErrorCode})";
+        }
     }
 
     public async Task JoinAsync(string[]? homeservers = null, string? reason = null) {
diff --git a/MatrixRoomUtils.Core/RoomTypes/SpaceRoom.cs b/MatrixRoomUtils.Core/RoomTypes/SpaceRoom.cs
index 3be3130..1b93064 100644
--- a/MatrixRoomUtils.Core/RoomTypes/SpaceRoom.cs
+++ b/MatrixRoomUtils.Core/RoomTypes/SpaceRoom.cs
@@ -13,15 +13,16 @@ public class SpaceRoom : GenericRoom {
         _homeServer = homeServer;
     }
 
-    public async Task<List<GenericRoom>> GetRoomsAsync(bool includeRemoved = false) {
+    private static SemaphoreSlim _semaphore = new(1, 1);
+    public async IAsyncEnumerable<GenericRoom> GetRoomsAsync(bool includeRemoved = false) {
+        await _semaphore.WaitAsync();
         var rooms = new List<GenericRoom>();
-        var state = GetFullStateAsync().ToBlockingEnumerable().ToList();
-        var childStates = state.Where(x => x.Type == "m.space.child");
-        foreach (var stateEvent in childStates) {
-            if (stateEvent.TypedContent.ToJson() != "{}" || includeRemoved)
-                rooms.Add(await _homeServer.GetRoom(stateEvent.StateKey));
+        var state = GetFullStateAsync();
+        await foreach (var stateEvent in state) {
+            if (stateEvent.Type != "m.space.child") continue;
+            if (stateEvent.RawContent.ToJson() != "{}" || includeRemoved)
+                yield return await _homeServer.GetRoom(stateEvent.StateKey);
         }
-
-        return rooms;
+        _semaphore.Release();
     }
 }
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Services/HomeserverProviderService.cs b/MatrixRoomUtils.Core/Services/HomeserverProviderService.cs
index 870e0d4..b2ea987 100644
--- a/MatrixRoomUtils.Core/Services/HomeserverProviderService.cs
+++ b/MatrixRoomUtils.Core/Services/HomeserverProviderService.cs
@@ -30,9 +30,9 @@ public class HomeserverProviderService {
                                   await _homeserverResolverService.ResolveHomeserverFromWellKnown(homeserver);
         hs._httpClient.Dispose();
         hs._httpClient = new MatrixHttpClient { BaseAddress = new Uri(hs.FullHomeServerDomain) };
-        hs._httpClient.Timeout = TimeSpan.FromSeconds(5);
+        hs._httpClient.Timeout = TimeSpan.FromSeconds(120);
         hs._httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
-        
+
         hs.WhoAmI = (await hs._httpClient.GetFromJsonAsync<WhoAmIResponse>("/_matrix/client/v3/account/whoami"))!;
         return hs;
     }
@@ -43,7 +43,7 @@ public class HomeserverProviderService {
                                   await _homeserverResolverService.ResolveHomeserverFromWellKnown(homeserver);
         hs._httpClient.Dispose();
         hs._httpClient = new MatrixHttpClient { BaseAddress = new Uri(hs.FullHomeServerDomain) };
-        hs._httpClient.Timeout = TimeSpan.FromSeconds(5);
+        hs._httpClient.Timeout = TimeSpan.FromSeconds(120);
         return hs;
     }