New type definitions
This commit is contained in:
parent
2b18bd8ae4
commit
da9be4735e
@ -16,6 +16,156 @@ public class JsonTests
|
||||
_testOutputHelper = testOutputHelper;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GuildCreateDeserialize()
|
||||
{
|
||||
string src = """
|
||||
{
|
||||
"op": 0,
|
||||
"t": "GUILD_CREATE",
|
||||
"s": 3,
|
||||
"d":{
|
||||
"id": "197038439483310086",
|
||||
"name": "Discord Testers",
|
||||
"icon": "f64c482b807da4f539cff778d174971c",
|
||||
"description": "The official place to report Discord Bugs!",
|
||||
"splash": null,
|
||||
"discovery_splash": null,
|
||||
"features": [
|
||||
"ANIMATED_ICON",
|
||||
"VERIFIED",
|
||||
"NEWS",
|
||||
"VANITY_URL",
|
||||
"DISCOVERABLE",
|
||||
"MORE_EMOJI",
|
||||
"INVITE_SPLASH",
|
||||
"BANNER",
|
||||
"COMMUNITY"
|
||||
],
|
||||
"emojis": [],
|
||||
"banner": "9b6439a7de04f1d26af92f84ac9e1e4a",
|
||||
"owner_id": "73193882359173120",
|
||||
"application_id": null,
|
||||
"region": null,
|
||||
"afk_channel_id": null,
|
||||
"afk_timeout": 300,
|
||||
"system_channel_id": null,
|
||||
"widget_enabled": true,
|
||||
"widget_channel_id": null,
|
||||
"verification_level": 3,
|
||||
"roles": [],
|
||||
"default_message_notifications": 1,
|
||||
"mfa_level": 1,
|
||||
"explicit_content_filter": 2,
|
||||
"max_presences": 40000,
|
||||
"max_members": 250000,
|
||||
"vanity_url_code": "discord-testers",
|
||||
"premium_tier": 3,
|
||||
"premium_subscription_count": 33,
|
||||
"system_channel_flags": 0,
|
||||
"preferred_locale": "en-US",
|
||||
"rules_channel_id": "441688182833020939",
|
||||
"public_updates_channel_id": "281283303326089216",
|
||||
"safety_alerts_channel_id": "281283303326089216",
|
||||
"joined_at": "2024-06-27T11:59:36Z",
|
||||
"large": false,
|
||||
"member_count": 69,
|
||||
"voice_states": [
|
||||
{
|
||||
"channel_id": "157733188964188161",
|
||||
"user_id": "80351110224678912",
|
||||
"session_id": "90326bd25d71d39b9ef95b299e3872ff",
|
||||
"deaf": false,
|
||||
"mute": false,
|
||||
"self_deaf": false,
|
||||
"self_mute": true,
|
||||
"suppress": false,
|
||||
"request_to_speak_timestamp": "2021-03-31T18:45:31.297561+00:00"
|
||||
}
|
||||
],
|
||||
"members":[
|
||||
{
|
||||
"user": {
|
||||
"id": "80351110224678912",
|
||||
"username": "Nelly",
|
||||
"discriminator": "1337",
|
||||
"avatar": "8342729096ea3675442027381ff50dfe",
|
||||
"verified": true,
|
||||
"email": "nelly@discord.com",
|
||||
"flags": 64,
|
||||
"banner": "06c16474723fe537c283b8efa61a30c8",
|
||||
"accent_color": 16711680,
|
||||
"premium_type": 1,
|
||||
"public_flags": 64,
|
||||
"avatar_decoration_data": {
|
||||
"sku_id": "1144058844004233369",
|
||||
"asset": "a_fed43ab12698df65902ba06727e20c0e"
|
||||
}
|
||||
},
|
||||
"nick": "NOT API SUPPORT",
|
||||
"avatar": null,
|
||||
"roles": [],
|
||||
"joined_at": "2015-04-26T06:26:56.936000+00:00",
|
||||
"deaf": false,
|
||||
"mute": false
|
||||
}
|
||||
],
|
||||
"channels":[
|
||||
{
|
||||
"id": "41771983423143937",
|
||||
"guild_id": "197038439483310086",
|
||||
"name": "general",
|
||||
"type": 0,
|
||||
"position": 6,
|
||||
"permission_overwrites": [],
|
||||
"rate_limit_per_user": 2,
|
||||
"nsfw": true,
|
||||
"topic": "24/7 chat about how to gank Mike #2",
|
||||
"last_message_id": "155117677105512449",
|
||||
"parent_id": "399942396007890945",
|
||||
"default_auto_archive_duration": 60
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
GatewayPacket? gateway_packet = JsonSerializer.Deserialize(src, SourceGenerationContext.Default.GatewayPacket);
|
||||
Assert.IsType<GuildCreatePacket>(gateway_packet);
|
||||
Assert.IsType<GuildData>((gateway_packet as GuildCreatePacket)!.Data);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnavailableGuildCreateDeserialize()
|
||||
{
|
||||
string src = """
|
||||
{
|
||||
"op": 0,
|
||||
"t": "GUILD_CREATE",
|
||||
"s": 3,
|
||||
"d":{
|
||||
"id": "922243411795390566",
|
||||
"unavailable": true
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
GatewayPacket? packet =
|
||||
JsonSerializer.Deserialize<GatewayPacket>(src, SourceGenerationContext.Default.GatewayPacket);
|
||||
|
||||
Assert.IsType<GuildCreatePacket>(packet);
|
||||
Assert.IsType<UnavailableGuildData>(((GuildCreatePacket)packet).Data);
|
||||
Assert.True(packet is GuildCreatePacket
|
||||
{
|
||||
Data: UnavailableGuildData
|
||||
{
|
||||
Id: 922243411795390566,
|
||||
Unavailable: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InvalidSessionDeserialize()
|
||||
{
|
||||
|
||||
20
Discord.API/DataTypes/GuildData.cs
Normal file
20
Discord.API/DataTypes/GuildData.cs
Normal file
@ -0,0 +1,20 @@
|
||||
namespace Discord.API;
|
||||
|
||||
public class GuildData : UnavailableGuildData
|
||||
{
|
||||
public override bool Unavailable => false;
|
||||
public string? Name { get; init; }
|
||||
public ulong? AfkChannelId { get; init; }
|
||||
public int? AfkTimeout { get; init; }
|
||||
public RoleData[]? Roles { get; init; }
|
||||
public ulong? SystemChannelId { get; init; }
|
||||
public uint? SystemChannelFlags { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public 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; }
|
||||
}
|
||||
51
Discord.API/DataTypes/GuildDataConverter.cs
Normal file
51
Discord.API/DataTypes/GuildDataConverter.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Discord.API;
|
||||
|
||||
internal class GuildDataConverter : 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() ?? "")
|
||||
};
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
Discord.API/DataTypes/GuildMemberData.cs
Normal file
14
Discord.API/DataTypes/GuildMemberData.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Discord.API;
|
||||
|
||||
public class GuildMemberData
|
||||
{
|
||||
public UserData? User { get; init; }
|
||||
public string? Nick { get; init; }
|
||||
public ulong[]? Roles { get; init; }
|
||||
public DateTime? JoinedAt { get; init; }
|
||||
public bool? Deaf { get; init; }
|
||||
public bool? Mute { get; init; }
|
||||
//TODO: More fields
|
||||
}
|
||||
15
Discord.API/DataTypes/RoleData.cs
Normal file
15
Discord.API/DataTypes/RoleData.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Discord.API;
|
||||
|
||||
public class RoleData
|
||||
{
|
||||
[JsonRequired]
|
||||
public ulong Id { get; init; }
|
||||
public string? Name { get; init; }
|
||||
public uint? Color { get; init; }
|
||||
public bool? Hoist { get; init; }
|
||||
public int? Position { get; init; }
|
||||
public bool? Managed { get; init; }
|
||||
public bool? Mentionable { get; init; }
|
||||
}
|
||||
@ -2,8 +2,10 @@ using System.Text.Json.Serialization;
|
||||
|
||||
namespace Discord.API;
|
||||
|
||||
public sealed class UnavailableGuildData
|
||||
[JsonPolymorphic(UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor)]
|
||||
[JsonDerivedType(typeof(GuildData))]
|
||||
public class UnavailableGuildData
|
||||
{
|
||||
public required ulong Id { get; init; }
|
||||
public bool Unavailable { get; init; }
|
||||
public virtual bool Unavailable => true;
|
||||
}
|
||||
21
Discord.API/DataTypes/VoiceStateData.cs
Normal file
21
Discord.API/DataTypes/VoiceStateData.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Discord.API;
|
||||
|
||||
public class VoiceStateData
|
||||
{
|
||||
public ulong? GuildId { get; init; }
|
||||
public ulong? ChannelId { get; init; }
|
||||
[JsonRequired]
|
||||
public required ulong UserId { get; init; }
|
||||
public GuildMemberData? Member { get; init; }
|
||||
public string? SessionId { get; init; }
|
||||
public bool? Mute { get; init; }
|
||||
public bool? Deaf { get; init; }
|
||||
public bool? SelfMute { get; init; }
|
||||
public bool? SelfDeaf { get; init; }
|
||||
public bool? SelfStream { get; init; }
|
||||
public bool? SelfVideo { get; init; }
|
||||
public bool? Suppress { get; init; }
|
||||
public DateTime? RequestToSpeakTimestamp { get; init; }
|
||||
}
|
||||
@ -4,7 +4,7 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>api</RootNamespace>
|
||||
<RootNamespace>Discord.API</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@ -8,6 +8,7 @@ namespace Discord.API;
|
||||
[JsonDerivedType(typeof(ChannelUpdatePacket))]
|
||||
[JsonDerivedType(typeof(ChannelDeletePacket))]
|
||||
[JsonDerivedType(typeof(ReadyPacket))]
|
||||
[JsonDerivedType(typeof(GuildCreatePacket))]
|
||||
internal abstract class DispatchPacket : GatewayPacket
|
||||
{
|
||||
public override Opcode Op => Opcode.Dispatch;
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Discord.API;
|
||||
|
||||
internal class GuildCreatePacket : DispatchPacket
|
||||
{
|
||||
public override string Event => "GUILD_CREATE";
|
||||
[JsonRequired]
|
||||
[JsonPropertyName("d")]
|
||||
public required UnavailableGuildData Data { get; init; }
|
||||
}
|
||||
@ -52,6 +52,8 @@ internal class GatewayPacketConverter : JsonConverter<GatewayPacket>
|
||||
SourceGenerationContext.Default.ChannelUpdatePacket),
|
||||
"CHANNEL_DELETE" => json_doc.Deserialize(
|
||||
SourceGenerationContext.Default.ChannelDeletePacket),
|
||||
"GUILD_CREATE" => json_doc.Deserialize(
|
||||
SourceGenerationContext.Default.GuildCreatePacket),
|
||||
_ => throw new NotSupportedException($"Packet {event_name} is not supported in json deserialization")
|
||||
};
|
||||
default:
|
||||
|
||||
@ -10,7 +10,7 @@ using System.Text.Json;
|
||||
IgnoreReadOnlyProperties = false,
|
||||
IncludeFields = true,
|
||||
PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower,
|
||||
Converters = [typeof(GatewayPacketConverter)],
|
||||
Converters = [typeof(GatewayPacketConverter), typeof(GuildDataConverter)],
|
||||
NumberHandling = JsonNumberHandling.AllowReadingFromString
|
||||
)]
|
||||
[JsonSerializable(typeof(GatewayPacket))]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user