From ae18c049338dfcb33f721eeeb0a05571e8bd87a9 Mon Sep 17 00:00:00 2001 From: Rory& Date: Thu, 30 May 2024 08:02:40 +0000 Subject: Rename StateEvent to LegacyMatrixEvent --- LibMatrix/LegacyMatrixEvent.cs | 225 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 LibMatrix/LegacyMatrixEvent.cs (limited to 'LibMatrix/LegacyMatrixEvent.cs') diff --git a/LibMatrix/LegacyMatrixEvent.cs b/LibMatrix/LegacyMatrixEvent.cs new file mode 100644 index 0000000..1cfc879 --- /dev/null +++ b/LibMatrix/LegacyMatrixEvent.cs @@ -0,0 +1,225 @@ +using System.Collections.Frozen; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; +using ArcaneLibs; +using ArcaneLibs.Attributes; +using ArcaneLibs.Extensions; +using LibMatrix.EventTypes; +using LibMatrix.Extensions; + +namespace LibMatrix; + +public class LegacyMatrixEvent { + public static FrozenSet KnownStateEventTypes { get; } = new ClassCollector().ResolveFromAllAccessibleAssemblies().ToFrozenSet(); + + public static FrozenDictionary KnownStateEventTypesByName { get; } = KnownStateEventTypes.Aggregate( + new Dictionary(), + (dict, type) => { + var attrs = type.GetCustomAttributes(); + foreach (var attr in attrs) { + if (dict.TryGetValue(attr.EventName, out var existing)) + Console.WriteLine($"Duplicate event type '{attr.EventName}' registered for types '{existing.Name}' and '{type.Name}'"); + dict[attr.EventName] = type; + } + + return dict; + }).OrderBy(x => x.Key).ToFrozenDictionary(); + + public static Type GetStateEventType(string? type) => + string.IsNullOrWhiteSpace(type) ? typeof(UnknownEventContent) : KnownStateEventTypesByName.GetValueOrDefault(type) ?? typeof(UnknownEventContent); + + [JsonIgnore] + public Type MappedType => GetStateEventType(Type); + + [JsonIgnore] + public bool IsLegacyType => MappedType.GetCustomAttributes().FirstOrDefault(x => x.EventName == Type)?.Legacy ?? false; + + [JsonIgnore] + public string FriendlyTypeName => MappedType.GetFriendlyNameOrNull() ?? Type; + + [JsonIgnore] + public string FriendlyTypeNamePlural => MappedType.GetFriendlyNamePluralOrNull() ?? Type; + + private static readonly JsonSerializerOptions TypedContentSerializerOptions = new() { + Converters = { + new JsonFloatStringConverter(), + new JsonDoubleStringConverter(), + new JsonDecimalStringConverter() + } + }; + + [JsonIgnore] + [SuppressMessage("ReSharper", "PropertyCanBeMadeInitOnly.Global")] + public EventContent? TypedContent { + get { + // if (Type == "m.receipt") { + // return null; + // } + try { + var mappedType = GetStateEventType(Type); + if (mappedType == typeof(UnknownEventContent)) + Console.WriteLine($"Warning: unknown event type '{Type}'"); + var deserialisedContent = (EventContent)RawContent.Deserialize(mappedType, TypedContentSerializerOptions)!; + return deserialisedContent; + } + catch (JsonException e) { + Console.WriteLine(e); + Console.WriteLine("Content:\n" + (RawContent?.ToJson() ?? "null")); + } + + return null; + } + set { + if (value is null) + RawContent?.Clear(); + else + RawContent = JsonSerializer.Deserialize(JsonSerializer.Serialize(value, value.GetType(), + new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull })); + } + } + + [JsonPropertyName("state_key")] + public string? StateKey { get; set; } + + [JsonPropertyName("type")] + public string Type { get; set; } + + [JsonPropertyName("replaces_state")] + public string? ReplacesState { get; set; } + + private JsonObject? _rawContent; + + [JsonPropertyName("content")] + public JsonObject? RawContent { + get => _rawContent; + set => _rawContent = value; + } + + [JsonIgnore] + public string InternalSelfTypeName { + get { + var res = GetType().Name switch { + "StateEvent`1" => "StateEvent", + _ => GetType().Name + }; + return res; + } + } + + [JsonIgnore] + public string InternalContentTypeName => TypedContent?.GetType().Name ?? "null"; +} + +public class LegacyMatrixEventResponse : LegacyMatrixEvent { + [JsonPropertyName("origin_server_ts")] + public long? OriginServerTs { get; set; } + + [JsonPropertyName("room_id")] + public string? RoomId { get; set; } + + [JsonPropertyName("sender")] + public string? Sender { get; set; } + + [JsonPropertyName("unsigned")] + public UnsignedData? Unsigned { get; set; } + + [JsonPropertyName("event_id")] + public string? EventId { get; set; } + + public class UnsignedData { + [JsonPropertyName("age")] + public ulong? Age { get; set; } + + [JsonPropertyName("redacted_because")] + public object? RedactedBecause { get; set; } + + [JsonPropertyName("transaction_id")] + public string? TransactionId { get; set; } + + [JsonPropertyName("replaces_state")] + public string? ReplacesState { get; set; } + + [JsonPropertyName("prev_sender")] + public string? PrevSender { get; set; } + + [JsonPropertyName("prev_content")] + public JsonObject? PrevContent { get; set; } + } +} + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(ChunkedStateEventResponse))] +internal partial class ChunkedStateEventResponseSerializerContext : JsonSerializerContext; + +public class EventList { + public EventList() { } + + public EventList(List? events) { + Events = events; + } + + [JsonPropertyName("events")] + public List? Events { get; set; } = new(); +} + +public class ChunkedStateEventResponse { + [JsonPropertyName("chunk")] + public List? Chunk { get; set; } = new(); +} + +public class PaginatedChunkedStateEventResponse : ChunkedStateEventResponse { + [JsonPropertyName("start")] + public string? Start { get; set; } + + [JsonPropertyName("end")] + public string? End { get; set; } +} + +public class BatchedChunkedStateEventResponse : ChunkedStateEventResponse { + [JsonPropertyName("next_batch")] + public string? NextBatch { get; set; } + + [JsonPropertyName("prev_batch")] + public string? PrevBatch { get; set; } +} + +public class RecursedBatchedChunkedStateEventResponse : BatchedChunkedStateEventResponse { + [JsonPropertyName("recursion_depth")] + public int? RecursionDepth { get; set; } +} + +#region Unused code + +/* +public class StateEventContentPolymorphicTypeInfoResolver : DefaultJsonTypeInfoResolver +{ + public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options) + { + JsonTypeInfo jsonTypeInfo = base.GetTypeInfo(type, options); + + Type baseType = typeof(EventContent); + if (jsonTypeInfo.Type == baseType) { + jsonTypeInfo.PolymorphismOptions = new JsonPolymorphismOptions { + TypeDiscriminatorPropertyName = "type", + IgnoreUnrecognizedTypeDiscriminators = true, + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType, + + DerivedTypes = StateEvent.KnownStateEventTypesByName.Select(x => new JsonDerivedType(x.Value, x.Key)).ToList() + + // DerivedTypes = new ClassCollector() + // .ResolveFromAllAccessibleAssemblies() + // .SelectMany(t => t.GetCustomAttributes() + // .Select(a => new JsonDerivedType(t, attr.EventName)); + + }; + } + + return jsonTypeInfo; + } +} +*/ + +#endregion \ No newline at end of file -- cgit 1.4.1