Guild data polymorphism

This commit is contained in:
Kecskeméti László 2024-07-09 11:34:41 +02:00
parent da9be4735e
commit 073e17c96b
7 changed files with 102 additions and 53 deletions

View File

@ -5,7 +5,7 @@ namespace Discord.API;
public class ChannelData public class ChannelData
{ {
public required ulong Id { get; init; } public required ulong Id { get; init; }
public int? Type { get; init; } public required int Type { get; init; }
public ulong? GuildId { get; init; } public ulong? GuildId { get; init; }
public int? Position { get; init; } public int? Position { get; init; }
public string? Name { get; init; } public string? Name { get; init; }

View File

@ -0,0 +1,10 @@
namespace Discord.API;
public class GuildCreateData : GuildData{
public required DateTime JoinedAt { get; init; }
public required bool Large { get; init; }
public required uint MemberCount { get; init; }
public required VoiceStateData[] VoiceStates { get; init; }
public required GuildMemberData[] Members { get; init; }
public required ChannelData[] Channels { get; init; }
}

View File

@ -1,20 +1,20 @@
using System.Text.Json.Serialization;
namespace Discord.API; namespace Discord.API;
public class GuildData : UnavailableGuildData
[JsonPolymorphic(UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor)]
[JsonDerivedType(typeof(GuildCreateData))]
[JsonDerivedType(typeof(GuildUpdateData))]
public abstract class GuildData : UnavailableGuildData
{ {
public override bool Unavailable => false; public override bool Unavailable => false;
public string? Name { get; init; } public required string Name { get; init; }
public ulong? AfkChannelId { get; init; } public required ulong? AfkChannelId { get; init; }
public int? AfkTimeout { get; init; } public required int AfkTimeout { get; init; }
public RoleData[]? Roles { get; init; } public required RoleData[] Roles { get; init; }
public ulong? SystemChannelId { get; init; } public required ulong? SystemChannelId { get; init; }
public uint? SystemChannelFlags { get; init; } public required uint SystemChannelFlags { get; init; }
public string? Description { get; init; } public required string? Description { get; init; }
public int? NsfwLevel { get; init; } public required int NsfwLevel { get; init; }
public DateTime? JoinedAt { get; init; }
public bool? Large { get; init; }
public uint? MemberCount { get; init; }
public VoiceStateData[]? VoiceStates { get; init; }
public GuildMemberData[]? Members { get; init; }
public ChannelData[]? Channels { get; init; }
} }

View File

@ -3,49 +3,31 @@ using System.Text.Json.Serialization;
namespace Discord.API; namespace Discord.API;
internal class GuildDataConverter : JsonConverter<UnavailableGuildData> internal class GuildDataConverter : JsonConverter<GuildData>
{ {
public override UnavailableGuildData? Read(ref Utf8JsonReader reader, Type typeToConvert, public override GuildData? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
JsonSerializerOptions options)
{ {
JsonDocument json_doc = JsonDocument.ParseValue(ref reader); JsonDocument json_doc = JsonDocument.ParseValue(ref reader);
if (!json_doc.RootElement.TryGetProperty("unavailable", out var unavailable_prop) || if(json_doc.RootElement.TryGetProperty("joined_at", out _)){
unavailable_prop.ValueKind == JsonValueKind.False) return json_doc.Deserialize(SourceGenerationContext.Default.GuildCreateData);
{ }else{
return json_doc.Deserialize(SourceGenerationContext.Default.GuildData); return json_doc.Deserialize(SourceGenerationContext.Default.GuildUpdateData);
}
else
{
if (json_doc.RootElement.TryGetProperty("id", out var id_prop) &&
id_prop.ValueKind is JsonValueKind.String or JsonValueKind.Number)
{
ulong id = id_prop.ValueKind switch
{
JsonValueKind.Number => id_prop.GetUInt64(),
JsonValueKind.String => ulong.Parse(id_prop.GetString() ?? "")
};
return new UnavailableGuildData()
{
Id = id
};
}
else
{
throw new JsonException("Id property not found in guild data");
}
} }
} }
public override void Write(Utf8JsonWriter writer, UnavailableGuildData value, JsonSerializerOptions options) public override void Write(Utf8JsonWriter writer, GuildData value, JsonSerializerOptions options)
{
if (value is GuildData)
{
writer.WriteRawValue(JsonSerializer.SerializeToUtf8Bytes(value, SourceGenerationContext.Default.GuildData));
}
else
{ {
switch(value){
case GuildCreateData gcd:
writer.WriteRawValue(JsonSerializer.SerializeToUtf8Bytes(gcd, SourceGenerationContext.Default.GuildCreateData));
break;
case GuildUpdateData gud:
writer.WriteRawValue(JsonSerializer.SerializeToUtf8Bytes(gud, SourceGenerationContext.Default.GuildUpdateData));
break;
default:
writer.WriteStartObject(); writer.WriteStartObject();
writer.WriteBoolean("unavailable", true); writer.WriteEndObject();
break;
} }
} }
} }

View File

@ -0,0 +1,5 @@
namespace Discord.API;
public class GuildUpdateData : GuildData{
}

View File

@ -0,0 +1,52 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Discord.API;
internal class UnavailableGuildDataConverter : JsonConverter<UnavailableGuildData>
{
public override UnavailableGuildData? Read(ref Utf8JsonReader reader, Type typeToConvert,
JsonSerializerOptions options)
{
JsonDocument json_doc = JsonDocument.ParseValue(ref reader);
if (!json_doc.RootElement.TryGetProperty("unavailable", out var unavailable_prop) ||
unavailable_prop.ValueKind == JsonValueKind.False)
{
return json_doc.Deserialize(SourceGenerationContext.Default.GuildData);
}
else
{
if (json_doc.RootElement.TryGetProperty("id", out var id_prop) &&
id_prop.ValueKind is JsonValueKind.String or JsonValueKind.Number)
{
ulong id = id_prop.ValueKind switch
{
JsonValueKind.Number => id_prop.GetUInt64(),
JsonValueKind.String => ulong.Parse(id_prop.GetString() ?? ""),
_ => throw new JsonException("This should be impossible")
};
return new UnavailableGuildData()
{
Id = id
};
}
else
{
throw new JsonException("Id property not found in guild data");
}
}
}
public override void Write(Utf8JsonWriter writer, UnavailableGuildData value, JsonSerializerOptions options)
{
if (value is GuildData)
{
writer.WriteRawValue(JsonSerializer.SerializeToUtf8Bytes(value, SourceGenerationContext.Default.GuildData));
}
else
{
writer.WriteStartObject();
writer.WriteBoolean("unavailable", true);
}
}
}

View File

@ -10,7 +10,7 @@ using System.Text.Json;
IgnoreReadOnlyProperties = false, IgnoreReadOnlyProperties = false,
IncludeFields = true, IncludeFields = true,
PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower, PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower,
Converters = [typeof(GatewayPacketConverter), typeof(GuildDataConverter)], Converters = [typeof(GatewayPacketConverter), typeof(UnavailableGuildDataConverter)],
NumberHandling = JsonNumberHandling.AllowReadingFromString NumberHandling = JsonNumberHandling.AllowReadingFromString
)] )]
[JsonSerializable(typeof(GatewayPacket))] [JsonSerializable(typeof(GatewayPacket))]