From cf90f02e1f9c9f7d037976cace2b9c49119c741c Mon Sep 17 00:00:00 2001 From: Rory& Date: Thu, 30 May 2024 19:07:09 +0000 Subject: Start implementing new event system --- .../JsonElementExtensions.cs | 147 +++++++++++++++++++++ .../LibMatrix.DebugDataValidationApi.csproj | 4 +- .../Services/CommandListenerHostedService.cs | 16 +-- .../Services/InviteListenerHostedService.cs | 16 +-- 4 files changed, 166 insertions(+), 17 deletions(-) create mode 100644 Utilities/LibMatrix.DebugDataValidationApi/JsonElementExtensions.cs (limited to 'Utilities') diff --git a/Utilities/LibMatrix.DebugDataValidationApi/JsonElementExtensions.cs b/Utilities/LibMatrix.DebugDataValidationApi/JsonElementExtensions.cs new file mode 100644 index 0000000..a2faddc --- /dev/null +++ b/Utilities/LibMatrix.DebugDataValidationApi/JsonElementExtensions.cs @@ -0,0 +1,147 @@ +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; + +namespace LibMatrix.Extensions; + +public static class JsonElementExtensions { + public static bool FindExtraJsonElementFields(this JsonElement obj, Type objectType, string objectPropertyName) { + if (objectPropertyName == "content" && objectType == typeof(JsonObject)) + objectType = typeof(LegacyMatrixEventResponse); + // if (t == typeof(JsonNode)) + // return false; + + Console.WriteLine($"{objectType.Name} {objectPropertyName}"); + var unknownPropertyFound = false; + var mappedPropsDict = objectType.GetProperties() + .Where(x => x.GetCustomAttribute() is not null) + .ToDictionary(x => x.GetCustomAttribute()!.Name, x => x); + objectType.GetProperties().Where(x => !mappedPropsDict.ContainsKey(x.Name)) + .ToList().ForEach(x => mappedPropsDict.TryAdd(x.Name, x)); + + foreach (var field in obj.EnumerateObject()) { + if (mappedPropsDict.TryGetValue(field.Name, out var mappedProperty)) { + //dictionary + if (mappedProperty.PropertyType.IsGenericType && + mappedProperty.PropertyType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) { + unknownPropertyFound |= _checkDictionary(field, objectType, mappedProperty.PropertyType); + continue; + } + + if (mappedProperty.PropertyType.IsGenericType && + mappedProperty.PropertyType.GetGenericTypeDefinition() == typeof(List<>)) { + unknownPropertyFound |= _checkList(field, objectType, mappedProperty.PropertyType); + continue; + } + + if (field.Name == "content" && (objectType == typeof(LegacyMatrixEventResponse) || objectType == typeof(LegacyMatrixEvent))) { + unknownPropertyFound |= field.FindExtraJsonPropertyFieldsByValueKind( + LegacyMatrixEvent.GetStateEventType(obj.GetProperty("type").GetString()!), // We expect type to always be present + mappedProperty.PropertyType); + continue; + } + + unknownPropertyFound |= + field.FindExtraJsonPropertyFieldsByValueKind(objectType, mappedProperty.PropertyType); + continue; + } + + Console.WriteLine($"[!!] Unknown property {field.Name} in {objectType.Name}!"); + unknownPropertyFound = true; + } + + return unknownPropertyFound; + } + + private static bool FindExtraJsonPropertyFieldsByValueKind(this JsonProperty field, Type containerType, + Type propertyType) { + if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) propertyType = propertyType.GetGenericArguments()[0]; + + var switchResult = false; + switch (field.Value.ValueKind) { + case JsonValueKind.Array: + switchResult = field.Value.EnumerateArray().Aggregate(switchResult, + (current, element) => current | element.FindExtraJsonElementFields(propertyType, field.Name)); + break; + case JsonValueKind.Object: + switchResult |= field.Value.FindExtraJsonElementFields(propertyType, field.Name); + break; + case JsonValueKind.True: + case JsonValueKind.False: + return _checkBool(field, containerType, propertyType); + case JsonValueKind.String: + return _checkString(field, containerType, propertyType); + case JsonValueKind.Number: + return _checkNumber(field, containerType, propertyType); + case JsonValueKind.Undefined: + case JsonValueKind.Null: + break; + default: + throw new ArgumentOutOfRangeException(); + } + + return switchResult; + } + + private static bool _checkBool(this JsonProperty field, Type containerType, Type propertyType) { + if (propertyType == typeof(bool)) return true; + Console.WriteLine( + $"[!!] Encountered bool for {field.Name} in {containerType.Name}, the class defines {propertyType.Name}!"); + return false; + } + + private static bool _checkString(this JsonProperty field, Type containerType, Type propertyType) { + if (propertyType == typeof(string)) return true; + // ReSharper disable once BuiltInTypeReferenceStyle + if (propertyType == typeof(String)) return true; + Console.WriteLine( + $"[!!] Encountered string for {field.Name} in {containerType.Name}, the class defines {propertyType.Name}!"); + return false; + } + + private static bool _checkNumber(this JsonProperty field, Type containerType, Type propertyType) { + if (propertyType == typeof(int) || + propertyType == typeof(double) || + propertyType == typeof(float) || + propertyType == typeof(decimal) || + propertyType == typeof(long) || + propertyType == typeof(short) || + propertyType == typeof(uint) || + propertyType == typeof(ulong) || + propertyType == typeof(ushort) || + propertyType == typeof(byte) || + propertyType == typeof(sbyte)) + return true; + Console.WriteLine( + $"[!!] Encountered number for {field.Name} in {containerType.Name}, the class defines {propertyType.Name}!"); + return false; + } + + private static bool _checkDictionary(this JsonProperty field, Type containerType, Type propertyType) { + var keyType = propertyType.GetGenericArguments()[0]; + var valueType = propertyType.GetGenericArguments()[1]; + valueType = Nullable.GetUnderlyingType(valueType) ?? valueType; + Console.WriteLine( + $"Encountered dictionary {field.Name} with key type {keyType.Name} and value type {valueType.Name}!"); + + return field.Value.EnumerateObject() + .Where(key => !valueType.IsPrimitive && valueType != typeof(string)) + .Aggregate(false, (current, key) => + current | key.FindExtraJsonPropertyFieldsByValueKind(containerType, valueType) + ); + } + + private static bool _checkList(this JsonProperty field, Type containerType, Type propertyType) { + var valueType = propertyType.GetGenericArguments()[0]; + valueType = Nullable.GetUnderlyingType(valueType) ?? valueType; + Console.WriteLine( + $"Encountered list {field.Name} with value type {valueType.Name}!"); + + return field.Value.EnumerateArray() + .Where(key => !valueType.IsPrimitive && valueType != typeof(string)) + .Aggregate(false, (current, key) => + current | key.FindExtraJsonElementFields(valueType, field.Name) + ); + } +} \ No newline at end of file diff --git a/Utilities/LibMatrix.DebugDataValidationApi/LibMatrix.DebugDataValidationApi.csproj b/Utilities/LibMatrix.DebugDataValidationApi/LibMatrix.DebugDataValidationApi.csproj index 24fd617..ef8f443 100644 --- a/Utilities/LibMatrix.DebugDataValidationApi/LibMatrix.DebugDataValidationApi.csproj +++ b/Utilities/LibMatrix.DebugDataValidationApi/LibMatrix.DebugDataValidationApi.csproj @@ -14,7 +14,9 @@ - + + ExtraDefineConstants=WITH_LEGACY_EVENTS + diff --git a/Utilities/LibMatrix.Utilities.Bot/Services/CommandListenerHostedService.cs b/Utilities/LibMatrix.Utilities.Bot/Services/CommandListenerHostedService.cs index 46638e4..45118b3 100644 --- a/Utilities/LibMatrix.Utilities.Bot/Services/CommandListenerHostedService.cs +++ b/Utilities/LibMatrix.Utilities.Bot/Services/CommandListenerHostedService.cs @@ -41,14 +41,14 @@ public class CommandListenerHostedService : IHostedService { private async Task? Run(CancellationToken cancellationToken) { _logger.LogInformation("Starting command listener!"); - var filter = await _hs.NamedCaches.FilterCache.GetOrSetValueAsync("gay.rory.libmatrix.utilities.bot.command_listener_syncfilter.dev2", new SyncFilter() { - AccountData = new SyncFilter.EventFilter(notTypes: ["*"], limit: 1), - Presence = new SyncFilter.EventFilter(notTypes: ["*"]), - Room = new SyncFilter.RoomFilter() { - AccountData = new SyncFilter.RoomFilter.StateFilter(notTypes: ["*"]), - Ephemeral = new SyncFilter.RoomFilter.StateFilter(notTypes: ["*"]), - State = new SyncFilter.RoomFilter.StateFilter(notTypes: ["*"]), - Timeline = new SyncFilter.RoomFilter.StateFilter(types: ["m.room.message"], notSenders: [_hs.WhoAmI.UserId]), + var filter = await _hs.NamedCaches.FilterCache.GetOrSetValueAsync("gay.rory.libmatrix.utilities.bot.command_listener_syncfilter.dev2", new MatrixFilter() { + AccountData = new MatrixFilter.EventFilter(notTypes: ["*"], limit: 1), + Presence = new MatrixFilter.EventFilter(notTypes: ["*"]), + Room = new MatrixFilter.RoomFilter() { + AccountData = new MatrixFilter.RoomFilter.StateFilter(notTypes: ["*"]), + Ephemeral = new MatrixFilter.RoomFilter.StateFilter(notTypes: ["*"]), + State = new MatrixFilter.RoomFilter.StateFilter(notTypes: ["*"]), + Timeline = new MatrixFilter.RoomFilter.StateFilter(types: ["m.room.message"], notSenders: [_hs.WhoAmI.UserId]), } }); diff --git a/Utilities/LibMatrix.Utilities.Bot/Services/InviteListenerHostedService.cs b/Utilities/LibMatrix.Utilities.Bot/Services/InviteListenerHostedService.cs index c2aed04..b49a8e3 100644 --- a/Utilities/LibMatrix.Utilities.Bot/Services/InviteListenerHostedService.cs +++ b/Utilities/LibMatrix.Utilities.Bot/Services/InviteListenerHostedService.cs @@ -31,14 +31,14 @@ public class InviteHandlerHostedService : IHostedService { private async Task? Run(CancellationToken cancellationToken) { _logger.LogInformation("Starting invite listener!"); - var filter = await _hs.NamedCaches.FilterCache.GetOrSetValueAsync("gay.rory.libmatrix.utilities.bot.command_listener_syncfilter.dev2", new SyncFilter() { - AccountData = new SyncFilter.EventFilter(notTypes: ["*"], limit: 1), - Presence = new SyncFilter.EventFilter(notTypes: ["*"]), - Room = new SyncFilter.RoomFilter() { - AccountData = new SyncFilter.RoomFilter.StateFilter(notTypes: ["*"]), - Ephemeral = new SyncFilter.RoomFilter.StateFilter(notTypes: ["*"]), - State = new SyncFilter.RoomFilter.StateFilter(notTypes: ["*"]), - Timeline = new SyncFilter.RoomFilter.StateFilter(types: ["m.room.message"], notSenders: [_hs.WhoAmI.UserId]), + var filter = await _hs.NamedCaches.FilterCache.GetOrSetValueAsync("gay.rory.libmatrix.utilities.bot.command_listener_syncfilter.dev2", new MatrixFilter() { + AccountData = new MatrixFilter.EventFilter(notTypes: ["*"], limit: 1), + Presence = new MatrixFilter.EventFilter(notTypes: ["*"]), + Room = new MatrixFilter.RoomFilter() { + AccountData = new MatrixFilter.RoomFilter.StateFilter(notTypes: ["*"]), + Ephemeral = new MatrixFilter.RoomFilter.StateFilter(notTypes: ["*"]), + State = new MatrixFilter.RoomFilter.StateFilter(notTypes: ["*"]), + Timeline = new MatrixFilter.RoomFilter.StateFilter(types: ["m.room.message"], notSenders: [_hs.WhoAmI.UserId]), } }); -- cgit 1.4.1