Concrete class prototype

This commit is contained in:
RogueException
2016-09-22 21:15:37 -03:00
parent ab42129eb9
commit 6319933ed0
394 changed files with 3648 additions and 3224 deletions

View File

@@ -0,0 +1,16 @@
namespace Discord.API
{
public static class CDN
{
public static string GetApplicationIconUrl(ulong appId, string iconId)
=> iconId != null ? $"{DiscordConfig.CDNUrl}app-icons/{appId}/{iconId}.jpg" : null;
public static string GetUserAvatarUrl(ulong userId, string avatarId)
=> avatarId != null ? $"{DiscordConfig.CDNUrl}avatars/{userId}/{avatarId}.jpg" : null;
public static string GetGuildIconUrl(ulong guildId, string iconId)
=> iconId != null ? $"{DiscordConfig.CDNUrl}icons/{guildId}/{iconId}.jpg" : null;
public static string GetGuildSplashUrl(ulong guildId, string splashId)
=> splashId != null ? $"{DiscordConfig.CDNUrl}splashes/{guildId}/{splashId}.jpg" : null;
public static string GetChannelIconUrl(ulong channelId, string iconId)
=> iconId != null ? $"{DiscordConfig.CDNUrl}channel-icons/{channelId}/{iconId}.jpg" : null;
}
}

View File

@@ -0,0 +1,23 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class Application
{
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("rpc_origins")]
public string[] RPCOrigins { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("flags"), Int53]
public ulong Flags { get; set; }
[JsonProperty("owner")]
public User Owner { get; set; }
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("icon")]
public string Icon { get; set; }
}
}

View File

@@ -0,0 +1,23 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class Attachment
{
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("filename")]
public string Filename { get; set; }
[JsonProperty("size")]
public int Size { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("proxy_url")]
public string ProxyUrl { get; set; }
[JsonProperty("height")]
public Optional<int> Height { get; set; }
[JsonProperty("width")]
public Optional<int> Width { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class Ban
{
[JsonProperty("user")]
public User User { get; set; }
[JsonProperty("reason")]
public string Reason { get; set; }
}
}

View File

@@ -0,0 +1,47 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using System;
namespace Discord.API
{
public class Channel
{
//Shared
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("type")]
public ChannelType Type { get; set; }
[JsonProperty("last_message_id")]
public ulong? LastMessageId { get; set; }
//GuildChannel
[JsonProperty("guild_id")]
public Optional<ulong> GuildId { get; set; }
[JsonProperty("name")]
public Optional<string> Name { get; set; }
[JsonProperty("position")]
public Optional<int> Position { get; set; }
[JsonProperty("permission_overwrites")]
public Optional<Overwrite[]> PermissionOverwrites { get; set; }
//TextChannel
[JsonProperty("topic")]
public Optional<string> Topic { get; set; }
[JsonProperty("last_pin_timestamp")]
public Optional<DateTimeOffset?> LastPinTimestamp { get; set; }
//VoiceChannel
[JsonProperty("bitrate")]
public Optional<int> Bitrate { get; set; }
[JsonProperty("user_limit")]
public Optional<int> UserLimit { get; set; }
//PrivateChannel
[JsonProperty("recipients")]
public Optional<User[]> Recipients { get; set; }
//GroupChannel
[JsonProperty("icon")]
public Optional<string> Icon { get; set; }
}
}

View File

@@ -0,0 +1,21 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Discord.API
{
public class Connection
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("revoked")]
public bool Revoked { get; set; }
[JsonProperty("integrations")]
public IReadOnlyCollection<ulong> Integrations { get; set; }
}
}

View File

@@ -0,0 +1,21 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class Embed
{
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("thumbnail")]
public Optional<EmbedThumbnail> Thumbnail { get; set; }
[JsonProperty("provider")]
public Optional<EmbedProvider> Provider { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class EmbedProvider
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class EmbedThumbnail
{
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("proxy_url")]
public string ProxyUrl { get; set; }
[JsonProperty("height")]
public Optional<int> Height { get; set; }
[JsonProperty("width")]
public Optional<int> Width { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class Emoji
{
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("roles")]
public ulong[] Roles { get; set; }
[JsonProperty("require_colons")]
public bool RequireColons { get; set; }
[JsonProperty("managed")]
public bool Managed { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class Game
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("url")]
public Optional<string> StreamUrl { get; set; }
[JsonProperty("type")]
public Optional<StreamType?> StreamType { get; set; }
}
}

View File

@@ -0,0 +1,43 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class Guild
{
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("icon")]
public string Icon { get; set; }
[JsonProperty("splash")]
public string Splash { get; set; }
[JsonProperty("owner_id")]
public ulong OwnerId { get; set; }
[JsonProperty("region")]
public string Region { get; set; }
[JsonProperty("afk_channel_id")]
public ulong? AFKChannelId { get; set; }
[JsonProperty("afk_timeout")]
public int AFKTimeout { get; set; }
[JsonProperty("embed_enabled")]
public bool EmbedEnabled { get; set; }
[JsonProperty("embed_channel_id")]
public ulong? EmbedChannelId { get; set; }
[JsonProperty("verification_level")]
public VerificationLevel VerificationLevel { get; set; }
[JsonProperty("voice_states")]
public VoiceState[] VoiceStates { get; set; }
[JsonProperty("roles")]
public Role[] Roles { get; set; }
[JsonProperty("emojis")]
public Emoji[] Emojis { get; set; }
[JsonProperty("features")]
public string[] Features { get; set; }
[JsonProperty("mfa_level")]
public MfaLevel MfaLevel { get; set; }
[JsonProperty("default_message_notifications")]
public DefaultMessageNotifications DefaultMessageNotifications { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class GuildEmbed
{
[JsonProperty("enabled")]
public bool Enabled { get; set; }
[JsonProperty("channel_id")]
public ulong ChannelId { get; set; }
}
}

View File

@@ -0,0 +1,22 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using System;
namespace Discord.API
{
public class GuildMember
{
[JsonProperty("user")]
public User User { get; set; }
[JsonProperty("nick")]
public Optional<string> Nick { get; set; }
[JsonProperty("roles")]
public ulong[] Roles { get; set; }
[JsonProperty("joined_at")]
public DateTimeOffset JoinedAt { get; set; }
[JsonProperty("deaf")]
public bool Deaf { get; set; }
[JsonProperty("mute")]
public bool Mute { get; set; }
}
}

View File

@@ -0,0 +1,32 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using System;
namespace Discord.API
{
public class Integration
{
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("enabled")]
public bool Enabled { get; set; }
[JsonProperty("syncing")]
public bool Syncing { get; set; }
[JsonProperty("role_id")]
public ulong RoleId { get; set; }
[JsonProperty("expire_behavior")]
public ulong ExpireBehavior { get; set; }
[JsonProperty("expire_grace_period")]
public ulong ExpireGracePeriod { get; set; }
[JsonProperty("user")]
public User User { get; set; }
[JsonProperty("account")]
public IntegrationAccount Account { get; set; }
[JsonProperty("synced_at")]
public DateTimeOffset SyncedAt { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class IntegrationAccount
{
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class Invite
{
[JsonProperty("code")]
public string Code { get; set; }
[JsonProperty("guild")]
public InviteGuild Guild { get; set; }
[JsonProperty("channel")]
public InviteChannel Channel { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class InviteChannel
{
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class InviteGuild
{
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("splash_hash")]
public string SplashHash { get; set; }
}
}

View File

@@ -0,0 +1,24 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using System;
namespace Discord.API
{
public class InviteMetadata : Invite
{
[JsonProperty("inviter")]
public User Inviter { get; set; }
[JsonProperty("uses")]
public int Uses { get; set; }
[JsonProperty("max_uses")]
public int MaxUses { get; set; }
[JsonProperty("max_age")]
public int MaxAge { get; set; }
[JsonProperty("temporary")]
public bool Temporary { get; set; }
[JsonProperty("created_at")]
public DateTimeOffset CreatedAt { get; set; }
[JsonProperty("revoked")]
public bool Revoked { get; set; }
}
}

View File

@@ -0,0 +1,36 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using System;
namespace Discord.API
{
public class Message
{
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("type")]
public MessageType Type { get; set; }
[JsonProperty("channel_id")]
public ulong ChannelId { get; set; }
[JsonProperty("author")]
public Optional<User> Author { get; set; }
[JsonProperty("content")]
public Optional<string> Content { get; set; }
[JsonProperty("timestamp")]
public Optional<DateTimeOffset> Timestamp { get; set; }
[JsonProperty("edited_timestamp")]
public Optional<DateTimeOffset?> EditedTimestamp { get; set; }
[JsonProperty("tts")]
public Optional<bool> IsTextToSpeech { get; set; }
[JsonProperty("mention_everyone")]
public Optional<bool> MentionEveryone { get; set; }
[JsonProperty("mentions")]
public Optional<User[]> Mentions { get; set; }
[JsonProperty("attachments")]
public Optional<Attachment[]> Attachments { get; set; }
[JsonProperty("embeds")]
public Optional<Embed[]> Embeds { get; set; }
[JsonProperty("pinned")]
public Optional<bool> Pinned { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class Overwrite
{
[JsonProperty("id")]
public ulong TargetId { get; set; }
[JsonProperty("type")]
public PermissionTarget TargetType { get; set; }
[JsonProperty("deny"), Int53]
public ulong Deny { get; set; }
[JsonProperty("allow"), Int53]
public ulong Allow { get; set; }
}
}

View File

@@ -0,0 +1,22 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class Presence
{
[JsonProperty("user")]
public User User { get; set; }
[JsonProperty("guild_id")]
public Optional<ulong> GuildId { get; set; }
[JsonProperty("status")]
public UserStatus Status { get; set; }
[JsonProperty("game")]
public Game Game { get; set; }
[JsonProperty("roles")]
public Optional<ulong[]> Roles { get; set; }
[JsonProperty("nick")]
public Optional<string> Nick { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class ReadState
{
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("mention_count")]
public int MentionCount { get; set; }
[JsonProperty("last_message_id")]
public Optional<ulong> LastMessageId { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class Relationship
{
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("user")]
public User User { get; set; }
[JsonProperty("type")]
public RelationshipType Type { get; set; }
}
}

View File

@@ -0,0 +1,10 @@
#pragma warning disable CS1591
namespace Discord.API
{
public enum RelationshipType
{
Friend = 1,
Blocked = 2,
Pending = 4
}
}

View File

@@ -0,0 +1,23 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class Role
{
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("color")]
public uint Color { get; set; }
[JsonProperty("hoist")]
public bool Hoist { get; set; }
[JsonProperty("position")]
public int Position { get; set; }
[JsonProperty("permissions"), Int53]
public ulong Permissions { get; set; }
[JsonProperty("managed")]
public bool Managed { get; set; }
}
}

View File

@@ -0,0 +1,27 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class User
{
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("username")]
public Optional<string> Username { get; set; }
[JsonProperty("discriminator")]
public Optional<string> Discriminator { get; set; }
[JsonProperty("bot")]
public Optional<bool> Bot { get; set; }
[JsonProperty("avatar")]
public Optional<string> Avatar { get; set; }
//CurrentUser
[JsonProperty("verified")]
public Optional<bool> Verified { get; set; }
[JsonProperty("email")]
public Optional<string> Email { get; set; }
[JsonProperty("mfa_enabled")]
public Optional<bool> MfaEnabled { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class UserGuild
{
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("icon")]
public string Icon { get; set; }
[JsonProperty("owner")]
public bool Owner { get; set; }
[JsonProperty("permissions"), Int53]
public ulong Permissions { get; set; }
}
}

View File

@@ -0,0 +1,21 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class VoiceRegion
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("vip")]
public bool IsVip { get; set; }
[JsonProperty("optimal")]
public bool IsOptimal { get; set; }
[JsonProperty("sample_hostname")]
public string SampleHostname { get; set; }
[JsonProperty("sample_port")]
public int SamplePort { get; set; }
}
}

View File

@@ -0,0 +1,27 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class VoiceState
{
[JsonProperty("guild_id")]
public ulong? GuildId { get; set; }
[JsonProperty("channel_id")]
public ulong? ChannelId { get; set; }
[JsonProperty("user_id")]
public ulong UserId { get; set; }
[JsonProperty("session_id")]
public string SessionId { get; set; }
[JsonProperty("deaf")]
public bool Deaf { get; set; }
[JsonProperty("mute")]
public bool Mute { get; set; }
[JsonProperty("self_deaf")]
public bool SelfDeaf { get; set; }
[JsonProperty("self_mute")]
public bool SelfMute { get; set; }
[JsonProperty("suppress")]
public bool Suppress { get; set; }
}
}

View File

@@ -0,0 +1,923 @@
#pragma warning disable CS1591
using Discord.API.Rest;
using Discord.Net;
using Discord.Net.Converters;
using Discord.Net.Queue;
using Discord.Net.Rest;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Discord.API
{
public class DiscordRestApiClient : IDisposable
{
public event Func<string, string, double, Task> SentRequest { add { _sentRequestEvent.Add(value); } remove { _sentRequestEvent.Remove(value); } }
private readonly AsyncEvent<Func<string, string, double, Task>> _sentRequestEvent = new AsyncEvent<Func<string, string, double, Task>>();
protected readonly JsonSerializer _serializer;
protected readonly SemaphoreSlim _stateLock;
private readonly RestClientProvider _restClientProvider;
private readonly string _userAgent;
protected string _authToken;
protected bool _isDisposed;
private CancellationTokenSource _loginCancelToken;
private IRestClient _restClient;
public LoginState LoginState { get; private set; }
public TokenType AuthTokenType { get; private set; }
public User CurrentUser { get; private set; }
public RequestQueue RequestQueue { get; private set; }
public DiscordRestApiClient(RestClientProvider restClientProvider, string userAgent, JsonSerializer serializer = null, RequestQueue requestQueue = null)
{
_restClientProvider = restClientProvider;
_userAgent = userAgent;
_serializer = serializer ?? new JsonSerializer { ContractResolver = new DiscordContractResolver() };
RequestQueue = requestQueue;
_stateLock = new SemaphoreSlim(1, 1);
SetBaseUrl(DiscordConfig.ClientAPIUrl);
}
internal void SetBaseUrl(string baseUrl)
{
_restClient = _restClientProvider(baseUrl);
_restClient.SetHeader("accept", "*/*");
_restClient.SetHeader("user-agent", _userAgent);
_restClient.SetHeader("authorization", GetPrefixedToken(AuthTokenType, _authToken));
}
internal static string GetPrefixedToken(TokenType tokenType, string token)
{
switch (tokenType)
{
case TokenType.Bot:
return $"Bot {token}";
case TokenType.Bearer:
return $"Bearer {token}";
case TokenType.User:
return token;
default:
throw new ArgumentException("Unknown OAuth token type", nameof(tokenType));
}
}
internal virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
_loginCancelToken?.Dispose();
(_restClient as IDisposable)?.Dispose();
}
_isDisposed = true;
}
}
public void Dispose() => Dispose(true);
public async Task LoginAsync(TokenType tokenType, string token, RequestOptions options = null)
{
await _stateLock.WaitAsync().ConfigureAwait(false);
try
{
await LoginInternalAsync(tokenType, token, options).ConfigureAwait(false);
}
finally { _stateLock.Release(); }
}
private async Task LoginInternalAsync(TokenType tokenType, string token, RequestOptions options = null)
{
if (LoginState != LoginState.LoggedOut)
await LogoutInternalAsync().ConfigureAwait(false);
LoginState = LoginState.LoggingIn;
try
{
_loginCancelToken = new CancellationTokenSource();
AuthTokenType = TokenType.User;
_authToken = null;
await RequestQueue.SetCancelTokenAsync(_loginCancelToken.Token).ConfigureAwait(false);
_restClient.SetCancelToken(_loginCancelToken.Token);
AuthTokenType = tokenType;
_authToken = token;
_restClient.SetHeader("authorization", GetPrefixedToken(AuthTokenType, _authToken));
CurrentUser = await GetMyUserAsync();
LoginState = LoginState.LoggedIn;
}
catch (Exception)
{
await LogoutInternalAsync().ConfigureAwait(false);
throw;
}
}
public async Task LogoutAsync()
{
await _stateLock.WaitAsync().ConfigureAwait(false);
try
{
await LogoutInternalAsync().ConfigureAwait(false);
}
finally { _stateLock.Release(); }
}
private async Task LogoutInternalAsync()
{
//An exception here will lock the client into the unusable LoggingOut state, but that's probably fine since our client is in an undefined state too.
if (LoginState == LoginState.LoggedOut) return;
LoginState = LoginState.LoggingOut;
try { _loginCancelToken?.Cancel(false); }
catch { }
await DisconnectInternalAsync().ConfigureAwait(false);
await RequestQueue.ClearAsync().ConfigureAwait(false);
await RequestQueue.SetCancelTokenAsync(CancellationToken.None).ConfigureAwait(false);
_restClient.SetCancelToken(CancellationToken.None);
CurrentUser = null;
LoginState = LoginState.LoggedOut;
}
internal virtual Task ConnectInternalAsync() => Task.CompletedTask;
internal virtual Task DisconnectInternalAsync() => Task.CompletedTask;
//REST
public Task SendAsync(string method, string endpoint,
GlobalBucket bucket = GlobalBucket.GeneralRest, bool ignoreState = false, RequestOptions options = null)
=> SendInternalAsync(method, endpoint, null, true, BucketGroup.Global, (int)bucket, 0, ignoreState, options);
public Task SendAsync(string method, string endpoint, object payload,
GlobalBucket bucket = GlobalBucket.GeneralRest, bool ignoreState = false, RequestOptions options = null)
=> SendInternalAsync(method, endpoint, payload, true, BucketGroup.Global, (int)bucket, 0, ignoreState, options);
public async Task<TResponse> SendAsync<TResponse>(string method, string endpoint,
GlobalBucket bucket = GlobalBucket.GeneralRest, bool ignoreState = false, RequestOptions options = null) where TResponse : class
=> DeserializeJson<TResponse>(await SendInternalAsync(method, endpoint, null, false, BucketGroup.Global, (int)bucket, 0, ignoreState, options).ConfigureAwait(false));
public async Task<TResponse> SendAsync<TResponse>(string method, string endpoint, object payload, GlobalBucket bucket =
GlobalBucket.GeneralRest, bool ignoreState = false, RequestOptions options = null) where TResponse : class
=> DeserializeJson<TResponse>(await SendInternalAsync(method, endpoint, payload, false, BucketGroup.Global, (int)bucket, 0, ignoreState, options).ConfigureAwait(false));
public Task SendAsync(string method, string endpoint,
GuildBucket bucket, ulong guildId, bool ignoreState = false, RequestOptions options = null)
=> SendInternalAsync(method, endpoint, null, true, BucketGroup.Guild, (int)bucket, guildId, ignoreState, options);
public Task SendAsync(string method, string endpoint, object payload,
GuildBucket bucket, ulong guildId, bool ignoreState = false, RequestOptions options = null)
=> SendInternalAsync(method, endpoint, payload, true, BucketGroup.Guild, (int)bucket, guildId, ignoreState, options);
public async Task<TResponse> SendAsync<TResponse>(string method, string endpoint,
GuildBucket bucket, ulong guildId, bool ignoreState = false, RequestOptions options = null) where TResponse : class
=> DeserializeJson<TResponse>(await SendInternalAsync(method, endpoint, null, false, BucketGroup.Guild, (int)bucket, guildId, ignoreState, options).ConfigureAwait(false));
public async Task<TResponse> SendAsync<TResponse>(string method, string endpoint, object payload,
GuildBucket bucket, ulong guildId, bool ignoreState = false, RequestOptions options = null) where TResponse : class
=> DeserializeJson<TResponse>(await SendInternalAsync(method, endpoint, payload, false, BucketGroup.Guild, (int)bucket, guildId, ignoreState, options).ConfigureAwait(false));
//REST - Multipart
public Task SendMultipartAsync(string method, string endpoint, IReadOnlyDictionary<string, object> multipartArgs,
GlobalBucket bucket = GlobalBucket.GeneralRest, RequestOptions options = null)
=> SendMultipartInternalAsync(method, endpoint, multipartArgs, true, BucketGroup.Global, (int)bucket, 0, options);
public async Task<TResponse> SendMultipartAsync<TResponse>(string method, string endpoint, IReadOnlyDictionary<string, object> multipartArgs,
GlobalBucket bucket = GlobalBucket.GeneralRest, RequestOptions options = null) where TResponse : class
=> DeserializeJson<TResponse>(await SendMultipartInternalAsync(method, endpoint, multipartArgs, false, BucketGroup.Global, (int)bucket, 0, options).ConfigureAwait(false));
public Task SendMultipartAsync(string method, string endpoint, IReadOnlyDictionary<string, object> multipartArgs,
GuildBucket bucket, ulong guildId, RequestOptions options = null)
=> SendMultipartInternalAsync(method, endpoint, multipartArgs, true, BucketGroup.Guild, (int)bucket, guildId, options);
public async Task<TResponse> SendMultipartAsync<TResponse>(string method, string endpoint, IReadOnlyDictionary<string, object> multipartArgs,
GuildBucket bucket, ulong guildId, RequestOptions options = null) where TResponse : class
=> DeserializeJson<TResponse>(await SendMultipartInternalAsync(method, endpoint, multipartArgs, false, BucketGroup.Guild, (int)bucket, guildId, options).ConfigureAwait(false));
//Core
private async Task<Stream> SendInternalAsync(string method, string endpoint, object payload, bool headerOnly,
BucketGroup group, int bucketId, ulong guildId, bool ignoreState, RequestOptions options = null)
{
if (!ignoreState)
CheckState();
var stopwatch = Stopwatch.StartNew();
string json = null;
if (payload != null)
json = SerializeJson(payload);
var responseStream = await RequestQueue.SendAsync(new RestRequest(_restClient, method, endpoint, json, headerOnly, options), group, bucketId, guildId).ConfigureAwait(false);
stopwatch.Stop();
double milliseconds = ToMilliseconds(stopwatch);
await _sentRequestEvent.InvokeAsync(method, endpoint, milliseconds).ConfigureAwait(false);
return responseStream;
}
private async Task<Stream> SendMultipartInternalAsync(string method, string endpoint, IReadOnlyDictionary<string, object> multipartArgs, bool headerOnly,
BucketGroup group, int bucketId, ulong guildId, RequestOptions options = null)
{
CheckState();
var stopwatch = Stopwatch.StartNew();
var responseStream = await RequestQueue.SendAsync(new RestRequest(_restClient, method, endpoint, multipartArgs, headerOnly, options), group, bucketId, guildId).ConfigureAwait(false);
int bytes = headerOnly ? 0 : (int)responseStream.Length;
stopwatch.Stop();
double milliseconds = ToMilliseconds(stopwatch);
await _sentRequestEvent.InvokeAsync(method, endpoint, milliseconds).ConfigureAwait(false);
return responseStream;
}
//Auth
public async Task ValidateTokenAsync(RequestOptions options = null)
{
await SendAsync("GET", "auth/login", options: options).ConfigureAwait(false);
}
//Channels
public async Task<Channel> GetChannelAsync(ulong channelId, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
try
{
return await SendAsync<Channel>("GET", $"channels/{channelId}", options: options).ConfigureAwait(false);
}
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; }
}
public async Task<Channel> GetChannelAsync(ulong guildId, ulong channelId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(channelId, 0, nameof(channelId));
try
{
var model = await SendAsync<Channel>("GET", $"channels/{channelId}", options: options).ConfigureAwait(false);
if (!model.GuildId.IsSpecified || model.GuildId.Value != guildId)
return null;
return model;
}
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; }
}
public async Task<IReadOnlyCollection<Channel>> GetGuildChannelsAsync(ulong guildId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
return await SendAsync<IReadOnlyCollection<Channel>>("GET", $"guilds/{guildId}/channels", options: options).ConfigureAwait(false);
}
public async Task<Channel> CreateGuildChannelAsync(ulong guildId, CreateGuildChannelParams args, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotNull(args, nameof(args));
Preconditions.GreaterThan(args.Bitrate, 0, nameof(args.Bitrate));
Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name));
return await SendAsync<Channel>("POST", $"guilds/{guildId}/channels", args, options: options).ConfigureAwait(false);
}
public async Task<Channel> DeleteChannelAsync(ulong channelId, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
return await SendAsync<Channel>("DELETE", $"channels/{channelId}", options: options).ConfigureAwait(false);
}
public async Task<Channel> ModifyGuildChannelAsync(ulong channelId, ModifyGuildChannelParams args, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotNull(args, nameof(args));
Preconditions.AtLeast(args.Position, 0, nameof(args.Position));
Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name));
return await SendAsync<Channel>("PATCH", $"channels/{channelId}", args, options: options).ConfigureAwait(false);
}
public async Task<Channel> ModifyGuildChannelAsync(ulong channelId, ModifyTextChannelParams args, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotNull(args, nameof(args));
Preconditions.AtLeast(args.Position, 0, nameof(args.Position));
Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name));
return await SendAsync<Channel>("PATCH", $"channels/{channelId}", args, options: options).ConfigureAwait(false);
}
public async Task<Channel> ModifyGuildChannelAsync(ulong channelId, ModifyVoiceChannelParams args, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotNull(args, nameof(args));
Preconditions.GreaterThan(args.Bitrate, 0, nameof(args.Bitrate));
Preconditions.AtLeast(args.UserLimit, 0, nameof(args.Bitrate));
Preconditions.AtLeast(args.Position, 0, nameof(args.Position));
Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name));
return await SendAsync<Channel>("PATCH", $"channels/{channelId}", args, options: options).ConfigureAwait(false);
}
public async Task ModifyGuildChannelsAsync(ulong guildId, IEnumerable<ModifyGuildChannelsParams> args, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotNull(args, nameof(args));
var channels = args.ToArray();
switch (channels.Length)
{
case 0:
return;
case 1:
await ModifyGuildChannelAsync(channels[0].Id, new ModifyGuildChannelParams { Position = channels[0].Position }).ConfigureAwait(false);
break;
default:
await SendAsync("PATCH", $"guilds/{guildId}/channels", channels, options: options).ConfigureAwait(false);
break;
}
}
//Channel Messages
public async Task<Message> GetChannelMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotEqual(messageId, 0, nameof(messageId));
try
{
return await SendAsync<Message>("GET", $"channels/{channelId}/messages/{messageId}", options: options).ConfigureAwait(false);
}
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; }
}
public async Task<IReadOnlyCollection<Message>> GetChannelMessagesAsync(ulong channelId, GetChannelMessagesParams args, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotNull(args, nameof(args));
Preconditions.AtLeast(args.Limit, 0, nameof(args.Limit));
Preconditions.AtMost(args.Limit, DiscordConfig.MaxMessagesPerBatch, nameof(args.Limit));
int limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxMessagesPerBatch);
ulong? relativeId = args.RelativeMessageId.IsSpecified ? args.RelativeMessageId.Value : (ulong?)null;
string relativeDir;
switch (args.RelativeDirection.GetValueOrDefault(Direction.Before))
{
case Direction.Before:
default:
relativeDir = "before";
break;
case Direction.After:
relativeDir = "after";
break;
case Direction.Around:
relativeDir = "around";
break;
}
string endpoint;
if (relativeId != null)
endpoint = $"channels/{channelId}/messages?limit={limit}&{relativeDir}={relativeId}";
else
endpoint = $"channels/{channelId}/messages?limit={limit}";
return await SendAsync<IReadOnlyCollection<Message>>("GET", endpoint, options: options).ConfigureAwait(false);
}
public async Task<Message> CreateMessageAsync(ulong channelId, CreateMessageParams args, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotNull(args, nameof(args));
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));
if (args.Content.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content));
return await SendAsync<Message>("POST", $"channels/{channelId}/messages", args, GlobalBucket.DirectMessage, options: options).ConfigureAwait(false);
}
public async Task<Message> UploadFileAsync(ulong channelId, UploadFileParams args, RequestOptions options = null)
{
Preconditions.NotNull(args, nameof(args));
Preconditions.NotEqual(channelId, 0, nameof(channelId));
if (args.Content.GetValueOrDefault(null) == null)
args.Content = "";
else if (args.Content.IsSpecified)
{
if (args.Content.Value == null)
args.Content = "";
if (args.Content.Value?.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content));
}
return await SendMultipartAsync<Message>("POST", $"channels/{channelId}/messages", args.ToDictionary(), GlobalBucket.DirectMessage, options: options).ConfigureAwait(false);
}
public async Task DeleteMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotEqual(messageId, 0, nameof(messageId));
await SendAsync("DELETE", $"channels/{channelId}/messages/{messageId}", options: options).ConfigureAwait(false);
}
public async Task DeleteMessagesAsync(ulong channelId, DeleteMessagesParams args, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotNull(args, nameof(args));
Preconditions.NotNull(args.MessageIds, nameof(args.MessageIds));
Preconditions.AtMost(args.MessageIds.Length, 100, nameof(args.MessageIds.Length));
switch (args.MessageIds.Length)
{
case 0:
return;
case 1:
await DeleteMessageAsync(channelId, args.MessageIds[0]).ConfigureAwait(false);
break;
default:
await SendAsync("POST", $"channels/{channelId}/messages/bulk_delete", args, options: options).ConfigureAwait(false);
break;
}
}
public async Task<Message> ModifyMessageAsync(ulong channelId, ulong messageId, ModifyMessageParams args, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotEqual(messageId, 0, nameof(messageId));
Preconditions.NotNull(args, nameof(args));
if (args.Content.IsSpecified)
{
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));
if (args.Content.Value.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content));
}
return await SendAsync<Message>("PATCH", $"channels/{channelId}/messages/{messageId}", args, options: options).ConfigureAwait(false);
}
public async Task AckMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotEqual(messageId, 0, nameof(messageId));
await SendAsync("POST", $"channels/{channelId}/messages/{messageId}/ack", options: options).ConfigureAwait(false);
}
public async Task TriggerTypingIndicatorAsync(ulong channelId, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
await SendAsync("POST", $"channels/{channelId}/typing", options: options).ConfigureAwait(false);
}
//Channel Permissions
public async Task ModifyChannelPermissionsAsync(ulong channelId, ulong targetId, ModifyChannelPermissionsParams args, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotEqual(targetId, 0, nameof(targetId));
Preconditions.NotNull(args, nameof(args));
await SendAsync("PUT", $"channels/{channelId}/permissions/{targetId}", args, options: options).ConfigureAwait(false);
}
public async Task DeleteChannelPermissionAsync(ulong channelId, ulong targetId, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotEqual(targetId, 0, nameof(targetId));
await SendAsync("DELETE", $"channels/{channelId}/permissions/{targetId}", options: options).ConfigureAwait(false);
}
//Channel Pins
public async Task AddPinAsync(ulong channelId, ulong messageId, RequestOptions options = null)
{
Preconditions.GreaterThan(channelId, 0, nameof(channelId));
Preconditions.GreaterThan(messageId, 0, nameof(messageId));
await SendAsync("PUT", $"channels/{channelId}/pins/{messageId}", options: options).ConfigureAwait(false);
}
public async Task RemovePinAsync(ulong channelId, ulong messageId, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotEqual(messageId, 0, nameof(messageId));
await SendAsync("DELETE", $"channels/{channelId}/pins/{messageId}", options: options).ConfigureAwait(false);
}
public async Task<IReadOnlyCollection<Message>> GetPinsAsync(ulong channelId, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
return await SendAsync<IReadOnlyCollection<Message>>("GET", $"channels/{channelId}/pins", options: options).ConfigureAwait(false);
}
//Channel Recipients
public async Task AddGroupRecipientAsync(ulong channelId, ulong userId, RequestOptions options = null)
{
Preconditions.GreaterThan(channelId, 0, nameof(channelId));
Preconditions.GreaterThan(userId, 0, nameof(userId));
await SendAsync("PUT", $"channels/{channelId}/recipients/{userId}", options: options).ConfigureAwait(false);
}
public async Task RemoveGroupRecipientAsync(ulong channelId, ulong userId, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotEqual(userId, 0, nameof(userId));
await SendAsync("DELETE", $"channels/{channelId}/recipients/{userId}", options: options).ConfigureAwait(false);
}
//Guilds
public async Task<Guild> GetGuildAsync(ulong guildId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
try
{
return await SendAsync<Guild>("GET", $"guilds/{guildId}", options: options).ConfigureAwait(false);
}
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; }
}
public async Task<Guild> CreateGuildAsync(CreateGuildParams args, RequestOptions options = null)
{
Preconditions.NotNull(args, nameof(args));
Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name));
Preconditions.NotNullOrWhitespace(args.RegionId, nameof(args.RegionId));
return await SendAsync<Guild>("POST", "guilds", args, options: options).ConfigureAwait(false);
}
public async Task<Guild> DeleteGuildAsync(ulong guildId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
return await SendAsync<Guild>("DELETE", $"guilds/{guildId}", options: options).ConfigureAwait(false);
}
public async Task<Guild> LeaveGuildAsync(ulong guildId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
return await SendAsync<Guild>("DELETE", $"users/@me/guilds/{guildId}", options: options).ConfigureAwait(false);
}
public async Task<Guild> ModifyGuildAsync(ulong guildId, ModifyGuildParams args, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotNull(args, nameof(args));
Preconditions.NotEqual(args.AfkChannelId, 0, nameof(args.AfkChannelId));
Preconditions.AtLeast(args.AfkTimeout, 0, nameof(args.AfkTimeout));
Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name));
Preconditions.GreaterThan(args.OwnerId, 0, nameof(args.OwnerId));
Preconditions.NotNull(args.RegionId, nameof(args.RegionId));
return await SendAsync<Guild>("PATCH", $"guilds/{guildId}", args, options: options).ConfigureAwait(false);
}
public async Task<GetGuildPruneCountResponse> BeginGuildPruneAsync(ulong guildId, GuildPruneParams args, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotNull(args, nameof(args));
Preconditions.AtLeast(args.Days, 0, nameof(args.Days));
return await SendAsync<GetGuildPruneCountResponse>("POST", $"guilds/{guildId}/prune", args, options: options).ConfigureAwait(false);
}
public async Task<GetGuildPruneCountResponse> GetGuildPruneCountAsync(ulong guildId, GuildPruneParams args, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotNull(args, nameof(args));
Preconditions.AtLeast(args.Days, 0, nameof(args.Days));
return await SendAsync<GetGuildPruneCountResponse>("GET", $"guilds/{guildId}/prune", args, options: options).ConfigureAwait(false);
}
//Guild Bans
public async Task<IReadOnlyCollection<Ban>> GetGuildBansAsync(ulong guildId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
return await SendAsync<IReadOnlyCollection<Ban>>("GET", $"guilds/{guildId}/bans", options: options).ConfigureAwait(false);
}
public async Task CreateGuildBanAsync(ulong guildId, ulong userId, CreateGuildBanParams args, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(userId, 0, nameof(userId));
Preconditions.NotNull(args, nameof(args));
Preconditions.AtLeast(args.DeleteMessageDays, 0, nameof(args.DeleteMessageDays));
await SendAsync("PUT", $"guilds/{guildId}/bans/{userId}", args, options: options).ConfigureAwait(false);
}
public async Task RemoveGuildBanAsync(ulong guildId, ulong userId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(userId, 0, nameof(userId));
await SendAsync("DELETE", $"guilds/{guildId}/bans/{userId}", options: options).ConfigureAwait(false);
}
//Guild Embeds
public async Task<GuildEmbed> GetGuildEmbedAsync(ulong guildId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
try
{
return await SendAsync<GuildEmbed>("GET", $"guilds/{guildId}/embed", options: options).ConfigureAwait(false);
}
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; }
}
public async Task<GuildEmbed> ModifyGuildEmbedAsync(ulong guildId, ModifyGuildEmbedParams args, RequestOptions options = null)
{
Preconditions.NotNull(args, nameof(args));
Preconditions.NotEqual(guildId, 0, nameof(guildId));
return await SendAsync<GuildEmbed>("PATCH", $"guilds/{guildId}/embed", args, options: options).ConfigureAwait(false);
}
//Guild Integrations
public async Task<IReadOnlyCollection<Integration>> GetGuildIntegrationsAsync(ulong guildId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
return await SendAsync<IReadOnlyCollection<Integration>>("GET", $"guilds/{guildId}/integrations", options: options).ConfigureAwait(false);
}
public async Task<Integration> CreateGuildIntegrationAsync(ulong guildId, CreateGuildIntegrationParams args, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotNull(args, nameof(args));
Preconditions.NotEqual(args.Id, 0, nameof(args.Id));
return await SendAsync<Integration>("POST", $"guilds/{guildId}/integrations", options: options).ConfigureAwait(false);
}
public async Task<Integration> DeleteGuildIntegrationAsync(ulong guildId, ulong integrationId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(integrationId, 0, nameof(integrationId));
return await SendAsync<Integration>("DELETE", $"guilds/{guildId}/integrations/{integrationId}", options: options).ConfigureAwait(false);
}
public async Task<Integration> ModifyGuildIntegrationAsync(ulong guildId, ulong integrationId, ModifyGuildIntegrationParams args, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(integrationId, 0, nameof(integrationId));
Preconditions.NotNull(args, nameof(args));
Preconditions.AtLeast(args.ExpireBehavior, 0, nameof(args.ExpireBehavior));
Preconditions.AtLeast(args.ExpireGracePeriod, 0, nameof(args.ExpireGracePeriod));
return await SendAsync<Integration>("PATCH", $"guilds/{guildId}/integrations/{integrationId}", args, options: options).ConfigureAwait(false);
}
public async Task<Integration> SyncGuildIntegrationAsync(ulong guildId, ulong integrationId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(integrationId, 0, nameof(integrationId));
return await SendAsync<Integration>("POST", $"guilds/{guildId}/integrations/{integrationId}/sync", options: options).ConfigureAwait(false);
}
//Guild Invites
public async Task<Invite> GetInviteAsync(string inviteId, RequestOptions options = null)
{
Preconditions.NotNullOrEmpty(inviteId, nameof(inviteId));
//Remove trailing slash
if (inviteId[inviteId.Length - 1] == '/')
inviteId = inviteId.Substring(0, inviteId.Length - 1);
//Remove leading URL
int index = inviteId.LastIndexOf('/');
if (index >= 0)
inviteId = inviteId.Substring(index + 1);
try
{
return await SendAsync<Invite>("GET", $"invites/{inviteId}", options: options).ConfigureAwait(false);
}
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; }
}
public async Task<IReadOnlyCollection<InviteMetadata>> GetGuildInvitesAsync(ulong guildId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
return await SendAsync<IReadOnlyCollection<InviteMetadata>>("GET", $"guilds/{guildId}/invites", options: options).ConfigureAwait(false);
}
public async Task<IReadOnlyCollection<InviteMetadata>> GetChannelInvitesAsync(ulong channelId, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
return await SendAsync<IReadOnlyCollection<InviteMetadata>>("GET", $"channels/{channelId}/invites", options: options).ConfigureAwait(false);
}
public async Task<InviteMetadata> CreateChannelInviteAsync(ulong channelId, CreateChannelInviteParams args, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotNull(args, nameof(args));
Preconditions.AtLeast(args.MaxAge, 0, nameof(args.MaxAge));
Preconditions.AtLeast(args.MaxUses, 0, nameof(args.MaxUses));
return await SendAsync<InviteMetadata>("POST", $"channels/{channelId}/invites", args, options: options).ConfigureAwait(false);
}
public async Task<Invite> DeleteInviteAsync(string inviteCode, RequestOptions options = null)
{
Preconditions.NotNullOrEmpty(inviteCode, nameof(inviteCode));
return await SendAsync<Invite>("DELETE", $"invites/{inviteCode}", options: options).ConfigureAwait(false);
}
public async Task AcceptInviteAsync(string inviteCode, RequestOptions options = null)
{
Preconditions.NotNullOrEmpty(inviteCode, nameof(inviteCode));
await SendAsync("POST", $"invites/{inviteCode}", options: options).ConfigureAwait(false);
}
//Guild Members
public async Task<GuildMember> GetGuildMemberAsync(ulong guildId, ulong userId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(userId, 0, nameof(userId));
try
{
return await SendAsync<GuildMember>("GET", $"guilds/{guildId}/members/{userId}", options: options).ConfigureAwait(false);
}
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; }
}
public async Task<IReadOnlyCollection<GuildMember>> GetGuildMembersAsync(ulong guildId, GetGuildMembersParams args, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotNull(args, nameof(args));
Preconditions.GreaterThan(args.Limit, 0, nameof(args.Limit));
Preconditions.AtMost(args.Limit, DiscordConfig.MaxUsersPerBatch, nameof(args.Limit));
Preconditions.GreaterThan(args.AfterUserId, 0, nameof(args.AfterUserId));
int limit = args.Limit.GetValueOrDefault(int.MaxValue);
ulong afterUserId = args.AfterUserId.GetValueOrDefault(0);
string endpoint = $"guilds/{guildId}/members?limit={limit}&after={afterUserId}";
return await SendAsync<IReadOnlyCollection<GuildMember>>("GET", endpoint, options: options).ConfigureAwait(false);
}
public async Task RemoveGuildMemberAsync(ulong guildId, ulong userId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(userId, 0, nameof(userId));
await SendAsync("DELETE", $"guilds/{guildId}/members/{userId}", options: options).ConfigureAwait(false);
}
public async Task ModifyGuildMemberAsync(ulong guildId, ulong userId, ModifyGuildMemberParams args, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(userId, 0, nameof(userId));
Preconditions.NotNull(args, nameof(args));
bool isCurrentUser = userId == CurrentUser.Id;
if (isCurrentUser && args.Nickname.IsSpecified)
{
var nickArgs = new ModifyCurrentUserNickParams(args.Nickname.Value ?? "");
await ModifyMyNickAsync(guildId, nickArgs).ConfigureAwait(false);
args.Nickname = Optional.Create<string>(); //Remove
}
if (!isCurrentUser || args.Deaf.IsSpecified || args.Mute.IsSpecified || args.RoleIds.IsSpecified)
{
await SendAsync("PATCH", $"guilds/{guildId}/members/{userId}", args, GuildBucket.ModifyMember, guildId, options: options).ConfigureAwait(false);
}
}
//Guild Roles
public async Task<IReadOnlyCollection<Role>> GetGuildRolesAsync(ulong guildId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
return await SendAsync<IReadOnlyCollection<Role>>("GET", $"guilds/{guildId}/roles", options: options).ConfigureAwait(false);
}
public async Task<Role> CreateGuildRoleAsync(ulong guildId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
return await SendAsync<Role>("POST", $"guilds/{guildId}/roles", options: options).ConfigureAwait(false);
}
public async Task DeleteGuildRoleAsync(ulong guildId, ulong roleId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(roleId, 0, nameof(roleId));
await SendAsync("DELETE", $"guilds/{guildId}/roles/{roleId}", options: options).ConfigureAwait(false);
}
public async Task<Role> ModifyGuildRoleAsync(ulong guildId, ulong roleId, ModifyGuildRoleParams args, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(roleId, 0, nameof(roleId));
Preconditions.NotNull(args, nameof(args));
Preconditions.AtLeast(args.Color, 0, nameof(args.Color));
Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name));
Preconditions.AtLeast(args.Position, 0, nameof(args.Position));
return await SendAsync<Role>("PATCH", $"guilds/{guildId}/roles/{roleId}", args, options: options).ConfigureAwait(false);
}
public async Task<IReadOnlyCollection<Role>> ModifyGuildRolesAsync(ulong guildId, IEnumerable<ModifyGuildRolesParams> args, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotNull(args, nameof(args));
var roles = args.ToArray();
switch (roles.Length)
{
case 0:
return ImmutableArray.Create<Role>();
case 1:
return ImmutableArray.Create(await ModifyGuildRoleAsync(guildId, roles[0].Id, roles[0]).ConfigureAwait(false));
default:
return await SendAsync<IReadOnlyCollection<Role>>("PATCH", $"guilds/{guildId}/roles", args, options: options).ConfigureAwait(false);
}
}
//Users
public async Task<User> GetUserAsync(ulong userId, RequestOptions options = null)
{
Preconditions.NotEqual(userId, 0, nameof(userId));
try
{
return await SendAsync<User>("GET", $"users/{userId}", options: options).ConfigureAwait(false);
}
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; }
}
public async Task<User> GetUserAsync(string username, string discriminator, RequestOptions options = null)
{
Preconditions.NotNullOrEmpty(username, nameof(username));
Preconditions.NotNullOrEmpty(discriminator, nameof(discriminator));
try
{
var models = await QueryUsersAsync($"{username}#{discriminator}", 1, options: options).ConfigureAwait(false);
return models.FirstOrDefault();
}
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; }
}
public async Task<IReadOnlyCollection<User>> QueryUsersAsync(string query, int limit, RequestOptions options = null)
{
Preconditions.NotNullOrEmpty(query, nameof(query));
Preconditions.AtLeast(limit, 0, nameof(limit));
return await SendAsync<IReadOnlyCollection<User>>("GET", $"users?q={Uri.EscapeDataString(query)}&limit={limit}", options: options).ConfigureAwait(false);
}
//Current User/DMs
public async Task<User> GetMyUserAsync(RequestOptions options = null)
{
return await SendAsync<User>("GET", "users/@me", options: options).ConfigureAwait(false);
}
public async Task<IReadOnlyCollection<Connection>> GetMyConnectionsAsync(RequestOptions options = null)
{
return await SendAsync<IReadOnlyCollection<Connection>>("GET", "users/@me/connections", options: options).ConfigureAwait(false);
}
public async Task<IReadOnlyCollection<Channel>> GetMyPrivateChannelsAsync(RequestOptions options = null)
{
return await SendAsync<IReadOnlyCollection<Channel>>("GET", "users/@me/channels", options: options).ConfigureAwait(false);
}
public async Task<IReadOnlyCollection<UserGuild>> GetMyGuildsAsync(RequestOptions options = null)
{
return await SendAsync<IReadOnlyCollection<UserGuild>>("GET", "users/@me/guilds", options: options).ConfigureAwait(false);
}
public async Task<Application> GetMyApplicationAsync(RequestOptions options = null)
{
return await SendAsync<Application>("GET", "oauth2/applications/@me", options: options).ConfigureAwait(false);
}
public async Task<User> ModifySelfAsync(ModifyCurrentUserParams args, RequestOptions options = null)
{
Preconditions.NotNull(args, nameof(args));
Preconditions.NotNullOrEmpty(args.Username, nameof(args.Username));
return await SendAsync<User>("PATCH", "users/@me", args, options: options).ConfigureAwait(false);
}
public async Task ModifyMyNickAsync(ulong guildId, ModifyCurrentUserNickParams args, RequestOptions options = null)
{
Preconditions.NotNull(args, nameof(args));
Preconditions.NotNull(args.Nickname, nameof(args.Nickname));
await SendAsync("PATCH", $"guilds/{guildId}/members/@me/nick", args, options: options).ConfigureAwait(false);
}
public async Task<Channel> CreateDMChannelAsync(CreateDMChannelParams args, RequestOptions options = null)
{
Preconditions.NotNull(args, nameof(args));
Preconditions.GreaterThan(args.RecipientId, 0, nameof(args.RecipientId));
return await SendAsync<Channel>("POST", $"users/@me/channels", args, options: options).ConfigureAwait(false);
}
//Voice Regions
public async Task<IReadOnlyCollection<VoiceRegion>> GetVoiceRegionsAsync(RequestOptions options = null)
{
return await SendAsync<IReadOnlyCollection<VoiceRegion>>("GET", "voice/regions", options: options).ConfigureAwait(false);
}
public async Task<IReadOnlyCollection<VoiceRegion>> GetGuildVoiceRegionsAsync(ulong guildId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
return await SendAsync<IReadOnlyCollection<VoiceRegion>>("GET", $"guilds/{guildId}/regions", options: options).ConfigureAwait(false);
}
//Helpers
protected void CheckState()
{
if (LoginState != LoginState.LoggedIn)
throw new InvalidOperationException("Client is not logged in.");
}
protected static double ToMilliseconds(Stopwatch stopwatch) => Math.Round((double)stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0, 2);
protected string SerializeJson(object value)
{
var sb = new StringBuilder(256);
using (TextWriter text = new StringWriter(sb, CultureInfo.InvariantCulture))
using (JsonWriter writer = new JsonTextWriter(text))
_serializer.Serialize(writer, value);
return sb.ToString();
}
protected T DeserializeJson<T>(Stream jsonStream)
{
using (TextReader text = new StreamReader(jsonStream))
using (JsonReader reader = new JsonTextReader(text))
return _serializer.Deserialize<T>(reader);
}
}
}

View File

@@ -0,0 +1,21 @@
using System.IO;
namespace Discord.API
{
public struct Image
{
public Stream Stream { get; }
public string Hash { get; }
public Image(Stream stream)
{
Stream = stream;
Hash = null;
}
public Image(string hash)
{
Stream = null;
Hash = hash;
}
}
}

View File

@@ -0,0 +1,8 @@
#pragma warning disable CS1591
using System;
namespace Discord.API
{
[AttributeUsage(AttributeTargets.Property)]
public class Int53Attribute : Attribute { }
}

View File

@@ -0,0 +1,16 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class CreateChannelInviteParams
{
[JsonProperty("max_age")]
public Optional<int> MaxAge { get; set; }
[JsonProperty("max_uses")]
public Optional<int> MaxUses { get; set; }
[JsonProperty("temporary")]
public Optional<bool> IsTemporary { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class CreateDMChannelParams
{
[JsonProperty("recipient_id")]
public ulong RecipientId { get; }
public CreateDMChannelParams(ulong recipientId)
{
RecipientId = recipientId;
}
}
}

View File

@@ -0,0 +1,12 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class CreateGuildBanParams
{
[JsonProperty("delete-message-days")]
public Optional<int> DeleteMessageDays { get; set; }
}
}

View File

@@ -0,0 +1,23 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class CreateGuildChannelParams
{
[JsonProperty("name")]
public string Name { get; }
[JsonProperty("type")]
public ChannelType Type { get; }
[JsonProperty("bitrate")]
public Optional<int> Bitrate { get; set; }
public CreateGuildChannelParams(string name, ChannelType type)
{
Name = name;
Type = type;
}
}
}

View File

@@ -0,0 +1,20 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class CreateGuildIntegrationParams
{
[JsonProperty("id")]
public ulong Id { get; }
[JsonProperty("type")]
public string Type { get; }
public CreateGuildIntegrationParams(ulong id, string type)
{
Id = id;
Type = type;
}
}
}

View File

@@ -0,0 +1,23 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class CreateGuildParams
{
[JsonProperty("name")]
public string Name { get; }
[JsonProperty("region")]
public string RegionId { get; }
[JsonProperty("icon")]
public Optional<Image?> Icon { get; set; }
public CreateGuildParams(string name, string regionId)
{
Name = name;
RegionId = regionId;
}
}
}

View File

@@ -0,0 +1,22 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class CreateMessageParams
{
[JsonProperty("content")]
public string Content { get; }
[JsonProperty("nonce")]
public Optional<string> Nonce { get; set; }
[JsonProperty("tts")]
public Optional<bool> IsTTS { get; set; }
public CreateMessageParams(string content)
{
Content = content;
}
}
}

View File

@@ -0,0 +1,17 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class DeleteMessagesParams
{
[JsonProperty("messages")]
public ulong[] MessageIds { get; }
public DeleteMessagesParams(ulong[] messageIds)
{
MessageIds = messageIds;
}
}
}

View File

@@ -0,0 +1,10 @@
#pragma warning disable CS1591
namespace Discord.API.Rest
{
public class GetChannelMessagesParams
{
public Optional<int> Limit { get; set; }
public Optional<Direction> RelativeDirection { get; set; }
public Optional<ulong> RelativeMessageId { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
public class GetGatewayResponse
{
[JsonProperty("url")]
public string Url { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
#pragma warning disable CS1591
namespace Discord.API.Rest
{
public class GetGuildMembersParams
{
public Optional<int> Limit { get; set; }
public Optional<ulong> AfterUserId { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
public class GetGuildPruneCountResponse
{
[JsonProperty("pruned")]
public int Pruned { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class GuildPruneParams
{
[JsonProperty("days")]
public int Days { get; }
public GuildPruneParams(int days)
{
Days = days;
}
}
}

View File

@@ -0,0 +1,23 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyChannelPermissionsParams
{
[JsonProperty("type")]
public string Type { get; }
[JsonProperty("allow")]
public ulong Allow { get; }
[JsonProperty("deny")]
public ulong Deny { get; }
public ModifyChannelPermissionsParams(string type, ulong allow, ulong deny)
{
Type = type;
Allow = allow;
Deny = deny;
}
}
}

View File

@@ -0,0 +1,17 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyCurrentUserNickParams
{
[JsonProperty("nick")]
public string Nickname { get; }
public ModifyCurrentUserNickParams(string nickname)
{
Nickname = nickname;
}
}
}

View File

@@ -0,0 +1,14 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyCurrentUserParams
{
[JsonProperty("username")]
public Optional<string> Username { get; set; }
[JsonProperty("avatar")]
public Optional<Image> Avatar { get; set; }
}
}

View File

@@ -0,0 +1,14 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyGuildChannelParams
{
[JsonProperty("name")]
public Optional<string> Name { get; set; }
[JsonProperty("position")]
public Optional<int> Position { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyGuildChannelsParams
{
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("position")]
public int Position { get; set; }
public ModifyGuildChannelsParams(ulong id, int position)
{
Id = id;
Position = position;
}
}
}

View File

@@ -0,0 +1,14 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyGuildEmbedParams
{
[JsonProperty("enabled")]
public Optional<bool> Enabled { get; set; }
[JsonProperty("channel")]
public Optional<ulong?> ChannelId { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyGuildIntegrationParams
{
[JsonProperty("expire_behavior")]
public Optional<int> ExpireBehavior { get; set; }
[JsonProperty("expire_grace_period")]
public Optional<int> ExpireGracePeriod { get; set; }
[JsonProperty("enable_emoticons")]
public Optional<bool> EnableEmoticons { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyGuildMemberParams
{
[JsonProperty("mute")]
public Optional<bool> Mute { get; set; }
[JsonProperty("deaf")]
public Optional<bool> Deaf { get; set; }
[JsonProperty("nick")]
public Optional<string> Nickname { get; set; }
[JsonProperty("roles")]
public Optional<ulong[]> RoleIds { get; set; }
[JsonProperty("channel_id")]
public Optional<ulong> ChannelId { get; set; }
}
}

View File

@@ -0,0 +1,30 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyGuildParams
{
[JsonProperty("username")]
public Optional<string> Username { get; set; }
[JsonProperty("name")]
public Optional<string> Name { get; set; }
[JsonProperty("region")]
public Optional<string> RegionId { get; set; }
[JsonProperty("verification_level")]
public Optional<VerificationLevel> VerificationLevel { get; set; }
[JsonProperty("default_message_notifications")]
public Optional<DefaultMessageNotifications> DefaultMessageNotifications { get; set; }
[JsonProperty("afk_timeout")]
public Optional<int> AfkTimeout { get; set; }
[JsonProperty("icon")]
public Optional<Image?> Icon { get; set; }
[JsonProperty("splash")]
public Optional<Image?> Splash { get; set; }
[JsonProperty("afk_channel_id")]
public Optional<ulong?> AfkChannelId { get; set; }
[JsonProperty("owner_id")]
public Optional<ulong> OwnerId { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyGuildRoleParams
{
[JsonProperty("name")]
public Optional<string> Name { get; set; }
[JsonProperty("permissions")]
public Optional<ulong> Permissions { get; set; }
[JsonProperty("position")]
public Optional<int> Position { get; set; }
[JsonProperty("color")]
public Optional<uint> Color { get; set; }
[JsonProperty("hoist")]
public Optional<bool> Hoist { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyGuildRolesParams : ModifyGuildRoleParams
{
[JsonProperty("id")]
public ulong Id { get; }
public ModifyGuildRolesParams(ulong id)
{
Id = id;
}
}
}

View File

@@ -0,0 +1,12 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyMessageParams
{
[JsonProperty("content")]
public Optional<string> Content { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
#pragma warning disable CS1591
namespace Discord.API.Rest
{
public class ModifyPresenceParams
{
public Optional<UserStatus> Status { get; set; }
public Optional<Game> Game { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyTextChannelParams : ModifyGuildChannelParams
{
[JsonProperty("topic")]
public Optional<string> Topic { get; set; }
}
}

View File

@@ -0,0 +1,14 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyVoiceChannelParams : ModifyGuildChannelParams
{
[JsonProperty("bitrate")]
public Optional<int> Bitrate { get; set; }
[JsonProperty("user_limit")]
public Optional<int> UserLimit { get; set; }
}
}

View File

@@ -0,0 +1,35 @@
#pragma warning disable CS1591
using Discord.Net.Rest;
using System.Collections.Generic;
using System.IO;
namespace Discord.API.Rest
{
public class UploadFileParams
{
public Stream File { get; }
public Optional<string> Filename { get; set; }
public Optional<string> Content { get; set; }
public Optional<string> Nonce { get; set; }
public Optional<bool> IsTTS { get; set; }
public UploadFileParams(Stream file)
{
File = file;
}
public IReadOnlyDictionary<string, object> ToDictionary()
{
var d = new Dictionary<string, object>();
d["file"] = new MultipartFile(File, Filename.GetValueOrDefault("unknown.dat"));
if (Content.IsSpecified)
d["content"] = Content.Value;
if (IsTTS.IsSpecified)
d["tts"] = IsTTS.Value.ToString();
if (Nonce.IsSpecified)
d["nonce"] = Nonce.Value;
return d;
}
}
}

View File

@@ -0,0 +1,17 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class WebSocketMessage
{
[JsonProperty("op")]
public int Operation { get; set; }
[JsonProperty("t", NullValueHandling = NullValueHandling.Ignore)]
public string Type { get; set; }
[JsonProperty("s", NullValueHandling = NullValueHandling.Ignore)]
public int? Sequence { get; set; }
[JsonProperty("d")]
public object Payload { get; set; }
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.IO;
using System.Threading.Tasks;
namespace Discord.Audio
{
public interface IAudioClient
{
event Func<Task> Connected;
event Func<Exception, Task> Disconnected;
event Func<int, int, Task> LatencyUpdated;
/// <summary> Gets the current connection state of this client. </summary>
ConnectionState ConnectionState { get; }
/// <summary> Gets the estimated round-trip latency, in milliseconds, to the gateway server. </summary>
int Latency { get; }
Task DisconnectAsync();
Stream CreateOpusStream(int samplesPerFrame, int bufferSize = 4000);
Stream CreatePCMStream(int samplesPerFrame, int? bitrate = null, OpusApplication application = OpusApplication.MusicOrMixed, int bufferSize = 4000);
}
}

View File

@@ -0,0 +1,9 @@
namespace Discord.Audio
{
public enum OpusApplication : int
{
Voice = 2048,
MusicOrMixed = 2049,
LowLatency = 2051
}
}

View File

@@ -0,0 +1,10 @@
namespace Discord
{
public enum ConnectionState : byte
{
Disconnected,
Connecting,
Connected,
Disconnecting
}
}

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>91e9e7bd-75c9-4e98-84aa-2c271922e5c2</ProjectGuid>
<RootNamespace>Discord</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@@ -0,0 +1,24 @@
using System.Reflection;
namespace Discord
{
public class DiscordConfig
{
public const int APIVersion = 6;
public static string Version { get; } =
typeof(DiscordConfig).GetTypeInfo().Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ??
typeof(DiscordConfig).GetTypeInfo().Assembly.GetName().Version.ToString(3) ??
"Unknown";
public static readonly string ClientAPIUrl = $"https://discordapp.com/api/v{APIVersion}/";
public const string CDNUrl = "https://discordcdn.com/";
public const string InviteUrl = "https://discord.gg/";
public const int MaxMessageSize = 2000;
public const int MaxMessagesPerBatch = 100;
public const int MaxUsersPerBatch = 1000;
/// <summary> Gets or sets the minimum log level severity that will be sent to the LogMessage event. </summary>
public LogSeverity LogLevel { get; set; } = LogSeverity.Info;
}
}

View File

@@ -0,0 +1,10 @@
namespace Discord
{
public enum ChannelType
{
Text = 0,
DM = 1,
Voice = 2,
Group = 3
}
}

View File

@@ -0,0 +1,17 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Discord
{
public interface IChannel : ISnowflakeEntity
{
IReadOnlyCollection<IUser> CachedUsers { get; }
/// <summary> Gets a collection of all users in this channel. </summary>
IAsyncEnumerable<IReadOnlyCollection<IUser>> GetUsersAsync();
/// <summary> Gets a user in this channel with the provided id.</summary>
Task<IUser> GetUserAsync(ulong id);
IUser GetCachedUser(ulong id);
}
}

View File

@@ -0,0 +1,13 @@
using System.Threading.Tasks;
namespace Discord
{
public interface IDMChannel : IMessageChannel, IPrivateChannel
{
/// <summary> Gets the recipient of all messages in this channel. </summary>
IUser Recipient { get; }
/// <summary> Closes this private channel, removing it from your channel list. </summary>
Task CloseAsync();
}
}

View File

@@ -0,0 +1,16 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Discord
{
public interface IGroupChannel : IMessageChannel, IPrivateChannel
{
///// <summary> Adds a user to this group. </summary>
//Task AddUserAsync(IUser user);
//new IReadOnlyCollection<IGroupUser> CachedUsers { get; }
/// <summary> Leaves this group. </summary>
Task LeaveAsync();
}
}

View File

@@ -0,0 +1,52 @@
using Discord.API.Rest;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Discord
{
public interface IGuildChannel : IChannel, IDeletable
{
/// <summary> Gets the name of this channel. </summary>
string Name { get; }
/// <summary> Gets the position of this channel in the guild's channel list, relative to others of the same type. </summary>
int Position { get; }
/// <summary> Gets the id of the guild this channel is a member of. </summary>
ulong GuildId { get; }
new IReadOnlyCollection<IGuildUser> CachedUsers { get; }
/// <summary> Creates a new invite to this channel. </summary>
/// <param name="maxAge"> The time (in seconds) until the invite expires. Set to null to never expire. </param>
/// <param name="maxUses"> The max amount of times this invite may be used. Set to null to have unlimited uses. </param>
/// <param name="isTemporary"> If true, a user accepting this invite will be kicked from the guild after closing their client. </param>
Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 1800, int? maxUses = default(int?), bool isTemporary = false);
/// <summary> Returns a collection of all invites to this channel. </summary>
Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync();
/// <summary> Gets a collection of permission overwrites for this channel. </summary>
IReadOnlyCollection<Overwrite> PermissionOverwrites { get; }
/// <summary> Modifies this guild channel. </summary>
Task ModifyAsync(Action<ModifyGuildChannelParams> func);
/// <summary> Gets the permission overwrite for a specific role, or null if one does not exist. </summary>
OverwritePermissions? GetPermissionOverwrite(IRole role);
/// <summary> Gets the permission overwrite for a specific user, or null if one does not exist. </summary>
OverwritePermissions? GetPermissionOverwrite(IUser user);
/// <summary> Removes the permission overwrite for the given role, if one exists. </summary>
Task RemovePermissionOverwriteAsync(IRole role);
/// <summary> Removes the permission overwrite for the given user, if one exists. </summary>
Task RemovePermissionOverwriteAsync(IUser user);
/// <summary> Adds or updates the permission overwrite for the given role. </summary>
Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions);
/// <summary> Adds or updates the permission overwrite for the given user. </summary>
Task AddPermissionOverwriteAsync(IUser user, OverwritePermissions permissions);
/// <summary> Gets a collection of all users in this channel. </summary>
new IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> GetUsersAsync();
/// <summary> Gets a user in this channel with the provided id.</summary>
new Task<IGuildUser> GetUserAsync(ulong id);
new IGuildUser GetCachedUser(ulong id);
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace Discord
{
public interface IMessageChannel : IChannel
{
/// <summary> Gets all messages in this channel's cache. </summary>
IReadOnlyCollection<IMessage> CachedMessages { get; }
/// <summary> Sends a message to this message channel. </summary>
Task<IUserMessage> SendMessageAsync(string text, bool isTTS = false);
/// <summary> Sends a file to this text channel, with an optional caption. </summary>
Task<IUserMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false);
/// <summary> Sends a file to this text channel, with an optional caption. </summary>
Task<IUserMessage> SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false);
/// <summary> Gets a message from this message channel with the given id, or null if not found. </summary>
Task<IMessage> GetMessageAsync(ulong id);
/// <summary> Gets the message from this channel's cache with the given id, or null if not found. </summary>
IMessage GetCachedMessage(ulong id);
/// <summary> Gets the last N messages from this message channel. </summary>
IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch);
/// <summary> Gets a collection of messages in this channel. </summary>
IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch);
/// <summary> Gets a collection of pinned messages in this channel. </summary>
Task<IReadOnlyCollection<IMessage>> GetPinnedMessagesAsync();
/// <summary> Bulk deletes multiple messages. </summary>
Task DeleteMessagesAsync(IEnumerable<IMessage> messages);
/// <summary> Broadcasts the "user is typing" message to all users in this channel, lasting 10 seconds.</summary>
IDisposable EnterTypingState();
}
}

View File

@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Discord
{
public interface IPrivateChannel : IChannel
{
IReadOnlyCollection<IUser> Recipients { get; }
}
}

View File

@@ -0,0 +1,15 @@
using Discord.API.Rest;
using System;
using System.Threading.Tasks;
namespace Discord
{
public interface ITextChannel : IMessageChannel, IMentionable, IGuildChannel
{
/// <summary> Gets the current topic for this text channel. </summary>
string Topic { get; }
/// <summary> Modifies this text channel. </summary>
Task ModifyAsync(Action<ModifyTextChannelParams> func);
}
}

View File

@@ -0,0 +1,20 @@
using Discord.API.Rest;
using Discord.Audio;
using System;
using System.Threading.Tasks;
namespace Discord
{
public interface IVoiceChannel : IGuildChannel
{
/// <summary> Gets the bitrate, in bits per second, clients in this voice channel are requested to use. </summary>
int Bitrate { get; }
/// <summary> Gets the max amount of users allowed to be connected to this channel at one time. A value of 0 represents no limit. </summary>
int UserLimit { get; }
/// <summary> Modifies this voice channel. </summary>
Task ModifyAsync(Action<ModifyVoiceChannelParams> func);
/// <summary> Connects to this voice channel. </summary>
Task<IAudioClient> ConnectAsync();
}
}

View File

@@ -0,0 +1,10 @@
namespace Discord
{
public enum DefaultMessageNotifications
{
/// <summary> By default, only mentions will trigger notifications. </summary>
MentionsOnly = 0,
/// <summary> By default, all messages will trigger notifications. </summary>
AllMessages = 1
}
}

View File

@@ -0,0 +1,33 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Model = Discord.API.Emoji;
namespace Discord
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public struct Emoji
{
public ulong Id { get; }
public string Name { get; }
public bool IsManaged { get; }
public bool RequireColons { get; }
public IReadOnlyList<ulong> RoleIds { get; }
public Emoji(ulong id, string name, bool isManaged, bool requireColons, IReadOnlyList<ulong> roleIds)
{
Id = id;
Name = name;
IsManaged = isManaged;
RequireColons = requireColons;
RoleIds = roleIds;
}
public static Emoji Create(Model model)
{
return new Emoji(model.Id, model.Name, model.Managed, model.RequireColons, ImmutableArray.Create(model.Roles));
}
public override string ToString() => Name;
private string DebuggerDisplay => $"{Name} ({Id})";
}
}

View File

@@ -0,0 +1,13 @@
//using Discord.Rest;
using System.Diagnostics;
using Model = Discord.API.Ban;
namespace Discord
{
public interface IBan
{
IUser User { get; }
string Reason { get; }
}
}

View File

@@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Discord.API.Rest;
using Discord.Audio;
namespace Discord
{
public interface IGuild : IDeletable, ISnowflakeEntity
{
/// <summary> Gets the name of this guild. </summary>
string Name { get; }
/// <summary> Gets the amount of time (in seconds) a user must be inactive in a voice channel for until they are automatically moved to the AFK voice channel, if one is set. </summary>
int AFKTimeout { get; }
/// <summary> Returns true if this guild is embeddable (e.g. widget) </summary>
bool IsEmbeddable { get; }
/// <summary> Gets the default message notifications for users who haven't explicitly set their notification settings. </summary>
DefaultMessageNotifications DefaultMessageNotifications { get; }
/// <summary> Gets the level of mfa requirements a user must fulfill before being allowed to perform administrative actions in this guild. </summary>
MfaLevel MfaLevel { get; }
/// <summary> Gets the level of requirements a user must fulfill before being allowed to post messages in this guild. </summary>
VerificationLevel VerificationLevel { get; }
/// <summary> Returns the id of this guild's icon, or null if one is not set. </summary>
string IconId { get; }
/// <summary> Returns the url to this guild's icon, or null if one is not set. </summary>
string IconUrl { get; }
/// <summary> Returns the id of this guild's splash image, or null if one is not set. </summary>
string SplashId { get; }
/// <summary> Returns the url to this guild's splash image, or null if one is not set. </summary>
string SplashUrl { get; }
/// <summary> Returns true if this guild is currently connected and ready to be used. Only applies to the WebSocket client. </summary>
bool Available { get; }
/// <summary> Gets the id of the AFK voice channel for this guild if set, or null if not. </summary>
ulong? AFKChannelId { get; }
/// <summary> Gets the id of the the default channel for this guild. </summary>
ulong DefaultChannelId { get; }
/// <summary> Gets the id of the embed channel for this guild if set, or null if not. </summary>
ulong? EmbedChannelId { get; }
/// <summary> Gets the id of the user that created this guild. </summary>
ulong OwnerId { get; }
/// <summary> Gets the id of the region hosting this guild's voice channels. </summary>
string VoiceRegionId { get; }
/// <summary> Gets the IAudioClient currently associated with this guild. </summary>
IAudioClient AudioClient { get; }
/// <summary> Gets the built-in role containing all users in this guild. </summary>
IRole EveryoneRole { get; }
/// <summary> Gets a collection of all custom emojis for this guild. </summary>
IReadOnlyCollection<Emoji> Emojis { get; }
/// <summary> Gets a collection of all extra features added to this guild. </summary>
IReadOnlyCollection<string> Features { get; }
/// <summary> Gets a collection of all roles in this guild. </summary>
IReadOnlyCollection<IRole> Roles { get; }
IReadOnlyCollection<IGuildUser> CachedUsers { get; }
/// <summary> Modifies this guild. </summary>
Task ModifyAsync(Action<ModifyGuildParams> func);
/// <summary> Modifies this guild's embed. </summary>
Task ModifyEmbedAsync(Action<ModifyGuildEmbedParams> func);
/// <summary> Bulk modifies the channels of this guild. </summary>
Task ModifyChannelsAsync(IEnumerable<ModifyGuildChannelsParams> args);
/// <summary> Bulk modifies the roles of this guild. </summary>
Task ModifyRolesAsync(IEnumerable<ModifyGuildRolesParams> args);
/// <summary> Leaves this guild. If you are the owner, use Delete instead. </summary>
Task LeaveAsync();
/// <summary> Gets a collection of all users banned on this guild. </summary>
Task<IReadOnlyCollection<IBan>> GetBansAsync();
/// <summary> Bans the provided user from this guild and optionally prunes their recent messages. </summary>
Task AddBanAsync(IUser user, int pruneDays = 0);
/// <summary> Bans the provided user id from this guild and optionally prunes their recent messages. </summary>
Task AddBanAsync(ulong userId, int pruneDays = 0);
/// <summary> Unbans the provided user if it is currently banned. </summary>
Task RemoveBanAsync(IUser user);
/// <summary> Unbans the provided user id if it is currently banned. </summary>
Task RemoveBanAsync(ulong userId);
/// <summary> Gets a collection of all channels in this guild. </summary>
Task<IReadOnlyCollection<IGuildChannel>> GetChannelsAsync();
/// <summary> Gets the channel in this guild with the provided id, or null if not found. </summary>
Task<IGuildChannel> GetChannelAsync(ulong id);
IGuildChannel GetCachedChannel(ulong id);
/// <summary> Creates a new text channel. </summary>
Task<ITextChannel> CreateTextChannelAsync(string name);
/// <summary> Creates a new voice channel. </summary>
Task<IVoiceChannel> CreateVoiceChannelAsync(string name);
Task<IReadOnlyCollection<IGuildIntegration>> GetIntegrationsAsync();
Task<IGuildIntegration> CreateIntegrationAsync(ulong id, string type);
/// <summary> Gets a collection of all invites to this guild. </summary>
Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync();
/// <summary> Gets the role in this guild with the provided id, or null if not found. </summary>
IRole GetRole(ulong id);
/// <summary> Creates a new role. </summary>
Task<IRole> CreateRoleAsync(string name, GuildPermissions? permissions = null, Color? color = null, bool isHoisted = false);
/// <summary> Gets a collection of all users in this guild. </summary>
Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync();
/// <summary> Gets the user in this guild with the provided id, or null if not found. </summary>
Task<IGuildUser> GetUserAsync(ulong id);
IGuildUser GetCachedUser(ulong id);
/// <summary> Gets the current user for this guild. </summary>
Task<IGuildUser> GetCurrentUserAsync();
/// <summary> Downloads all users for this guild if the current list is incomplete. </summary>
Task DownloadUsersAsync();
/// <summary> Removes all users from this guild if they have not logged on in a provided number of days or, if simulate is true, returns the number of users that would be removed. </summary>
Task<int> PruneUsersAsync(int days = 30, bool simulate = false);
}
}

View File

@@ -0,0 +1,21 @@
using System;
namespace Discord
{
public interface IGuildIntegration
{
ulong Id { get; }
string Name { get; }
string Type { get; }
bool IsEnabled { get; }
bool IsSyncing { get; }
ulong ExpireBehavior { get; }
ulong ExpireGracePeriod { get; }
DateTimeOffset SyncedAt { get; }
IntegrationAccount Account { get; }
ulong GuildId { get; }
ulong RoleId { get; }
IUser User { get; }
}
}

View File

@@ -0,0 +1,14 @@
namespace Discord
{
public interface IUserGuild : IDeletable, ISnowflakeEntity
{
/// <summary> Gets the name of this guild. </summary>
string Name { get; }
/// <summary> Returns the url to this guild's icon, or null if one is not set. </summary>
string IconUrl { get; }
/// <summary> Returns true if the current user owns this guild. </summary>
bool IsOwner { get; }
/// <summary> Returns the current user's permissions for this guild. </summary>
GuildPermissions Permissions { get; }
}
}

View File

@@ -0,0 +1,18 @@
namespace Discord
{
public interface IVoiceRegion
{
/// <summary> Gets the unique identifier for this voice region. </summary>
string Id { get; }
/// <summary> Gets the name of this voice region. </summary>
string Name { get; }
/// <summary> Returns true if this voice region is exclusive to VIP accounts. </summary>
bool IsVip { get; }
/// <summary> Returns true if this voice region is the closest to your machine. </summary>
bool IsOptimal { get; }
/// <summary> Gets an example hostname for this voice region. </summary>
string SampleHostname { get; }
/// <summary> Gets an example port for this voice region. </summary>
int SamplePort { get; }
}
}

View File

@@ -0,0 +1,14 @@
using System.Diagnostics;
namespace Discord
{
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public struct IntegrationAccount
{
public string Id { get; }
public string Name { get; private set; }
public override string ToString() => Name;
private string DebuggerDisplay => $"{Name} ({Id})";
}
}

View File

@@ -0,0 +1,10 @@
namespace Discord
{
public enum MfaLevel
{
/// <summary> Users have no additional MFA restriction on this guild. </summary>
Disabled = 0,
/// <summary> Users must have MFA enabled on their account to perform administrative actions. </summary>
Enabled = 1
}
}

View File

@@ -0,0 +1,14 @@
namespace Discord
{
public enum VerificationLevel
{
/// <summary> Users have no additional restrictions on sending messages to this guild. </summary>
None = 0,
/// <summary> Users must have a verified email on their account. </summary>
Low = 1,
/// <summary> Users must fulfill the requirements of Low, and be registered on Discord for at least 5 minutes. </summary>
Medium = 2,
/// <summary> Users must fulfill the requirements of Medium, and be a member of this guild for at least 10 minutes. </summary>
High = 3
}
}

View File

@@ -0,0 +1,13 @@
namespace Discord
{
public interface IApplication : ISnowflakeEntity
{
string Name { get; }
string Description { get; }
string[] RPCOrigins { get; }
ulong Flags { get; }
string IconUrl { get; }
IUser Owner { get; }
}
}

View File

@@ -0,0 +1,10 @@
using System.Threading.Tasks;
namespace Discord
{
public interface IDeletable
{
/// <summary> Deletes this object and all its children. </summary>
Task DeleteAsync();
}
}

View File

@@ -0,0 +1,15 @@
using System;
namespace Discord
{
public interface IEntity<TId>
where TId : IEquatable<TId>
{
/// <summary> Gets the IDiscordClient that created this object. </summary>
IDiscordClient Discord { get; }
/// <summary> Gets the unique identifier for this object. </summary>
TId Id { get; }
}
}

View File

@@ -0,0 +1,8 @@
namespace Discord
{
public interface IMentionable
{
/// <summary> Returns a special string used to mention this object. </summary>
string Mention { get; }
}
}

View File

@@ -0,0 +1,6 @@
namespace Discord
{
public interface ISnowflakeEntity : IEntity<ulong>
{
}
}

View File

@@ -0,0 +1,10 @@
using System.Threading.Tasks;
namespace Discord
{
public interface IUpdateable
{
/// <summary> Updates this object's properties with its current state. </summary>
Task UpdateAsync();
}
}

View File

@@ -0,0 +1,20 @@
using System.Threading.Tasks;
namespace Discord
{
public interface IInvite : IEntity<string>, IDeletable
{
/// <summary> Gets the unique identifier for this invite. </summary>
string Code { get; }
/// <summary> Gets the url used to accept this invite, using Code. </summary>
string Url { get; }
/// <summary> Gets the id of the the channel this invite is linked to. </summary>
ulong ChannelId { get; }
/// <summary> Gets the id of the guild this invite is linked to. </summary>
ulong GuildId { get; }
/// <summary> Accepts this invite and joins the target guild. This will fail on bot accounts. </summary>
Task AcceptAsync();
}
}

View File

@@ -0,0 +1,22 @@
using System;
namespace Discord
{
public interface IInviteMetadata : IInvite
{
/// <summary> Gets the user that created this invite. </summary>
IUser Inviter { get; }
/// <summary> Returns true if this invite was revoked. </summary>
bool IsRevoked { get; }
/// <summary> Returns true if users accepting this invite will be removed from the guild when they log off. </summary>
bool IsTemporary { get; }
/// <summary> Gets the time (in seconds) until the invite expires, or null if it never expires. </summary>
int? MaxAge { get; }
/// <summary> Gets the max amount of times this invite may be used, or null if there is no limit. </summary>
int? MaxUses { get; }
/// <summary> Gets the amount of times this invite has been used. </summary>
int Uses { get; }
/// <summary> Gets when this invite was created. </summary>
DateTimeOffset CreatedAt { get; }
}
}

View File

@@ -0,0 +1,9 @@
namespace Discord
{
public enum Direction
{
Before,
After,
Around
}
}

View File

@@ -0,0 +1,20 @@
using Model = Discord.API.EmbedProvider;
namespace Discord
{
public struct EmbedProvider
{
public string Name { get; }
public string Url { get; }
public EmbedProvider(string name, string url)
{
Name = name;
Url = url;
}
public static EmbedProvider Create(Model model)
{
return new EmbedProvider(model.Name, model.Url);
}
}
}

View File

@@ -0,0 +1,26 @@
using Model = Discord.API.EmbedThumbnail;
namespace Discord
{
public struct EmbedThumbnail
{
public string Url { get; }
public string ProxyUrl { get; }
public int? Height { get; }
public int? Width { get; }
public EmbedThumbnail(string url, string proxyUrl, int? height, int? width)
{
Url = url;
ProxyUrl = proxyUrl;
Height = height;
Width = width;
}
public static EmbedThumbnail Create(Model model)
{
return new EmbedThumbnail(model.Url, model.ProxyUrl,
model.Height.IsSpecified ? model.Height.Value : (int?)null,
model.Width.IsSpecified ? model.Width.Value : (int?)null);
}
}
}

View File

@@ -0,0 +1,14 @@
namespace Discord
{
public interface IAttachment
{
ulong Id { get; }
string Filename { get; }
string Url { get; }
string ProxyUrl { get; }
int Size { get; }
int? Height { get; }
int? Width { get; }
}
}

Some files were not shown because too many files have changed in this diff Show More