about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTheArcaneBrony <myrainbowdash949@gmail.com>2023-10-14 23:19:25 +0200
committerTheArcaneBrony <myrainbowdash949@gmail.com>2023-10-14 23:19:25 +0200
commit4340b1899470c06f170817dbc1200040619fbf8d (patch)
treed1d6049d7bc8185c4222238a49846f964bfa7848
parentError handling (diff)
downloadLibMatrix-4340b1899470c06f170817dbc1200040619fbf8d.tar.xz
Handle floats etc in requests
-rw-r--r--LibMatrix/EventTypes/Spec/State/RoomInfo/RoomPowerLevelEventContent.cs30
-rw-r--r--LibMatrix/Extensions/HttpClientExtensions.cs58
-rw-r--r--LibMatrix/RoomTypes/GenericRoom.cs5
-rw-r--r--LibMatrix/StateEvent.cs8
4 files changed, 90 insertions, 11 deletions
diff --git a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomPowerLevelEventContent.cs b/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomPowerLevelEventContent.cs
index 7f37271..a1bf517 100644
--- a/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomPowerLevelEventContent.cs
+++ b/LibMatrix/EventTypes/Spec/State/RoomInfo/RoomPowerLevelEventContent.cs
@@ -3,13 +3,15 @@ using LibMatrix.Interfaces;
 
 namespace LibMatrix.EventTypes.Spec.State;
 
-[MatrixEvent(EventName = "m.room.power_levels")]
+[MatrixEvent(EventName = EventId)]
 public class RoomPowerLevelEventContent : EventContent {
+    public const string EventId = "m.room.power_levels";
+
     [JsonPropertyName("ban")]
     public long? Ban { get; set; } = 50;
 
     [JsonPropertyName("events_default")]
-    public long EventsDefault { get; set; } = 0;
+    public long? EventsDefault { get; set; } = 0;
 
     [JsonPropertyName("events")]
     public Dictionary<string, long>? Events { get; set; } // = null!;
@@ -46,10 +48,32 @@ public class RoomPowerLevelEventContent : EventContent {
     }
 
     public bool IsUserAdmin(string userId) {
+        if(userId is null) throw new ArgumentNullException(nameof(userId));
         return Users.TryGetValue(userId, out var level) && level >= Events.Max(x => x.Value);
     }
 
     public bool UserHasPermission(string userId, string eventType) {
-        return Users.TryGetValue(userId, out var level) && level >= Events.GetValueOrDefault(eventType, EventsDefault);
+        if(userId is null) throw new ArgumentNullException(nameof(userId));
+        return Users.TryGetValue(userId, out var level) && level >= Events.GetValueOrDefault(eventType, EventsDefault ?? 0);
+    }
+
+    public long GetUserPowerLevel(string userId) {
+        if(userId is null) throw new ArgumentNullException(nameof(userId));
+        return Users.TryGetValue(userId, out var level) ? level : UsersDefault ?? UsersDefault ?? 0;
+    }
+
+    public long GetEventPowerLevel(string eventType) {
+        return Events.TryGetValue(eventType, out var level) ? level : EventsDefault ?? EventsDefault ?? 0;
+    }
+
+    public void SetUserPowerLevel(string userId, long powerLevel) {
+        if(userId is null) throw new ArgumentNullException(nameof(userId));
+        Users ??= new();
+        if (Users.TryGetValue(userId, out var level)) {
+            Users[userId] = powerLevel;
+        }
+        else {
+            Users.Add(userId, powerLevel);
+        }
     }
 }
diff --git a/LibMatrix/Extensions/HttpClientExtensions.cs b/LibMatrix/Extensions/HttpClientExtensions.cs
index 62e9a98..bffd74a 100644
--- a/LibMatrix/Extensions/HttpClientExtensions.cs
+++ b/LibMatrix/Extensions/HttpClientExtensions.cs
@@ -1,5 +1,6 @@
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
 using System.Net.Http.Headers;
 using System.Reflection;
 using System.Text;
@@ -26,6 +27,15 @@ public static class HttpClientExtensions {
 public class MatrixHttpClient : HttpClient {
     internal string? AssertedUserId { get; set; }
 
+    private JsonSerializerOptions GetJsonSerializerOptions(JsonSerializerOptions? options = null) {
+        options ??= new JsonSerializerOptions();
+        options.Converters.Add(new JsonFloatStringConverter());
+        options.Converters.Add(new JsonDoubleStringConverter());
+        options.Converters.Add(new JsonDecimalStringConverter());
+        options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
+        return options;
+    }
+
     public override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
         CancellationToken cancellationToken) {
         if (request.RequestUri is null) throw new NullReferenceException("RequestUri is null");
@@ -68,7 +78,8 @@ public class MatrixHttpClient : HttpClient {
     }
 
     // GetFromJsonAsync
-    public async Task<T> GetFromJsonAsync<T>(string requestUri, CancellationToken cancellationToken = default) {
+    public async Task<T> GetFromJsonAsync<T>(string requestUri, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default) {
+        options = GetJsonSerializerOptions(options);
         var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
         request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
         var response = await SendAsync(request, cancellationToken);
@@ -82,7 +93,7 @@ public class MatrixHttpClient : HttpClient {
             Console.WriteLine("[!!] Checking sync response failed: " + e);
         }
 #endif
-        return await JsonSerializer.DeserializeAsync<T>(responseStream, cancellationToken: cancellationToken) ??
+        return await JsonSerializer.DeserializeAsync<T>(responseStream, options, cancellationToken: cancellationToken) ??
                throw new InvalidOperationException("Failed to deserialize response");
     }
 
@@ -97,19 +108,58 @@ public class MatrixHttpClient : HttpClient {
 
     public new async Task<HttpResponseMessage> PutAsJsonAsync<T>([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, T value, JsonSerializerOptions? options = null,
         CancellationToken cancellationToken = default) {
+        options = GetJsonSerializerOptions(options);
         var request = new HttpRequestMessage(HttpMethod.Put, requestUri);
         request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
-        request.Content = new StringContent(JsonSerializer.Serialize(value, value.GetType(), options ?? new() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }),
+        request.Content = new StringContent(JsonSerializer.Serialize(value, value.GetType(), options),
             Encoding.UTF8, "application/json");
         return await SendAsync(request, cancellationToken);
     }
 
     public async Task<HttpResponseMessage> PostAsJsonAsync<T>([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, T value, JsonSerializerOptions? options = null,
         CancellationToken cancellationToken = default) {
+        options ??= new();
+        options.Converters.Add(new JsonFloatStringConverter());
+        options.Converters.Add(new JsonDoubleStringConverter());
+        options.Converters.Add(new JsonDecimalStringConverter());
+        options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
         var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
         request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
-        request.Content = new StringContent(JsonSerializer.Serialize(value, value.GetType(), options ?? new() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }),
+        request.Content = new StringContent(JsonSerializer.Serialize(value, value.GetType(), options),
             Encoding.UTF8, "application/json");
         return await SendAsync(request, cancellationToken);
     }
+
+    public async IAsyncEnumerable<T?> GetAsyncEnumerableFromJsonAsync<T>([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, JsonSerializerOptions? options = null) {
+        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;
+        }
+    }
+}
+
+public class JsonFloatStringConverter : JsonConverter<float> {
+    public override float Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+        => float.Parse(reader.GetString()!);
+
+    public override void Write(Utf8JsonWriter writer, float value, JsonSerializerOptions options)
+        => writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
+}
+
+public class JsonDoubleStringConverter : JsonConverter<double> {
+    public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+        => double.Parse(reader.GetString()!);
+
+    public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options)
+        => writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
+}
+
+public class JsonDecimalStringConverter : JsonConverter<decimal> {
+    public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+        => decimal.Parse(reader.GetString()!);
+
+    public override void Write(Utf8JsonWriter writer, decimal value, JsonSerializerOptions options)
+        => writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
 }
diff --git a/LibMatrix/RoomTypes/GenericRoom.cs b/LibMatrix/RoomTypes/GenericRoom.cs
index 106b2f6..d11b28d 100644
--- a/LibMatrix/RoomTypes/GenericRoom.cs
+++ b/LibMatrix/RoomTypes/GenericRoom.cs
@@ -27,9 +27,8 @@ public class GenericRoom {
     public string RoomId { get; set; }
 
     public async IAsyncEnumerable<StateEventResponse?> GetFullStateAsync() {
-        var res = await _httpClient.GetAsync($"/_matrix/client/v3/rooms/{RoomId}/state");
-        var result =
-            JsonSerializer.DeserializeAsyncEnumerable<StateEventResponse>(await res.Content.ReadAsStreamAsync());
+        var result = _httpClient.GetAsyncEnumerableFromJsonAsync<StateEventResponse>(
+            $"/_matrix/client/v3/rooms/{RoomId}/state");
         await foreach (var resp in result) {
             yield return resp;
         }
diff --git a/LibMatrix/StateEvent.cs b/LibMatrix/StateEvent.cs
index e846811..fb4dd71 100644
--- a/LibMatrix/StateEvent.cs
+++ b/LibMatrix/StateEvent.cs
@@ -5,6 +5,7 @@ using System.Text.Json.Serialization;
 using ArcaneLibs;
 using ArcaneLibs.Extensions;
 using LibMatrix.EventTypes;
+using LibMatrix.Extensions;
 using LibMatrix.Interfaces;
 
 namespace LibMatrix;
@@ -41,7 +42,12 @@ public class StateEvent {
                 return null!;
             }
             try {
-                return (EventContent)RawContent.Deserialize(GetType)!;
+                var jse = new JsonSerializerOptions();
+                jse ??= new JsonSerializerOptions();
+                jse.Converters.Add(new JsonFloatStringConverter());
+                jse.Converters.Add(new JsonDoubleStringConverter());
+                jse.Converters.Add(new JsonDecimalStringConverter());
+                return (EventContent)RawContent.Deserialize(GetType, jse)!;
             }
             catch (JsonException e) {
                 Console.WriteLine(e);