@@ -2,6 +2,7 @@ | |||
namespace Discord.Commands | |||
{ | |||
//TODO: Check support for escaping | |||
public static class CommandParser | |||
{ | |||
private enum CommandParserPart | |||
@@ -35,6 +35,17 @@ | |||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> | |||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> | |||
</PropertyGroup> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'FullDebug|AnyCPU'"> | |||
<DebugSymbols>true</DebugSymbols> | |||
<OutputPath>bin\FullDebug\</OutputPath> | |||
<DefineConstants>TRACE;DEBUG;NET45,TEST_RESPONSES</DefineConstants> | |||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> | |||
<WarningLevel>2</WarningLevel> | |||
<DebugType>full</DebugType> | |||
<PlatformTarget>AnyCPU</PlatformTarget> | |||
<ErrorReport>prompt</ErrorReport> | |||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> | |||
<HintPath>..\..\..\DiscordBot\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> | |||
@@ -57,6 +68,33 @@ | |||
<None Include="packages.config" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Compile Include="..\Discord.Net\API\Common.cs"> | |||
<Link>API\Common.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\API\Endpoints.cs"> | |||
<Link>API\Endpoints.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\API\HttpException.cs"> | |||
<Link>API\HttpException.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\API\Requests.cs"> | |||
<Link>API\Requests.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\API\Responses.cs"> | |||
<Link>API\Responses.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\API\RestClient.BuiltIn.cs"> | |||
<Link>API\RestClient.BuiltIn.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\API\RestClient.cs"> | |||
<Link>API\RestClient.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\API\RestClient.Events.cs"> | |||
<Link>API\RestClient.Events.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\API\RestClient.SharpRest.cs"> | |||
<Link>API\RestClient.SharpRest.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Audio\Opus.cs"> | |||
<Link>Audio\Opus.cs</Link> | |||
</Compile> | |||
@@ -84,6 +122,9 @@ | |||
<Compile Include="..\Discord.Net\Collections\Users.cs"> | |||
<Link>Collections\Users.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\DiscordAPIClient.cs"> | |||
<Link>DiscordAPIClient.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\DiscordClient.API.cs"> | |||
<Link>DiscordClient.API.cs</Link> | |||
</Compile> | |||
@@ -150,74 +191,44 @@ | |||
<Compile Include="..\Discord.Net\Models\User.cs"> | |||
<Link>Models\User.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\API\Common.cs"> | |||
<Link>Net\API\Common.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\API\DiscordAPIClient.cs"> | |||
<Link>Net\API\DiscordAPIClient.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\API\Endpoints.cs"> | |||
<Link>Net\API\Endpoints.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\API\HttpException.cs"> | |||
<Link>Net\API\HttpException.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\API\Requests.cs"> | |||
<Link>Net\API\Requests.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\API\Responses.cs"> | |||
<Link>Net\API\Responses.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\API\RestClient.BuiltIn.cs"> | |||
<Link>Net\API\RestClient.BuiltIn.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\API\RestClient.cs"> | |||
<Link>Net\API\RestClient.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\API\RestClient.Events.cs"> | |||
<Link>Net\API\RestClient.Events.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\API\RestClient.SharpRest.cs"> | |||
<Link>Net\API\RestClient.SharpRest.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\WebSockets\Commands.cs"> | |||
<Link>Net\WebSockets\Commands.cs</Link> | |||
<Compile Include="..\Discord.Net\TimeoutException.cs"> | |||
<Link>TimeoutException.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\WebSockets\DataWebSocket.cs"> | |||
<Link>Net\WebSockets\DataWebSocket.cs</Link> | |||
<Compile Include="..\Discord.Net\WebSockets\Data\Commands.cs"> | |||
<Link>WebSockets\Data\Commands.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\WebSockets\DataWebSockets.Events.cs"> | |||
<Link>Net\WebSockets\DataWebSockets.Events.cs</Link> | |||
<Compile Include="..\Discord.Net\WebSockets\Data\DataWebSocket.cs"> | |||
<Link>WebSockets\Data\DataWebSocket.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\WebSockets\Events.cs"> | |||
<Link>Net\WebSockets\Events.cs</Link> | |||
<Compile Include="..\Discord.Net\WebSockets\Data\DataWebSockets.Events.cs"> | |||
<Link>WebSockets\Data\DataWebSockets.Events.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\WebSockets\VoiceCommands.cs"> | |||
<Link>Net\WebSockets\VoiceCommands.cs</Link> | |||
<Compile Include="..\Discord.Net\WebSockets\Data\Events.cs"> | |||
<Link>WebSockets\Data\Events.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\WebSockets\VoiceEvents.cs"> | |||
<Link>Net\WebSockets\VoiceEvents.cs</Link> | |||
<Compile Include="..\Discord.Net\WebSockets\Voice\Commands.cs"> | |||
<Link>WebSockets\Voice\Commands.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\WebSockets\VoiceWebSocket.cs"> | |||
<Link>Net\WebSockets\VoiceWebSocket.cs</Link> | |||
<Compile Include="..\Discord.Net\WebSockets\Voice\Events.cs"> | |||
<Link>WebSockets\Voice\Events.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\WebSockets\VoiceWebSocket.Events.cs"> | |||
<Link>Net\WebSockets\VoiceWebSocket.Events.cs</Link> | |||
<Compile Include="..\Discord.Net\WebSockets\Voice\VoiceWebSocket.cs"> | |||
<Link>WebSockets\Voice\VoiceWebSocket.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\WebSockets\WebSocket.BuiltIn.cs"> | |||
<Link>Net\WebSockets\WebSocket.BuiltIn.cs</Link> | |||
<Compile Include="..\Discord.Net\WebSockets\Voice\VoiceWebSocket.Events.cs"> | |||
<Link>WebSockets\Voice\VoiceWebSocket.Events.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\WebSockets\WebSocket.cs"> | |||
<Link>Net\WebSockets\WebSocket.cs</Link> | |||
<Compile Include="..\Discord.Net\WebSockets\WebSocket.BuiltIn.cs"> | |||
<Link>WebSockets\WebSocket.BuiltIn.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\WebSockets\WebSocket.Events.cs"> | |||
<Link>Net\WebSockets\WebSocket.Events.cs</Link> | |||
<Compile Include="..\Discord.Net\WebSockets\WebSocket.cs"> | |||
<Link>WebSockets\WebSocket.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\WebSockets\WebSocketMessage.cs"> | |||
<Link>Net\WebSockets\WebSocketMessage.cs</Link> | |||
<Compile Include="..\Discord.Net\WebSockets\WebSocket.Events.cs"> | |||
<Link>WebSockets\WebSocket.Events.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\TimeoutException.cs"> | |||
<Link>TimeoutException.cs</Link> | |||
<Compile Include="..\Discord.Net\WebSockets\WebSocketMessage.cs"> | |||
<Link>WebSockets\WebSocketMessage.cs</Link> | |||
</Compile> | |||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||
</ItemGroup> | |||
@@ -0,0 +1,295 @@ | |||
//Ignore unused/unassigned variable warnings | |||
#pragma warning disable CS0649 | |||
#pragma warning disable CS0169 | |||
using Newtonsoft.Json; | |||
using System; | |||
namespace Discord.API | |||
{ | |||
//User | |||
public class UserReference | |||
{ | |||
[JsonProperty("username")] | |||
public string Username; | |||
[JsonProperty("id")] | |||
public string Id; | |||
[JsonProperty("discriminator")] | |||
public string Discriminator; | |||
[JsonProperty("avatar")] | |||
public string Avatar; | |||
} | |||
public class SelfUserInfo : UserReference | |||
{ | |||
[JsonProperty("email")] | |||
public string Email; | |||
[JsonProperty("verified")] | |||
public bool IsVerified; | |||
} | |||
//Members | |||
public class MemberReference | |||
{ | |||
[JsonProperty("user_id")] | |||
public string UserId; | |||
[JsonProperty("user")] | |||
public UserReference User; | |||
[JsonProperty("guild_id")] | |||
public string GuildId; | |||
} | |||
public class MemberInfo : MemberReference | |||
{ | |||
[JsonProperty("joined_at")] | |||
public DateTime? JoinedAt; | |||
[JsonProperty("roles")] | |||
public string[] Roles; | |||
} | |||
public class ExtendedMemberInfo : MemberInfo | |||
{ | |||
[JsonProperty("mute")] | |||
public bool IsMuted; | |||
[JsonProperty("deaf")] | |||
public bool IsDeafened; | |||
} | |||
public class PresenceMemberInfo : MemberReference | |||
{ | |||
[JsonProperty("game_id")] | |||
public string GameId; | |||
[JsonProperty("status")] | |||
public string Status; | |||
} | |||
public class VoiceMemberInfo : MemberReference | |||
{ | |||
[JsonProperty("channel_id")] | |||
public string ChannelId; | |||
[JsonProperty("suppress")] | |||
public bool? IsSuppressed; | |||
[JsonProperty("session_id")] | |||
public string SessionId; | |||
[JsonProperty("self_mute")] | |||
public bool? IsSelfMuted; | |||
[JsonProperty("self_deaf")] | |||
public bool? IsSelfDeafened; | |||
[JsonProperty("mute")] | |||
public bool IsMuted; | |||
[JsonProperty("deaf")] | |||
public bool IsDeafened; | |||
[JsonProperty("token")] | |||
public string Token; | |||
} | |||
//Channels | |||
public class ChannelReference | |||
{ | |||
[JsonProperty("id")] | |||
public string Id; | |||
[JsonProperty("guild_id")] | |||
public string GuildId; | |||
[JsonProperty("name")] | |||
public string Name; | |||
[JsonProperty("type")] | |||
public string Type; | |||
} | |||
public class ChannelInfo : ChannelReference | |||
{ | |||
public sealed class PermissionOverwrite | |||
{ | |||
[JsonProperty("type")] | |||
public string Type; | |||
[JsonProperty("id")] | |||
public string Id; | |||
[JsonProperty("deny")] | |||
public uint Deny; | |||
[JsonProperty("allow")] | |||
public uint Allow; | |||
} | |||
[JsonProperty("last_message_id")] | |||
public string LastMessageId; | |||
[JsonProperty("is_private")] | |||
public bool IsPrivate; | |||
[JsonProperty("position")] | |||
public int Position; | |||
[JsonProperty("permission_overwrites")] | |||
public PermissionOverwrite[] PermissionOverwrites; | |||
[JsonProperty("recipient")] | |||
public UserReference Recipient; | |||
} | |||
//Guilds (Servers) | |||
public class GuildReference | |||
{ | |||
[JsonProperty("id")] | |||
public string Id; | |||
[JsonProperty("name")] | |||
public string Name; | |||
} | |||
public class GuildInfo : GuildReference | |||
{ | |||
[JsonProperty("afk_channel_id")] | |||
public string AFKChannelId; | |||
[JsonProperty("afk_timeout")] | |||
public int AFKTimeout; | |||
[JsonProperty("embed_channel_id")] | |||
public string EmbedChannelId; | |||
[JsonProperty("embed_enabled")] | |||
public bool EmbedEnabled; | |||
[JsonProperty("icon")] | |||
public string Icon; | |||
[JsonProperty("joined_at")] | |||
public DateTime? JoinedAt; | |||
[JsonProperty("owner_id")] | |||
public string OwnerId; | |||
[JsonProperty("region")] | |||
public string Region; | |||
[JsonProperty("roles")] | |||
public RoleInfo[] Roles; | |||
} | |||
public class ExtendedGuildInfo : GuildInfo | |||
{ | |||
[JsonProperty("channels")] | |||
public ChannelInfo[] Channels; | |||
[JsonProperty("members")] | |||
public ExtendedMemberInfo[] Members; | |||
[JsonProperty("presences")] | |||
public PresenceMemberInfo[] Presences; | |||
[JsonProperty("voice_states")] | |||
public VoiceMemberInfo[] VoiceStates; | |||
} | |||
//Messages | |||
public class MessageReference | |||
{ | |||
[JsonProperty("id")] | |||
public string Id; | |||
[JsonProperty("channel_id")] | |||
public string ChannelId; | |||
[JsonProperty("message_id")] | |||
public string MessageId { get { return Id; } set { Id = value; } } | |||
} | |||
public class Message : MessageReference | |||
{ | |||
public sealed class Attachment | |||
{ | |||
[JsonProperty("id")] | |||
public string Id; | |||
[JsonProperty("url")] | |||
public string Url; | |||
[JsonProperty("proxy_url")] | |||
public string ProxyUrl; | |||
[JsonProperty("size")] | |||
public int Size; | |||
[JsonProperty("filename")] | |||
public string Filename; | |||
[JsonProperty("width")] | |||
public int Width; | |||
[JsonProperty("height")] | |||
public int Height; | |||
} | |||
public sealed class Embed | |||
{ | |||
public sealed class Reference | |||
{ | |||
[JsonProperty("url")] | |||
public string Url; | |||
[JsonProperty("name")] | |||
public string Name; | |||
} | |||
public sealed class ThumbnailInfo | |||
{ | |||
[JsonProperty("url")] | |||
public string Url; | |||
[JsonProperty("proxy_url")] | |||
public string ProxyUrl; | |||
[JsonProperty("width")] | |||
public int Width; | |||
[JsonProperty("height")] | |||
public int Height; | |||
} | |||
[JsonProperty("url")] | |||
public string Url; | |||
[JsonProperty("type")] | |||
public string Type; | |||
[JsonProperty("title")] | |||
public string Title; | |||
[JsonProperty("description")] | |||
public string Description; | |||
[JsonProperty("author")] | |||
public Reference Author; | |||
[JsonProperty("provider")] | |||
public Reference Provider; | |||
[JsonProperty("thumbnail")] | |||
public ThumbnailInfo Thumbnail; | |||
} | |||
[JsonProperty("tts")] | |||
public bool IsTextToSpeech; | |||
[JsonProperty("mention_everyone")] | |||
public bool IsMentioningEveryone; | |||
[JsonProperty("timestamp")] | |||
public DateTime Timestamp; | |||
[JsonProperty("edited_timestamp")] | |||
public DateTime? EditedTimestamp; | |||
[JsonProperty("mentions")] | |||
public UserReference[] Mentions; | |||
[JsonProperty("embeds")] | |||
public Embed[] Embeds; //TODO: Parse this | |||
[JsonProperty("attachments")] | |||
public Attachment[] Attachments; | |||
[JsonProperty("content")] | |||
public string Content; | |||
[JsonProperty("author")] | |||
public UserReference Author; | |||
[JsonProperty("nonce")] | |||
public string Nonce; | |||
} | |||
//Roles | |||
public class RoleReference | |||
{ | |||
[JsonProperty("guild_id")] | |||
public string GuildId; | |||
[JsonProperty("role_id")] | |||
public string RoleId; | |||
} | |||
public class RoleInfo | |||
{ | |||
[JsonProperty("permissions")] | |||
public int Permissions; | |||
[JsonProperty("name")] | |||
public string Name; | |||
[JsonProperty("id")] | |||
public string Id; | |||
} | |||
//Invites | |||
public class Invite | |||
{ | |||
[JsonProperty("inviter")] | |||
public UserReference Inviter; | |||
[JsonProperty("guild")] | |||
public GuildReference Guild; | |||
[JsonProperty("channel")] | |||
public ChannelReference Channel; | |||
[JsonProperty("code")] | |||
public string Code; | |||
[JsonProperty("xkcdpass")] | |||
public string XkcdPass; | |||
} | |||
public class ExtendedInvite : Invite | |||
{ | |||
[JsonProperty("max_age")] | |||
public int MaxAge; | |||
[JsonProperty("max_uses")] | |||
public int MaxUses; | |||
[JsonProperty("revoked")] | |||
public bool IsRevoked; | |||
[JsonProperty("temporary")] | |||
public bool IsTemporary; | |||
[JsonProperty("uses")] | |||
public int Uses; | |||
[JsonProperty("created_at")] | |||
public DateTime CreatedAt; | |||
} | |||
} |
@@ -1,4 +1,4 @@ | |||
namespace Discord.Net.API | |||
namespace Discord.API | |||
{ | |||
internal static class Endpoints | |||
{ | |||
@@ -45,5 +45,6 @@ | |||
public const string StatusActiveMaintenance = "scheduled-maintenances/active.json"; | |||
public const string StatusUnresolvedMaintenance = "scheduled-maintenances/unresolved.json"; | |||
public const string StatusUpcomingMaintenance = "scheduled-maintenances/upcoming.json"; | |||
} | |||
} |
@@ -1,7 +1,7 @@ | |||
using System; | |||
using System.Net; | |||
namespace Discord.Net.API | |||
namespace Discord.API | |||
{ | |||
public class HttpException : Exception | |||
{ |
@@ -0,0 +1,142 @@ | |||
//Ignore unused/unassigned variable warnings | |||
#pragma warning disable CS0649 | |||
#pragma warning disable CS0169 | |||
using Newtonsoft.Json; | |||
namespace Discord.API | |||
{ | |||
//Auth | |||
internal sealed class RegisterRequest | |||
{ | |||
[JsonProperty("fingerprint")] | |||
public string Fingerprint; | |||
[JsonProperty("username")] | |||
public string Username; | |||
} | |||
internal sealed class LoginRequest | |||
{ | |||
[JsonProperty("email")] | |||
public string Email; | |||
[JsonProperty("password")] | |||
public string Password; | |||
} | |||
//Channels | |||
internal sealed class CreateChannelRequest | |||
{ | |||
[JsonProperty("name")] | |||
public string Name; | |||
[JsonProperty("type")] | |||
public string Type; | |||
} | |||
internal sealed class CreatePMChannelRequest | |||
{ | |||
[JsonProperty("recipient_id")] | |||
public string RecipientId; | |||
} | |||
internal sealed class EditChannelRequest | |||
{ | |||
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] | |||
public string Name; | |||
[JsonProperty("topic", NullValueHandling = NullValueHandling.Ignore)] | |||
public string Topic; | |||
} | |||
//Invites | |||
internal sealed class CreateInviteRequest | |||
{ | |||
[JsonProperty("max_age")] | |||
public int MaxAge; | |||
[JsonProperty("max_uses")] | |||
public int MaxUses; | |||
[JsonProperty("temporary")] | |||
public bool IsTemporary; | |||
[JsonProperty("xkcdpass")] | |||
public bool WithXkcdPass; | |||
} | |||
//Members | |||
internal sealed class EditMemberRequest | |||
{ | |||
[JsonProperty(PropertyName = "mute", NullValueHandling = NullValueHandling.Ignore)] | |||
public bool? Mute; | |||
[JsonProperty(PropertyName = "deaf", NullValueHandling = NullValueHandling.Ignore)] | |||
public bool? Deaf; | |||
[JsonProperty(PropertyName = "roles", NullValueHandling = NullValueHandling.Ignore)] | |||
public string[] Roles; | |||
} | |||
//Messages | |||
internal sealed class SendMessageRequest | |||
{ | |||
[JsonProperty("content")] | |||
public string Content; | |||
[JsonProperty("mentions")] | |||
public string[] Mentions; | |||
[JsonProperty("nonce", NullValueHandling = NullValueHandling.Ignore)] | |||
public string Nonce; | |||
[JsonProperty("tts", NullValueHandling = NullValueHandling.Ignore)] | |||
public bool IsTTS; | |||
} | |||
internal sealed class EditMessageRequest | |||
{ | |||
[JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)] | |||
public string Content; | |||
[JsonProperty("mentions", NullValueHandling = NullValueHandling.Ignore)] | |||
public string[] Mentions; | |||
} | |||
//Permissions | |||
internal sealed class SetChannelPermissionsRequest //Both creates and modifies | |||
{ | |||
[JsonProperty("id")] | |||
public string Id; | |||
[JsonProperty("type")] | |||
public string Type; | |||
[JsonProperty("allow")] | |||
public uint Allow; | |||
[JsonProperty("deny")] | |||
public uint Deny; | |||
} | |||
//Profile | |||
internal sealed class EditProfileRequest | |||
{ | |||
[JsonProperty(PropertyName = "password")] | |||
public string CurrentPassword; | |||
[JsonProperty(PropertyName = "email", NullValueHandling = NullValueHandling.Ignore)] | |||
public string Email; | |||
[JsonProperty(PropertyName = "new_password", NullValueHandling = NullValueHandling.Ignore)] | |||
public string Password; | |||
[JsonProperty(PropertyName = "username", NullValueHandling = NullValueHandling.Ignore)] | |||
public string Username; | |||
[JsonProperty(PropertyName = "avatar", NullValueHandling = NullValueHandling.Ignore)] | |||
public string Avatar; | |||
} | |||
//Roles | |||
internal sealed class EditRoleRequest | |||
{ | |||
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] | |||
public string Name; | |||
[JsonProperty("permissions", NullValueHandling = NullValueHandling.Ignore)] | |||
public uint? Permissions; | |||
} | |||
//Servers | |||
internal sealed class CreateServerRequest | |||
{ | |||
[JsonProperty("name")] | |||
public string Name; | |||
[JsonProperty("region")] | |||
public string Region; | |||
} | |||
internal sealed class EditServerRequest | |||
{ | |||
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] | |||
public string Name; | |||
[JsonProperty("region", NullValueHandling = NullValueHandling.Ignore)] | |||
public string Region; | |||
} | |||
} |
@@ -1,7 +1,7 @@ | |||
using System; | |||
using System.Net.Http; | |||
namespace Discord.Net.API | |||
namespace Discord.API | |||
{ | |||
internal partial class RestClient | |||
{ |
@@ -6,7 +6,7 @@ using System.Net.Http; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
namespace Discord.Net.API | |||
namespace Discord.API | |||
{ | |||
internal class RestSharpRestEngine : IRestEngine | |||
{ |
@@ -6,7 +6,7 @@ using System.Reflection; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
namespace Discord.Net.API | |||
namespace Discord.API | |||
{ | |||
internal interface IRestEngine | |||
{ |
@@ -1,6 +1,5 @@ | |||
using Discord.Helpers; | |||
using Discord.Net; | |||
using Discord.Net.API; | |||
using Discord.API; | |||
using Discord.Helpers; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
@@ -17,34 +16,54 @@ namespace Discord | |||
public partial class DiscordClient | |||
{ | |||
//Servers | |||
/// <summary> Creates a new server with the provided name and region (see Regions). </summary> | |||
public async Task<Server> CreateServer(string name, string region) | |||
public const int MaxMessageSize = 2000; | |||
//Bans | |||
/// <summary> Bans a user from the provided server. </summary> | |||
public Task Ban(Member member) | |||
=> Ban(member?.ServerId, member?.UserId); | |||
/// <summary> Bans a user from the provided server. </summary> | |||
public Task Ban(Server server, User user) | |||
=> Ban(server?.Id, user?.Id); | |||
/// <summary> Bans a user from the provided server. </summary> | |||
public Task Ban(Server server, string userId) | |||
=> Ban(server?.Id, userId); | |||
/// <summary> Bans a user from the provided server. </summary> | |||
public Task Ban(string server, User user) | |||
=> Ban(server, user?.Id); | |||
/// <summary> Bans a user from the provided server. </summary> | |||
public Task Ban(string serverId, string userId) | |||
{ | |||
CheckReady(); | |||
if (name == null) throw new ArgumentNullException(nameof(name)); | |||
if (region == null) throw new ArgumentNullException(nameof(region)); | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
if (userId == null) throw new ArgumentNullException(nameof(userId)); | |||
var response = await _api.CreateServer(name, region).ConfigureAwait(false); | |||
var server = _servers.GetOrAdd(response.Id); | |||
server.Update(response); | |||
return server; | |||
return _api.Ban(serverId, userId); | |||
} | |||
/// <summary> Leaves the provided server, destroying it if you are the owner. </summary> | |||
public Task<Server> LeaveServer(Server server) | |||
=> LeaveServer(server?.Id); | |||
/// <summary> Leaves the provided server, destroying it if you are the owner. </summary> | |||
public async Task<Server> LeaveServer(string serverId) | |||
/// <summary> Unbans a user from the provided server. </summary> | |||
public Task Unban(Member member) | |||
=> Unban(member?.ServerId, member?.UserId); | |||
/// <summary> Unbans a user from the provided server. </summary> | |||
public Task Unban(Server server, User user) | |||
=> Unban(server?.Id, user?.Id); | |||
/// <summary> Unbans a user from the provided server. </summary> | |||
public Task Unban(Server server, string userId) | |||
=> Unban(server?.Id, userId); | |||
/// <summary> Unbans a user from the provided server. </summary> | |||
public Task Unban(string server, User user) | |||
=> Unban(server, user?.Id); | |||
/// <summary> Unbans a user from the provided server. </summary> | |||
public async Task Unban(string serverId, string userId) | |||
{ | |||
CheckReady(); | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
if (userId == null) throw new ArgumentNullException(nameof(userId)); | |||
try { await _api.LeaveServer(serverId).ConfigureAwait(false); } | |||
try { await _api.Unban(serverId, userId).ConfigureAwait(false); } | |||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | |||
return _servers.TryRemove(serverId); | |||
} | |||
//Channels | |||
/// <summary> Creates a new channel with the provided name and type (see ChannelTypes). </summary> | |||
public Task<Channel> CreateChannel(Server server, string name, string type) | |||
@@ -62,6 +81,7 @@ namespace Discord | |||
channel.Update(response); | |||
return channel; | |||
} | |||
/// <summary> Returns the private channel with the provided user, creating one if it does not currently exist. </summary> | |||
public Task<Channel> CreatePMChannel(string userId) => CreatePMChannel(_users[userId], userId); | |||
/// <summary> Returns the private channel with the provided user, creating one if it does not currently exist. </summary> | |||
@@ -70,7 +90,7 @@ namespace Discord | |||
public Task<Channel> CreatePMChannel(Member member) => CreatePMChannel(member.User, member.UserId); | |||
private async Task<Channel> CreatePMChannel(User user, string userId) | |||
{ | |||
CheckReady(); | |||
CheckReady(); | |||
if (userId == null) throw new ArgumentNullException(nameof(userId)); | |||
Channel channel = null; | |||
@@ -85,6 +105,19 @@ namespace Discord | |||
return channel; | |||
} | |||
/// <summary> Edits the provided channel, changing only non-null attributes. </summary> | |||
public Task EditChannel(Channel channel) | |||
=> EditChannel(channel?.Id); | |||
/// <summary> Edits the provided channel, changing only non-null attributes. </summary> | |||
public Task EditChannel(string channelId, string name = null, string topic = null) | |||
{ | |||
CheckReady(); | |||
if (channelId == null) throw new ArgumentNullException(nameof(channelId)); | |||
if (topic == null) throw new ArgumentNullException(nameof(topic)); | |||
return _api.EditChannel(channelId, name: name, topic: topic); | |||
} | |||
/// <summary> Destroys the provided channel. </summary> | |||
public Task<Channel> DestroyChannel(Channel channel) | |||
=> DestroyChannel(channel?.Id); | |||
@@ -99,52 +132,6 @@ namespace Discord | |||
return _channels.TryRemove(channelId); | |||
} | |||
//Bans | |||
/// <summary> Bans a user from the provided server. </summary> | |||
public Task Ban(Member member) | |||
=> Ban(member?.ServerId, member?.UserId); | |||
/// <summary> Bans a user from the provided server. </summary> | |||
public Task Ban(Server server, User user) | |||
=> Ban(server?.Id, user?.Id); | |||
/// <summary> Bans a user from the provided server. </summary> | |||
public Task Ban(Server server, string userId) | |||
=> Ban(server?.Id, userId); | |||
/// <summary> Bans a user from the provided server. </summary> | |||
public Task Ban(string server, User user) | |||
=> Ban(server, user?.Id); | |||
/// <summary> Bans a user from the provided server. </summary> | |||
public Task Ban(string serverId, string userId) | |||
{ | |||
CheckReady(); | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
if (userId == null) throw new ArgumentNullException(nameof(userId)); | |||
return _api.Ban(serverId, userId); | |||
} | |||
/// <summary> Unbans a user from the provided server. </summary> | |||
public Task Unban(Member member) | |||
=> Unban(member?.ServerId, member?.UserId); | |||
/// <summary> Unbans a user from the provided server. </summary> | |||
public Task Unban(Server server, User user) | |||
=> Unban(server?.Id, user?.Id); | |||
/// <summary> Unbans a user from the provided server. </summary> | |||
public Task Unban(Server server, string userId) | |||
=> Unban(server?.Id, userId); | |||
/// <summary> Unbans a user from the provided server. </summary> | |||
public Task Unban(string server, User user) | |||
=> Unban(server, user?.Id); | |||
/// <summary> Unbans a user from the provided server. </summary> | |||
public async Task Unban(string serverId, string userId) | |||
{ | |||
CheckReady(); | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
if (userId == null) throw new ArgumentNullException(nameof(userId)); | |||
try { await _api.Unban(serverId, userId).ConfigureAwait(false); } | |||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | |||
} | |||
//Invites | |||
/// <summary> Creates a new invite to the default channel of the provided server. </summary> | |||
/// <param name="maxAge"> Time (in seconds) until the invite expires. Set to 0 to never expire. </param> | |||
@@ -178,14 +165,29 @@ namespace Discord | |||
return invite; | |||
} | |||
/// <summary> Deletes the provided invite. </summary> | |||
public async Task DestroyInvite(string inviteId) | |||
{ | |||
CheckReady(); | |||
if (inviteId == null) throw new ArgumentNullException(nameof(inviteId)); | |||
try | |||
{ | |||
//Check if this is a human-readable link and get its ID | |||
var response = await _api.GetInvite(inviteId).ConfigureAwait(false); | |||
await _api.DeleteInvite(response.Code).ConfigureAwait(false); | |||
} | |||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | |||
} | |||
/// <summary> Gets more info about the provided invite code. </summary> | |||
/// <remarks> Supported formats: inviteCode, xkcdCode, https://discord.gg/inviteCode, https://discord.gg/xkcdCode </remarks> | |||
public async Task<Invite> GetInvite(string id) | |||
public async Task<Invite> GetInvite(string inviteIdOrXkcd) | |||
{ | |||
CheckReady(); | |||
if (id == null) throw new ArgumentNullException(nameof(id)); | |||
if (inviteIdOrXkcd == null) throw new ArgumentNullException(nameof(inviteIdOrXkcd)); | |||
var response = await _api.GetInvite(id).ConfigureAwait(false); | |||
var response = await _api.GetInvite(inviteIdOrXkcd).ConfigureAwait(false); | |||
var invite = new Invite(this, response.Code, response.XkcdPass, response.Guild.Id); | |||
invite.Update(response); | |||
return invite; | |||
@@ -200,39 +202,42 @@ namespace Discord | |||
return _api.AcceptInvite(invite.Id); | |||
} | |||
/// <summary> Accepts the provided invite. </summary> | |||
public async Task AcceptInvite(string code) | |||
public async Task AcceptInvite(string inviteId) | |||
{ | |||
CheckReady(); | |||
if (code == null) throw new ArgumentNullException(nameof(code)); | |||
if (inviteId == null) throw new ArgumentNullException(nameof(inviteId)); | |||
//Remove trailing slash and any non-code url parts | |||
if (code.Length > 0 && code[code.Length - 1] == '/') | |||
code = code.Substring(0, code.Length - 1); | |||
int index = code.LastIndexOf('/'); | |||
if (inviteId.Length > 0 && inviteId[inviteId.Length - 1] == '/') | |||
inviteId = inviteId.Substring(0, inviteId.Length - 1); | |||
int index = inviteId.LastIndexOf('/'); | |||
if (index >= 0) | |||
code = code.Substring(index + 1); | |||
inviteId = inviteId.Substring(index + 1); | |||
//Check if this is a human-readable link and get its ID | |||
var invite = await GetInvite(code).ConfigureAwait(false); | |||
var invite = await GetInvite(inviteId).ConfigureAwait(false); | |||
await _api.AcceptInvite(invite.Id).ConfigureAwait(false); | |||
} | |||
/// <summary> Deletes the provided invite. </summary> | |||
public async Task DeleteInvite(string code) | |||
//Members | |||
public Task EditMember(Member member, bool? mute = null, bool? deaf = null, string[] roles = null) | |||
=> EditMember(member?.ServerId, member?.UserId, mute, deaf, roles); | |||
public Task EditMember(Server server, User user, bool? mute = null, bool? deaf = null, string[] roles = null) | |||
=> EditMember(server?.Id, user?.Id, mute, deaf, roles); | |||
public Task EditMember(Server server, string userId, bool? mute = null, bool? deaf = null, string[] roles = null) | |||
=> EditMember(server?.Id, userId, mute, deaf, roles); | |||
public Task EditMember(string serverId, User user, bool? mute = null, bool? deaf = null, string[] roles = null) | |||
=> EditMember(serverId, user?.Id, mute, deaf, roles); | |||
public Task EditMember(string serverId, string userId, bool? mute = null, bool? deaf = null, string[] roles = null) | |||
{ | |||
CheckReady(); | |||
if (code == null) throw new ArgumentNullException(nameof(code)); | |||
if (serverId == null) throw new NullReferenceException(nameof(serverId)); | |||
if (userId == null) throw new NullReferenceException(nameof(userId)); | |||
try | |||
{ | |||
//Check if this is a human-readable link and get its ID | |||
var response = await _api.GetInvite(code).ConfigureAwait(false); | |||
await _api.DeleteInvite(response.Code).ConfigureAwait(false); | |||
} | |||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | |||
return _api.EditMember(serverId, userId, mute, deaf, roles); | |||
} | |||
//Chat | |||
//Messages | |||
/// <summary> Sends a message to the provided channel. </summary> | |||
public Task<Message[]> SendMessage(Channel channel, string text) | |||
=> SendMessage(channel?.Id, text, new string[0]); | |||
@@ -252,18 +257,18 @@ namespace Discord | |||
if (text == null) throw new ArgumentNullException(nameof(text)); | |||
if (mentions == null) throw new ArgumentNullException(nameof(mentions)); | |||
int blockCount = (int)Math.Ceiling(text.Length / (double)DiscordAPIClient.MaxMessageSize); | |||
int blockCount = (int)Math.Ceiling(text.Length / (double)MaxMessageSize); | |||
Message[] result = new Message[blockCount]; | |||
for (int i = 0; i < blockCount; i++) | |||
{ | |||
int index = i * DiscordAPIClient.MaxMessageSize; | |||
int index = i * MaxMessageSize; | |||
string blockText = text.Substring(index, Math.Min(2000, text.Length - index)); | |||
var nonce = GenerateNonce(); | |||
if (_config.UseMessageQueue) | |||
{ | |||
var msg = _messages.GetOrAdd("nonce_" + nonce, channel.Id, _currentUserId); | |||
var currentMember = _members[msg.UserId, channel.ServerId]; | |||
msg.Update(new Net.API.Message | |||
msg.Update(new API.Message | |||
{ | |||
Content = blockText, | |||
Timestamp = DateTime.UtcNow, | |||
@@ -302,35 +307,37 @@ namespace Discord | |||
return await SendMessage(channel, text, new string[0]).ConfigureAwait(false); | |||
} | |||
/// <summary> Edits a message the provided message. </summary> | |||
public Task EditMessage(Message message, string text) | |||
=> EditMessage(message?.ChannelId, message?.Id, text, new string[0]); | |||
/// <summary> Edits a message the provided message. </summary> | |||
public Task EditMessage(Channel channel, string messageId, string text) | |||
=> EditMessage(channel?.Id, messageId, text, new string[0]); | |||
/// <summary> Edits a message the provided message. </summary> | |||
public Task EditMessage(string channelId, string messageId, string text) | |||
=> EditMessage(channelId, messageId, text, new string[0]); | |||
/// <summary> Edits a message the provided message, mentioning certain users. </summary> | |||
/// <summary> Sends a file to the provided channel. </summary> | |||
public Task SendFile(Channel channel, string filePath) | |||
=> SendFile(channel?.Id, filePath); | |||
/// <summary> Sends a file to the provided channel. </summary> | |||
public Task SendFile(string channelId, string filePath) | |||
{ | |||
CheckReady(); | |||
if (channelId == null) throw new ArgumentNullException(nameof(channelId)); | |||
if (filePath == null) throw new ArgumentNullException(nameof(filePath)); | |||
return _api.SendFile(channelId, filePath); | |||
} | |||
/// <summary> Edits the provided message, changing only non-null attributes. </summary> | |||
/// <remarks> While not required, it is recommended to include a mention reference in the text (see Mention.User). </remarks> | |||
public Task EditMessage(Message message, string text, string[] mentions) | |||
public Task EditMessage(Message message, string text = null, string[] mentions = null) | |||
=> EditMessage(message?.ChannelId, message?.Id, text, mentions); | |||
/// <summary> Edits a message the provided message, mentioning certain users. </summary> | |||
/// <summary> Edits the provided message, changing only non-null attributes. </summary> | |||
/// <remarks> While not required, it is recommended to include a mention reference in the text (see Mention.User). </remarks> | |||
public Task EditMessage(Channel channel, string messageId, string text, string[] mentions) | |||
public Task EditMessage(Channel channel, string messageId, string text = null, string[] mentions = null) | |||
=> EditMessage(channel?.Id, messageId, text, mentions); | |||
/// <summary> Edits a message the provided message, mentioning certain users. </summary> | |||
/// <summary> Edits the provided message, changing only non-null attributes. </summary> | |||
/// <remarks> While not required, it is recommended to include a mention reference in the text (see Mention.User). </remarks> | |||
public async Task EditMessage(string channelId, string messageId, string text, string[] mentions) | |||
public async Task EditMessage(string channelId, string messageId, string text = null, string[] mentions = null) | |||
{ | |||
CheckReady(); | |||
if (channelId == null) throw new ArgumentNullException(nameof(channelId)); | |||
if (messageId == null) throw new ArgumentNullException(nameof(messageId)); | |||
if (text == null) throw new ArgumentNullException(nameof(text)); | |||
if (mentions == null) throw new ArgumentNullException(nameof(mentions)); | |||
if (text.Length > DiscordAPIClient.MaxMessageSize) | |||
text = text.Substring(0, DiscordAPIClient.MaxMessageSize); | |||
if (text != null && text.Length > MaxMessageSize) | |||
text = text.Substring(0, MaxMessageSize); | |||
var model = await _api.EditMessage(messageId, channelId, text, mentions).ConfigureAwait(false); | |||
var msg = _messages[messageId]; | |||
@@ -383,19 +390,6 @@ namespace Discord | |||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | |||
} | |||
} | |||
/// <summary> Sends a file to the provided channel. </summary> | |||
public Task SendFile(Channel channel, string filePath) | |||
=> SendFile(channel?.Id, filePath); | |||
/// <summary> Sends a file to the provided channel. </summary> | |||
public Task SendFile(string channelId, string filePath) | |||
{ | |||
CheckReady(); | |||
if (channelId == null) throw new ArgumentNullException(nameof(channelId)); | |||
if (filePath == null) throw new ArgumentNullException(nameof(filePath)); | |||
return _api.SendFile(channelId, filePath); | |||
} | |||
/// <summary> Downloads last count messages from the server, starting at beforeMessageId if it's provided. </summary> | |||
public Task<Message[]> DownloadMessages(Channel channel, int count, string beforeMessageId = null, bool cache = true) | |||
@@ -449,113 +443,6 @@ namespace Discord | |||
return null; | |||
} | |||
//Roles | |||
/// <summary>Note: due to current API limitations, the created role cannot be returned. </summary> | |||
public Task CreateRole(Server server) | |||
=> CreateRole(server?.Id); | |||
/// <summary>Note: due to current API limitations, the created role cannot be returned. </summary> | |||
public Task CreateRole(string serverId) | |||
{ | |||
CheckReady(); | |||
if (serverId == null) throw new NullReferenceException(nameof(serverId)); | |||
return _api.CreateRole(serverId); | |||
} | |||
public Task RenameRole(Role role, string newName) | |||
=> RenameRole(role?.ServerId, role?.Id, newName); | |||
public Task RenameRole(string serverId, string roleId, string newName) | |||
{ | |||
CheckReady(); | |||
if (roleId == null) throw new NullReferenceException(nameof(roleId)); | |||
if (newName == null) throw new NullReferenceException(nameof(newName)); | |||
return _api.RenameRole(serverId, roleId, newName); | |||
} | |||
public Task DeleteRole(Role role) | |||
=> DeleteRole(role?.ServerId, role?.Id); | |||
public Task DeleteRole(string serverId, string roleId) | |||
{ | |||
CheckReady(); | |||
if (roleId == null) throw new NullReferenceException(nameof(roleId)); | |||
return _api.DeleteRole(serverId, roleId); | |||
} | |||
public Task AddRoleMember(Role role, string serverId, string userId) | |||
=> AddRoleMember(role?.Id, GetMember(serverId, userId)); | |||
public Task AddRoleMember(Role role, string serverId, User user) | |||
=> AddRoleMember(role?.Id, GetMember(serverId, user)); | |||
public Task AddRoleMember(Role role, Server server, string userId) | |||
=> AddRoleMember(role?.Id, GetMember(server, userId)); | |||
public Task AddRoleMember(Role role, Server server, User user) | |||
=> AddRoleMember(role?.Id, GetMember(server, user)); | |||
public Task AddRoleMember(Role role, Member member) | |||
=> AddRoleMember(role?.Id, member); | |||
public Task AddRoleMember(string roleId, string serverId, string userId) | |||
=> AddRoleMember(roleId, GetMember(serverId, userId)); | |||
public Task AddRoleMember(string roleId, string serverId, User user) | |||
=> AddRoleMember(roleId, GetMember(serverId, user)); | |||
public Task AddRoleMember(string roleId, Server server, string userId) | |||
=> AddRoleMember(roleId, GetMember(server, userId)); | |||
public Task AddRoleMember(string roleId, Server server, User user) | |||
=> AddRoleMember(roleId, GetMember(server, user)); | |||
public Task AddRoleMember(string roleId, Member member) | |||
{ | |||
CheckReady(); | |||
if (roleId == null) throw new NullReferenceException(nameof(roleId)); | |||
if (member == null) throw new NullReferenceException(nameof(member)); | |||
if (!member.RoleIds.Contains(roleId)) | |||
{ | |||
var oldRoles = member.RoleIds; | |||
string[] newRoles = new string[oldRoles.Length + 1]; | |||
for (int i = 0; i < oldRoles.Length; i++) | |||
newRoles[i] = oldRoles[i]; | |||
return _api.SetMemberRoles(member.ServerId, member.UserId, newRoles); | |||
} | |||
return TaskHelper.CompletedTask; | |||
} | |||
public Task RemoveRoleMember(Role role, string serverId, string userId) | |||
=> RemoveRoleMember(role?.Id, GetMember(serverId, userId)); | |||
public Task RemoveRoleMember(Role role, string serverId, User user) | |||
=> RemoveRoleMember(role?.Id, GetMember(serverId, user)); | |||
public Task RemoveRoleMember(Role role, Server server, string userId) | |||
=> RemoveRoleMember(role?.Id, GetMember(server, userId)); | |||
public Task RemoveRoleMember(Role role, Server server, User user) | |||
=> RemoveRoleMember(role?.Id, GetMember(server, user)); | |||
public Task RemoveRoleMember(Role role, Member member) | |||
=> RemoveRoleMember(role?.Id, member); | |||
public Task RemoveRoleMember(string roleId, string serverId, string userId) | |||
=> RemoveRoleMember(roleId, GetMember(serverId, userId)); | |||
public Task RemoveRoleMember(string roleId, string serverId, User user) | |||
=> RemoveRoleMember(roleId, GetMember(serverId, user)); | |||
public Task RemoveRoleMember(string roleId, Server server, string userId) | |||
=> RemoveRoleMember(roleId, GetMember(server, userId)); | |||
public Task RemoveRoleMember(string roleId, Server server, User user) | |||
=> RemoveRoleMember(roleId, GetMember(server, user)); | |||
public Task RemoveRoleMember(string roleId, Member member) | |||
{ | |||
CheckReady(); | |||
if (roleId == null) throw new NullReferenceException(nameof(roleId)); | |||
if (member == null) throw new NullReferenceException(nameof(member)); | |||
if (member.RoleIds.Contains(roleId)) | |||
{ | |||
var oldRoles = member.RoleIds; | |||
string[] newRoles = new string[oldRoles.Length - 1]; | |||
for (int i = 0, j = 0; i < oldRoles.Length; i++) | |||
{ | |||
if (oldRoles[i] != roleId) | |||
newRoles[j++] = oldRoles[i]; | |||
} | |||
return _api.SetMemberRoles(member.ServerId, member.UserId, newRoles); | |||
} | |||
return TaskHelper.CompletedTask; | |||
} | |||
//Permissions | |||
public Task SetChannelUserPermissions(Channel channel, Member member, PackedPermissions allow, PackedPermissions deny) | |||
=> SetChannelPermissions(channel?.Id, member?.UserId, "member", allow, deny); | |||
@@ -585,7 +472,7 @@ namespace Discord | |||
if (channelId == null) throw new NullReferenceException(nameof(channelId)); | |||
if (userOrRoleId == null) throw new NullReferenceException(nameof(userOrRoleId)); | |||
return _api.SetChannelPermissions(channelId, userOrRoleId, idType, allow, deny); | |||
return _api.SetChannelPermissions(channelId, userOrRoleId, idType, allow.RawValue, deny.RawValue); | |||
//TODO: Remove permission from cache | |||
} | |||
@@ -625,128 +512,90 @@ namespace Discord | |||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | |||
} | |||
//Voice | |||
/// <summary> Mutes a user on the provided server. </summary> | |||
public Task Mute(Member member) | |||
=> Mute(member?.ServerId, member?.UserId); | |||
/// <summary> Mutes a user on the provided server. </summary> | |||
public Task Mute(Server server, User user) | |||
=> Mute(server?.Id, user?.Id); | |||
/// <summary> Mutes a user on the provided server. </summary> | |||
public Task Mute(Server server, string userId) | |||
=> Mute(server?.Id, userId); | |||
/// <summary> Mutes a user on the provided server. </summary> | |||
public Task Mute(string server, User user) | |||
=> Mute(server, user?.Id); | |||
/// <summary> Mutes a user on the provided server. </summary> | |||
public Task Mute(string serverId, string userId) | |||
//Profile | |||
public Task<EditProfileResponse> EditProfile(string currentPassword, | |||
string username = null, string email = null, string password = null, | |||
AvatarImageType avatarType = AvatarImageType.Png, byte[] avatar = null) | |||
{ | |||
CheckReady(); | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
if (userId == null) throw new ArgumentNullException(nameof(userId)); | |||
if (currentPassword == null) throw new ArgumentNullException(nameof(currentPassword)); | |||
return _api.Mute(serverId, userId); | |||
return _api.EditProfile(currentPassword, username: username, email: email, password: password, | |||
avatarType: avatarType, avatar: avatar); | |||
} | |||
/// <summary> Mutes a user on the provided server. </summary> | |||
public Task Unmute(Member member) | |||
=> Unmute(member?.ServerId, member?.UserId); | |||
/// <summary> Unmutes a user on the provided server. </summary> | |||
public Task Unmute(Server server, User user) | |||
=> Unmute(server?.Id, user?.Id); | |||
/// <summary> Unmutes a user on the provided server. </summary> | |||
public Task Unmute(Server server, string userId) | |||
=> Unmute(server?.Id, userId); | |||
/// <summary> Unmutes a user on the provided server. </summary> | |||
public Task Unmute(string server, User user) | |||
=> Unmute(server, user?.Id); | |||
/// <summary> Unmutes a user on the provided server. </summary> | |||
public Task Unmute(string serverId, string userId) | |||
//Roles | |||
/// <summary> Note: due to current API limitations, the created role cannot be returned. </summary> | |||
public Task CreateRole(Server server) | |||
=> CreateRole(server?.Id); | |||
/// <summary> Note: due to current API limitations, the created role cannot be returned. </summary> | |||
public Task CreateRole(string serverId) | |||
{ | |||
CheckReady(); | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
if (userId == null) throw new ArgumentNullException(nameof(userId)); | |||
if (serverId == null) throw new NullReferenceException(nameof(serverId)); | |||
return _api.Unmute(serverId, userId); | |||
return _api.CreateRole(serverId); | |||
} | |||
/// <summary> Deafens a user on the provided server. </summary> | |||
public Task Deafen(Member member) | |||
=> Deafen(member?.ServerId, member?.UserId); | |||
/// <summary> Deafens a user on the provided server. </summary> | |||
public Task Deafen(Server server, User user) | |||
=> Deafen(server?.Id, user?.Id); | |||
/// <summary> Deafens a user on the provided server. </summary> | |||
public Task Deafen(Server server, string userId) | |||
=> Deafen(server?.Id, userId); | |||
/// <summary> Deafens a user on the provided server. </summary> | |||
public Task Deafen(string server, User user) | |||
=> Deafen(server, user?.Id); | |||
/// <summary> Deafens a user on the provided server. </summary> | |||
public Task Deafen(string serverId, string userId) | |||
public Task EditRole(Role role, string newName) | |||
=> EditRole(role?.ServerId, role?.Id, newName); | |||
public Task EditRole(string serverId, string roleId, string name = null, PackedPermissions permissions = null) | |||
{ | |||
CheckReady(); | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
if (userId == null) throw new ArgumentNullException(nameof(userId)); | |||
if (serverId == null) throw new NullReferenceException(nameof(serverId)); | |||
if (roleId == null) throw new NullReferenceException(nameof(roleId)); | |||
return _api.Deafen(serverId, userId); | |||
return _api.EditRole(serverId, roleId, name: name, permissions: permissions?.RawValue); | |||
} | |||
/// <summary> Undeafens a user on the provided server. </summary> | |||
public Task Undeafen(Member member) | |||
=> Undeafen(member?.ServerId, member?.UserId); | |||
/// <summary> Undeafens a user on the provided server. </summary> | |||
public Task Undeafen(Server server, User user) | |||
=> Undeafen(server?.Id, user?.Id); | |||
/// <summary> Undeafens a user on the provided server. </summary> | |||
public Task Undeafen(Server server, string userId) | |||
=> Undeafen(server?.Id, userId); | |||
/// <summary> Undeafens a user on the provided server. </summary> | |||
public Task Undeafen(string server, User user) | |||
=> Undeafen(server, user?.Id); | |||
/// <summary> Undeafens a user on the provided server. </summary> | |||
public Task Undeafen(string serverId, string userId) | |||
public Task DeleteRole(Role role) | |||
=> DeleteRole(role?.ServerId, role?.Id); | |||
public Task DeleteRole(string serverId, string roleId) | |||
{ | |||
CheckReady(); | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
if (userId == null) throw new ArgumentNullException(nameof(userId)); | |||
if (serverId == null) throw new NullReferenceException(nameof(serverId)); | |||
if (roleId == null) throw new NullReferenceException(nameof(roleId)); | |||
return _api.Undeafen(serverId, userId); | |||
return _api.DeleteRole(serverId, roleId); | |||
} | |||
//Profile | |||
/// <summary> Changes your username to newName. </summary> | |||
public async Task ChangeUsername(string newName, string currentEmail, string currentPassword) | |||
{ | |||
CheckReady(); | |||
var response = await _api.ChangeUsername(newName, currentEmail, currentPassword).ConfigureAwait(false); | |||
_currentUser.Update(response); | |||
foreach (var membership in _currentUser.Memberships) | |||
membership.Update(response); | |||
} | |||
/// <summary> Changes your email to newEmail. </summary> | |||
public async Task ChangeEmail(string newEmail, string currentPassword) | |||
//Servers | |||
/// <summary> Creates a new server with the provided name and region (see Regions). </summary> | |||
public async Task<Server> CreateServer(string name, string region) | |||
{ | |||
CheckReady(); | |||
var response = await _api.ChangeEmail(newEmail, currentPassword).ConfigureAwait(false); | |||
_currentUser.Update(response); | |||
if (name == null) throw new ArgumentNullException(nameof(name)); | |||
if (region == null) throw new ArgumentNullException(nameof(region)); | |||
var response = await _api.CreateServer(name, region).ConfigureAwait(false); | |||
var server = _servers.GetOrAdd(response.Id); | |||
server.Update(response); | |||
return server; | |||
} | |||
/// <summary> Changes your password to newPassword. </summary> | |||
public async Task ChangePassword(string newPassword, string currentEmail, string currentPassword) | |||
/// <summary> Edits the provided server, changing only non-null attributes. </summary> | |||
public Task EditServer(Server server) | |||
=> EditServer(server?.Id); | |||
/// <summary> Edits the provided server, changing only non-null attributes. </summary> | |||
public Task EditServer(string serverId, string name = null, string region = null) | |||
{ | |||
CheckReady(); | |||
await _api.ChangePassword(newPassword, currentEmail, currentPassword).ConfigureAwait(false); | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
return _api.EditServer(serverId, name: name, region: region); | |||
} | |||
/// <summary> Changes your avatar. </summary> | |||
/// <remarks>Only supports PNG and JPEG (see AvatarImageType)</remarks> | |||
public async Task ChangeAvatar(AvatarImageType imageType, byte[] bytes, string currentEmail, string currentPassword) | |||
/// <summary> Leaves the provided server, destroying it if you are the owner. </summary> | |||
public Task<Server> LeaveServer(Server server) | |||
=> LeaveServer(server?.Id); | |||
/// <summary> Leaves the provided server, destroying it if you are the owner. </summary> | |||
public async Task<Server> LeaveServer(string serverId) | |||
{ | |||
CheckReady(); | |||
var response = await _api.ChangeAvatar(imageType, bytes, currentEmail, currentPassword).ConfigureAwait(false); | |||
_currentUser.Update(response); | |||
foreach (var membership in _currentUser.Memberships) | |||
membership.Update(response); | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
try { await _api.LeaveServer(serverId).ConfigureAwait(false); } | |||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | |||
return _servers.TryRemove(serverId); | |||
} | |||
} | |||
} |
@@ -1,4 +1,5 @@ | |||
using Discord.Helpers; | |||
using Discord.WebSockets; | |||
using System; | |||
using System.Threading.Tasks; | |||
@@ -36,7 +37,7 @@ namespace Discord | |||
{ | |||
CheckReady(checkVoice: true); | |||
if (_voiceSocket.State != Net.WebSockets.WebSocketState.Disconnected) | |||
if (_voiceSocket.State != WebSocketState.Disconnected) | |||
{ | |||
var serverId = _voiceSocket.CurrentVoiceServerId; | |||
if (serverId != null) | |||
@@ -1,8 +1,8 @@ | |||
using Discord.Collections; | |||
using Discord.API; | |||
using Discord.Collections; | |||
using Discord.Helpers; | |||
using Discord.Net; | |||
using Discord.Net.API; | |||
using Discord.Net.WebSockets; | |||
using Discord.WebSockets; | |||
using Discord.WebSockets.Data; | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Concurrent; | |||
@@ -10,6 +10,7 @@ using System.Net; | |||
using System.Runtime.ExceptionServices; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
using VoiceWebSocket = Discord.WebSockets.Voice.VoiceWebSocket; | |||
namespace Discord | |||
{ | |||
@@ -279,7 +280,7 @@ namespace Discord | |||
//Global | |||
case "READY": //Resync | |||
{ | |||
var data = e.Payload.ToObject<Events.Ready>(_serializer); | |||
var data = e.Payload.ToObject<ReadyEvent>(_serializer); | |||
_currentUserId = data.User.Id; | |||
_currentUser = _users.GetOrAdd(data.User.Id); | |||
_currentUser.Update(data.User); | |||
@@ -303,7 +304,7 @@ namespace Discord | |||
//Servers | |||
case "GUILD_CREATE": | |||
{ | |||
var model = e.Payload.ToObject<Events.GuildCreate>(_serializer); | |||
var model = e.Payload.ToObject<GuildCreateEvent>(_serializer); | |||
var server = _servers.GetOrAdd(model.Id); | |||
server.Update(model); | |||
RaiseServerCreated(server); | |||
@@ -311,7 +312,7 @@ namespace Discord | |||
break; | |||
case "GUILD_UPDATE": | |||
{ | |||
var model = e.Payload.ToObject<Events.GuildUpdate>(_serializer); | |||
var model = e.Payload.ToObject<GuildUpdateEvent>(_serializer); | |||
var server = _servers[model.Id]; | |||
if (server != null) | |||
{ | |||
@@ -322,7 +323,7 @@ namespace Discord | |||
break; | |||
case "GUILD_DELETE": | |||
{ | |||
var data = e.Payload.ToObject<Events.GuildDelete>(_serializer); | |||
var data = e.Payload.ToObject<GuildDeleteEvent>(_serializer); | |||
var server = _servers.TryRemove(data.Id); | |||
if (server != null) | |||
RaiseServerDestroyed(server); | |||
@@ -332,7 +333,7 @@ namespace Discord | |||
//Channels | |||
case "CHANNEL_CREATE": | |||
{ | |||
var data = e.Payload.ToObject<Events.ChannelCreate>(_serializer); | |||
var data = e.Payload.ToObject<ChannelCreateEvent>(_serializer); | |||
Channel channel; | |||
if (data.IsPrivate) | |||
{ | |||
@@ -348,7 +349,7 @@ namespace Discord | |||
break; | |||
case "CHANNEL_UPDATE": | |||
{ | |||
var data = e.Payload.ToObject<Events.ChannelUpdate>(_serializer); | |||
var data = e.Payload.ToObject<ChannelUpdateEvent>(_serializer); | |||
var channel = _channels[data.Id]; | |||
if (channel != null) | |||
{ | |||
@@ -359,7 +360,7 @@ namespace Discord | |||
break; | |||
case "CHANNEL_DELETE": | |||
{ | |||
var data = e.Payload.ToObject<Events.ChannelDelete>(_serializer); | |||
var data = e.Payload.ToObject<ChannelDeleteEvent>(_serializer); | |||
var channel = _channels.TryRemove(data.Id); | |||
if (channel != null) | |||
RaiseChannelDestroyed(channel); | |||
@@ -369,7 +370,7 @@ namespace Discord | |||
//Members | |||
case "GUILD_MEMBER_ADD": | |||
{ | |||
var data = e.Payload.ToObject<Events.GuildMemberAdd>(_serializer); | |||
var data = e.Payload.ToObject<GuildMemberAddEvent>(_serializer); | |||
var user = _users.GetOrAdd(data.User.Id); | |||
var member = _members.GetOrAdd(data.User.Id, data.GuildId); | |||
user.Update(data.User); | |||
@@ -381,7 +382,7 @@ namespace Discord | |||
break; | |||
case "GUILD_MEMBER_UPDATE": | |||
{ | |||
var data = e.Payload.ToObject<Events.GuildMemberUpdate>(_serializer); | |||
var data = e.Payload.ToObject<GuildMemberUpdateEvent>(_serializer); | |||
var member = _members[data.User.Id, data.GuildId]; | |||
if (member != null) | |||
{ | |||
@@ -392,7 +393,7 @@ namespace Discord | |||
break; | |||
case "GUILD_MEMBER_REMOVE": | |||
{ | |||
var data = e.Payload.ToObject<Events.GuildMemberRemove>(_serializer); | |||
var data = e.Payload.ToObject<GuildMemberRemoveEvent>(_serializer); | |||
var member = _members.TryRemove(data.UserId, data.GuildId); | |||
if (member != null) | |||
RaiseUserRemoved(member); | |||
@@ -402,7 +403,7 @@ namespace Discord | |||
//Roles | |||
case "GUILD_ROLE_CREATE": | |||
{ | |||
var data = e.Payload.ToObject<Events.GuildRoleCreate>(_serializer); | |||
var data = e.Payload.ToObject<GuildRoleCreateEvent>(_serializer); | |||
var role = _roles.GetOrAdd(data.Data.Id, data.GuildId); | |||
role.Update(data.Data); | |||
RaiseRoleUpdated(role); | |||
@@ -410,7 +411,7 @@ namespace Discord | |||
break; | |||
case "GUILD_ROLE_UPDATE": | |||
{ | |||
var data = e.Payload.ToObject<Events.GuildRoleUpdate>(_serializer); | |||
var data = e.Payload.ToObject<GuildRoleUpdateEvent>(_serializer); | |||
var role = _roles[data.Data.Id]; | |||
if (role != null) | |||
role.Update(data.Data); | |||
@@ -419,7 +420,7 @@ namespace Discord | |||
break; | |||
case "GUILD_ROLE_DELETE": | |||
{ | |||
var data = e.Payload.ToObject<Events.GuildRoleDelete>(_serializer); | |||
var data = e.Payload.ToObject<GuildRoleDeleteEvent>(_serializer); | |||
var role = _roles.TryRemove(data.RoleId); | |||
if (role != null) | |||
RaiseRoleDeleted(role); | |||
@@ -429,7 +430,7 @@ namespace Discord | |||
//Bans | |||
case "GUILD_BAN_ADD": | |||
{ | |||
var data = e.Payload.ToObject<Events.GuildBanAdd>(_serializer); | |||
var data = e.Payload.ToObject<GuildBanAddEvent>(_serializer); | |||
var server = _servers[data.GuildId]; | |||
if (server != null) | |||
{ | |||
@@ -440,7 +441,7 @@ namespace Discord | |||
break; | |||
case "GUILD_BAN_REMOVE": | |||
{ | |||
var data = e.Payload.ToObject<Events.GuildBanRemove>(_serializer); | |||
var data = e.Payload.ToObject<GuildBanRemoveEvent>(_serializer); | |||
var server = _servers[data.GuildId]; | |||
if (server != null && server.RemoveBan(data.UserId)) | |||
RaiseBanRemoved(data.UserId, server); | |||
@@ -450,7 +451,7 @@ namespace Discord | |||
//Messages | |||
case "MESSAGE_CREATE": | |||
{ | |||
var data = e.Payload.ToObject<Events.MessageCreate>(_serializer); | |||
var data = e.Payload.ToObject<MessageCreateEvent>(_serializer); | |||
Message msg = null; | |||
bool wasLocal = _config.UseMessageQueue && data.Author.Id == _currentUserId && data.Nonce != null; | |||
@@ -490,7 +491,7 @@ namespace Discord | |||
break; | |||
case "MESSAGE_UPDATE": | |||
{ | |||
var data = e.Payload.ToObject<Events.MessageUpdate>(_serializer); | |||
var data = e.Payload.ToObject<MessageUpdateEvent>(_serializer); | |||
var msg = _messages[data.Id]; | |||
if (msg != null) | |||
{ | |||
@@ -501,7 +502,7 @@ namespace Discord | |||
break; | |||
case "MESSAGE_DELETE": | |||
{ | |||
var data = e.Payload.ToObject<Events.MessageDelete>(_serializer); | |||
var data = e.Payload.ToObject<MessageDeleteEvent>(_serializer); | |||
var msg = _messages.TryRemove(data.Id); | |||
if (msg != null) | |||
RaiseMessageDeleted(msg); | |||
@@ -509,7 +510,7 @@ namespace Discord | |||
break; | |||
case "MESSAGE_ACK": | |||
{ | |||
var data = e.Payload.ToObject<Events.MessageAck>(_serializer); | |||
var data = e.Payload.ToObject<MessageAckEvent>(_serializer); | |||
var msg = GetMessage(data.MessageId); | |||
if (msg != null) | |||
RaiseMessageReadRemotely(msg); | |||
@@ -519,7 +520,7 @@ namespace Discord | |||
//Statuses | |||
case "PRESENCE_UPDATE": | |||
{ | |||
var data = e.Payload.ToObject<Events.PresenceUpdate>(_serializer); | |||
var data = e.Payload.ToObject<PresenceUpdateEvent>(_serializer); | |||
var member = _members[data.User.Id, data.GuildId]; | |||
/*if (_config.TrackActivity) | |||
{ | |||
@@ -536,7 +537,7 @@ namespace Discord | |||
break; | |||
case "VOICE_STATE_UPDATE": | |||
{ | |||
var data = e.Payload.ToObject<Events.VoiceStateUpdate>(_serializer); | |||
var data = e.Payload.ToObject<VoiceStateUpdateEvent>(_serializer); | |||
var member = _members[data.UserId, data.GuildId]; | |||
/*if (_config.TrackActivity) | |||
{ | |||
@@ -558,7 +559,7 @@ namespace Discord | |||
break; | |||
case "TYPING_START": | |||
{ | |||
var data = e.Payload.ToObject<Events.TypingStart>(_serializer); | |||
var data = e.Payload.ToObject<TypingStartEvent>(_serializer); | |||
var channel = _channels[data.ChannelId]; | |||
var user = _users[data.UserId]; | |||
@@ -587,7 +588,7 @@ namespace Discord | |||
//Voice | |||
case "VOICE_SERVER_UPDATE": | |||
{ | |||
var data = e.Payload.ToObject<Events.VoiceServerUpdate>(_serializer); | |||
var data = e.Payload.ToObject<VoiceServerUpdateEvent>(_serializer); | |||
if (data.GuildId == _voiceSocket.CurrentVoiceServerId) | |||
{ | |||
var server = _servers[data.GuildId]; | |||
@@ -603,7 +604,7 @@ namespace Discord | |||
//Settings | |||
case "USER_UPDATE": | |||
{ | |||
var data = e.Payload.ToObject<Events.UserUpdate>(_serializer); | |||
var data = e.Payload.ToObject<UserUpdateEvent>(_serializer); | |||
var user = _users[data.Id]; | |||
if (user != null) | |||
{ | |||
@@ -670,8 +671,8 @@ namespace Discord | |||
_token = token; | |||
_state = (int)DiscordClientState.Connecting; | |||
string url = (await _api.GetWebSocketEndpoint().ConfigureAwait(false)).Url; | |||
if (_config.LogLevel >= LogMessageSeverity.Verbose) | |||
string url = (await _api.Gateway().ConfigureAwait(false)).Url; | |||
if (_config.LogLevel >= LogMessageSeverity.Verbose) | |||
RaiseOnLog(LogMessageSeverity.Verbose, LogMessageSource.Client, $"Websocket endpoint: {url}"); | |||
_dataSocket.Host = url; | |||
@@ -838,7 +839,7 @@ namespace Discord | |||
while (_pendingMessages.TryDequeue(out msg)) | |||
{ | |||
bool hasFailed = false; | |||
Responses.SendMessage response = null; | |||
SendMessageResponse response = null; | |||
try | |||
{ | |||
response = await _api.SendMessage(msg.ChannelId, msg.RawText, msg.MentionIds, msg.Nonce, msg.IsTTS).ConfigureAwait(false); | |||
@@ -1,5 +1,4 @@ | |||
using Discord.Net.API; | |||
using System.Text; | |||
using System.Text; | |||
namespace Discord | |||
{ | |||
@@ -11,7 +10,7 @@ namespace Discord | |||
static Format() | |||
{ | |||
_patterns = new string[] { "__", "_", "**", "*", "~~" }; | |||
_builder = new StringBuilder(DiscordAPIClient.MaxMessageSize); | |||
_builder = new StringBuilder(DiscordClient.MaxMessageSize); | |||
} | |||
/// <summary> Removes all special formatting characters from the provided text. </summary> | |||
@@ -1,9 +1,4 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
namespace Discord | |||
namespace Discord | |||
{ | |||
public static class Mention | |||
{ | |||
@@ -1,5 +1,4 @@ | |||
using Discord.Net.API; | |||
using Newtonsoft.Json; | |||
using Newtonsoft.Json; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
@@ -64,14 +63,14 @@ namespace Discord | |||
_messages = new ConcurrentDictionary<string, bool>(); | |||
} | |||
internal void Update(ChannelReference model) | |||
internal void Update(API.ChannelReference model) | |||
{ | |||
Name = model.Name; | |||
Type = model.Type; | |||
} | |||
internal void Update(ChannelInfo model) | |||
internal void Update(API.ChannelInfo model) | |||
{ | |||
Update(model as ChannelReference); | |||
Update(model as API.ChannelReference); | |||
Position = model.Position; | |||
@@ -1,5 +1,4 @@ | |||
using Discord.Net.API; | |||
using Newtonsoft.Json; | |||
using Newtonsoft.Json; | |||
namespace Discord | |||
{ | |||
@@ -24,7 +23,7 @@ namespace Discord | |||
public string XkcdPass { get; } | |||
/// <summary> Returns a URL for this invite using XkcdPass if available or Id if not. </summary> | |||
public string Url => Endpoints.InviteUrl(XkcdPass ?? Id); | |||
public string Url => API.Endpoints.InviteUrl(XkcdPass ?? Id); | |||
/// <summary> Returns the id of the user that created this invite. </summary> | |||
public string InviterId { get; internal set; } | |||
@@ -54,16 +53,16 @@ namespace Discord | |||
public override string ToString() => XkcdPass ?? Id; | |||
internal void Update(Net.API.Invite model) | |||
internal void Update(API.Invite model) | |||
{ | |||
ChannelId = model.Channel.Id; | |||
InviterId = model.Inviter?.Id; | |||
ServerId = model.Guild.Id; | |||
} | |||
internal void Update(Net.API.ExtendedInvite model) | |||
internal void Update(API.ExtendedInvite model) | |||
{ | |||
Update(model as Net.API.Invite); | |||
Update(model as API.Invite); | |||
IsRevoked = model.IsRevoked; | |||
IsTemporary = model.IsTemporary; | |||
MaxAge = model.MaxAge; | |||
@@ -1,5 +1,4 @@ | |||
using Discord.Net.API; | |||
using Newtonsoft.Json; | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
@@ -17,7 +16,7 @@ namespace Discord | |||
/// <summary> Returns the unique identifier for this user's current avatar. </summary> | |||
public string AvatarId { get; internal set; } | |||
/// <summary> Returns the URL to this user's current avatar. </summary> | |||
public string AvatarUrl => Endpoints.UserAvatar(UserId, AvatarId); | |||
public string AvatarUrl => API.Endpoints.UserAvatar(UserId, AvatarId); | |||
/// <summary> Returns the datetime that this user joined this server. </summary> | |||
public DateTime JoinedAt { get; internal set; } | |||
@@ -70,7 +69,7 @@ namespace Discord | |||
public override string ToString() => UserId; | |||
internal void Update(UserReference model) | |||
internal void Update(API.UserReference model) | |||
{ | |||
if (model.Avatar != null) | |||
AvatarId = model.Avatar; | |||
@@ -79,7 +78,7 @@ namespace Discord | |||
if (model.Username != null) | |||
Name = model.Username; | |||
} | |||
internal void Update(MemberInfo model) | |||
internal void Update(API.MemberInfo model) | |||
{ | |||
if (model.User != null) | |||
Update(model.User); | |||
@@ -87,13 +86,13 @@ namespace Discord | |||
if (model.JoinedAt.HasValue) | |||
JoinedAt = model.JoinedAt.Value; | |||
} | |||
internal void Update(ExtendedMemberInfo model) | |||
internal void Update(API.ExtendedMemberInfo model) | |||
{ | |||
Update(model as MemberInfo); | |||
Update(model as API.MemberInfo); | |||
IsDeafened = model.IsDeafened; | |||
IsMuted = model.IsMuted; | |||
} | |||
internal void Update(PresenceMemberInfo model) | |||
internal void Update(API.PresenceMemberInfo model) | |||
{ | |||
if (Status != model.Status) | |||
{ | |||
@@ -103,7 +102,7 @@ namespace Discord | |||
} | |||
GameId = model.GameId; | |||
} | |||
internal void Update(VoiceMemberInfo model) | |||
internal void Update(API.VoiceMemberInfo model) | |||
{ | |||
IsDeafened = model.IsDeafened; | |||
IsMuted = model.IsMuted; | |||
@@ -122,7 +122,7 @@ namespace Discord | |||
UserId = userId; | |||
} | |||
internal void Update(Net.API.Message model) | |||
internal void Update(API.Message model) | |||
{ | |||
if (model.Attachments != null) | |||
{ | |||
@@ -71,8 +71,7 @@ namespace Discord | |||
else | |||
_rawValue &= ~(1U << (pos - 1)); | |||
} | |||
public static implicit operator uint (PackedPermissions perms) => perms._rawValue; | |||
public PackedPermissions Copy() => new PackedPermissions(false, _rawValue); | |||
} | |||
} |
@@ -1,5 +1,4 @@ | |||
using Newtonsoft.Json; | |||
using System.Threading; | |||
namespace Discord | |||
{ | |||
@@ -29,7 +28,7 @@ namespace Discord | |||
Permissions = new PackedPermissions(true); | |||
} | |||
internal void Update(Net.API.RoleInfo model) | |||
internal void Update(API.RoleInfo model) | |||
{ | |||
Name = model.Name; | |||
Permissions.RawValue = (uint)model.Permissions; | |||
@@ -1,5 +1,4 @@ | |||
using Discord.Net.API; | |||
using Newtonsoft.Json; | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
@@ -100,7 +99,7 @@ namespace Discord | |||
_roles = new ConcurrentDictionary<string, bool>(); | |||
} | |||
internal void Update(GuildInfo model) | |||
internal void Update(API.GuildInfo model) | |||
{ | |||
AFKChannelId = model.AFKChannelId; | |||
AFKTimeout = model.AFKTimeout; | |||
@@ -117,9 +116,9 @@ namespace Discord | |||
role.Update(subModel); | |||
} | |||
} | |||
internal void Update(ExtendedGuildInfo model) | |||
internal void Update(API.ExtendedGuildInfo model) | |||
{ | |||
Update(model as GuildInfo); | |||
Update(model as API.GuildInfo); | |||
var channels = _client.Channels; | |||
foreach (var subModel in model.Channels) | |||
@@ -1,5 +1,4 @@ | |||
using Discord.Net.API; | |||
using Newtonsoft.Json; | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
@@ -24,7 +23,7 @@ namespace Discord | |||
/// <summary> Returns the unique identifier for this user's current avatar. </summary> | |||
public string AvatarId { get; internal set; } | |||
/// <summary> Returns the URL to this user's current avatar. </summary> | |||
public string AvatarUrl => Endpoints.UserAvatar(Id, AvatarId); | |||
public string AvatarUrl => API.Endpoints.UserAvatar(Id, AvatarId); | |||
/// <summary> Returns the email for this user. </summary> | |||
/// <remarks> This field is only ever populated for the current logged in user. </remarks> | |||
@@ -78,7 +77,7 @@ namespace Discord | |||
_servers = new ConcurrentDictionary<string, bool>(); | |||
} | |||
internal void Update(UserReference model) | |||
internal void Update(API.UserReference model) | |||
{ | |||
if (model.Avatar != null) | |||
AvatarId = model.Avatar; | |||
@@ -87,9 +86,9 @@ namespace Discord | |||
if (model.Username != null) | |||
Name = model.Username; | |||
} | |||
internal void Update(SelfUserInfo model) | |||
internal void Update(API.SelfUserInfo model) | |||
{ | |||
Update(model as UserReference); | |||
Update(model as API.UserReference); | |||
Email = model.Email; | |||
IsVerified = model.IsVerified; | |||
} | |||
@@ -1,295 +0,0 @@ | |||
//Ignore unused/unassigned variable warnings | |||
#pragma warning disable CS0649 | |||
#pragma warning disable CS0169 | |||
using Newtonsoft.Json; | |||
using System; | |||
namespace Discord.Net.API | |||
{ | |||
//User | |||
internal class UserReference | |||
{ | |||
[JsonProperty(PropertyName = "username")] | |||
public string Username; | |||
[JsonProperty(PropertyName = "id")] | |||
public string Id; | |||
[JsonProperty(PropertyName = "discriminator")] | |||
public string Discriminator; | |||
[JsonProperty(PropertyName = "avatar")] | |||
public string Avatar; | |||
} | |||
internal class SelfUserInfo : UserReference | |||
{ | |||
[JsonProperty(PropertyName = "email")] | |||
public string Email; | |||
[JsonProperty(PropertyName = "verified")] | |||
public bool IsVerified; | |||
} | |||
//Members | |||
internal class MemberReference | |||
{ | |||
[JsonProperty(PropertyName = "user_id")] | |||
public string UserId; | |||
[JsonProperty(PropertyName = "user")] | |||
public UserReference User; | |||
[JsonProperty(PropertyName = "guild_id")] | |||
public string GuildId; | |||
} | |||
internal class MemberInfo : MemberReference | |||
{ | |||
[JsonProperty(PropertyName = "joined_at")] | |||
public DateTime? JoinedAt; | |||
[JsonProperty(PropertyName = "roles")] | |||
public string[] Roles; | |||
} | |||
internal class ExtendedMemberInfo : MemberInfo | |||
{ | |||
[JsonProperty(PropertyName = "mute")] | |||
public bool IsMuted; | |||
[JsonProperty(PropertyName = "deaf")] | |||
public bool IsDeafened; | |||
} | |||
internal class PresenceMemberInfo : MemberReference | |||
{ | |||
[JsonProperty(PropertyName = "game_id")] | |||
public string GameId; | |||
[JsonProperty(PropertyName = "status")] | |||
public string Status; | |||
} | |||
internal class VoiceMemberInfo : MemberReference | |||
{ | |||
[JsonProperty(PropertyName = "channel_id")] | |||
public string ChannelId; | |||
[JsonProperty(PropertyName = "suppress")] | |||
public bool? IsSuppressed; | |||
[JsonProperty(PropertyName = "session_id")] | |||
public string SessionId; | |||
[JsonProperty(PropertyName = "self_mute")] | |||
public bool? IsSelfMuted; | |||
[JsonProperty(PropertyName = "self_deaf")] | |||
public bool? IsSelfDeafened; | |||
[JsonProperty(PropertyName = "mute")] | |||
public bool IsMuted; | |||
[JsonProperty(PropertyName = "deaf")] | |||
public bool IsDeafened; | |||
[JsonProperty(PropertyName = "token")] | |||
public string Token; | |||
} | |||
//Channels | |||
internal class ChannelReference | |||
{ | |||
[JsonProperty(PropertyName = "id")] | |||
public string Id; | |||
[JsonProperty(PropertyName = "guild_id")] | |||
public string GuildId; | |||
[JsonProperty(PropertyName = "name")] | |||
public string Name; | |||
[JsonProperty(PropertyName = "type")] | |||
public string Type; | |||
} | |||
internal class ChannelInfo : ChannelReference | |||
{ | |||
public sealed class PermissionOverwrite | |||
{ | |||
[JsonProperty(PropertyName = "type")] | |||
public string Type; | |||
[JsonProperty(PropertyName = "id")] | |||
public string Id; | |||
[JsonProperty(PropertyName = "deny")] | |||
public uint Deny; | |||
[JsonProperty(PropertyName = "allow")] | |||
public uint Allow; | |||
} | |||
[JsonProperty(PropertyName = "last_message_id")] | |||
public string LastMessageId; | |||
[JsonProperty(PropertyName = "is_private")] | |||
public bool IsPrivate; | |||
[JsonProperty(PropertyName = "position")] | |||
public int Position; | |||
[JsonProperty(PropertyName = "permission_overwrites")] | |||
public PermissionOverwrite[] PermissionOverwrites; | |||
[JsonProperty(PropertyName = "recipient")] | |||
public UserReference Recipient; | |||
} | |||
//Guilds (Servers) | |||
internal class GuildReference | |||
{ | |||
[JsonProperty(PropertyName = "id")] | |||
public string Id; | |||
[JsonProperty(PropertyName = "name")] | |||
public string Name; | |||
} | |||
internal class GuildInfo : GuildReference | |||
{ | |||
[JsonProperty(PropertyName = "afk_channel_id")] | |||
public string AFKChannelId; | |||
[JsonProperty(PropertyName = "afk_timeout")] | |||
public int AFKTimeout; | |||
[JsonProperty(PropertyName = "embed_channel_id")] | |||
public string EmbedChannelId; | |||
[JsonProperty(PropertyName = "embed_enabled")] | |||
public bool EmbedEnabled; | |||
[JsonProperty(PropertyName = "icon")] | |||
public string Icon; | |||
[JsonProperty(PropertyName = "joined_at")] | |||
public DateTime? JoinedAt; | |||
[JsonProperty(PropertyName = "owner_id")] | |||
public string OwnerId; | |||
[JsonProperty(PropertyName = "region")] | |||
public string Region; | |||
[JsonProperty(PropertyName = "roles")] | |||
public RoleInfo[] Roles; | |||
} | |||
internal class ExtendedGuildInfo : GuildInfo | |||
{ | |||
[JsonProperty(PropertyName = "channels")] | |||
public ChannelInfo[] Channels; | |||
[JsonProperty(PropertyName = "members")] | |||
public ExtendedMemberInfo[] Members; | |||
[JsonProperty(PropertyName = "presences")] | |||
public PresenceMemberInfo[] Presences; | |||
[JsonProperty(PropertyName = "voice_states")] | |||
public VoiceMemberInfo[] VoiceStates; | |||
} | |||
//Messages | |||
internal class MessageReference | |||
{ | |||
[JsonProperty(PropertyName = "id")] | |||
public string Id; | |||
[JsonProperty(PropertyName = "channel_id")] | |||
public string ChannelId; | |||
[JsonProperty(PropertyName = "message_id")] | |||
public string MessageId { get { return Id; } set { Id = value; } } | |||
} | |||
internal class Message : MessageReference | |||
{ | |||
public sealed class Attachment | |||
{ | |||
[JsonProperty(PropertyName = "id")] | |||
public string Id; | |||
[JsonProperty(PropertyName = "url")] | |||
public string Url; | |||
[JsonProperty(PropertyName = "proxy_url")] | |||
public string ProxyUrl; | |||
[JsonProperty(PropertyName = "size")] | |||
public int Size; | |||
[JsonProperty(PropertyName = "filename")] | |||
public string Filename; | |||
[JsonProperty(PropertyName = "width")] | |||
public int Width; | |||
[JsonProperty(PropertyName = "height")] | |||
public int Height; | |||
} | |||
public sealed class Embed | |||
{ | |||
public sealed class Reference | |||
{ | |||
[JsonProperty(PropertyName = "url")] | |||
public string Url; | |||
[JsonProperty(PropertyName = "name")] | |||
public string Name; | |||
} | |||
public sealed class ThumbnailInfo | |||
{ | |||
[JsonProperty(PropertyName = "url")] | |||
public string Url; | |||
[JsonProperty(PropertyName = "proxy_url")] | |||
public string ProxyUrl; | |||
[JsonProperty(PropertyName = "width")] | |||
public int Width; | |||
[JsonProperty(PropertyName = "height")] | |||
public int Height; | |||
} | |||
[JsonProperty(PropertyName = "url")] | |||
public string Url; | |||
[JsonProperty(PropertyName = "type")] | |||
public string Type; | |||
[JsonProperty(PropertyName = "title")] | |||
public string Title; | |||
[JsonProperty(PropertyName = "description")] | |||
public string Description; | |||
[JsonProperty(PropertyName = "author")] | |||
public Reference Author; | |||
[JsonProperty(PropertyName = "provider")] | |||
public Reference Provider; | |||
[JsonProperty(PropertyName = "thumbnail")] | |||
public ThumbnailInfo Thumbnail; | |||
} | |||
[JsonProperty(PropertyName = "tts")] | |||
public bool IsTextToSpeech; | |||
[JsonProperty(PropertyName = "mention_everyone")] | |||
public bool IsMentioningEveryone; | |||
[JsonProperty(PropertyName = "timestamp")] | |||
public DateTime Timestamp; | |||
[JsonProperty(PropertyName = "edited_timestamp")] | |||
public DateTime? EditedTimestamp; | |||
[JsonProperty(PropertyName = "mentions")] | |||
public UserReference[] Mentions; | |||
[JsonProperty(PropertyName = "embeds")] | |||
public Embed[] Embeds; //TODO: Parse this | |||
[JsonProperty(PropertyName = "attachments")] | |||
public Attachment[] Attachments; | |||
[JsonProperty(PropertyName = "content")] | |||
public string Content; | |||
[JsonProperty(PropertyName = "author")] | |||
public UserReference Author; | |||
[JsonProperty(PropertyName = "nonce")] | |||
public string Nonce; | |||
} | |||
//Roles | |||
internal class RoleReference | |||
{ | |||
[JsonProperty(PropertyName = "guild_id")] | |||
public string GuildId; | |||
[JsonProperty(PropertyName = "role_id")] | |||
public string RoleId; | |||
} | |||
internal class RoleInfo | |||
{ | |||
[JsonProperty(PropertyName = "permissions")] | |||
public int Permissions; | |||
[JsonProperty(PropertyName = "name")] | |||
public string Name; | |||
[JsonProperty(PropertyName = "id")] | |||
public string Id; | |||
} | |||
//Invites | |||
internal class Invite | |||
{ | |||
[JsonProperty(PropertyName = "inviter")] | |||
public UserReference Inviter; | |||
[JsonProperty(PropertyName = "guild")] | |||
public GuildReference Guild; | |||
[JsonProperty(PropertyName = "channel")] | |||
public ChannelReference Channel; | |||
[JsonProperty(PropertyName = "code")] | |||
public string Code; | |||
[JsonProperty(PropertyName = "xkcdpass")] | |||
public string XkcdPass; | |||
} | |||
internal class ExtendedInvite : Invite | |||
{ | |||
[JsonProperty(PropertyName = "max_age")] | |||
public int MaxAge; | |||
[JsonProperty(PropertyName = "max_uses")] | |||
public int MaxUses; | |||
[JsonProperty(PropertyName = "revoked")] | |||
public bool IsRevoked; | |||
[JsonProperty(PropertyName = "temporary")] | |||
public bool IsTemporary; | |||
[JsonProperty(PropertyName = "uses")] | |||
public int Uses; | |||
[JsonProperty(PropertyName = "created_at")] | |||
public DateTime CreatedAt; | |||
} | |||
} |
@@ -1,212 +0,0 @@ | |||
using System; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
namespace Discord.Net.API | |||
{ | |||
internal class DiscordAPIClient | |||
{ | |||
public const int MaxMessageSize = 2000; | |||
public RestClient RestClient => _rest; | |||
private readonly RestClient _rest; | |||
public DiscordAPIClient(LogMessageSeverity logLevel, int timeout) | |||
{ | |||
_rest = new RestClient(logLevel, timeout); | |||
} | |||
private string _token; | |||
public string Token | |||
{ | |||
get { return _token; } | |||
set { _token = value; _rest.SetToken(value); } | |||
} | |||
private CancellationToken _cancelToken; | |||
public CancellationToken CancelToken | |||
{ | |||
get { return _cancelToken; } | |||
set { _cancelToken = value; _rest.SetCancelToken(value); } | |||
} | |||
//Auth | |||
public Task<Responses.Gateway> GetWebSocketEndpoint() | |||
=> _rest.Get<Responses.Gateway>(Endpoints.Gateway); | |||
public async Task<Responses.AuthRegister> LoginAnonymous(string username) | |||
{ | |||
var fingerprintResponse = await _rest.Post<Responses.AuthFingerprint>(Endpoints.AuthFingerprint).ConfigureAwait(false); | |||
var registerRequest = new Requests.AuthRegister { Fingerprint = fingerprintResponse.Fingerprint, Username = username }; | |||
var registerResponse = await _rest.Post<Responses.AuthRegister>(Endpoints.AuthRegister, registerRequest).ConfigureAwait(false); | |||
return registerResponse; | |||
} | |||
public async Task<Responses.AuthLogin> Login(string email, string password) | |||
{ | |||
var request = new Requests.AuthLogin { Email = email, Password = password }; | |||
var response = await _rest.Post<Responses.AuthLogin>(Endpoints.AuthLogin, request).ConfigureAwait(false); | |||
return response; | |||
} | |||
public Task Logout() | |||
=> _rest.Post(Endpoints.AuthLogout); | |||
//Servers | |||
public Task<Responses.CreateServer> CreateServer(string name, string region) | |||
{ | |||
var request = new Requests.CreateServer { Name = name, Region = region }; | |||
return _rest.Post<Responses.CreateServer>(Endpoints.Servers, request); | |||
} | |||
public Task LeaveServer(string id) | |||
=> _rest.Delete<Responses.DeleteServer>(Endpoints.Server(id)); | |||
//Channels | |||
public Task<Responses.CreateChannel> CreateChannel(string serverId, string name, string channelType) | |||
{ | |||
var request = new Requests.CreateChannel { Name = name, Type = channelType }; | |||
return _rest.Post<Responses.CreateChannel>(Endpoints.ServerChannels(serverId), request); | |||
} | |||
public Task<Responses.CreateChannel> CreatePMChannel(string myId, string recipientId) | |||
{ | |||
var request = new Requests.CreatePMChannel { RecipientId = recipientId }; | |||
return _rest.Post<Responses.CreateChannel>(Endpoints.UserChannels(myId), request); | |||
} | |||
public Task<Responses.DestroyChannel> DestroyChannel(string channelId) | |||
=> _rest.Delete<Responses.DestroyChannel>(Endpoints.Channel(channelId)); | |||
public Task<Responses.GetMessages[]> GetMessages(string channelId, int count) | |||
=> _rest.Get<Responses.GetMessages[]>(Endpoints.ChannelMessages(channelId, count)); | |||
//Members | |||
public Task Kick(string serverId, string userId) | |||
=> _rest.Delete(Endpoints.ServerMember(serverId, userId)); | |||
public Task Ban(string serverId, string userId) | |||
=> _rest.Put(Endpoints.ServerBan(serverId, userId)); | |||
public Task Unban(string serverId, string userId) | |||
=> _rest.Delete(Endpoints.ServerBan(serverId, userId)); | |||
public Task SetMemberRoles(string serverId, string userId, string[] roles) | |||
{ | |||
var request = new Requests.ModifyMember { Roles = roles }; | |||
return _rest.Patch(Endpoints.ServerMember(serverId, userId)); | |||
} | |||
//Invites | |||
public Task<Responses.CreateInvite> CreateInvite(string channelId, int maxAge, int maxUses, bool isTemporary, bool withXkcdPass) | |||
{ | |||
var request = new Requests.CreateInvite { MaxAge = maxAge, MaxUses = maxUses, IsTemporary = isTemporary, WithXkcdPass = withXkcdPass }; | |||
return _rest.Post<Responses.CreateInvite>(Endpoints.ChannelInvites(channelId), request); | |||
} | |||
public Task<Responses.GetInvite> GetInvite(string id) | |||
=> _rest.Get<Responses.GetInvite>(Endpoints.Invite(id)); | |||
public Task AcceptInvite(string id) | |||
=> _rest.Post<Responses.AcceptInvite>(Endpoints.Invite(id)); | |||
public Task DeleteInvite(string id) | |||
=> _rest.Delete(Endpoints.Invite(id)); | |||
//Roles | |||
public Task CreateRole(string serverId) | |||
{ | |||
//TODO: Return a result when Discord starts giving us one | |||
return _rest.Post(Endpoints.ServerRoles(serverId)); | |||
} | |||
public Task RenameRole(string serverId, string roleId, string newName) | |||
{ | |||
var request = new Requests.ModifyRole { Name = newName }; | |||
return _rest.Patch(Endpoints.ServerRole(serverId, roleId), request); | |||
} | |||
public Task SetRolePermissions(string serverId, string roleId, PackedPermissions permissions) | |||
{ | |||
var request = new Requests.ModifyRole { Permissions = permissions.RawValue }; | |||
return _rest.Patch(Endpoints.ServerRole(serverId, roleId), request); | |||
} | |||
public Task DeleteRole(string serverId, string roleId) | |||
{ | |||
return _rest.Delete(Endpoints.ServerRole(serverId, roleId)); | |||
} | |||
//Permissions | |||
public Task SetChannelPermissions(string channelId, string userOrRoleId, string idType, PackedPermissions allow, PackedPermissions deny) | |||
{ | |||
var request = new Requests.SetChannelPermissions { Id = userOrRoleId, Type = idType, Allow = allow.RawValue, Deny = deny.RawValue }; | |||
return _rest.Put(Endpoints.ChannelPermission(channelId, userOrRoleId), request); | |||
} | |||
public Task DeleteChannelPermissions(string channelId, string userOrRoleId) | |||
{ | |||
return _rest.Delete(Endpoints.ChannelPermission(channelId, userOrRoleId), null); | |||
} | |||
//Chat | |||
public Task<Responses.SendMessage> SendMessage(string channelId, string message, string[] mentions, string nonce, bool isTTS) | |||
{ | |||
var request = new Requests.SendMessage { Content = message, Mentions = mentions, Nonce = nonce, IsTTS = isTTS }; | |||
return _rest.Post<Responses.SendMessage>(Endpoints.ChannelMessages(channelId), request); | |||
} | |||
public Task<Responses.EditMessage> EditMessage(string messageId, string channelId, string message, string[] mentions) | |||
{ | |||
var request = new Requests.EditMessage { Content = message, Mentions = mentions }; | |||
return _rest.Patch<Responses.EditMessage>(Endpoints.ChannelMessage(channelId, messageId), request); | |||
} | |||
public Task SendIsTyping(string channelId) | |||
=> _rest.Post(Endpoints.ChannelTyping(channelId)); | |||
public Task DeleteMessage(string channelId, string msgId) | |||
=> _rest.Delete(Endpoints.ChannelMessage(channelId, msgId)); | |||
public Task SendFile(string channelId, string filePath) | |||
=> _rest.PostFile<Responses.SendMessage>(Endpoints.ChannelMessages(channelId), filePath); | |||
//Voice | |||
public Task<Responses.GetRegions[]> GetVoiceRegions() | |||
=> _rest.Get<Responses.GetRegions[]>(Endpoints.VoiceRegions); | |||
public Task<Responses.GetIce> GetVoiceIce() | |||
=> _rest.Get<Responses.GetIce>(Endpoints.VoiceIce); | |||
public Task Mute(string serverId, string memberId) | |||
{ | |||
var request = new Requests.SetMemberMute { Value = true }; | |||
return _rest.Patch(Endpoints.ServerMember(serverId, memberId)); | |||
} | |||
public Task Unmute(string serverId, string memberId) | |||
{ | |||
var request = new Requests.SetMemberMute { Value = false }; | |||
return _rest.Patch(Endpoints.ServerMember(serverId, memberId)); | |||
} | |||
public Task Deafen(string serverId, string memberId) | |||
{ | |||
var request = new Requests.SetMemberDeaf { Value = true }; | |||
return _rest.Patch(Endpoints.ServerMember(serverId, memberId)); | |||
} | |||
public Task Undeafen(string serverId, string memberId) | |||
{ | |||
var request = new Requests.SetMemberDeaf { Value = false }; | |||
return _rest.Patch(Endpoints.ServerMember(serverId, memberId)); | |||
} | |||
//Profile | |||
public Task<Responses.ChangeProfile> ChangeUsername(string newUsername, string currentEmail, string currentPassword) | |||
{ | |||
var request = new Requests.ChangeUsername { Username = newUsername, CurrentEmail = currentEmail, CurrentPassword = currentPassword }; | |||
return _rest.Patch<Responses.ChangeProfile>(Endpoints.UserMe, request); | |||
} | |||
public Task<Responses.ChangeProfile> ChangeEmail(string newEmail, string currentPassword) | |||
{ | |||
var request = new Requests.ChangeEmail { NewEmail = newEmail, CurrentPassword = currentPassword }; | |||
return _rest.Patch<Responses.ChangeProfile>(Endpoints.UserMe, request); | |||
} | |||
public Task<Responses.ChangeProfile> ChangePassword(string newPassword, string currentEmail, string currentPassword) | |||
{ | |||
var request = new Requests.ChangePassword { NewPassword = newPassword, CurrentEmail = currentEmail, CurrentPassword = currentPassword }; | |||
return _rest.Patch<Responses.ChangeProfile>(Endpoints.UserMe, request); | |||
} | |||
public Task<Responses.ChangeProfile> ChangeAvatar(AvatarImageType imageType, byte[] bytes, string currentEmail, string currentPassword) | |||
{ | |||
string base64 = Convert.ToBase64String(bytes); | |||
string type = imageType == AvatarImageType.Jpeg ? "image/jpeg;base64" : "image/png;base64"; | |||
var request = new Requests.ChangeAvatar { Avatar = $"data:{type},/9j/{base64}", CurrentEmail = currentEmail, CurrentPassword = currentPassword }; | |||
return _rest.Patch<Responses.ChangeProfile>(Endpoints.UserMe, request); | |||
} | |||
//Other | |||
/*public Task<Responses.Status> GetUnresolvedIncidents() | |||
{ | |||
return _rest.Get<Responses.Status>(Endpoints.StatusUnresolvedMaintenance); | |||
} | |||
public Task<Responses.Status> GetActiveIncidents() | |||
{ | |||
return _rest.Get<Responses.Status>(Endpoints.StatusActiveMaintenance); | |||
}*/ | |||
} | |||
} |
@@ -1,158 +0,0 @@ | |||
//Ignore unused/unassigned variable warnings | |||
#pragma warning disable CS0649 | |||
#pragma warning disable CS0169 | |||
using Newtonsoft.Json; | |||
namespace Discord.Net.API | |||
{ | |||
internal static class Requests | |||
{ | |||
//Auth | |||
public sealed class AuthRegister | |||
{ | |||
[JsonProperty(PropertyName = "fingerprint")] | |||
public string Fingerprint; | |||
[JsonProperty(PropertyName = "username")] | |||
public string Username; | |||
} | |||
public sealed class AuthLogin | |||
{ | |||
[JsonProperty(PropertyName = "email")] | |||
public string Email; | |||
[JsonProperty(PropertyName = "password")] | |||
public string Password; | |||
} | |||
//Servers | |||
public sealed class CreateServer | |||
{ | |||
[JsonProperty(PropertyName = "name")] | |||
public string Name; | |||
[JsonProperty(PropertyName = "region")] | |||
public string Region; | |||
} | |||
//Channels | |||
public sealed class CreateChannel | |||
{ | |||
[JsonProperty(PropertyName = "name")] | |||
public string Name; | |||
[JsonProperty(PropertyName = "type")] | |||
public string Type; | |||
} | |||
public sealed class CreatePMChannel | |||
{ | |||
[JsonProperty(PropertyName = "recipient_id")] | |||
public string RecipientId; | |||
} | |||
//Invites | |||
public sealed class CreateInvite | |||
{ | |||
[JsonProperty(PropertyName = "max_age")] | |||
public int MaxAge; | |||
[JsonProperty(PropertyName = "max_uses")] | |||
public int MaxUses; | |||
[JsonProperty(PropertyName = "temporary")] | |||
public bool IsTemporary; | |||
[JsonProperty(PropertyName = "xkcdpass")] | |||
public bool WithXkcdPass; | |||
} | |||
//Messages | |||
public sealed class SendMessage | |||
{ | |||
[JsonProperty(PropertyName = "content")] | |||
public string Content; | |||
[JsonProperty(PropertyName = "mentions")] | |||
public string[] Mentions; | |||
[JsonProperty(PropertyName = "nonce")] | |||
public string Nonce; | |||
[JsonProperty(PropertyName = "tts")] | |||
public bool IsTTS; | |||
} | |||
public sealed class EditMessage | |||
{ | |||
[JsonProperty(PropertyName = "content")] | |||
public string Content; | |||
[JsonProperty(PropertyName = "mentions")] | |||
public string[] Mentions; | |||
} | |||
//Members | |||
public sealed class SetMemberMute | |||
{ | |||
[JsonProperty(PropertyName = "mute")] | |||
public bool Value; | |||
} | |||
public sealed class SetMemberDeaf | |||
{ | |||
[JsonProperty(PropertyName = "deaf")] | |||
public bool Value; | |||
} | |||
public sealed class ModifyMember | |||
{ | |||
[JsonProperty(PropertyName = "roles")] | |||
public string[] Roles; | |||
} | |||
//Profile | |||
public sealed class ChangeUsername | |||
{ | |||
[JsonProperty(PropertyName = "email")] | |||
public string CurrentEmail; | |||
[JsonProperty(PropertyName = "password")] | |||
public string CurrentPassword; | |||
[JsonProperty(PropertyName = "username")] | |||
public string Username; | |||
} | |||
public sealed class ChangeEmail | |||
{ | |||
[JsonProperty(PropertyName = "email")] | |||
public string NewEmail; | |||
[JsonProperty(PropertyName = "password")] | |||
public string CurrentPassword; | |||
} | |||
public sealed class ChangePassword | |||
{ | |||
[JsonProperty(PropertyName = "email")] | |||
public string CurrentEmail; | |||
[JsonProperty(PropertyName = "password")] | |||
public string CurrentPassword; | |||
[JsonProperty(PropertyName = "new_password")] | |||
public string NewPassword; | |||
} | |||
public sealed class ChangeAvatar | |||
{ | |||
[JsonProperty(PropertyName = "email")] | |||
public string CurrentEmail; | |||
[JsonProperty(PropertyName = "password")] | |||
public string CurrentPassword; | |||
[JsonProperty(PropertyName = "avatar")] | |||
public string Avatar; | |||
} | |||
//Roles | |||
public sealed class ModifyRole | |||
{ | |||
[JsonProperty(PropertyName = "name", NullValueHandling = NullValueHandling.Ignore)] | |||
public string Name; | |||
[JsonProperty(PropertyName = "permissions", NullValueHandling = NullValueHandling.Ignore)] | |||
public uint Permissions; | |||
} | |||
//Permissions | |||
public sealed class SetChannelPermissions | |||
{ | |||
[JsonProperty(PropertyName = "id")] | |||
public string Id; | |||
[JsonProperty(PropertyName = "type")] | |||
public string Type; | |||
[JsonProperty(PropertyName = "allow")] | |||
public uint Allow; | |||
[JsonProperty(PropertyName = "deny")] | |||
public uint Deny; | |||
} | |||
} | |||
} |
@@ -1,85 +0,0 @@ | |||
//Ignore unused/unassigned variable warnings | |||
#pragma warning disable CS0649 | |||
#pragma warning disable CS0169 | |||
using Newtonsoft.Json; | |||
using System; | |||
namespace Discord.Net.API | |||
{ | |||
internal static class Responses | |||
{ | |||
//Auth | |||
public sealed class Gateway | |||
{ | |||
[JsonProperty(PropertyName = "url")] | |||
public string Url; | |||
} | |||
public sealed class AuthFingerprint | |||
{ | |||
[JsonProperty(PropertyName = "fingerprint")] | |||
public string Fingerprint; | |||
} | |||
public sealed class AuthRegister | |||
{ | |||
[JsonProperty(PropertyName = "token")] | |||
public string Token; | |||
} | |||
public sealed class AuthLogin | |||
{ | |||
[JsonProperty(PropertyName = "token")] | |||
public string Token; | |||
} | |||
//Users | |||
public sealed class ChangeProfile : SelfUserInfo { } | |||
//Servers | |||
public sealed class CreateServer : GuildInfo { } | |||
public sealed class DeleteServer : GuildInfo { } | |||
//Channels | |||
public sealed class CreateChannel : ChannelInfo { } | |||
public sealed class DestroyChannel : ChannelInfo { } | |||
//Invites | |||
public sealed class CreateInvite : ExtendedInvite { } | |||
public sealed class GetInvite : Invite { } | |||
public sealed class AcceptInvite : Invite { } | |||
//Messages | |||
public sealed class SendMessage : Message { } | |||
public sealed class EditMessage : Message { } | |||
public sealed class GetMessages : Message { } | |||
//Voice | |||
public sealed class GetRegions | |||
{ | |||
[JsonProperty(PropertyName = "sample_hostname")] | |||
public string Hostname; | |||
[JsonProperty(PropertyName = "sample_port")] | |||
public int Port; | |||
[JsonProperty(PropertyName = "id")] | |||
public string Id; | |||
[JsonProperty(PropertyName = "name")] | |||
public string Name; | |||
} | |||
public sealed class GetIce | |||
{ | |||
[JsonProperty(PropertyName = "ttl")] | |||
public string TTL; | |||
[JsonProperty(PropertyName = "servers")] | |||
public Server[] Servers; | |||
public sealed class Server | |||
{ | |||
[JsonProperty(PropertyName = "url")] | |||
public string URL; | |||
[JsonProperty(PropertyName = "username")] | |||
public string Username; | |||
[JsonProperty(PropertyName = "credential")] | |||
public string Credential; | |||
} | |||
} | |||
} | |||
} |
@@ -1,71 +0,0 @@ | |||
//Ignore unused/unassigned variable warnings | |||
#pragma warning disable CS0649 | |||
#pragma warning disable CS0169 | |||
using Newtonsoft.Json; | |||
using Newtonsoft.Json.Linq; | |||
using System; | |||
using System.Collections.Generic; | |||
namespace Discord.Net.WebSockets | |||
{ | |||
internal static class Commands | |||
{ | |||
public sealed class KeepAlive : WebSocketMessage<ulong> | |||
{ | |||
public KeepAlive() : base(1, GetTimestamp()) { } | |||
private static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); | |||
private static ulong GetTimestamp() => (ulong)(DateTime.UtcNow - epoch).TotalMilliseconds; | |||
} | |||
public sealed class Login : WebSocketMessage<Login.Data> | |||
{ | |||
public Login() : base(2) { } | |||
public class Data | |||
{ | |||
[JsonProperty(PropertyName = "token")] | |||
public string Token; | |||
[JsonProperty(PropertyName = "v")] | |||
public int Version = 3; | |||
[JsonProperty(PropertyName = "properties")] | |||
public Dictionary<string, string> Properties = new Dictionary<string, string>(); | |||
} | |||
} | |||
public sealed class UpdateStatus : WebSocketMessage<UpdateStatus.Data> | |||
{ | |||
public UpdateStatus() : base(3) { } | |||
public class Data | |||
{ | |||
[JsonProperty(PropertyName = "idle_since")] | |||
public string IdleSince; | |||
[JsonProperty(PropertyName = "game_id")] | |||
public string GameId; | |||
} | |||
} | |||
public sealed class JoinVoice : WebSocketMessage<JoinVoice.Data> | |||
{ | |||
public JoinVoice() : base(4) { } | |||
public class Data | |||
{ | |||
[JsonProperty(PropertyName = "guild_id")] | |||
public string ServerId; | |||
[JsonProperty(PropertyName = "channel_id")] | |||
public string ChannelId; | |||
[JsonProperty(PropertyName = "self_mute")] | |||
public string SelfMute; | |||
[JsonProperty(PropertyName = "self_deaf")] | |||
public string SelfDeaf; | |||
} | |||
} | |||
public sealed class Resume : WebSocketMessage<Resume.Data> | |||
{ | |||
public Resume() : base(6) { } | |||
public class Data | |||
{ | |||
[JsonProperty(PropertyName = "session_id")] | |||
public string SessionId; | |||
[JsonProperty(PropertyName = "seq")] | |||
public int Sequence; | |||
} | |||
} | |||
} | |||
} |
@@ -1,118 +0,0 @@ | |||
//Ignore unused/unassigned variable warnings | |||
#pragma warning disable CS0649 | |||
#pragma warning disable CS0169 | |||
using Discord.Net.API; | |||
using Newtonsoft.Json; | |||
namespace Discord.Net.WebSockets | |||
{ | |||
internal static class Events | |||
{ | |||
public sealed class Ready | |||
{ | |||
public sealed class ReadStateInfo | |||
{ | |||
[JsonProperty(PropertyName = "id")] | |||
public string ChannelId; | |||
[JsonProperty(PropertyName = "mention_count")] | |||
public int MentionCount; | |||
[JsonProperty(PropertyName = "last_message_id")] | |||
public string LastMessageId; | |||
} | |||
[JsonProperty(PropertyName = "v")] | |||
public int Version; | |||
[JsonProperty(PropertyName = "user")] | |||
public SelfUserInfo User; | |||
[JsonProperty(PropertyName = "session_id")] | |||
public string SessionId; | |||
[JsonProperty(PropertyName = "read_state")] | |||
public ReadStateInfo[] ReadState; | |||
[JsonProperty(PropertyName = "guilds")] | |||
public ExtendedGuildInfo[] Guilds; | |||
[JsonProperty(PropertyName = "private_channels")] | |||
public ChannelInfo[] PrivateChannels; | |||
[JsonProperty(PropertyName = "heartbeat_interval")] | |||
public int HeartbeatInterval; | |||
} | |||
public sealed class Resumed | |||
{ | |||
[JsonProperty(PropertyName = "heartbeat_interval")] | |||
public int HeartbeatInterval; | |||
} | |||
public sealed class Redirect | |||
{ | |||
[JsonProperty(PropertyName = "url")] | |||
public string Url; | |||
} | |||
//Servers | |||
public sealed class GuildCreate : ExtendedGuildInfo { } | |||
public sealed class GuildUpdate : GuildInfo { } | |||
public sealed class GuildDelete : ExtendedGuildInfo { } | |||
//Channels | |||
public sealed class ChannelCreate : ChannelInfo { } | |||
public sealed class ChannelDelete : ChannelInfo { } | |||
public sealed class ChannelUpdate : ChannelInfo { } | |||
//Memberships | |||
public sealed class GuildMemberAdd : MemberInfo { } | |||
public sealed class GuildMemberUpdate : MemberInfo { } | |||
public sealed class GuildMemberRemove : MemberInfo { } | |||
//Roles | |||
public sealed class GuildRoleCreate | |||
{ | |||
[JsonProperty(PropertyName = "guild_id")] | |||
public string GuildId; | |||
[JsonProperty(PropertyName = "role")] | |||
public RoleInfo Data; | |||
} | |||
public sealed class GuildRoleUpdate | |||
{ | |||
[JsonProperty(PropertyName = "guild_id")] | |||
public string GuildId; | |||
[JsonProperty(PropertyName = "role")] | |||
public RoleInfo Data; | |||
} | |||
public sealed class GuildRoleDelete : RoleReference { } | |||
//Bans | |||
public sealed class GuildBanAdd : MemberReference { } | |||
public sealed class GuildBanRemove : MemberReference { } | |||
//User | |||
public sealed class UserUpdate : SelfUserInfo { } | |||
public sealed class PresenceUpdate : PresenceMemberInfo { } | |||
public sealed class VoiceStateUpdate : VoiceMemberInfo { } | |||
//Chat | |||
public sealed class MessageCreate : API.Message { } | |||
public sealed class MessageUpdate : API.Message { } | |||
public sealed class MessageDelete : MessageReference { } | |||
public sealed class MessageAck : MessageReference { } | |||
public sealed class TypingStart | |||
{ | |||
[JsonProperty(PropertyName = "user_id")] | |||
public string UserId; | |||
[JsonProperty(PropertyName = "channel_id")] | |||
public string ChannelId; | |||
[JsonProperty(PropertyName = "timestamp")] | |||
public int Timestamp; | |||
} | |||
//Voice | |||
public sealed class VoiceServerUpdate | |||
{ | |||
[JsonProperty(PropertyName = "guild_id")] | |||
public string GuildId; | |||
[JsonProperty(PropertyName = "endpoint")] | |||
public string Endpoint; | |||
[JsonProperty(PropertyName = "token")] | |||
public string Token; | |||
} | |||
} | |||
} |
@@ -1,62 +0,0 @@ | |||
//Ignore unused/unassigned variable warnings | |||
#pragma warning disable CS0649 | |||
#pragma warning disable CS0169 | |||
using Newtonsoft.Json; | |||
namespace Discord.Net.WebSockets | |||
{ | |||
internal static class VoiceCommands | |||
{ | |||
public sealed class Login : WebSocketMessage<Login.Data> | |||
{ | |||
public Login() : base(0) { } | |||
public class Data | |||
{ | |||
[JsonProperty(PropertyName = "server_id")] | |||
public string ServerId; | |||
[JsonProperty(PropertyName = "user_id")] | |||
public string UserId; | |||
[JsonProperty(PropertyName = "session_id")] | |||
public string SessionId; | |||
[JsonProperty(PropertyName = "token")] | |||
public string Token; | |||
} | |||
} | |||
public sealed class Login2 : WebSocketMessage<Login2.Data> | |||
{ | |||
public Login2() : base(1) { } | |||
public class Data | |||
{ | |||
public class SocketInfo | |||
{ | |||
[JsonProperty(PropertyName = "address")] | |||
public string Address; | |||
[JsonProperty(PropertyName = "port")] | |||
public int Port; | |||
[JsonProperty(PropertyName = "mode")] | |||
public string Mode = "xsalsa20_poly1305"; | |||
} | |||
[JsonProperty(PropertyName = "protocol")] | |||
public string Protocol = "udp"; | |||
[JsonProperty(PropertyName = "data")] | |||
public SocketInfo SocketData = new SocketInfo(); | |||
} | |||
} | |||
public sealed class KeepAlive : WebSocketMessage<object> | |||
{ | |||
public KeepAlive() : base(3, null) { } | |||
} | |||
public sealed class IsTalking : WebSocketMessage<IsTalking.Data> | |||
{ | |||
public IsTalking() : base(5) { } | |||
public class Data | |||
{ | |||
[JsonProperty(PropertyName = "delay")] | |||
public int Delay; | |||
[JsonProperty(PropertyName = "speaking")] | |||
public bool IsSpeaking; | |||
} | |||
} | |||
} | |||
} |
@@ -1,41 +0,0 @@ | |||
//Ignore unused/unassigned variable warnings | |||
#pragma warning disable CS0649 | |||
#pragma warning disable CS0169 | |||
using Newtonsoft.Json; | |||
namespace Discord.Net.WebSockets | |||
{ | |||
internal static class VoiceEvents | |||
{ | |||
public sealed class Ready | |||
{ | |||
[JsonProperty(PropertyName = "ssrc")] | |||
public uint SSRC; | |||
[JsonProperty(PropertyName = "port")] | |||
public ushort Port; | |||
[JsonProperty(PropertyName = "modes")] | |||
public string[] Modes; | |||
[JsonProperty(PropertyName = "heartbeat_interval")] | |||
public int HeartbeatInterval; | |||
} | |||
public sealed class JoinServer | |||
{ | |||
[JsonProperty(PropertyName = "secret_key")] | |||
public byte[] SecretKey; | |||
[JsonProperty(PropertyName = "mode")] | |||
public string Mode; | |||
} | |||
public sealed class IsTalking | |||
{ | |||
[JsonProperty(PropertyName = "user_id")] | |||
public string UserId; | |||
[JsonProperty(PropertyName = "ssrc")] | |||
public uint SSRC; | |||
[JsonProperty(PropertyName = "speaking")] | |||
public bool IsSpeaking; | |||
} | |||
} | |||
} |
@@ -1,8 +1,4 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
@@ -0,0 +1,67 @@ | |||
//Ignore unused/unassigned variable warnings | |||
#pragma warning disable CS0649 | |||
#pragma warning disable CS0169 | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Generic; | |||
namespace Discord.WebSockets.Data | |||
{ | |||
internal sealed class KeepAliveCommand : WebSocketMessage<ulong> | |||
{ | |||
public KeepAliveCommand() : base(1, GetTimestamp()) { } | |||
private static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); | |||
private static ulong GetTimestamp() => (ulong)(DateTime.UtcNow - epoch).TotalMilliseconds; | |||
} | |||
internal sealed class LoginCommand : WebSocketMessage<LoginCommand.Data> | |||
{ | |||
public LoginCommand() : base(2) { } | |||
public class Data | |||
{ | |||
[JsonProperty("token")] | |||
public string Token; | |||
[JsonProperty("v")] | |||
public int Version = 3; | |||
[JsonProperty("properties")] | |||
public Dictionary<string, string> Properties = new Dictionary<string, string>(); | |||
} | |||
} | |||
internal sealed class UpdateStatusCommand : WebSocketMessage<UpdateStatusCommand.Data> | |||
{ | |||
public UpdateStatusCommand() : base(3) { } | |||
public class Data | |||
{ | |||
[JsonProperty("idle_since")] | |||
public string IdleSince; | |||
[JsonProperty("game_id")] | |||
public string GameId; | |||
} | |||
} | |||
internal sealed class JoinVoiceCommand : WebSocketMessage<JoinVoiceCommand.Data> | |||
{ | |||
public JoinVoiceCommand() : base(4) { } | |||
public class Data | |||
{ | |||
[JsonProperty("guild_id")] | |||
public string ServerId; | |||
[JsonProperty("channel_id")] | |||
public string ChannelId; | |||
[JsonProperty("self_mute")] | |||
public string SelfMute; | |||
[JsonProperty("self_deaf")] | |||
public string SelfDeaf; | |||
} | |||
} | |||
internal sealed class ResumeCommand : WebSocketMessage<ResumeCommand.Data> | |||
{ | |||
public ResumeCommand() : base(6) { } | |||
public class Data | |||
{ | |||
[JsonProperty("session_id")] | |||
public string SessionId; | |||
[JsonProperty("seq")] | |||
public int Sequence; | |||
} | |||
} | |||
} |
@@ -1,10 +1,9 @@ | |||
using Newtonsoft.Json; | |||
using Newtonsoft.Json.Linq; | |||
using System; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
namespace Discord.Net.WebSockets | |||
namespace Discord.WebSockets.Data | |||
{ | |||
internal partial class DataWebSocket : WebSocket | |||
{ | |||
@@ -22,7 +21,7 @@ namespace Discord.Net.WebSockets | |||
{ | |||
await Connect().ConfigureAwait(false); | |||
Commands.Login msg = new Commands.Login(); | |||
LoginCommand msg = new LoginCommand(); | |||
msg.Payload.Token = token; | |||
msg.Payload.Properties["$device"] = "Discord.Net"; | |||
QueueMessage(msg); | |||
@@ -32,7 +31,7 @@ namespace Discord.Net.WebSockets | |||
await DisconnectInternal(isUnexpected: false).ConfigureAwait(false); | |||
await Connect().ConfigureAwait(false); | |||
var resumeMsg = new Commands.Resume(); | |||
var resumeMsg = new ResumeCommand(); | |||
resumeMsg.Payload.SessionId = _sessionId; | |||
resumeMsg.Payload.Sequence = _lastSeq; | |||
QueueMessage(resumeMsg); | |||
@@ -75,16 +74,16 @@ namespace Discord.Net.WebSockets | |||
JToken token = msg.Payload as JToken; | |||
if (msg.Type == "READY") | |||
{ | |||
var payload = token.ToObject<Events.Ready>(); | |||
var payload = token.ToObject<ReadyEvent>(); | |||
_sessionId = payload.SessionId; | |||
_heartbeatInterval = payload.HeartbeatInterval; | |||
QueueMessage(new Commands.UpdateStatus()); | |||
QueueMessage(new UpdateStatusCommand()); | |||
} | |||
else if (msg.Type == "RESUMED") | |||
{ | |||
var payload = token.ToObject<Events.Resumed>(); | |||
var payload = token.ToObject<ResumedEvent>(); | |||
_heartbeatInterval = payload.HeartbeatInterval; | |||
QueueMessage(new Commands.UpdateStatus()); | |||
QueueMessage(new UpdateStatusCommand()); | |||
} | |||
RaiseReceivedEvent(msg.Type, token); | |||
if (msg.Type == "READY" || msg.Type == "RESUMED") | |||
@@ -93,7 +92,7 @@ namespace Discord.Net.WebSockets | |||
break; | |||
case 7: //Redirect | |||
{ | |||
var payload = (msg.Payload as JToken).ToObject<Events.Redirect>(); | |||
var payload = (msg.Payload as JToken).ToObject<RedirectEvent>(); | |||
Host = payload.Url; | |||
if (_logLevel >= LogMessageSeverity.Info) | |||
RaiseOnLog(LogMessageSeverity.Info, "Redirected to " + payload.Url); | |||
@@ -109,19 +108,19 @@ namespace Discord.Net.WebSockets | |||
protected override object GetKeepAlive() | |||
{ | |||
return new Commands.KeepAlive(); | |||
return new KeepAliveCommand(); | |||
} | |||
public void SendJoinVoice(string serverId, string channelId) | |||
{ | |||
var joinVoice = new Commands.JoinVoice(); | |||
var joinVoice = new JoinVoiceCommand(); | |||
joinVoice.Payload.ServerId = serverId; | |||
joinVoice.Payload.ChannelId = channelId; | |||
QueueMessage(joinVoice); | |||
} | |||
public void SendLeaveVoice(string serverId) | |||
{ | |||
var leaveVoice = new Commands.JoinVoice(); | |||
var leaveVoice = new JoinVoiceCommand(); | |||
leaveVoice.Payload.ServerId = serverId; | |||
QueueMessage(leaveVoice); | |||
} |
@@ -1,9 +1,9 @@ | |||
using Newtonsoft.Json.Linq; | |||
using System; | |||
namespace Discord.Net.WebSockets | |||
namespace Discord.WebSockets.Data | |||
{ | |||
public sealed class WebSocketEventEventArgs : EventArgs | |||
internal sealed class WebSocketEventEventArgs : EventArgs | |||
{ | |||
public readonly string Type; | |||
public readonly JToken Payload; |
@@ -0,0 +1,115 @@ | |||
//Ignore unused/unassigned variable warnings | |||
#pragma warning disable CS0649 | |||
#pragma warning disable CS0169 | |||
using Discord.API; | |||
using Newtonsoft.Json; | |||
namespace Discord.WebSockets.Data | |||
{ | |||
internal sealed class ReadyEvent | |||
{ | |||
public sealed class ReadStateInfo | |||
{ | |||
[JsonProperty("id")] | |||
public string ChannelId; | |||
[JsonProperty("mention_count")] | |||
public int MentionCount; | |||
[JsonProperty("last_message_id")] | |||
public string LastMessageId; | |||
} | |||
[JsonProperty("v")] | |||
public int Version; | |||
[JsonProperty("user")] | |||
public SelfUserInfo User; | |||
[JsonProperty("session_id")] | |||
public string SessionId; | |||
[JsonProperty("read_state")] | |||
public ReadStateInfo[] ReadState; | |||
[JsonProperty("guilds")] | |||
public ExtendedGuildInfo[] Guilds; | |||
[JsonProperty("private_channels")] | |||
public ChannelInfo[] PrivateChannels; | |||
[JsonProperty("heartbeat_interval")] | |||
public int HeartbeatInterval; | |||
} | |||
internal sealed class ResumedEvent | |||
{ | |||
[JsonProperty("heartbeat_interval")] | |||
public int HeartbeatInterval; | |||
} | |||
internal sealed class RedirectEvent | |||
{ | |||
[JsonProperty("url")] | |||
public string Url; | |||
} | |||
//Servers | |||
internal sealed class GuildCreateEvent : ExtendedGuildInfo { } | |||
internal sealed class GuildUpdateEvent : GuildInfo { } | |||
internal sealed class GuildDeleteEvent : ExtendedGuildInfo { } | |||
//Channels | |||
internal sealed class ChannelCreateEvent : ChannelInfo { } | |||
internal sealed class ChannelDeleteEvent : ChannelInfo { } | |||
internal sealed class ChannelUpdateEvent : ChannelInfo { } | |||
//Memberships | |||
internal sealed class GuildMemberAddEvent : MemberInfo { } | |||
internal sealed class GuildMemberUpdateEvent : MemberInfo { } | |||
internal sealed class GuildMemberRemoveEvent : MemberInfo { } | |||
//Roles | |||
internal sealed class GuildRoleCreateEvent | |||
{ | |||
[JsonProperty("guild_id")] | |||
public string GuildId; | |||
[JsonProperty("role")] | |||
public RoleInfo Data; | |||
} | |||
internal sealed class GuildRoleUpdateEvent | |||
{ | |||
[JsonProperty("guild_id")] | |||
public string GuildId; | |||
[JsonProperty("role")] | |||
public RoleInfo Data; | |||
} | |||
internal sealed class GuildRoleDeleteEvent : RoleReference { } | |||
//Bans | |||
internal sealed class GuildBanAddEvent : MemberReference { } | |||
internal sealed class GuildBanRemoveEvent : MemberReference { } | |||
//User | |||
internal sealed class UserUpdateEvent : SelfUserInfo { } | |||
internal sealed class PresenceUpdateEvent : PresenceMemberInfo { } | |||
internal sealed class VoiceStateUpdateEvent : VoiceMemberInfo { } | |||
//Chat | |||
internal sealed class MessageCreateEvent : API.Message { } | |||
internal sealed class MessageUpdateEvent : API.Message { } | |||
internal sealed class MessageDeleteEvent : MessageReference { } | |||
internal sealed class MessageAckEvent : MessageReference { } | |||
internal sealed class TypingStartEvent | |||
{ | |||
[JsonProperty("user_id")] | |||
public string UserId; | |||
[JsonProperty("channel_id")] | |||
public string ChannelId; | |||
[JsonProperty("timestamp")] | |||
public int Timestamp; | |||
} | |||
//Voice | |||
internal sealed class VoiceServerUpdateEvent | |||
{ | |||
[JsonProperty("guild_id")] | |||
public string GuildId; | |||
[JsonProperty("endpoint")] | |||
public string Endpoint; | |||
[JsonProperty("token")] | |||
public string Token; | |||
} | |||
} |
@@ -0,0 +1,59 @@ | |||
//Ignore unused/unassigned variable warnings | |||
#pragma warning disable CS0649 | |||
#pragma warning disable CS0169 | |||
using Newtonsoft.Json; | |||
namespace Discord.WebSockets.Voice | |||
{ | |||
internal sealed class LoginCommand : WebSocketMessage<LoginCommand.Data> | |||
{ | |||
public LoginCommand() : base(0) { } | |||
public class Data | |||
{ | |||
[JsonProperty("server_id")] | |||
public string ServerId; | |||
[JsonProperty("user_id")] | |||
public string UserId; | |||
[JsonProperty("session_id")] | |||
public string SessionId; | |||
[JsonProperty("token")] | |||
public string Token; | |||
} | |||
} | |||
internal sealed class Login2Command : WebSocketMessage<Login2Command.Data> | |||
{ | |||
public Login2Command() : base(1) { } | |||
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 KeepAliveCommand : WebSocketMessage<object> | |||
{ | |||
public KeepAliveCommand() : base(3, null) { } | |||
} | |||
internal sealed class IsTalkingCommand : WebSocketMessage<IsTalkingCommand.Data> | |||
{ | |||
public IsTalkingCommand() : base(5) { } | |||
public class Data | |||
{ | |||
[JsonProperty("delay")] | |||
public int Delay; | |||
[JsonProperty("speaking")] | |||
public bool IsSpeaking; | |||
} | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
//Ignore unused/unassigned variable warnings | |||
#pragma warning disable CS0649 | |||
#pragma warning disable CS0169 | |||
using Newtonsoft.Json; | |||
namespace Discord.WebSockets.Voice | |||
{ | |||
internal sealed class ReadyEvent | |||
{ | |||
[JsonProperty("ssrc")] | |||
public uint SSRC; | |||
[JsonProperty("port")] | |||
public ushort Port; | |||
[JsonProperty("modes")] | |||
public string[] Modes; | |||
[JsonProperty("heartbeat_interval")] | |||
public int HeartbeatInterval; | |||
} | |||
internal sealed class JoinServerEvent | |||
{ | |||
[JsonProperty("secret_key")] | |||
public byte[] SecretKey; | |||
[JsonProperty("mode")] | |||
public string Mode; | |||
} | |||
internal sealed class IsTalkingEvent | |||
{ | |||
[JsonProperty("user_id")] | |||
public string UserId; | |||
[JsonProperty("ssrc")] | |||
public uint SSRC; | |||
[JsonProperty("speaking")] | |||
public bool IsSpeaking; | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
using System; | |||
namespace Discord.Net.WebSockets | |||
namespace Discord.WebSockets.Voice | |||
{ | |||
public sealed class IsTalkingEventArgs : EventArgs | |||
{ |
@@ -12,7 +12,7 @@ using System.Text; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
namespace Discord.Net.WebSockets | |||
namespace Discord.WebSockets.Voice | |||
{ | |||
internal partial class VoiceWebSocket : WebSocket | |||
{ | |||
@@ -106,7 +106,7 @@ namespace Discord.Net.WebSockets | |||
_udp.AllowNatTraversal(true); | |||
#endif | |||
VoiceCommands.Login msg = new VoiceCommands.Login(); | |||
LoginCommand msg = new LoginCommand(); | |||
msg.Payload.ServerId = _serverId; | |||
msg.Payload.SessionId = _sessionId; | |||
msg.Payload.Token = _token; | |||
@@ -294,7 +294,7 @@ namespace Discord.Net.WebSockets | |||
{ | |||
if (_state != (int)WebSocketState.Connected) | |||
{ | |||
var payload = (msg.Payload as JToken).ToObject<VoiceEvents.Ready>(); | |||
var payload = (msg.Payload as JToken).ToObject<ReadyEvent>(); | |||
_heartbeatInterval = payload.HeartbeatInterval; | |||
_ssrc = payload.SSRC; | |||
_endpoint = new IPEndPoint((await Dns.GetHostAddressesAsync(Host.Replace("wss://", "")).ConfigureAwait(false)).FirstOrDefault(), payload.Port); | |||
@@ -319,7 +319,7 @@ namespace Discord.Net.WebSockets | |||
break; | |||
case 4: //SESSION_DESCRIPTION | |||
{ | |||
var payload = (msg.Payload as JToken).ToObject<VoiceEvents.JoinServer>(); | |||
var payload = (msg.Payload as JToken).ToObject<JoinServerEvent>(); | |||
_secretKey = payload.SecretKey; | |||
SendIsTalking(true); | |||
_connectWaitOnLogin.Set(); | |||
@@ -327,7 +327,7 @@ namespace Discord.Net.WebSockets | |||
break; | |||
case 5: | |||
{ | |||
var payload = (msg.Payload as JToken).ToObject<VoiceEvents.IsTalking>(); | |||
var payload = (msg.Payload as JToken).ToObject<IsTalkingEvent>(); | |||
RaiseIsSpeaking(payload.UserId, payload.IsSpeaking); | |||
} | |||
break; | |||
@@ -358,7 +358,7 @@ namespace Discord.Net.WebSockets | |||
CompleteConnect(); | |||
var login2 = new VoiceCommands.Login2(); | |||
var login2 = new Login2Command(); | |||
login2.Payload.Protocol = "udp"; | |||
login2.Payload.SocketData.Address = ip; | |||
login2.Payload.SocketData.Mode = _isEncrypted ? EncryptedMode : UnencryptedMode; | |||
@@ -503,7 +503,7 @@ namespace Discord.Net.WebSockets | |||
private void SendIsTalking(bool value) | |||
{ | |||
var isTalking = new VoiceCommands.IsTalking(); | |||
var isTalking = new IsTalkingCommand(); | |||
isTalking.Payload.IsSpeaking = value; | |||
isTalking.Payload.Delay = 0; | |||
QueueMessage(isTalking); | |||
@@ -511,7 +511,7 @@ namespace Discord.Net.WebSockets | |||
protected override object GetKeepAlive() | |||
{ | |||
return new VoiceCommands.KeepAlive(); | |||
return new KeepAliveCommand(); | |||
} | |||
public void WaitForQueue() |
@@ -8,7 +8,7 @@ using System.Threading; | |||
using System.Threading.Tasks; | |||
using State = System.Net.WebSockets.WebSocketState; | |||
namespace Discord.Net.WebSockets | |||
namespace Discord.WebSockets | |||
{ | |||
internal class BuiltInWebSocketEngine : IWebSocketEngine | |||
{ |
@@ -1,6 +1,6 @@ | |||
using System; | |||
namespace Discord.Net.WebSockets | |||
namespace Discord.WebSockets | |||
{ | |||
internal partial class WebSocket | |||
{ |
@@ -7,7 +7,7 @@ using System.Text; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
namespace Discord.Net.WebSockets | |||
namespace Discord.WebSockets | |||
{ | |||
public enum WebSocketState : byte | |||
{ | |||
@@ -88,7 +88,7 @@ namespace Discord.Net.WebSockets | |||
_cancelToken = CancellationTokenSource.CreateLinkedTokenSource(_cancelTokenSource.Token, ParentCancelToken).Token; | |||
else | |||
_cancelToken = _cancelTokenSource.Token; | |||
await _engine.Connect(Host, _cancelToken).ConfigureAwait(false); | |||
_lastHeartbeat = DateTime.UtcNow; | |||
@@ -107,8 +107,6 @@ namespace Discord.Net.WebSockets | |||
_connectedEvent.Set(); | |||
RaiseConnected(); | |||
} | |||
/*public Task Reconnect(CancellationToken cancelToken) | |||
=> Connect(_host, _cancelToken);*/ | |||
public Task Disconnect() => DisconnectInternal(new Exception("Disconnect was requested by user."), isUnexpected: false); | |||
protected async Task DisconnectInternal(Exception ex = null, bool isUnexpected = true, bool skipAwait = false) |
@@ -1,17 +1,17 @@ | |||
using Newtonsoft.Json; | |||
using Newtonsoft.Json.Linq; | |||
namespace Discord.Net.WebSockets | |||
namespace Discord.WebSockets | |||
{ | |||
public class WebSocketMessage | |||
{ | |||
[JsonProperty(PropertyName = "op")] | |||
[JsonProperty("op")] | |||
public int Operation; | |||
[JsonProperty(PropertyName = "d")] | |||
[JsonProperty("d")] | |||
public object Payload; | |||
[JsonProperty(PropertyName = "t", NullValueHandling = NullValueHandling.Ignore)] | |||
[JsonProperty("t", NullValueHandling = NullValueHandling.Ignore)] | |||
public string Type; | |||
[JsonProperty(PropertyName = "s", NullValueHandling = NullValueHandling.Ignore)] | |||
[JsonProperty("s", NullValueHandling = NullValueHandling.Ignore)] | |||
public int? Sequence; | |||
} | |||
internal abstract class WebSocketMessage<T> : WebSocketMessage |