| @@ -1,20 +0,0 @@ | |||||
| //Ignore unused/unassigned variable warnings | |||||
| #pragma warning disable CS0649 | |||||
| #pragma warning disable CS0169 | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API | |||||
| { | |||||
| internal sealed class VoiceServerUpdateEvent | |||||
| { | |||||
| [JsonProperty("guild_id")] | |||||
| [JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong ServerId; | |||||
| [JsonProperty("endpoint")] | |||||
| public string Endpoint; | |||||
| [JsonProperty("token")] | |||||
| public string Token; | |||||
| } | |||||
| } | |||||
| @@ -1,111 +0,0 @@ | |||||
| //Ignore unused/unassigned variable warnings | |||||
| #pragma warning disable CS0649 | |||||
| #pragma warning disable CS0169 | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API | |||||
| { | |||||
| public enum VoiceOpCodes : byte | |||||
| { | |||||
| /// <summary> Client --> Server - Used to associate a connection with a token. </summary> | |||||
| Identify = 0, | |||||
| /// <summary> Client --> Server - Used to specify configuration. </summary> | |||||
| SelectProtocol = 1, | |||||
| /// <summary> Client <-- Server - Used to notify that the voice connection was successful and informs the client of available protocols. </summary> | |||||
| Ready = 2, | |||||
| /// <summary> Client <-> Server - Used to keep the connection alive and measure latency. </summary> | |||||
| Heartbeat = 3, | |||||
| /// <summary> Client <-- Server - Used to provide an encryption key to the client. </summary> | |||||
| SessionDescription = 4, | |||||
| /// <summary> Client <-> Server - Used to inform that a certain user is speaking. </summary> | |||||
| Speaking = 5 | |||||
| } | |||||
| //Commands | |||||
| internal sealed class IdentifyCommand : WebSocketMessage<IdentifyCommand.Data> | |||||
| { | |||||
| public IdentifyCommand() : base((int)VoiceOpCodes.Identify) { } | |||||
| public class Data | |||||
| { | |||||
| [JsonProperty("server_id")] | |||||
| [JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong ServerId; | |||||
| [JsonProperty("user_id")] | |||||
| [JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong UserId; | |||||
| [JsonProperty("session_id")] | |||||
| public string SessionId; | |||||
| [JsonProperty("token")] | |||||
| public string Token; | |||||
| } | |||||
| } | |||||
| internal sealed class SelectProtocolCommand : WebSocketMessage<SelectProtocolCommand.Data> | |||||
| { | |||||
| public SelectProtocolCommand() : base((int)VoiceOpCodes.SelectProtocol) { } | |||||
| public class Data | |||||
| { | |||||
| public class SocketInfo | |||||
| { | |||||
| [JsonProperty("address")] | |||||
| public string Address; | |||||
| [JsonProperty("port")] | |||||
| public int Port; | |||||
| [JsonProperty("mode")] | |||||
| public string Mode = "xsalsa20_poly1305"; | |||||
| } | |||||
| [JsonProperty("protocol")] | |||||
| public string Protocol = "udp"; | |||||
| [JsonProperty("data")] | |||||
| public SocketInfo SocketData = new SocketInfo(); | |||||
| } | |||||
| } | |||||
| internal sealed class HeartbeatCommand : WebSocketMessage<long> | |||||
| { | |||||
| public HeartbeatCommand() : base((int)VoiceOpCodes.Heartbeat, EpochTime.GetMilliseconds()) { } | |||||
| } | |||||
| internal sealed class SpeakingCommand : WebSocketMessage<SpeakingCommand.Data> | |||||
| { | |||||
| public SpeakingCommand() : base((int)VoiceOpCodes.Speaking) { } | |||||
| public class Data | |||||
| { | |||||
| [JsonProperty("delay")] | |||||
| public int Delay; | |||||
| [JsonProperty("speaking")] | |||||
| public bool IsSpeaking; | |||||
| } | |||||
| } | |||||
| //Events | |||||
| public class VoiceReadyEvent | |||||
| { | |||||
| [JsonProperty("ssrc")] | |||||
| public uint SSRC; | |||||
| [JsonProperty("port")] | |||||
| public ushort Port; | |||||
| [JsonProperty("modes")] | |||||
| public string[] Modes; | |||||
| [JsonProperty("heartbeat_interval")] | |||||
| public int HeartbeatInterval; | |||||
| } | |||||
| public class JoinServerEvent | |||||
| { | |||||
| [JsonProperty("secret_key")] | |||||
| public byte[] SecretKey; | |||||
| [JsonProperty("mode")] | |||||
| public string Mode; | |||||
| } | |||||
| public class IsTalkingEvent | |||||
| { | |||||
| [JsonProperty("user_id")] | |||||
| [JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong UserId; | |||||
| [JsonProperty("ssrc")] | |||||
| public uint SSRC; | |||||
| [JsonProperty("speaking")] | |||||
| public bool IsSpeaking; | |||||
| } | |||||
| } | |||||
| @@ -7,7 +7,7 @@ | |||||
| <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" /> | <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" /> | ||||
| <PropertyGroup Label="Globals"> | <PropertyGroup Label="Globals"> | ||||
| <ProjectGuid>dff7afe3-ca77-4109-bade-b4b49a4f6648</ProjectGuid> | <ProjectGuid>dff7afe3-ca77-4109-bade-b4b49a4f6648</ProjectGuid> | ||||
| <RootNamespace>Discord.Audio</RootNamespace> | |||||
| <RootNamespace>Discord</RootNamespace> | |||||
| <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath> | <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath> | ||||
| <OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath> | <OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath> | ||||
| </PropertyGroup> | </PropertyGroup> | ||||
| @@ -1,4 +1,5 @@ | |||||
| using Discord.API; | using Discord.API; | ||||
| using Discord.API.Client.GatewaySocket; | |||||
| using Discord.Net.WebSockets; | using Discord.Net.WebSockets; | ||||
| using System; | using System; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| @@ -76,7 +77,7 @@ namespace Discord.Audio | |||||
| case "VOICE_SERVER_UPDATE": | case "VOICE_SERVER_UPDATE": | ||||
| { | { | ||||
| var data = e.Payload.ToObject<VoiceServerUpdateEvent>(_gatewaySocket.Serializer); | var data = e.Payload.ToObject<VoiceServerUpdateEvent>(_gatewaySocket.Serializer); | ||||
| var serverId = data.ServerId; | |||||
| var serverId = data.GuildId; | |||||
| if (serverId == ServerId) | if (serverId == ServerId) | ||||
| { | { | ||||
| @@ -96,10 +97,6 @@ namespace Discord.Audio | |||||
| }; | }; | ||||
| } | } | ||||
| public Task Disconnect() | |||||
| { | |||||
| return _voiceSocket.Disconnect(); | |||||
| } | |||||
| internal void SetServerId(ulong serverId) | internal void SetServerId(ulong serverId) | ||||
| { | { | ||||
| @@ -115,14 +112,17 @@ namespace Discord.Audio | |||||
| await _voiceSocket.Disconnect().ConfigureAwait(false); | await _voiceSocket.Disconnect().ConfigureAwait(false); | ||||
| _voiceSocket.ChannelId = channel.Id; | _voiceSocket.ChannelId = channel.Id; | ||||
| _gatewaySocket.SendJoinVoice(channel.Server.Id, channel.Id); | |||||
| _gatewaySocket.SendUpdateVoice(channel.Server.Id, channel.Id, | |||||
| (_service.Config.Mode | AudioMode.Outgoing) == 0, | |||||
| (_service.Config.Mode | AudioMode.Incoming) == 0); | |||||
| await _voiceSocket.WaitForConnection(_service.Config.ConnectionTimeout).ConfigureAwait(false); | await _voiceSocket.WaitForConnection(_service.Config.ConnectionTimeout).ConfigureAwait(false); | ||||
| } | |||||
| } | |||||
| public Task Disconnect() => _voiceSocket.Disconnect(); | |||||
| /// <summary> Sends a PCM frame to the voice server. Will block until space frees up in the outgoing buffer. </summary> | |||||
| /// <param name="data">PCM frame to send. This must be a single or collection of uncompressed 48Kz monochannel 20ms PCM frames. </param> | |||||
| /// <param name="count">Number of bytes in this frame. </param> | |||||
| public void Send(byte[] data, int count) | |||||
| /// <summary> Sends a PCM frame to the voice server. Will block until space frees up in the outgoing buffer. </summary> | |||||
| /// <param name="data">PCM frame to send. This must be a single or collection of uncompressed 48Kz monochannel 20ms PCM frames. </param> | |||||
| /// <param name="count">Number of bytes in this frame. </param> | |||||
| public void Send(byte[] data, int count) | |||||
| { | { | ||||
| if (data == null) throw new ArgumentException(nameof(data)); | if (data == null) throw new ArgumentException(nameof(data)); | ||||
| if (count < 0) throw new ArgumentOutOfRangeException(nameof(count)); | if (count < 0) throw new ArgumentOutOfRangeException(nameof(count)); | ||||
| @@ -1,4 +1,6 @@ | |||||
| using Discord.API; | using Discord.API; | ||||
| using Discord.API.Client; | |||||
| using Discord.API.Client.VoiceSocket; | |||||
| using Discord.Audio; | using Discord.Audio; | ||||
| using Discord.Audio.Opus; | using Discord.Audio.Opus; | ||||
| using Discord.Audio.Sodium; | using Discord.Audio.Sodium; | ||||
| @@ -394,14 +396,14 @@ namespace Discord.Net.WebSockets | |||||
| { | { | ||||
| await base.ProcessMessage(json).ConfigureAwait(false); | await base.ProcessMessage(json).ConfigureAwait(false); | ||||
| var msg = JsonConvert.DeserializeObject<WebSocketMessage>(json); | var msg = JsonConvert.DeserializeObject<WebSocketMessage>(json); | ||||
| var opCode = (VoiceOpCodes)msg.Operation; | |||||
| var opCode = (OpCodes)msg.Operation; | |||||
| switch (opCode) | switch (opCode) | ||||
| { | { | ||||
| case VoiceOpCodes.Ready: | |||||
| case OpCodes.Ready: | |||||
| { | { | ||||
| if (_state != ConnectionState.Connected) | if (_state != ConnectionState.Connected) | ||||
| { | { | ||||
| var payload = (msg.Payload as JToken).ToObject<VoiceReadyEvent>(_serializer); | |||||
| var payload = (msg.Payload as JToken).ToObject<ReadyEvent>(_serializer); | |||||
| _heartbeatInterval = payload.HeartbeatInterval; | _heartbeatInterval = payload.HeartbeatInterval; | ||||
| _ssrc = payload.SSRC; | _ssrc = payload.SSRC; | ||||
| var address = (await Dns.GetHostAddressesAsync(Host.Replace("wss://", "")).ConfigureAwait(false)).FirstOrDefault(); | var address = (await Dns.GetHostAddressesAsync(Host.Replace("wss://", "")).ConfigureAwait(false)).FirstOrDefault(); | ||||
| @@ -435,7 +437,7 @@ namespace Discord.Net.WebSockets | |||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| case VoiceOpCodes.Heartbeat: | |||||
| case OpCodes.Heartbeat: | |||||
| { | { | ||||
| long time = EpochTime.GetMilliseconds(); | long time = EpochTime.GetMilliseconds(); | ||||
| var payload = (long)msg.Payload; | var payload = (long)msg.Payload; | ||||
| @@ -443,17 +445,17 @@ namespace Discord.Net.WebSockets | |||||
| //TODO: Use this to estimate latency | //TODO: Use this to estimate latency | ||||
| } | } | ||||
| break; | break; | ||||
| case VoiceOpCodes.SessionDescription: | |||||
| case OpCodes.SessionDescription: | |||||
| { | { | ||||
| var payload = (msg.Payload as JToken).ToObject<JoinServerEvent>(_serializer); | |||||
| var payload = (msg.Payload as JToken).ToObject<SessionDescriptionEvent>(_serializer); | |||||
| _secretKey = payload.SecretKey; | _secretKey = payload.SecretKey; | ||||
| SendIsTalking(true); | |||||
| SendSetSpeaking(true); | |||||
| EndConnect(); | EndConnect(); | ||||
| } | } | ||||
| break; | break; | ||||
| case VoiceOpCodes.Speaking: | |||||
| case OpCodes.Speaking: | |||||
| { | { | ||||
| var payload = (msg.Payload as JToken).ToObject<IsTalkingEvent>(_serializer); | |||||
| var payload = (msg.Payload as JToken).ToObject<SpeakingEvent>(_serializer); | |||||
| RaiseIsSpeaking(payload.UserId, payload.IsSpeaking); | RaiseIsSpeaking(payload.UserId, payload.IsSpeaking); | ||||
| } | } | ||||
| break; | break; | ||||
| @@ -493,37 +495,14 @@ namespace Discord.Net.WebSockets | |||||
| }); | }); | ||||
| } | } | ||||
| public void SendIdentify() | |||||
| { | |||||
| var msg = new IdentifyCommand(); | |||||
| msg.Payload.ServerId = _serverId.Value; | |||||
| msg.Payload.SessionId = _client.SessionId; | |||||
| msg.Payload.Token = _audioClient.Token; | |||||
| msg.Payload.UserId = _client.UserId.Value; | |||||
| QueueMessage(msg); | |||||
| } | |||||
| public void SendSelectProtocol(string externalIp, int externalPort) | |||||
| { | |||||
| var msg = new SelectProtocolCommand(); | |||||
| msg.Payload.Protocol = "udp"; | |||||
| msg.Payload.SocketData.Address = externalIp; | |||||
| msg.Payload.SocketData.Mode = _encryptionMode; | |||||
| msg.Payload.SocketData.Port = externalPort; | |||||
| QueueMessage(msg); | |||||
| } | |||||
| public override void SendHeartbeat() | |||||
| => QueueMessage(new HeartbeatCommand()); | |||||
| public void SendIdentify() | |||||
| => QueueMessage(new IdentifyCommand { GuildId = _serverId.Value, UserId = _client.UserId.Value, SessionId = _client.SessionId, Token = _audioClient.Token }); | |||||
| public void SendSelectProtocol(string externalAddress, int externalPort) | |||||
| => QueueMessage(new SelectProtocolCommand { Protocol = "udp", ExternalAddress = externalAddress, ExternalPort = externalPort, EncryptionMode = _encryptionMode }); | |||||
| public void SendSetSpeaking(bool value) | |||||
| => QueueMessage(new SetSpeakingCommand { IsSpeaking = value, Delay = 0 }); | |||||
| public void SendIsTalking(bool value) | |||||
| { | |||||
| var isTalking = new SpeakingCommand(); | |||||
| isTalking.Payload.IsSpeaking = value; | |||||
| isTalking.Payload.Delay = 0; | |||||
| QueueMessage(isTalking); | |||||
| } | |||||
| public override void SendHeartbeat() | |||||
| { | |||||
| QueueMessage(new HeartbeatCommand()); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,34 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client | |||||
| { | |||||
| public class Channel : ChannelReference | |||||
| { | |||||
| public sealed class PermissionOverwrite | |||||
| { | |||||
| [JsonProperty("type")] | |||||
| public string Type { get; set; } | |||||
| [JsonProperty("id")] | |||||
| [JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong Id { get; set; } | |||||
| [JsonProperty("deny")] | |||||
| public uint Deny { get; set; } | |||||
| [JsonProperty("allow")] | |||||
| public uint Allow { get; set; } | |||||
| } | |||||
| [JsonProperty("last_message_id"), JsonConverter(typeof(NullableLongStringConverter))] | |||||
| public ulong LastMessageId { get; set; } | |||||
| [JsonProperty("is_private")] | |||||
| public bool IsPrivate { get; set; } | |||||
| [JsonProperty("position")] | |||||
| public int Position { get; set; } | |||||
| [JsonProperty("topic")] | |||||
| public string Topic { get; set; } | |||||
| [JsonProperty("permission_overwrites")] | |||||
| public PermissionOverwrite[] PermissionOverwrites { get; set; } | |||||
| [JsonProperty("recipient")] | |||||
| public UserReference Recipient { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,17 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client | |||||
| { | |||||
| public class ChannelReference | |||||
| { | |||||
| [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong Id { get; set; } | |||||
| [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong GuildId { get; set; } | |||||
| [JsonProperty("name")] | |||||
| public string Name { get; set; } | |||||
| [JsonProperty("type")] | |||||
| public string Type { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,26 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client | |||||
| { | |||||
| public class ExtendedGuild : Guild | |||||
| { | |||||
| public sealed class ExtendedMemberInfo : Member | |||||
| { | |||||
| [JsonProperty("mute")] | |||||
| public bool? IsServerMuted { get; set; } | |||||
| [JsonProperty("deaf")] | |||||
| public bool? IsServerDeafened { get; set; } | |||||
| } | |||||
| [JsonProperty("channels")] | |||||
| public Channel[] Channels { get; set; } | |||||
| [JsonProperty("members")] | |||||
| public ExtendedMemberInfo[] Members { get; set; } | |||||
| [JsonProperty("presences")] | |||||
| public MemberPresence[] Presences { get; set; } | |||||
| [JsonProperty("voice_states")] | |||||
| public MemberVoiceState[] VoiceStates { get; set; } | |||||
| [JsonProperty("unavailable")] | |||||
| public bool? Unavailable { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,28 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| using System; | |||||
| namespace Discord.API.Client | |||||
| { | |||||
| public class Guild : GuildReference | |||||
| { | |||||
| [JsonProperty("afk_channel_id"), JsonConverter(typeof(NullableLongStringConverter))] | |||||
| public ulong? AFKChannelId { get; set; } | |||||
| [JsonProperty("afk_timeout")] | |||||
| public int? AFKTimeout { get; set; } | |||||
| [JsonProperty("embed_channel_id"), JsonConverter(typeof(NullableLongStringConverter))] | |||||
| public ulong? EmbedChannelId { get; set; } | |||||
| [JsonProperty("embed_enabled")] | |||||
| public bool EmbedEnabled { get; set; } | |||||
| [JsonProperty("icon")] | |||||
| public string Icon { get; set; } | |||||
| [JsonProperty("joined_at")] | |||||
| public DateTime? JoinedAt { get; set; } | |||||
| [JsonProperty("owner_id"), JsonConverter(typeof(NullableLongStringConverter))] | |||||
| public ulong? OwnerId { get; set; } | |||||
| [JsonProperty("region")] | |||||
| public string Region { get; set; } | |||||
| [JsonProperty("roles")] | |||||
| public Role[] Roles { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,13 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client | |||||
| { | |||||
| public class GuildReference | |||||
| { | |||||
| [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong Id { get; set; } | |||||
| [JsonProperty("name")] | |||||
| public string Name { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,23 @@ | |||||
| using Newtonsoft.Json; | |||||
| using System; | |||||
| namespace Discord.API.Client | |||||
| { | |||||
| public class Invite : InviteReference | |||||
| { | |||||
| [JsonProperty("max_age")] | |||||
| public int? MaxAge { get; set; } | |||||
| [JsonProperty("max_uses")] | |||||
| public int? MaxUses { get; set; } | |||||
| [JsonProperty("revoked")] | |||||
| public bool? IsRevoked { get; set; } | |||||
| [JsonProperty("temporary")] | |||||
| public bool? IsTemporary { get; set; } | |||||
| [JsonProperty("uses")] | |||||
| public int? Uses { get; set; } | |||||
| [JsonProperty("created_at")] | |||||
| public DateTime? CreatedAt { get; set; } | |||||
| [JsonProperty("inviter")] | |||||
| public UserReference Inviter { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,16 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client | |||||
| { | |||||
| public class InviteReference | |||||
| { | |||||
| [JsonProperty("guild")] | |||||
| public GuildReference Guild { get; set; } | |||||
| [JsonProperty("channel")] | |||||
| public ChannelReference Channel { get; set; } | |||||
| [JsonProperty("code")] | |||||
| public string Code { get; set; } | |||||
| [JsonProperty("xkcdpass")] | |||||
| public string XkcdPass { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,14 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| using System; | |||||
| namespace Discord.API.Client | |||||
| { | |||||
| public class Member : MemberReference | |||||
| { | |||||
| [JsonProperty("joined_at")] | |||||
| public DateTime? JoinedAt { get; set; } | |||||
| [JsonProperty("roles"), JsonConverter(typeof(LongStringArrayConverter))] | |||||
| public ulong[] Roles { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,15 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client | |||||
| { | |||||
| public class MemberPresence : MemberReference | |||||
| { | |||||
| [JsonProperty("game_id")] | |||||
| public int? GameId { get; set; } | |||||
| [JsonProperty("status")] | |||||
| public string Status { get; set; } | |||||
| [JsonProperty("roles"), JsonConverter(typeof(LongStringArrayConverter))] | |||||
| public ulong[] Roles { get; set; } //TODO: Might be temporary | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,13 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client | |||||
| { | |||||
| public class MemberReference | |||||
| { | |||||
| [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong GuildId { get; set; } | |||||
| [JsonProperty("user")] | |||||
| public UserReference User { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,26 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client | |||||
| { | |||||
| public class MemberVoiceState : MemberReference | |||||
| { | |||||
| [JsonProperty("channel_id"), JsonConverter(typeof(NullableLongStringConverter))] | |||||
| public ulong? ChannelId { get; set; } | |||||
| [JsonProperty("session_id")] | |||||
| public string SessionId { get; set; } | |||||
| [JsonProperty("token")] | |||||
| public string Token { get; set; } | |||||
| [JsonProperty("self_mute")] | |||||
| public bool? IsSelfMuted { get; set; } | |||||
| [JsonProperty("self_deaf")] | |||||
| public bool? IsSelfDeafened { get; set; } | |||||
| [JsonProperty("mute")] | |||||
| public bool? IsServerMuted { get; set; } | |||||
| [JsonProperty("deaf")] | |||||
| public bool? IsServerDeafened { get; set; } | |||||
| [JsonProperty("suppress")] | |||||
| public bool? IsServerSuppressed { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,85 @@ | |||||
| using Newtonsoft.Json; | |||||
| using System; | |||||
| namespace Discord.API.Client | |||||
| { | |||||
| public class Message : MessageReference | |||||
| { | |||||
| public sealed class Attachment | |||||
| { | |||||
| [JsonProperty("id")] | |||||
| public string Id { get; set; } | |||||
| [JsonProperty("url")] | |||||
| public string Url { get; set; } | |||||
| [JsonProperty("proxy_url")] | |||||
| public string ProxyUrl { get; set; } | |||||
| [JsonProperty("size")] | |||||
| public int Size { get; set; } | |||||
| [JsonProperty("filename")] | |||||
| public string Filename { get; set; } | |||||
| [JsonProperty("width")] | |||||
| public int Width { get; set; } | |||||
| [JsonProperty("height")] | |||||
| public int Height { get; set; } | |||||
| } | |||||
| public sealed class Embed | |||||
| { | |||||
| public sealed class Reference | |||||
| { | |||||
| [JsonProperty("url")] | |||||
| public string Url { get; set; } | |||||
| [JsonProperty("name")] | |||||
| public string Name { get; set; } | |||||
| } | |||||
| public sealed class ThumbnailInfo | |||||
| { | |||||
| [JsonProperty("url")] | |||||
| public string Url { get; set; } | |||||
| [JsonProperty("proxy_url")] | |||||
| public string ProxyUrl { get; set; } | |||||
| [JsonProperty("width")] | |||||
| public int Width { get; set; } | |||||
| [JsonProperty("height")] | |||||
| public int Height { get; set; } | |||||
| } | |||||
| [JsonProperty("url")] | |||||
| public string Url { get; set; } | |||||
| [JsonProperty("type")] | |||||
| public string Type { get; set; } | |||||
| [JsonProperty("title")] | |||||
| public string Title { get; set; } | |||||
| [JsonProperty("description")] | |||||
| public string Description { get; set; } | |||||
| [JsonProperty("author")] | |||||
| public Reference Author { get; set; } | |||||
| [JsonProperty("provider")] | |||||
| public Reference Provider { get; set; } | |||||
| [JsonProperty("thumbnail")] | |||||
| public ThumbnailInfo Thumbnail { get; set; } | |||||
| } | |||||
| [JsonProperty("tts")] | |||||
| public bool? IsTextToSpeech { get; set; } | |||||
| [JsonProperty("mention_everyone")] | |||||
| public bool? IsMentioningEveryone { get; set; } | |||||
| [JsonProperty("timestamp")] | |||||
| public DateTime? Timestamp { get; set; } | |||||
| [JsonProperty("edited_timestamp")] | |||||
| public DateTime? EditedTimestamp { get; set; } | |||||
| [JsonProperty("mentions")] | |||||
| public UserReference[] Mentions { get; set; } | |||||
| [JsonProperty("embeds")] | |||||
| public Embed[] Embeds { get; set; } //TODO: Parse this | |||||
| [JsonProperty("attachments")] | |||||
| public Attachment[] Attachments { get; set; } | |||||
| [JsonProperty("content")] | |||||
| public string Content { get; set; } | |||||
| [JsonProperty("author")] | |||||
| public UserReference Author { get; set; } | |||||
| [JsonProperty("nonce")] | |||||
| public string Nonce { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,15 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client | |||||
| { | |||||
| public class MessageReference | |||||
| { | |||||
| [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong Id { get; set; } | |||||
| [JsonProperty("message_id"), JsonConverter(typeof(LongStringConverter))] //Only used in MESSAGE_ACK | |||||
| public ulong MessageId { get { return Id; } set { Id = value; } } | |||||
| [JsonProperty("channel_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong ChannelId { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,13 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client | |||||
| { | |||||
| public class RoleReference | |||||
| { | |||||
| [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong GuildId { get; set; } | |||||
| [JsonProperty("role_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong RoleId { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,17 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client | |||||
| { | |||||
| public class UserReference | |||||
| { | |||||
| [JsonProperty("username")] | |||||
| public string Username { get; set; } | |||||
| [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong Id { get; set; } | |||||
| [JsonProperty("discriminator")] | |||||
| public ushort? Discriminator { get; set; } | |||||
| [JsonProperty("avatar")] | |||||
| public string Avatar { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,12 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class HeartbeatCommand : IWebSocketMessage | |||||
| { | |||||
| int IWebSocketMessage.OpCode => (int)OpCodes.Heartbeat; | |||||
| object IWebSocketMessage.Payload => EpochTime.GetMilliseconds(); | |||||
| bool IWebSocketMessage.IsPrivate => false; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,23 @@ | |||||
| using Newtonsoft.Json; | |||||
| using System.Collections.Generic; | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| internal sealed class IdentifyCommand : IWebSocketMessage | |||||
| { | |||||
| int IWebSocketMessage.OpCode => (int)OpCodes.Identify; | |||||
| object IWebSocketMessage.Payload => this; | |||||
| bool IWebSocketMessage.IsPrivate => false; | |||||
| [JsonProperty("v")] | |||||
| public int Version { get; set; } | |||||
| [JsonProperty("token")] | |||||
| public string Token { get; set; } | |||||
| [JsonProperty("properties")] | |||||
| public Dictionary<string, string> Properties { get; set; } | |||||
| [JsonProperty("large_threshold", NullValueHandling = NullValueHandling.Ignore)] | |||||
| public int? LargeThreshold { get; set; } | |||||
| [JsonProperty("compress")] | |||||
| public bool UseCompression { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,20 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| internal sealed class RequestMembersCommand : IWebSocketMessage | |||||
| { | |||||
| int IWebSocketMessage.OpCode => (int)OpCodes.RequestGuildMembers; | |||||
| object IWebSocketMessage.Payload => this; | |||||
| bool IWebSocketMessage.IsPrivate => false; | |||||
| [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong GuildId { get; set; } | |||||
| [JsonProperty("query")] | |||||
| public string Query { get; set; } | |||||
| [JsonProperty("limit")] | |||||
| public int Limit { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,17 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class ResumeCommand : IWebSocketMessage | |||||
| { | |||||
| int IWebSocketMessage.OpCode => (int)OpCodes.Resume; | |||||
| object IWebSocketMessage.Payload => this; | |||||
| bool IWebSocketMessage.IsPrivate => false; | |||||
| [JsonProperty("session_id")] | |||||
| public string SessionId { get; set; } | |||||
| [JsonProperty("seq")] | |||||
| public int Sequence { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,17 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class UpdateStatusCommand : IWebSocketMessage | |||||
| { | |||||
| int IWebSocketMessage.OpCode => (int)OpCodes.StatusUpdate; | |||||
| object IWebSocketMessage.Payload => this; | |||||
| bool IWebSocketMessage.IsPrivate => false; | |||||
| [JsonProperty("idle_since")] | |||||
| public long? IdleSince { get; set; } | |||||
| [JsonProperty("game_id")] | |||||
| public int? GameId { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,22 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class UpdateVoiceCommand : IWebSocketMessage | |||||
| { | |||||
| int IWebSocketMessage.OpCode => (int)OpCodes.StatusUpdate; | |||||
| object IWebSocketMessage.Payload => this; | |||||
| bool IWebSocketMessage.IsPrivate => false; | |||||
| [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong GuildId { get; set; } | |||||
| [JsonProperty("channel_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong ChannelId { get; set; } | |||||
| [JsonProperty("self_mute")] | |||||
| public bool IsSelfMuted { get; set; } | |||||
| [JsonProperty("self_deaf")] | |||||
| public bool IsSelfDeafened { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class ChannelCreateEvent : Channel { } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class ChannelDeleteEvent : Channel { } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class ChannelUpdateEvent : Channel { } | |||||
| } | |||||
| @@ -0,0 +1,13 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class GuildBanAddEvent | |||||
| { | |||||
| [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong GuildId { get; } | |||||
| [JsonProperty("user_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong UserId { get; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,13 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class GuildBanRemoveEvent | |||||
| { | |||||
| [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong GuildId { get; } | |||||
| [JsonProperty("user_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong UserId { get; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class GuildCreateEvent : ExtendedGuild { } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class GuildDeleteEvent : ExtendedGuild { } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| //public sealed class GuildIntegrationsUpdateEvent { } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class GuildMemberAddEvent : Member { } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class GuildMemberRemoveEvent : Member { } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class GuildMemberUpdateEvent : Member { } | |||||
| } | |||||
| @@ -0,0 +1,10 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class GuildMembersChunkEvent | |||||
| { | |||||
| [JsonProperty("members")] | |||||
| public Member[] Members; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,13 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class GuildRoleCreateEvent | |||||
| { | |||||
| [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong GuildId { get; } | |||||
| [JsonProperty("role")] | |||||
| public Role Data { get; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class GuildRoleDeleteEvent : RoleReference { } | |||||
| } | |||||
| @@ -0,0 +1,13 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class GuildRoleUpdateEvent | |||||
| { | |||||
| [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong GuildId { get; } | |||||
| [JsonProperty("role")] | |||||
| public Role Data { get; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class GuildUpdateEvent : Guild { } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class MessageAckEvent : MessageReference { } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class MessageCreateEvent : Message { } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class MessageDeleteEvent : MessageReference { } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class MessageUpdateEvent : Message { } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class PresenceUpdateEvent : MemberPresence { } | |||||
| } | |||||
| @@ -0,0 +1,32 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class ReadyEvent | |||||
| { | |||||
| public sealed class ReadState | |||||
| { | |||||
| [JsonProperty("id")] | |||||
| public string ChannelId { get; } | |||||
| [JsonProperty("mention_count")] | |||||
| public int MentionCount { get; } | |||||
| [JsonProperty("last_message_id")] | |||||
| public string LastMessageId { get; } | |||||
| } | |||||
| [JsonProperty("v")] | |||||
| public int Version { get; } | |||||
| [JsonProperty("user")] | |||||
| public User User { get; } | |||||
| [JsonProperty("session_id")] | |||||
| public string SessionId { get; } | |||||
| [JsonProperty("read_state")] | |||||
| public ReadState[] ReadStates { get; } | |||||
| [JsonProperty("guilds")] | |||||
| public ExtendedGuild[] Guilds { get; } | |||||
| [JsonProperty("private_channels")] | |||||
| public Channel[] PrivateChannels { get; } | |||||
| [JsonProperty("heartbeat_interval")] | |||||
| public int HeartbeatInterval { get; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,10 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class RedirectEvent | |||||
| { | |||||
| [JsonProperty("url")] | |||||
| public string Url { get; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,10 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class ResumedEvent | |||||
| { | |||||
| [JsonProperty("heartbeat_interval")] | |||||
| public int HeartbeatInterval { get; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,15 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class TypingStartEvent | |||||
| { | |||||
| [JsonProperty("user_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong UserId { get; } | |||||
| [JsonProperty("channel_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong ChannelId { get; } | |||||
| [JsonProperty("timestamp")] | |||||
| public int Timestamp { get; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| //public sealed class UserSettingsUpdateEvent { } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class UserUpdateEvent : User { } | |||||
| } | |||||
| @@ -0,0 +1,15 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class VoiceServerUpdateEvent | |||||
| { | |||||
| [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong GuildId { get; } | |||||
| [JsonProperty("endpoint")] | |||||
| public string Endpoint { get; } | |||||
| [JsonProperty("token")] | |||||
| public string Token { get; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,4 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public sealed class VoiceStateUpdateEvent : MemberVoiceState { } | |||||
| } | |||||
| @@ -0,0 +1,24 @@ | |||||
| namespace Discord.API.Client.GatewaySocket | |||||
| { | |||||
| public enum OpCodes : byte | |||||
| { | |||||
| /// <summary> C←S - Used to send most events. </summary> | |||||
| Dispatch = 0, | |||||
| /// <summary> C↔S - Used to keep the connection alive and measure latency. </summary> | |||||
| Heartbeat = 1, | |||||
| /// <summary> C→S - Used to associate a connection with a token and specify configuration. </summary> | |||||
| Identify = 2, | |||||
| /// <summary> C→S - Used to update client's status and current game id. </summary> | |||||
| StatusUpdate = 3, | |||||
| /// <summary> C→S - Used to join a particular voice channel. </summary> | |||||
| VoiceStateUpdate = 4, | |||||
| /// <summary> C→S - Used to ensure the server's voice server is alive. Only send this if voice connection fails or suddenly drops. </summary> | |||||
| VoiceServerPing = 5, | |||||
| /// <summary> C→S - Used to resume a connection after a redirect occurs. </summary> | |||||
| Resume = 6, | |||||
| /// <summary> C←S - Used to notify a client that they must reconnect to another gateway. </summary> | |||||
| Redirect = 7, | |||||
| /// <summary> C→S - Used to request all members that were withheld by large_threshold </summary> | |||||
| RequestGuildMembers = 8 | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,29 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client | |||||
| { | |||||
| public interface IWebSocketMessage | |||||
| { | |||||
| int OpCode { get; } | |||||
| object Payload { get; } | |||||
| bool IsPrivate { get; } | |||||
| } | |||||
| public class WebSocketMessage | |||||
| { | |||||
| [JsonProperty("op")] | |||||
| public int Operation { get; } | |||||
| [JsonProperty("d")] | |||||
| public object Payload { get; } | |||||
| [JsonProperty("t", NullValueHandling = NullValueHandling.Ignore)] | |||||
| public string Type { get; } | |||||
| [JsonProperty("s", NullValueHandling = NullValueHandling.Ignore)] | |||||
| public int? Sequence { get; } | |||||
| public WebSocketMessage() { } | |||||
| public WebSocketMessage(IWebSocketMessage msg) | |||||
| { | |||||
| Operation = msg.OpCode; | |||||
| Payload = msg.Payload; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,20 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class AcceptInviteRequest : IRestRequest<InviteReference> | |||||
| { | |||||
| string IRestRequest.Method => "POST"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/invite/{InviteId}"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public string InviteId { get; } | |||||
| public AcceptInviteRequest(string inviteId) | |||||
| { | |||||
| InviteId = inviteId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,25 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class AckMessageRequest : IRestRequest | |||||
| { | |||||
| string IRestRequest.Method => "POST"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/channels/{ChannelId}/messages/{MessageId}/ack"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong ChannelId { get; } | |||||
| public ulong MessageId { get; } | |||||
| /*[JsonProperty("manual")] | |||||
| public bool Manual { get; set; }*/ | |||||
| public AckMessageRequest(ulong channelId, ulong messageId) | |||||
| { | |||||
| ChannelId = channelId; | |||||
| MessageId = messageId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,24 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class AddGuildBanRequest : IRestRequest | |||||
| { | |||||
| string IRestRequest.Method => "PUT"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/guilds/{GuildId}/bans/{UserId}?delete-message-days={PruneDays}"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong GuildId { get; } | |||||
| public ulong UserId { get; } | |||||
| public int PruneDays { get; set; } = 0; | |||||
| public AddGuildBanRequest(ulong guildId, ulong userId) | |||||
| { | |||||
| GuildId = guildId; | |||||
| UserId = UserId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,20 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class BroadcastTypingRequest : IRestRequest | |||||
| { | |||||
| string IRestRequest.Method => "POST"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/channels/{ChannelId}/typing"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong ChannelId { get; } | |||||
| public BroadcastTypingRequest(ulong channelId) | |||||
| { | |||||
| ChannelId = channelId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,25 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class CreateChannelRequest : IRestRequest<Channel> | |||||
| { | |||||
| string IRestRequest.Method => "POST"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/guilds/{GuildId}/channels"; | |||||
| object IRestRequest.Payload => this; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong GuildId { get; } | |||||
| [JsonProperty("name")] | |||||
| public string Name { get; set; } | |||||
| [JsonProperty("type")] | |||||
| public string Type { get; set; } | |||||
| public CreateChannelRequest(ulong guildId) | |||||
| { | |||||
| GuildId = guildId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,20 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class CreateGuildRequest : IRestRequest<Guild> | |||||
| { | |||||
| string IRestRequest.Method => "POST"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/guilds"; | |||||
| object IRestRequest.Payload => this; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| [JsonProperty("name")] | |||||
| public string Name { get; set; } | |||||
| [JsonProperty("region")] | |||||
| public string Region { get; set; } | |||||
| [JsonProperty("icon")] | |||||
| public string IconBase64 { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,31 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class CreateInviteRequest : IRestRequest<Invite> | |||||
| { | |||||
| string IRestRequest.Method => "POST"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/channels/{ChannelId}/invites"; | |||||
| object IRestRequest.Payload => this; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong ChannelId { get; } | |||||
| [JsonProperty("max_age")] | |||||
| public int MaxAge { get; set; } = 1800; | |||||
| [JsonProperty("max_uses")] | |||||
| public int MaxUses { get; set; } = 0; | |||||
| [JsonProperty("temporary")] | |||||
| public bool IsTemporary { get; set; } = false; | |||||
| [JsonProperty("xkcdpass")] | |||||
| public bool WithXkcdPass { get; set; } = false; | |||||
| /*[JsonProperty("validate")] | |||||
| public bool Validate { get; set; }*/ | |||||
| public CreateInviteRequest(ulong channelId) | |||||
| { | |||||
| ChannelId = channelId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,17 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class CreatePrivateChannelRequest : IRestRequest<Channel> | |||||
| { | |||||
| string IRestRequest.Method => "POST"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/users/@me/channels"; | |||||
| object IRestRequest.Payload => this; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| [JsonProperty("recipient_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong RecipientId { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,20 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class CreateRoleRequest : IRestRequest<Role> | |||||
| { | |||||
| string IRestRequest.Method => "POST"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/guilds/{GuildId}/roles"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong GuildId { get; } | |||||
| public CreateRoleRequest(ulong guildId) | |||||
| { | |||||
| GuildId = guildId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,20 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class DeleteChannelRequest : IRestRequest<Channel> | |||||
| { | |||||
| string IRestRequest.Method => "DELETE"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/channels/{ChannelId}"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong ChannelId { get; } | |||||
| public DeleteChannelRequest(ulong channelId) | |||||
| { | |||||
| ChannelId = channelId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,20 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class DeleteInviteRequest : IRestRequest<Invite> | |||||
| { | |||||
| string IRestRequest.Method => "DELETE"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/invite/{InviteCode}"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public string InviteCode { get; } | |||||
| public DeleteInviteRequest(string inviteCode) | |||||
| { | |||||
| InviteCode = inviteCode; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,22 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class DeleteMessageRequest : IRestRequest | |||||
| { | |||||
| string IRestRequest.Method => "DELETE"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/channels/{ChannelId}/messages/{MessageId}"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong ChannelId { get; } | |||||
| public ulong MessageId { get; } | |||||
| public DeleteMessageRequest(ulong channelId, ulong messageId) | |||||
| { | |||||
| ChannelId = channelId; | |||||
| MessageId = messageId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,22 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class DeleteRoleRequest : IRestRequest | |||||
| { | |||||
| string IRestRequest.Method => "DELETE"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/guilds/{GuildId}/roles/{RoleId}"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong GuildId { get; } | |||||
| public ulong RoleId { get; } | |||||
| public DeleteRoleRequest(ulong guildId, ulong roleId) | |||||
| { | |||||
| GuildId = guildId; | |||||
| RoleId = roleId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,19 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class GatewayRequest : IRestRequest<GatewayResponse> | |||||
| { | |||||
| string IRestRequest.Method => "GET"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/gateway"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| } | |||||
| public sealed class GatewayResponse | |||||
| { | |||||
| [JsonProperty("url")] | |||||
| public string Url { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,20 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class GetInviteRequest : IRestRequest<InviteReference> | |||||
| { | |||||
| string IRestRequest.Method => "GET"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/invite/{InviteCode}"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public string InviteCode { get; } | |||||
| public GetInviteRequest(string inviteCode) | |||||
| { | |||||
| InviteCode = inviteCode; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,20 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class GetInvitesRequest : IRestRequest<InviteReference[]> | |||||
| { | |||||
| string IRestRequest.Method => "GET"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/guilds/{GuildId}/invites"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong GuildId { get; } | |||||
| public GetInvitesRequest(ulong guildId) | |||||
| { | |||||
| GuildId = guildId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,35 @@ | |||||
| using Newtonsoft.Json; | |||||
| using System.Text; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class GetMessagesRequest : IRestRequest<Message[]> | |||||
| { | |||||
| string IRestRequest.Method => "GET"; | |||||
| string IRestRequest.Endpoint | |||||
| { | |||||
| get | |||||
| { | |||||
| StringBuilder query = new StringBuilder(); | |||||
| this.AddQueryParam(query, "limit", Limit.ToString()); | |||||
| if (RelativeDir != null) | |||||
| this.AddQueryParam(query, RelativeDir, RelativeId.Value.ToString()); | |||||
| return $"{DiscordConfig.ClientAPIUrl}/channels/{ChannelId}/messages{query}"; | |||||
| } | |||||
| } | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong ChannelId { get; } | |||||
| public int Limit { get; set; } = 100; | |||||
| public string RelativeDir { get; set; } = null; | |||||
| public ulong? RelativeId { get; set; } = 0; | |||||
| public GetMessagesRequest(ulong channelId) | |||||
| { | |||||
| ChannelId = channelId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,25 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class GetVoiceRegionsRequest : IRestRequest<GetVoiceRegionsResponse[]> | |||||
| { | |||||
| string IRestRequest.Method => "GET"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/voice/regions"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| } | |||||
| public sealed class GetVoiceRegionsResponse | |||||
| { | |||||
| [JsonProperty("sample_hostname")] | |||||
| public string Hostname { get; set; } | |||||
| [JsonProperty("sample_port")] | |||||
| public int Port { get; set; } | |||||
| [JsonProperty("id")] | |||||
| public string Id { get; set; } | |||||
| [JsonProperty("name")] | |||||
| public string Name { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,61 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class GetWidgetRequest : IRestRequest<GetWidgetResponse> | |||||
| { | |||||
| string IRestRequest.Method => "GET"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/servers/{GuildId}/widget.json"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong GuildId { get; } | |||||
| public GetWidgetRequest(ulong guildId) | |||||
| { | |||||
| GuildId = guildId; | |||||
| } | |||||
| } | |||||
| public sealed class GetWidgetResponse | |||||
| { | |||||
| public sealed class Channel | |||||
| { | |||||
| [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong Id { get; set; } | |||||
| [JsonProperty("name")] | |||||
| public string Name { get; set; } | |||||
| [JsonProperty("position")] | |||||
| public int Position { get; set; } | |||||
| } | |||||
| public sealed class User : UserReference | |||||
| { | |||||
| [JsonProperty("avatar_url")] | |||||
| public string AvatarUrl { get; set; } | |||||
| [JsonProperty("status")] | |||||
| public string Status { get; set; } | |||||
| [JsonProperty("game")] | |||||
| public UserGame Game { get; set; } | |||||
| } | |||||
| public sealed class UserGame | |||||
| { | |||||
| [JsonProperty("id")] | |||||
| public int Id { get; set; } | |||||
| [JsonProperty("name")] | |||||
| public string Name { get; set; } | |||||
| } | |||||
| [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong Id { get; set; } | |||||
| [JsonProperty("channels")] | |||||
| public Channel[] Channels { get; set; } | |||||
| [JsonProperty("members")] | |||||
| public MemberReference[] Members { get; set; } | |||||
| [JsonProperty("instant_invite")] | |||||
| public string InstantInviteUrl { get; set; } | |||||
| [JsonProperty("name")] | |||||
| public string Name { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,22 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class KickMemberRequest : IRestRequest | |||||
| { | |||||
| string IRestRequest.Method => "DELETE"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/guilds/{GuildId}/members/{UserId}"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong GuildId { get; } | |||||
| public ulong UserId { get; } | |||||
| public KickMemberRequest(ulong guildId, ulong userId) | |||||
| { | |||||
| GuildId = guildId; | |||||
| UserId = userId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,20 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class LeaveGuildRequest : IRestRequest<Guild> | |||||
| { | |||||
| string IRestRequest.Method => "DELETE"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/guilds/{GuildId}"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong GuildId { get; } | |||||
| public LeaveGuildRequest(ulong guildId) | |||||
| { | |||||
| GuildId = guildId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,13 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class LogoutRequest : IRestRequest | |||||
| { | |||||
| string IRestRequest.Method => "POST"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/auth/logout"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,29 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class PruneMembersRequest : IRestRequest<PruneMembersResponse> | |||||
| { | |||||
| string IRestRequest.Method => IsSimulation ? "GET" : "POST"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/guilds/{GuildId}/prune?days={Days}"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong GuildId { get; } | |||||
| public int Days { get; set; } = 30; | |||||
| public bool IsSimulation { get; set; } = false; | |||||
| public PruneMembersRequest(ulong guildId) | |||||
| { | |||||
| GuildId = guildId; | |||||
| } | |||||
| } | |||||
| public sealed class PruneMembersResponse | |||||
| { | |||||
| [JsonProperty("pruned")] | |||||
| public int Pruned { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,22 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class RemoveChannelPermissionsRequest : IRestRequest | |||||
| { | |||||
| string IRestRequest.Method => "DELETE"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/channels/{ChannelId}/permissions/{TargetId}"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong ChannelId { get; } | |||||
| public ulong TargetId { get; } | |||||
| public RemoveChannelPermissionsRequest(ulong channelId, ulong targetId) | |||||
| { | |||||
| ChannelId = channelId; | |||||
| TargetId = targetId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,22 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class RemoveGuildBanRequest : IRestRequest | |||||
| { | |||||
| string IRestRequest.Method => "DELETE"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/guilds/{GuildId}/bans/{UserId}"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong GuildId { get; } | |||||
| public ulong UserId { get; } | |||||
| public RemoveGuildBanRequest(ulong guildId, ulong userId) | |||||
| { | |||||
| GuildId = guildId; | |||||
| UserId = userId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,46 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| using System.Linq; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class ReorderChannelsRequest : IRestRequest | |||||
| { | |||||
| string IRestRequest.Method => "PATCH"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/guilds/{GuildId}/channels"; | |||||
| object IRestRequest.Payload | |||||
| { | |||||
| get | |||||
| { | |||||
| int pos = StartPos; | |||||
| return ChannelIds.Select(x => new Channel(x, pos++)); | |||||
| } | |||||
| } | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public sealed class Channel | |||||
| { | |||||
| [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong Id; | |||||
| [JsonProperty("position")] | |||||
| public int Position; | |||||
| public Channel(ulong id, int position) | |||||
| { | |||||
| Id = id; | |||||
| Position = position; | |||||
| } | |||||
| } | |||||
| public ulong GuildId { get; } | |||||
| public ulong[] ChannelIds { get; set; } = new ulong[0]; | |||||
| public int StartPos { get; set; } = 0; | |||||
| public ReorderChannelsRequest(ulong guildId) | |||||
| { | |||||
| GuildId = guildId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,46 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| using System.Linq; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class ReorderRolesRequest : IRestRequest<Role[]> | |||||
| { | |||||
| string IRestRequest.Method => "PATCH"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/guilds/{GuildId}/roles"; | |||||
| object IRestRequest.Payload | |||||
| { | |||||
| get | |||||
| { | |||||
| int pos = StartPos; | |||||
| return RoleIds.Select(x => new Role(x, pos++)); | |||||
| } | |||||
| } | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public sealed class Role | |||||
| { | |||||
| [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong Id { get; } | |||||
| [JsonProperty("position")] | |||||
| public int Position { get; } | |||||
| public Role(ulong id, int pos) | |||||
| { | |||||
| Id = id; | |||||
| Position = pos; | |||||
| } | |||||
| } | |||||
| public ulong GuildId { get; } | |||||
| public ulong[] RoleIds { get; set; } = new ulong[0]; | |||||
| public int StartPos { get; set; } = 0; | |||||
| public ReorderRolesRequest(ulong guildId) | |||||
| { | |||||
| GuildId = guildId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,26 @@ | |||||
| using Newtonsoft.Json; | |||||
| using System.IO; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class SendFileRequest : IRestFileRequest<Message> | |||||
| { | |||||
| string IRestRequest.Method => "POST"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/channels/{ChannelId}/messages"; | |||||
| object IRestRequest.Payload => null; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| string IRestFileRequest.Filename => Filename; | |||||
| Stream IRestFileRequest.Stream => Stream; | |||||
| public ulong ChannelId { get; } | |||||
| public string Filename { get; set; } | |||||
| public Stream Stream { get; set; } | |||||
| public SendFileRequest(ulong channelId) | |||||
| { | |||||
| ChannelId = channelId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,30 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class SendMessageRequest : IRestRequest<Message> | |||||
| { | |||||
| string IRestRequest.Method => "POST"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/channels/{ChannelId}/messages"; | |||||
| object IRestRequest.Payload => this; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong ChannelId { get; } | |||||
| [JsonProperty("content")] | |||||
| public string Content { get; set; } | |||||
| [JsonProperty("mentions"), JsonConverter(typeof(LongStringArrayConverter))] | |||||
| public ulong[] MentionedUserIds { get; set; } | |||||
| [JsonProperty("nonce", NullValueHandling = NullValueHandling.Ignore)] | |||||
| public string Nonce { get; set; } | |||||
| [JsonProperty("tts")] | |||||
| public bool IsTTS { get; set; } | |||||
| public SendMessageRequest(ulong channelId) | |||||
| { | |||||
| ChannelId = channelId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,27 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class UpdateChannelRequest : IRestRequest<Channel> | |||||
| { | |||||
| string IRestRequest.Method => "PATCH"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/channels/{ChannelId}"; | |||||
| object IRestRequest.Payload => this; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong ChannelId { get; } | |||||
| [JsonProperty("name")] | |||||
| public string Name { get; set; } | |||||
| [JsonProperty("topic")] | |||||
| public string Topic { get; set; } | |||||
| [JsonProperty("position")] | |||||
| public int Position { get; set; } | |||||
| public UpdateChannelRequest(ulong channelId) | |||||
| { | |||||
| ChannelId = channelId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,32 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class UpdateGuildRequest : IRestRequest<Guild> | |||||
| { | |||||
| string IRestRequest.Method => "PATCH"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/guilds/{GuildId}"; | |||||
| object IRestRequest.Payload => this; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong GuildId { get; } | |||||
| [JsonProperty("name")] | |||||
| public string Name { get; set; } | |||||
| [JsonProperty("region")] | |||||
| public string Region { get; set; } | |||||
| [JsonProperty("icon")] | |||||
| public string IconBase64 { get; set; } | |||||
| [JsonProperty("afk_channel_id"), JsonConverter(typeof(NullableLongStringConverter))] | |||||
| public ulong? AFKChannelId { get; set; } | |||||
| [JsonProperty("afk_timeout")] | |||||
| public int AFKTimeout { get; set; } | |||||
| public UpdateGuildRequest(ulong guildId) | |||||
| { | |||||
| GuildId = guildId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,33 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| using System.Collections.Generic; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class UpdateMemberRequest : IRestRequest | |||||
| { | |||||
| string IRestRequest.Method => "PATCH"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/guilds/{GuildId}/members/{UserId}"; | |||||
| object IRestRequest.Payload => this; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong GuildId { get; } | |||||
| public ulong UserId { get; } | |||||
| [JsonProperty("mute")] | |||||
| public bool IsMuted { get; set; } | |||||
| [JsonProperty("deaf")] | |||||
| public bool IsDeafened { get; set; } | |||||
| [JsonProperty("channel_id"), JsonConverter(typeof(NullableLongStringConverter))] | |||||
| public ulong? VoiceChannelId { get; set; } | |||||
| [JsonProperty("roles"), JsonConverter(typeof(LongStringArrayConverter))] | |||||
| public ulong[] RoleIds { get; set; } | |||||
| public UpdateMemberRequest(ulong guildId, ulong userId) | |||||
| { | |||||
| GuildId = guildId; | |||||
| UserId = userId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,28 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class UpdateMessageRequest : IRestRequest<Message> | |||||
| { | |||||
| string IRestRequest.Method => "PATCH"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/channels/{ChannelId}/messages/{MessageId}"; | |||||
| object IRestRequest.Payload => this; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong ChannelId { get; } | |||||
| public ulong MessageId { get; } | |||||
| [JsonProperty("content")] | |||||
| public string Content { get; set; } = ""; | |||||
| [JsonProperty("mentions"), JsonConverter(typeof(LongStringArrayConverter))] | |||||
| public ulong[] MentionedUserIds { get; set; } = new ulong[0]; | |||||
| public UpdateMessageRequest(ulong channelId, ulong messageId) | |||||
| { | |||||
| ChannelId = channelId; | |||||
| MessageId = messageId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,24 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class UpdateProfileRequest : IRestRequest<User> | |||||
| { | |||||
| string IRestRequest.Method => "PATCH"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/users/@me"; | |||||
| object IRestRequest.Payload => this; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| [JsonProperty("password")] | |||||
| public string CurrentPassword { get; set; } | |||||
| [JsonProperty("email")] | |||||
| public string Email { get; set; } | |||||
| [JsonProperty("new_password")] | |||||
| public string Password { get; set; } | |||||
| [JsonProperty("username")] | |||||
| public string Username { get; set; } | |||||
| [JsonProperty("avatar")] | |||||
| public string AvatarBase64 { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,31 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization.OptIn)] | |||||
| public sealed class UpdateRoleRequest : IRestRequest<Role> | |||||
| { | |||||
| string IRestRequest.Method => "PATCH"; | |||||
| string IRestRequest.Endpoint => $"{DiscordConfig.ClientAPIUrl}/guilds/{GuildId}/roles/{RoleId}"; | |||||
| object IRestRequest.Payload => this; | |||||
| bool IRestRequest.IsPrivate => false; | |||||
| public ulong GuildId { get; } | |||||
| public ulong RoleId { get; } | |||||
| [JsonProperty("name")] | |||||
| public string Name { get; set; } | |||||
| [JsonProperty("permissions")] | |||||
| public uint Permissions { get; set; } | |||||
| [JsonProperty("hoist")] | |||||
| public bool IsHoisted { get; set; } | |||||
| [JsonProperty("color")] | |||||
| public uint Color { get; set; } | |||||
| public UpdateRoleRequest(ulong guildId, ulong roleId) | |||||
| { | |||||
| GuildId = guildId; | |||||
| RoleId = roleId; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,9 @@ | |||||
| namespace Discord.API.Client.VoiceSocket | |||||
| { | |||||
| public sealed class HeartbeatCommand : IWebSocketMessage | |||||
| { | |||||
| int IWebSocketMessage.OpCode => (int)OpCodes.Heartbeat; | |||||
| object IWebSocketMessage.Payload => EpochTime.GetMilliseconds(); | |||||
| bool IWebSocketMessage.IsPrivate => false; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,21 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.VoiceSocket | |||||
| { | |||||
| public sealed class IdentifyCommand : IWebSocketMessage | |||||
| { | |||||
| int IWebSocketMessage.OpCode => (int)OpCodes.Identify; | |||||
| object IWebSocketMessage.Payload => this; | |||||
| bool IWebSocketMessage.IsPrivate => true; | |||||
| [JsonProperty("server_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong GuildId { get; set; } | |||||
| [JsonProperty("user_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong UserId { get; set; } | |||||
| [JsonProperty("session_id")] | |||||
| public string SessionId { get; set; } | |||||
| [JsonProperty("token")] | |||||
| public string Token { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,29 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.VoiceSocket | |||||
| { | |||||
| public sealed class SelectProtocolCommand : IWebSocketMessage | |||||
| { | |||||
| int IWebSocketMessage.OpCode => (int)OpCodes.SelectProtocol; | |||||
| object IWebSocketMessage.Payload => this; | |||||
| bool IWebSocketMessage.IsPrivate => false; | |||||
| public sealed class Data | |||||
| { | |||||
| [JsonProperty("address")] | |||||
| public string Address { get; set; } | |||||
| [JsonProperty("port")] | |||||
| public int Port { get; set; } | |||||
| [JsonProperty("mode")] | |||||
| public string Mode { get; set; } | |||||
| } | |||||
| [JsonProperty("protocol")] | |||||
| public string Protocol { get; set; } = "udp"; | |||||
| [JsonProperty("data")] | |||||
| private Data ProtocolData { get; } = new Data(); | |||||
| public string ExternalAddress { get { return ProtocolData.Address; } set { ProtocolData.Address = value; } } | |||||
| public int ExternalPort { get { return ProtocolData.Port; } set { ProtocolData.Port = value; } } | |||||
| public string EncryptionMode { get { return ProtocolData.Mode; } set { ProtocolData.Mode = value; } } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,16 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.VoiceSocket | |||||
| { | |||||
| public sealed class SetSpeakingCommand : IWebSocketMessage | |||||
| { | |||||
| int IWebSocketMessage.OpCode => (int)OpCodes.Speaking; | |||||
| object IWebSocketMessage.Payload => this; | |||||
| bool IWebSocketMessage.IsPrivate => false; | |||||
| [JsonProperty("speaking")] | |||||
| public bool IsSpeaking { get; set; } | |||||
| [JsonProperty("delay")] | |||||
| public int Delay { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,16 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.VoiceSocket | |||||
| { | |||||
| public sealed class ReadyEvent | |||||
| { | |||||
| [JsonProperty("ssrc")] | |||||
| public uint SSRC { get; set; } | |||||
| [JsonProperty("port")] | |||||
| public ushort Port { get; set; } | |||||
| [JsonProperty("modes")] | |||||
| public string[] Modes { get; set; } | |||||
| [JsonProperty("heartbeat_interval")] | |||||
| public int HeartbeatInterval { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,12 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.VoiceSocket | |||||
| { | |||||
| public sealed class SessionDescriptionEvent | |||||
| { | |||||
| [JsonProperty("secret_key")] | |||||
| public byte[] SecretKey { get; set; } | |||||
| [JsonProperty("mode")] | |||||
| public string Mode { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,15 @@ | |||||
| using Discord.API.Converters; | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Client.VoiceSocket | |||||
| { | |||||
| public sealed class SpeakingEvent | |||||
| { | |||||
| [JsonProperty("user_id"), JsonConverter(typeof(LongStringConverter))] | |||||
| public ulong UserId { get; set; } | |||||
| [JsonProperty("ssrc")] | |||||
| public uint SSRC { get; set; } | |||||
| [JsonProperty("speaking")] | |||||
| public bool IsSpeaking { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,18 @@ | |||||
| namespace Discord.API.Client.VoiceSocket | |||||
| { | |||||
| public enum OpCodes : byte | |||||
| { | |||||
| /// <summary> C→S - Used to associate a connection with a token. </summary> | |||||
| Identify = 0, | |||||
| /// <summary> C→S - Used to specify configuration. </summary> | |||||
| SelectProtocol = 1, | |||||
| /// <summary> C←S - Used to notify that the voice connection was successful and informs the client of available protocols. </summary> | |||||
| Ready = 2, | |||||
| /// <summary> C↔S - Used to keep the connection alive and measure latency. </summary> | |||||
| Heartbeat = 3, | |||||
| /// <summary> C←S - Used to provide an encryption key to the client. </summary> | |||||
| SessionDescription = 4, | |||||
| /// <summary> C↔S - Used to inform that a certain user is speaking. </summary> | |||||
| Speaking = 5 | |||||
| } | |||||
| } | |||||