From 2b18bd8ae46beb381dc2e64a77016508ac3afe89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kecskem=C3=A9ti=20L=C3=A1szl=C3=B3?= Date: Wed, 26 Jun 2024 00:36:59 +0200 Subject: [PATCH] A lot more type definitions --- Discord.API.Tests/JsonTests.cs | 188 ++++++++++++++++-- Discord.API/DataTypes/ChannelData.cs | 22 +- .../DataTypes/PartialApplicationData.cs | 7 +- Discord.API/DataTypes/UnavailableGuildData.cs | 6 +- Discord.API/DataTypes/UserData.cs | 11 +- .../DispatchPacket/ChannelCreatePacket.cs | 4 +- .../DispatchPacket/ChannelDeletePacket.cs | 4 +- .../DispatchPacket/ChannelUpdatePacket.cs | 4 +- .../DispatchPacket/DispatchPacket.cs | 9 +- .../DispatchPacket/ReadyPacket.cs | 19 +- .../GatewayPacketTypes/GatewayPacket.cs | 13 +- .../GatewayPacketConverter.cs | 98 ++++----- .../GatewayPacketTypes/HeartbeatAckPacket.cs | 6 + .../GatewayPacketTypes/HeartbeatPacket.cs | 11 + Discord.API/GatewayPacketTypes/HelloPacket.cs | 18 ++ .../GatewayPacketTypes/IdentifyPacket.cs | 6 +- .../InvalidSessionPacket.cs | 10 + .../GatewayPacketTypes/ReconnectPacket.cs | 6 + .../GatewayPacketTypes/ResumePacket.cs | 23 +++ Discord.API/IDiscordApi.cs | 15 +- Discord.API/{ => Lifetime}/LifeTime.cs | 0 .../{ => Lifetime}/SingleEventLifeTime.cs | 0 22 files changed, 361 insertions(+), 119 deletions(-) create mode 100644 Discord.API/GatewayPacketTypes/HeartbeatAckPacket.cs create mode 100644 Discord.API/GatewayPacketTypes/HeartbeatPacket.cs create mode 100644 Discord.API/GatewayPacketTypes/HelloPacket.cs create mode 100644 Discord.API/GatewayPacketTypes/InvalidSessionPacket.cs create mode 100644 Discord.API/GatewayPacketTypes/ReconnectPacket.cs create mode 100644 Discord.API/GatewayPacketTypes/ResumePacket.cs rename Discord.API/{ => Lifetime}/LifeTime.cs (100%) rename Discord.API/{ => Lifetime}/SingleEventLifeTime.cs (100%) diff --git a/Discord.API.Tests/JsonTests.cs b/Discord.API.Tests/JsonTests.cs index b953b52..9f44e89 100644 --- a/Discord.API.Tests/JsonTests.cs +++ b/Discord.API.Tests/JsonTests.cs @@ -1,4 +1,7 @@ using System.Text.Json; +using Newtonsoft.Json; +using Xunit.Abstractions; +using JsonSerializer = System.Text.Json.JsonSerializer; namespace Discord.API.Tests; using Xunit; @@ -6,26 +9,132 @@ using Discord.API; public class JsonTests { - [Fact] - public void GatewayPacketEncodeJsonTest() - { - var gateway_packet = new GatewayPacket() - { - Op = GatewayPacket.Opcode.Heartbeat - }; + private readonly ITestOutputHelper _testOutputHelper; - string json = JsonSerializer.Serialize(gateway_packet, SourceGenerationContext.Default.GatewayPacket); - - Assert.Equal("""{"op":1}""", json); + public JsonTests(ITestOutputHelper testOutputHelper) + { + _testOutputHelper = testOutputHelper; } [Fact] - public void GatewayPacketDecodeTest() + public void InvalidSessionDeserialize() { - const string src = """{"op":1}"""; - var gateway_packet = - JsonSerializer.Deserialize(src, SourceGenerationContext.Default.GatewayPacket); - Assert.Equal(GatewayPacket.Opcode.Heartbeat, gateway_packet?.Op); + string src = """ + { + "op": 9 + } + """; + GatewayPacket? gateway_packet = JsonSerializer.Deserialize(src, SourceGenerationContext.Default.GatewayPacket); + Assert.IsType(gateway_packet); + } + + [Fact] + public void ReconnectPacketDeserialize() + { + string src = """ + { + "op": 7, + "d": null + } + """; + GatewayPacket? gateway_packet = JsonSerializer.Deserialize(src, SourceGenerationContext.Default.GatewayPacket); + + Assert.IsType(gateway_packet); + } + + [Fact] + public void ResumePacketSerialize() + { + ResumePacket gateway_packet = new() + { + Data = new() + { + Token = "tokenlol", + Sequence = 10, + SessionId = "sessionlol69" + } + }; + + string serialized = JsonSerializer.Serialize(gateway_packet, SourceGenerationContext.Default.GatewayPacket); + + _testOutputHelper.WriteLine($"Serilazed Resume packet: {serialized}"); + + //TODO: Verify the string + } + + [Fact] + public void HelloPacketDeserialize() + { + string src = """ + { + "op": 10, + "d": { + "heartbeat_interval": 45000 + } + } + """; + + GatewayPacket? gateway_packet = JsonSerializer.Deserialize(src, SourceGenerationContext.Default.GatewayPacket); + Assert.IsType(gateway_packet); + Assert.True(gateway_packet is HelloPacket + { + Op: GatewayPacket.Opcode.Hello, + Data.HeartbeatInterval: 45000 + }); + } + + [Fact] + public void HeartbeatAckDeserialize() + { + string src = """ + {"op":11} + """; + + GatewayPacket? gateway_packet = JsonSerializer.Deserialize(src, SourceGenerationContext.Default.GatewayPacket); + + Assert.IsType(gateway_packet); + Assert.Equal(GatewayPacket.Opcode.HeartbeatAck, gateway_packet.Op); + } + + [Fact] + public void HeartbeatPacketSerialize() + { + HeartbeatPacket heartbeat_packet = new() + { + Sequence = 69 + }; + string serialized = JsonSerializer.Serialize(heartbeat_packet, SourceGenerationContext.Default.GatewayPacket); + + JsonDocument json_doc = JsonDocument.Parse(serialized); + Assert.True(json_doc.RootElement.TryGetProperty("op", out var opcode) && + opcode.ValueKind == JsonValueKind.Number && + opcode.TryGetInt32(out int op) && op == (int)GatewayPacket.Opcode.Heartbeat); + + Assert.True(json_doc.RootElement.TryGetProperty("d", out var sequence) && + sequence.ValueKind == JsonValueKind.Number && + sequence.TryGetUInt64(out ulong seq) && seq == 69); + } + + [Fact] + public void IdentifyPacketSerialize() + { + IdentifyPacket identify_packet = new() + { + Data = new() + { + Token = "token_lol", + Intents = 6969, + Shard = [1, 2], + LargeThreshold = 42 + } + }; + + string serialized = + JsonSerializer.Serialize(identify_packet, SourceGenerationContext.Default.GatewayPacket); + + _testOutputHelper.WriteLine($"Serialized Identify packet: {serialized}"); + + //TODO: Test the output string } [Fact] @@ -146,4 +255,53 @@ public class JsonTests }); } + + [Fact] + public void ChannelUpdateDeserialize() + { + string src = """ + { + "op":0, + "t":"CHANNEL_UPDATE", + "s":1, + "d":{ + "id": "922243411795390570", + "type": 2, + "guild_id": "5678", + "position": 3, + "name": "voice csennel", + "topic": "A very interesting topic", + "nsfw": true, + "last_message_id":"6969", + "bitrate":420, + "parent_id": "5555" + } + } + """; + + var gateway_packet = + JsonSerializer.Deserialize(src, SourceGenerationContext.Default.GatewayPacket); + + Assert.IsType(gateway_packet); + + Assert.True(gateway_packet is ChannelUpdatePacket + { + Op: GatewayPacket.Opcode.Dispatch, + Event: "CHANNEL_UPDATE", + Sequence: 1, + Data: + { + Id: 922243411795390570, + Name: "voice csennel", + GuildId: 5678, + Type: 2, + Position: 3, + Topic: "A very interesting topic", + Nsfw: true, + Bitrate: 420, + ParentId: 5555, + LastMessageId: 6969 + } + }); + } } \ No newline at end of file diff --git a/Discord.API/DataTypes/ChannelData.cs b/Discord.API/DataTypes/ChannelData.cs index 6b74c0b..e48c17d 100644 --- a/Discord.API/DataTypes/ChannelData.cs +++ b/Discord.API/DataTypes/ChannelData.cs @@ -4,17 +4,15 @@ namespace Discord.API; public class ChannelData { - [JsonRequired] - public ulong Id; - [JsonRequired] - public int Type; - public ulong? GuildId; - public int? Position; - public string? Name; - public string? Topic; - public bool? Nsfw; - public ulong? LastMessageId; - public int? Bitrate; - public ulong? ParentId; + public required ulong Id { get; init; } + public int? Type { get; init; } + public ulong? GuildId { get; init; } + public int? Position { get; init; } + public string? Name { get; init; } + public string? Topic { get; init; } + public bool? Nsfw { get; init; } + public ulong? LastMessageId { get; init; } + public int? Bitrate { get; init; } + public ulong? ParentId { get; init; } //TODO: Missing fields } \ No newline at end of file diff --git a/Discord.API/DataTypes/PartialApplicationData.cs b/Discord.API/DataTypes/PartialApplicationData.cs index 2ca685d..f2539ed 100644 --- a/Discord.API/DataTypes/PartialApplicationData.cs +++ b/Discord.API/DataTypes/PartialApplicationData.cs @@ -4,9 +4,6 @@ namespace Discord.API; public sealed class PartialApplicationData { - [JsonRequired] - public ulong Id; - - [JsonRequired] - public ulong Flags; + public required ulong Id { get; init; } + public ulong Flags { get; init; } } \ No newline at end of file diff --git a/Discord.API/DataTypes/UnavailableGuildData.cs b/Discord.API/DataTypes/UnavailableGuildData.cs index dd698a2..debaad5 100644 --- a/Discord.API/DataTypes/UnavailableGuildData.cs +++ b/Discord.API/DataTypes/UnavailableGuildData.cs @@ -4,8 +4,6 @@ namespace Discord.API; public sealed class UnavailableGuildData { - [JsonRequired] - public ulong Id; - [JsonRequired] - public bool Unavailable; + public required ulong Id { get; init; } + public bool Unavailable { get; init; } } \ No newline at end of file diff --git a/Discord.API/DataTypes/UserData.cs b/Discord.API/DataTypes/UserData.cs index e5ba94f..506e679 100644 --- a/Discord.API/DataTypes/UserData.cs +++ b/Discord.API/DataTypes/UserData.cs @@ -5,12 +5,9 @@ namespace Discord.API; public sealed class UserData { - [JsonRequired] - public ulong Id; - [JsonRequired] - public string Username; - [JsonRequired] - public string Discriminator; - public string? GlobalName; + public required ulong Id { get; init; } + public string? Username { get; init; } + public string? Discriminator { get; init; } + public string? GlobalName { get; init; } //TODO More fields } \ No newline at end of file diff --git a/Discord.API/GatewayPacketTypes/DispatchPacket/ChannelCreatePacket.cs b/Discord.API/GatewayPacketTypes/DispatchPacket/ChannelCreatePacket.cs index 7f33064..837ba6e 100644 --- a/Discord.API/GatewayPacketTypes/DispatchPacket/ChannelCreatePacket.cs +++ b/Discord.API/GatewayPacketTypes/DispatchPacket/ChannelCreatePacket.cs @@ -5,7 +5,9 @@ namespace Discord.API; internal class ChannelCreatePacket : DispatchPacket { + public override string Event => "CHANNEL_CREATE"; + [JsonRequired] [JsonPropertyName("d")] - public ChannelData Data; + public required ChannelData Data { get; init; } } \ No newline at end of file diff --git a/Discord.API/GatewayPacketTypes/DispatchPacket/ChannelDeletePacket.cs b/Discord.API/GatewayPacketTypes/DispatchPacket/ChannelDeletePacket.cs index ea7ff8f..1fc4378 100644 --- a/Discord.API/GatewayPacketTypes/DispatchPacket/ChannelDeletePacket.cs +++ b/Discord.API/GatewayPacketTypes/DispatchPacket/ChannelDeletePacket.cs @@ -5,7 +5,9 @@ namespace Discord.API; internal class ChannelDeletePacket : DispatchPacket { + public override string Event => "CHANNEL_DELETE"; + [JsonRequired] [JsonPropertyName("d")] - public ChannelData Data; + public required ChannelData Data { get; init; } } \ No newline at end of file diff --git a/Discord.API/GatewayPacketTypes/DispatchPacket/ChannelUpdatePacket.cs b/Discord.API/GatewayPacketTypes/DispatchPacket/ChannelUpdatePacket.cs index f863ef4..2132e13 100644 --- a/Discord.API/GatewayPacketTypes/DispatchPacket/ChannelUpdatePacket.cs +++ b/Discord.API/GatewayPacketTypes/DispatchPacket/ChannelUpdatePacket.cs @@ -5,7 +5,9 @@ namespace Discord.API; internal class ChannelUpdatePacket : DispatchPacket { + public override string Event => "CHANNEL_UPDATE"; + [JsonRequired] [JsonPropertyName("d")] - public ChannelData Data; + public required ChannelData Data { get; init; } } \ No newline at end of file diff --git a/Discord.API/GatewayPacketTypes/DispatchPacket/DispatchPacket.cs b/Discord.API/GatewayPacketTypes/DispatchPacket/DispatchPacket.cs index a7ae7b5..aa833ea 100644 --- a/Discord.API/GatewayPacketTypes/DispatchPacket/DispatchPacket.cs +++ b/Discord.API/GatewayPacketTypes/DispatchPacket/DispatchPacket.cs @@ -3,16 +3,17 @@ using System.Text.Json.Serialization; namespace Discord.API; -[JsonPolymorphic(IgnoreUnrecognizedTypeDiscriminators = true, TypeDiscriminatorPropertyName = "t", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonPolymorphic(UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor)] [JsonDerivedType(typeof(ChannelCreatePacket))] [JsonDerivedType(typeof(ChannelUpdatePacket))] [JsonDerivedType(typeof(ChannelDeletePacket))] [JsonDerivedType(typeof(ReadyPacket))] -internal class DispatchPacket : GatewayPacket +internal abstract class DispatchPacket : GatewayPacket { + public override Opcode Op => Opcode.Dispatch; + [JsonPropertyName("t")] - [JsonRequired] - public string Event; + public abstract string Event { get; } [JsonPropertyName("s")] public ulong? Sequence; diff --git a/Discord.API/GatewayPacketTypes/DispatchPacket/ReadyPacket.cs b/Discord.API/GatewayPacketTypes/DispatchPacket/ReadyPacket.cs index 064ae15..6077fb0 100644 --- a/Discord.API/GatewayPacketTypes/DispatchPacket/ReadyPacket.cs +++ b/Discord.API/GatewayPacketTypes/DispatchPacket/ReadyPacket.cs @@ -1,5 +1,4 @@ using System.Text.Json.Serialization; -#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. namespace Discord.API; @@ -7,28 +6,30 @@ namespace Discord.API; [JsonDerivedType(typeof(ReadyPacket))] internal class ReadyPacket : DispatchPacket { - public sealed class ReadyData + public override string Event => "READY"; + public struct ReadyData { + [JsonRequired] [JsonPropertyName("v")] - public int Version; + public required int Version { get; init; } [JsonRequired] - public UserData User; + public required UserData User { get; init; } [JsonRequired] - public UnavailableGuildData[] Guilds; + public required UnavailableGuildData[] Guilds { get; init; } [JsonRequired] - public string SessionId; + public required string SessionId { get; init; } [JsonRequired] - public string ResumeGatewayUrl; + public required string ResumeGatewayUrl { get; init; } [JsonRequired] - public PartialApplicationData Application; + public required PartialApplicationData Application { get; init; } } [JsonRequired] [JsonPropertyName("d")] - public ReadyData Data; + public required ReadyData Data { get; init; } } \ No newline at end of file diff --git a/Discord.API/GatewayPacketTypes/GatewayPacket.cs b/Discord.API/GatewayPacketTypes/GatewayPacket.cs index cce0c8e..d4284eb 100644 --- a/Discord.API/GatewayPacketTypes/GatewayPacket.cs +++ b/Discord.API/GatewayPacketTypes/GatewayPacket.cs @@ -3,10 +3,16 @@ using System.Text.Json.Serialization; namespace Discord.API; -[JsonPolymorphic(IgnoreUnrecognizedTypeDiscriminators = true, TypeDiscriminatorPropertyName = "op", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonPolymorphic(UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor)] [JsonDerivedType(typeof(IdentifyPacket))] [JsonDerivedType(typeof(DispatchPacket))] -internal class GatewayPacket +[JsonDerivedType(typeof(HeartbeatPacket))] +[JsonDerivedType(typeof(HeartbeatAckPacket))] +[JsonDerivedType(typeof(HelloPacket))] +[JsonDerivedType(typeof(ResumePacket))] +[JsonDerivedType(typeof(ReconnectPacket))] +[JsonDerivedType(typeof(InvalidSessionPacket))] +public abstract class GatewayPacket { public enum Opcode { @@ -23,7 +29,6 @@ internal class GatewayPacket HeartbeatAck = 11 } - [JsonRequired] [JsonPropertyName("op")] - public Opcode Op; + public abstract Opcode Op { get; } } \ No newline at end of file diff --git a/Discord.API/GatewayPacketTypes/GatewayPacketConverter.cs b/Discord.API/GatewayPacketTypes/GatewayPacketConverter.cs index 33128c8..906eced 100644 --- a/Discord.API/GatewayPacketTypes/GatewayPacketConverter.cs +++ b/Discord.API/GatewayPacketTypes/GatewayPacketConverter.cs @@ -1,3 +1,4 @@ +using System.Reflection.Emit; using System.Text.Json; using System.Text.Json.Serialization; @@ -8,53 +9,54 @@ internal class GatewayPacketConverter : JsonConverter public override GatewayPacket? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { JsonDocument json_doc = JsonDocument.ParseValue(ref reader); - if(json_doc.RootElement.TryGetProperty("op", out JsonElement opcode_element)) - { - if (opcode_element.ValueKind != JsonValueKind.Number) - { - throw new JsonException("Opcode is not a number"); - } - - GatewayPacket.Opcode op = (GatewayPacket.Opcode)opcode_element.GetInt32(); - - switch (op) - { - case GatewayPacket.Opcode.Dispatch: - if (json_doc.RootElement.TryGetProperty("t", out JsonElement event_element)) - { - if (event_element.ValueKind != JsonValueKind.String) - { - throw new Exception("Event name not string"); - } - - string? event_name = event_element.GetString(); - switch (event_name) - { - case "READY": - return json_doc.Deserialize(SourceGenerationContext.Default.ReadyPacket); - case "CHANNEL_CREATE": - return json_doc.Deserialize(SourceGenerationContext.Default - .ChannelCreatePacket); - case "CHANNEL_UPDATE": - return json_doc.Deserialize(SourceGenerationContext.Default.ChannelUpdatePacket); - case "CHANNEL_DELETE": - return json_doc.Deserialize(SourceGenerationContext.Default.ChannelDeletePacket); - default: - throw new NotSupportedException($"Packet {event_name} is not supported"); - } - } - else - { - throw new JsonException("Event name not found"); - } - default: - throw new NotSupportedException($"Opcode {op} is not supported in json deserialization"); - } - } - else + if (!json_doc.RootElement.TryGetProperty("op", out JsonElement opcode_element)) { throw new Exception("Opcode not found"); } + + if (opcode_element.ValueKind != JsonValueKind.Number) + { + throw new JsonException("Opcode is not a number"); + } + + GatewayPacket.Opcode op = (GatewayPacket.Opcode)opcode_element.GetInt32(); + + switch (op) + { + case GatewayPacket.Opcode.HeartbeatAck: + return json_doc.Deserialize(SourceGenerationContext.Default.HeartbeatAckPacket); + case GatewayPacket.Opcode.Hello: + return json_doc.Deserialize(SourceGenerationContext.Default.HelloPacket); + case GatewayPacket.Opcode.Reconnect: + return json_doc.Deserialize(SourceGenerationContext.Default.ReconnectPacket); + case GatewayPacket.Opcode.InvalidSession: + return json_doc.Deserialize(SourceGenerationContext.Default.InvalidSessionPacket); + case GatewayPacket.Opcode.Dispatch: + if (!json_doc.RootElement.TryGetProperty("t", out JsonElement event_element)) + { + throw new JsonException("Event name not found"); + } + + if (event_element.ValueKind != JsonValueKind.String) + { + throw new Exception("Event name not string"); + } + + string? event_name = event_element.GetString(); + return event_name switch + { + "READY" => json_doc.Deserialize(SourceGenerationContext.Default.ReadyPacket), + "CHANNEL_CREATE" => json_doc.Deserialize( + SourceGenerationContext.Default.ChannelCreatePacket), + "CHANNEL_UPDATE" => json_doc.Deserialize( + SourceGenerationContext.Default.ChannelUpdatePacket), + "CHANNEL_DELETE" => json_doc.Deserialize( + SourceGenerationContext.Default.ChannelDeletePacket), + _ => throw new NotSupportedException($"Packet {event_name} is not supported in json deserialization") + }; + default: + throw new NotSupportedException($"Opcode {op} is not supported in json deserialization"); + } } public override void Write(Utf8JsonWriter writer, GatewayPacket value, JsonSerializerOptions options) @@ -64,8 +66,14 @@ internal class GatewayPacketConverter : JsonConverter case IdentifyPacket id_packet: writer.WriteRawValue(JsonSerializer.SerializeToUtf8Bytes(id_packet, SourceGenerationContext.Default.IdentifyPacket)); break; + case HeartbeatPacket heartbeat_packet: + writer.WriteRawValue(JsonSerializer.SerializeToUtf8Bytes(heartbeat_packet, SourceGenerationContext.Default.HeartbeatPacket)); + break; + case ResumePacket resume_packet: + writer.WriteRawValue(JsonSerializer.SerializeToUtf8Bytes(value, SourceGenerationContext.Default.ResumePacket)); + break; default: - writer.WriteRawValue(JsonSerializer.SerializeToUtf8Bytes(value, SourceGenerationContext.Default.IdentifyPacket)); + writer.WriteRawValue(JsonSerializer.SerializeToUtf8Bytes(value, SourceGenerationContext.Default.GatewayPacket)); break; } } diff --git a/Discord.API/GatewayPacketTypes/HeartbeatAckPacket.cs b/Discord.API/GatewayPacketTypes/HeartbeatAckPacket.cs new file mode 100644 index 0000000..d879dc4 --- /dev/null +++ b/Discord.API/GatewayPacketTypes/HeartbeatAckPacket.cs @@ -0,0 +1,6 @@ +namespace Discord.API; + +internal class HeartbeatAckPacket : GatewayPacket +{ + public override Opcode Op => Opcode.HeartbeatAck; +} \ No newline at end of file diff --git a/Discord.API/GatewayPacketTypes/HeartbeatPacket.cs b/Discord.API/GatewayPacketTypes/HeartbeatPacket.cs new file mode 100644 index 0000000..60252af --- /dev/null +++ b/Discord.API/GatewayPacketTypes/HeartbeatPacket.cs @@ -0,0 +1,11 @@ +using System.Text.Json.Serialization; + +namespace Discord.API; + +internal class HeartbeatPacket : GatewayPacket +{ + public override Opcode Op => Opcode.Heartbeat; + [JsonRequired] + [JsonPropertyName("d")] + public required ulong? Sequence { get; init; } +} \ No newline at end of file diff --git a/Discord.API/GatewayPacketTypes/HelloPacket.cs b/Discord.API/GatewayPacketTypes/HelloPacket.cs new file mode 100644 index 0000000..65c5a8f --- /dev/null +++ b/Discord.API/GatewayPacketTypes/HelloPacket.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace Discord.API; + +internal class HelloPacket : GatewayPacket +{ + public override Opcode Op => Opcode.Hello; + + public struct HelloData + { + [JsonRequired] + public uint HeartbeatInterval { init; get; } + } + + [JsonRequired] + [JsonPropertyName("d")] + public HelloData Data { init; get; } +} \ No newline at end of file diff --git a/Discord.API/GatewayPacketTypes/IdentifyPacket.cs b/Discord.API/GatewayPacketTypes/IdentifyPacket.cs index 8250d04..bd40e7f 100644 --- a/Discord.API/GatewayPacketTypes/IdentifyPacket.cs +++ b/Discord.API/GatewayPacketTypes/IdentifyPacket.cs @@ -5,8 +5,10 @@ namespace Discord.API; internal class IdentifyPacket : GatewayPacket { - public sealed class IdentifyData + public override Opcode Op => Opcode.Identify; + public struct IdentifyData { + public IdentifyData() { } public class PropertiesClass { public string Os => Environment.OSVersion.ToString(); @@ -27,10 +29,12 @@ internal class IdentifyPacket : GatewayPacket public int LargeThreshold = 250; public int[]? Shard = null; //presence + [JsonRequired] public required ulong Intents { get; init; } } [JsonPropertyName("d")] + [JsonRequired] public required IdentifyData Data { get; init; } } \ No newline at end of file diff --git a/Discord.API/GatewayPacketTypes/InvalidSessionPacket.cs b/Discord.API/GatewayPacketTypes/InvalidSessionPacket.cs new file mode 100644 index 0000000..c609a35 --- /dev/null +++ b/Discord.API/GatewayPacketTypes/InvalidSessionPacket.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace Discord.API; + +internal class InvalidSessionPacket : GatewayPacket +{ + public override Opcode Op => Opcode.InvalidSession; + [JsonPropertyName("d")] + public bool? Reconnect { get; init; } +} \ No newline at end of file diff --git a/Discord.API/GatewayPacketTypes/ReconnectPacket.cs b/Discord.API/GatewayPacketTypes/ReconnectPacket.cs new file mode 100644 index 0000000..d5c0dd2 --- /dev/null +++ b/Discord.API/GatewayPacketTypes/ReconnectPacket.cs @@ -0,0 +1,6 @@ +namespace Discord.API; + +internal class ReconnectPacket : GatewayPacket +{ + public override Opcode Op => Opcode.Reconnect; +} \ No newline at end of file diff --git a/Discord.API/GatewayPacketTypes/ResumePacket.cs b/Discord.API/GatewayPacketTypes/ResumePacket.cs new file mode 100644 index 0000000..5894f35 --- /dev/null +++ b/Discord.API/GatewayPacketTypes/ResumePacket.cs @@ -0,0 +1,23 @@ +using System.Text.Json.Serialization; + +namespace Discord.API; + +internal class ResumePacket : GatewayPacket +{ + public override Opcode Op => Opcode.Resume; + + public struct ResumeData + { + [JsonRequired] + public required string Token { get; init; } + [JsonRequired] + public required string SessionId { get; init; } + [JsonRequired] + [JsonPropertyName("seq")] + public required ulong Sequence { get; init; } + } + + [JsonRequired] + [JsonPropertyName("d")] + public required ResumeData Data { get; init; } +} \ No newline at end of file diff --git a/Discord.API/IDiscordApi.cs b/Discord.API/IDiscordApi.cs index 8929dd2..d6beb2f 100644 --- a/Discord.API/IDiscordApi.cs +++ b/Discord.API/IDiscordApi.cs @@ -5,16 +5,11 @@ public interface IDiscordApi public void OpenConnection(); public void Close(); - public delegate void DiscordEventHandler(IDiscordApi sender, T data, LifeTime lifetime); + public delegate void DiscordEventHandler(IDiscordApi sender, T data); + + public event DiscordEventHandler? OnPacketReceived; + + public void SendPacket(GatewayPacket packet); - /*public event DiscordEventHandler? OnReady; - public event DiscordEventHandler? OnChannelCreate; - public event DiscordEventHandler? OnChannelUpdate; - public event DiscordEventHandler? OnChannelDelete; - public event DiscordEventHandler? OnGuildCreate; - public event DiscordEventHandler? OnGuildUpdate; - public event DiscordEventHandler? OnGuildDelete;*/ - - } \ No newline at end of file diff --git a/Discord.API/LifeTime.cs b/Discord.API/Lifetime/LifeTime.cs similarity index 100% rename from Discord.API/LifeTime.cs rename to Discord.API/Lifetime/LifeTime.cs diff --git a/Discord.API/SingleEventLifeTime.cs b/Discord.API/Lifetime/SingleEventLifeTime.cs similarity index 100% rename from Discord.API/SingleEventLifeTime.cs rename to Discord.API/Lifetime/SingleEventLifeTime.cs