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,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>bfc6dc28-0351-4573-926a-d4124244c04f</ProjectGuid>
<RootNamespace>Discord.Rest</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@@ -0,0 +1,324 @@
using Discord.API.Rest;
using Discord.Net;
using Discord.Net.Queue;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using Discord.Logging;
namespace Discord.Rest
{
public class DiscordRestClient : IDiscordClient
{
private readonly object _eventLock = new object();
public event Func<LogMessage, Task> Log { add { _logEvent.Add(value); } remove { _logEvent.Remove(value); } }
private readonly AsyncEvent<Func<LogMessage, Task>> _logEvent = new AsyncEvent<Func<LogMessage, Task>>();
public event Func<Task> LoggedIn { add { _loggedInEvent.Add(value); } remove { _loggedInEvent.Remove(value); } }
private readonly AsyncEvent<Func<Task>> _loggedInEvent = new AsyncEvent<Func<Task>>();
public event Func<Task> LoggedOut { add { _loggedOutEvent.Add(value); } remove { _loggedOutEvent.Remove(value); } }
private readonly AsyncEvent<Func<Task>> _loggedOutEvent = new AsyncEvent<Func<Task>>();
internal readonly Logger _clientLogger, _restLogger, _queueLogger;
internal readonly SemaphoreSlim _connectionLock;
private bool _isFirstLogSub;
internal bool _isDisposed;
public API.DiscordRestApiClient ApiClient { get; }
internal LogManager LogManager { get; }
public LoginState LoginState { get; private set; }
public RestSelfUser CurrentUser { get; private set; }
/// <summary> Creates a new REST-only discord client. </summary>
public DiscordRestClient() : this(new DiscordRestConfig()) { }
public DiscordRestClient(DiscordRestConfig config) : this(config, CreateApiClient(config)) { }
/// <summary> Creates a new REST-only discord client. </summary>
internal DiscordRestClient(DiscordRestConfig config, API.DiscordRestApiClient client)
{
ApiClient = client;
LogManager = new LogManager(config.LogLevel);
LogManager.Message += async msg => await _logEvent.InvokeAsync(msg).ConfigureAwait(false);
_clientLogger = LogManager.CreateLogger("Client");
_restLogger = LogManager.CreateLogger("Rest");
_queueLogger = LogManager.CreateLogger("Queue");
_isFirstLogSub = true;
_connectionLock = new SemaphoreSlim(1, 1);
ApiClient.RequestQueue.RateLimitTriggered += async (id, bucket, millis) =>
{
await _queueLogger.WarningAsync($"Rate limit triggered (id = \"{id ?? "null"}\")").ConfigureAwait(false);
if (bucket == null && id != null)
await _queueLogger.WarningAsync($"Unknown rate limit bucket \"{id ?? "null"}\"").ConfigureAwait(false);
};
ApiClient.SentRequest += async (method, endpoint, millis) => await _restLogger.VerboseAsync($"{method} {endpoint}: {millis} ms").ConfigureAwait(false);
}
private static API.DiscordRestApiClient CreateApiClient(DiscordRestConfig config)
=> new API.DiscordRestApiClient(config.RestClientProvider, DiscordRestConfig.UserAgent, requestQueue: new RequestQueue());
/// <inheritdoc />
public async Task LoginAsync(TokenType tokenType, string token, bool validateToken = true)
{
await _connectionLock.WaitAsync().ConfigureAwait(false);
try
{
await LoginInternalAsync(tokenType, token).ConfigureAwait(false);
}
finally { _connectionLock.Release(); }
}
private async Task LoginInternalAsync(TokenType tokenType, string token)
{
if (_isFirstLogSub)
{
_isFirstLogSub = false;
await WriteInitialLog().ConfigureAwait(false);
}
if (LoginState != LoginState.LoggedOut)
await LogoutInternalAsync().ConfigureAwait(false);
LoginState = LoginState.LoggingIn;
try
{
await ApiClient.LoginAsync(tokenType, token).ConfigureAwait(false);
CurrentUser = RestSelfUser.Create(this, ApiClient.CurrentUser);
await OnLoginAsync(tokenType, token).ConfigureAwait(false);
LoginState = LoginState.LoggedIn;
}
catch (Exception)
{
await LogoutInternalAsync().ConfigureAwait(false);
throw;
}
await _loggedInEvent.InvokeAsync().ConfigureAwait(false);
}
protected virtual Task OnLoginAsync(TokenType tokenType, string token) => Task.CompletedTask;
/// <inheritdoc />
public async Task LogoutAsync()
{
await _connectionLock.WaitAsync().ConfigureAwait(false);
try
{
await LogoutInternalAsync().ConfigureAwait(false);
}
finally { _connectionLock.Release(); }
}
private async Task LogoutInternalAsync()
{
if (LoginState == LoginState.LoggedOut) return;
LoginState = LoginState.LoggingOut;
await ApiClient.LogoutAsync().ConfigureAwait(false);
await OnLogoutAsync().ConfigureAwait(false);
CurrentUser = null;
LoginState = LoginState.LoggedOut;
await _loggedOutEvent.InvokeAsync().ConfigureAwait(false);
}
protected virtual Task OnLogoutAsync() => Task.CompletedTask;
/// <inheritdoc />
public async Task<IApplication> GetApplicationInfoAsync()
{
var model = await ApiClient.GetMyApplicationAsync().ConfigureAwait(false);
return RestApplication.Create(this, model);
}
/// <inheritdoc />
public virtual async Task<IChannel> GetChannelAsync(ulong id)
{
var model = await ApiClient.GetChannelAsync(id).ConfigureAwait(false);
if (model != null)
{
switch (model.Type)
{
case ChannelType.Text:
return RestTextChannel.Create(this, model);
case ChannelType.Voice:
return RestVoiceChannel.Create(this, model);
case ChannelType.DM:
return RestDMChannel.Create(this, model);
case ChannelType.Group:
return RestGroupChannel.Create(this, model);
default:
throw new InvalidOperationException($"Unexpected channel type: {model.Type}");
}
}
return null;
}
/// <inheritdoc />
public virtual async Task<IReadOnlyCollection<IPrivateChannel>> GetPrivateChannelsAsync()
{
var models = await ApiClient.GetMyPrivateChannelsAsync().ConfigureAwait(false);
return models.Select(x => RestDMChannel.Create(this, x)).ToImmutableArray();
}
/// <inheritdoc />
public async Task<IReadOnlyCollection<RestConnection>> GetConnectionsAsync()
{
var models = await ApiClient.GetMyConnectionsAsync().ConfigureAwait(false);
return models.Select(x => RestConnection.Create(x)).ToImmutableArray();
}
/// <inheritdoc />
public virtual async Task<RestInvite> GetInviteAsync(string inviteId)
{
var model = await ApiClient.GetInviteAsync(inviteId).ConfigureAwait(false);
if (model != null)
return RestInvite.Create(this, model);
return null;
}
/// <inheritdoc />
public virtual async Task<RestGuild> GetGuildAsync(ulong id)
{
var model = await ApiClient.GetGuildAsync(id).ConfigureAwait(false);
if (model != null)
return RestGuild.Create(this, model);
return null;
}
/// <inheritdoc />
public virtual async Task<RestGuildEmbed?> GetGuildEmbedAsync(ulong id)
{
var model = await ApiClient.GetGuildEmbedAsync(id).ConfigureAwait(false);
if (model != null)
return RestGuildEmbed.Create(model);
return null;
}
/// <inheritdoc />
public virtual async Task<IReadOnlyCollection<RestUserGuild>> GetGuildSummariesAsync()
{
var models = await ApiClient.GetMyGuildsAsync().ConfigureAwait(false);
return models.Select(x => RestUserGuild.Create(this, x)).ToImmutableArray();
}
/// <inheritdoc />
public virtual async Task<IReadOnlyCollection<RestGuild>> GetGuildsAsync()
{
var summaryModels = await ApiClient.GetMyGuildsAsync().ConfigureAwait(false);
var guilds = ImmutableArray.CreateBuilder<RestGuild>(summaryModels.Count);
foreach (var summaryModel in summaryModels)
{
var guildModel = await ApiClient.GetGuildAsync(summaryModel.Id).ConfigureAwait(false);
if (guildModel != null)
guilds.Add(RestGuild.Create(this, guildModel));
}
return guilds.ToImmutable();
}
/// <inheritdoc />
public virtual async Task<RestGuild> CreateGuildAsync(string name, IVoiceRegion region, Stream jpegIcon = null)
{
var args = new CreateGuildParams(name, region.Id);
var model = await ApiClient.CreateGuildAsync(args).ConfigureAwait(false);
return RestGuild.Create(this, model);
}
/// <inheritdoc />
public virtual async Task<RestUser> GetUserAsync(ulong id)
{
var model = await ApiClient.GetUserAsync(id).ConfigureAwait(false);
if (model != null)
return RestUser.Create(this, model);
return null;
}
/// <inheritdoc />
public virtual async Task<RestUser> GetUserAsync(string username, string discriminator)
{
var model = await ApiClient.GetUserAsync(username, discriminator).ConfigureAwait(false);
if (model != null)
return RestUser.Create(this, model);
return null;
}
/// <inheritdoc />
public virtual async Task<IReadOnlyCollection<RestUser>> QueryUsersAsync(string query, int limit)
{
var models = await ApiClient.QueryUsersAsync(query, limit).ConfigureAwait(false);
return models.Select(x => RestUser.Create(this, x)).ToImmutableArray();
}
/// <inheritdoc />
public virtual async Task<IReadOnlyCollection<RestVoiceRegion>> GetVoiceRegionsAsync()
{
var models = await ApiClient.GetVoiceRegionsAsync().ConfigureAwait(false);
return models.Select(x => RestVoiceRegion.Create(this, x)).ToImmutableArray();
}
/// <inheritdoc />
public virtual async Task<RestVoiceRegion> GetVoiceRegionAsync(string id)
{
var models = await ApiClient.GetVoiceRegionsAsync().ConfigureAwait(false);
return models.Select(x => RestVoiceRegion.Create(this, x)).Where(x => x.Id == id).FirstOrDefault();
}
internal virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
ApiClient.Dispose();
_isDisposed = true;
}
}
/// <inheritdoc />
public void Dispose() => Dispose(true);
private async Task WriteInitialLog()
{
/*if (this is DiscordSocketClient)
await _clientLogger.InfoAsync($"DiscordSocketClient v{DiscordConfig.Version} (API v{DiscordConfig.APIVersion}, {DiscordSocketConfig.GatewayEncoding})").ConfigureAwait(false);
else if (this is DiscordRpcClient)
await _clientLogger.InfoAsync($"DiscordRpcClient v{DiscordConfig.Version} (API v{DiscordConfig.APIVersion}, RPC API v{DiscordRpcConfig.RpcAPIVersion})").ConfigureAwait(false);*/
await _clientLogger.InfoAsync($"Discord.Net v{DiscordConfig.Version} (API v{DiscordConfig.APIVersion})").ConfigureAwait(false);
await _clientLogger.VerboseAsync($"Runtime: {RuntimeInformation.FrameworkDescription.Trim()} ({ToArchString(RuntimeInformation.ProcessArchitecture)})").ConfigureAwait(false);
await _clientLogger.VerboseAsync($"OS: {RuntimeInformation.OSDescription.Trim()} ({ToArchString(RuntimeInformation.OSArchitecture)})").ConfigureAwait(false);
await _clientLogger.VerboseAsync($"Processors: {Environment.ProcessorCount}").ConfigureAwait(false);
}
private static string ToArchString(Architecture arch)
{
switch (arch)
{
case Architecture.X64: return "x64";
case Architecture.X86: return "x86";
default: return arch.ToString();
}
}
//IDiscordClient
ConnectionState IDiscordClient.ConnectionState => ConnectionState.Disconnected;
ISelfUser IDiscordClient.CurrentUser => CurrentUser;
async Task<IReadOnlyCollection<IConnection>> IDiscordClient.GetConnectionsAsync()
=> await GetConnectionsAsync().ConfigureAwait(false);
async Task<IInvite> IDiscordClient.GetInviteAsync(string inviteId)
=> await GetInviteAsync(inviteId).ConfigureAwait(false);
async Task<IGuild> IDiscordClient.GetGuildAsync(ulong id)
=> await GetGuildAsync(id).ConfigureAwait(false);
async Task<IReadOnlyCollection<IUserGuild>> IDiscordClient.GetGuildSummariesAsync()
=> await GetGuildSummariesAsync().ConfigureAwait(false);
async Task<IReadOnlyCollection<IGuild>> IDiscordClient.GetGuildsAsync()
=> await GetGuildsAsync().ConfigureAwait(false);
async Task<IGuild> IDiscordClient.CreateGuildAsync(string name, IVoiceRegion region, Stream jpegIcon)
=> await CreateGuildAsync(name, region, jpegIcon).ConfigureAwait(false);
async Task<IUser> IDiscordClient.GetUserAsync(ulong id)
=> await GetUserAsync(id).ConfigureAwait(false);
async Task<IUser> IDiscordClient.GetUserAsync(string username, string discriminator)
=> await GetUserAsync(username, discriminator).ConfigureAwait(false);
async Task<IReadOnlyCollection<IUser>> IDiscordClient.QueryUsersAsync(string query, int limit)
=> await QueryUsersAsync(query, limit).ConfigureAwait(false);
async Task<IReadOnlyCollection<IVoiceRegion>> IDiscordClient.GetVoiceRegionsAsync()
=> await GetVoiceRegionsAsync().ConfigureAwait(false);
async Task<IVoiceRegion> IDiscordClient.GetVoiceRegionAsync(string id)
=> await GetVoiceRegionAsync(id).ConfigureAwait(false);
Task IDiscordClient.ConnectAsync() { throw new NotSupportedException(); }
Task IDiscordClient.DisconnectAsync() { throw new NotSupportedException(); }
}
}

View File

@@ -0,0 +1,16 @@
using Discord.Net.Rest;
namespace Discord.Rest
{
public class DiscordRestConfig : DiscordConfig
{
public static string UserAgent { get; } = $"DiscordBot (https://github.com/RogueException/Discord.Net, v{Version})";
internal const int RestTimeout = 10000;
internal const int MessageQueueInterval = 100;
internal const int WebSocketQueueInterval = 100;
/// <summary> Gets or sets the provider used to generate new REST connections. </summary>
public RestClientProvider RestClientProvider { get; set; } = url => new DefaultRestClient(url);
}
}

View File

@@ -0,0 +1,211 @@
using Discord.API.Rest;
using System.IO;
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Immutable;
using Model = Discord.API.Channel;
namespace Discord.Rest
{
internal static class ChannelHelper
{
//General
public static async Task<Model> GetAsync(IGuildChannel channel, DiscordRestClient client)
{
return await client.ApiClient.GetChannelAsync(channel.GuildId, channel.Id).ConfigureAwait(false);
}
public static async Task<Model> GetAsync(IPrivateChannel channel, DiscordRestClient client)
{
return await client.ApiClient.GetChannelAsync(channel.Id).ConfigureAwait(false);
}
public static async Task DeleteAsync(IChannel channel, DiscordRestClient client)
{
await client.ApiClient.DeleteChannelAsync(channel.Id).ConfigureAwait(false);
}
public static async Task ModifyAsync(IGuildChannel channel, DiscordRestClient client,
Action<ModifyGuildChannelParams> func)
{
var args = new ModifyGuildChannelParams();
func(args);
await client.ApiClient.ModifyGuildChannelAsync(channel.Id, args);
}
public static async Task ModifyAsync(ITextChannel channel, DiscordRestClient client,
Action<ModifyTextChannelParams> func)
{
var args = new ModifyTextChannelParams();
func(args);
await client.ApiClient.ModifyGuildChannelAsync(channel.Id, args);
}
public static async Task ModifyAsync(IVoiceChannel channel, DiscordRestClient client,
Action<ModifyVoiceChannelParams> func)
{
var args = new ModifyVoiceChannelParams();
func(args);
await client.ApiClient.ModifyGuildChannelAsync(channel.Id, args);
}
//Invites
public static async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(IChannel channel, DiscordRestClient client)
{
var models = await client.ApiClient.GetChannelInvitesAsync(channel.Id);
return models.Select(x => RestInviteMetadata.Create(client, x)).ToImmutableArray();
}
public static async Task<RestInviteMetadata> CreateInviteAsync(IChannel channel, DiscordRestClient client,
int? maxAge, int? maxUses, bool isTemporary)
{
var args = new CreateChannelInviteParams { IsTemporary = isTemporary };
if (maxAge.HasValue)
args.MaxAge = maxAge.Value;
if (maxUses.HasValue)
args.MaxUses = maxUses.Value;
var model = await client.ApiClient.CreateChannelInviteAsync(channel.Id, args);
return RestInviteMetadata.Create(client, model);
}
//Messages
public static async Task<RestMessage> GetMessageAsync(IChannel channel, DiscordRestClient client,
ulong id)
{
var model = await client.ApiClient.GetChannelMessageAsync(channel.Id, id).ConfigureAwait(false);
return RestMessage.Create(client, model);
}
public static PagedAsyncEnumerable<RestMessage> GetMessagesAsync(IChannel channel, DiscordRestClient client,
ulong? fromMessageId = null, Direction dir = Direction.Before, int limit = DiscordConfig.MaxMessagesPerBatch)
{
//TODO: Test this with Around direction
return new PagedAsyncEnumerable<RestMessage>(
DiscordConfig.MaxMessagesPerBatch,
async (info, ct) =>
{
var args = new GetChannelMessagesParams
{
RelativeDirection = dir,
Limit = info.PageSize
};
if (info.Position != null)
args.RelativeMessageId = info.Position.Value;
var models = await client.ApiClient.GetChannelMessagesAsync(channel.Id, args);
return models.Select(x => RestMessage.Create(client, x)).ToImmutableArray(); ;
},
nextPage: (info, lastPage) =>
{
if (dir == Direction.Before)
info.Position = lastPage.Min(x => x.Id);
else
info.Position = lastPage.Max(x => x.Id);
if (lastPage.Count != DiscordConfig.MaxMessagesPerBatch)
info.Remaining = 0;
},
start: fromMessageId,
count: (uint)limit
);
}
public static async Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync(IChannel channel, DiscordRestClient client)
{
var models = await client.ApiClient.GetPinsAsync(channel.Id).ConfigureAwait(false);
return models.Select(x => RestMessage.Create(client, x)).ToImmutableArray();
}
public static async Task<RestUserMessage> SendMessageAsync(IChannel channel, DiscordRestClient client,
string text, bool isTTS)
{
var args = new CreateMessageParams(text) { IsTTS = isTTS };
var model = await client.ApiClient.CreateMessageAsync(channel.Id, args).ConfigureAwait(false);
return RestUserMessage.Create(client, model);
}
public static Task<RestUserMessage> SendFileAsync(IChannel channel, DiscordRestClient client,
string filePath, string text, bool isTTS)
{
string filename = Path.GetFileName(filePath);
using (var file = File.OpenRead(filePath))
return SendFileAsync(channel, client, file, filename, text, isTTS);
}
public static async Task<RestUserMessage> SendFileAsync(IChannel channel, DiscordRestClient client,
Stream stream, string filename, string text, bool isTTS)
{
var args = new UploadFileParams(stream) { Filename = filename, Content = text, IsTTS = isTTS };
var model = await client.ApiClient.UploadFileAsync(channel.Id, args).ConfigureAwait(false);
return RestUserMessage.Create(client, model);
}
public static async Task DeleteMessagesAsync(IChannel channel, DiscordRestClient client,
IEnumerable<IMessage> messages)
{
var args = new DeleteMessagesParams(messages.Select(x => x.Id).ToArray());
await client.ApiClient.DeleteMessagesAsync(channel.Id, args).ConfigureAwait(false);
}
//Permission Overwrites
public static async Task AddPermissionOverwriteAsync(IGuildChannel channel, DiscordRestClient client,
IUser user, OverwritePermissions perms)
{
var args = new ModifyChannelPermissionsParams("member", perms.AllowValue, perms.DenyValue);
await client.ApiClient.ModifyChannelPermissionsAsync(channel.Id, user.Id, args).ConfigureAwait(false);
}
public static async Task AddPermissionOverwriteAsync(IGuildChannel channel, DiscordRestClient client,
IRole role, OverwritePermissions perms)
{
var args = new ModifyChannelPermissionsParams("role", perms.AllowValue, perms.DenyValue);
await client.ApiClient.ModifyChannelPermissionsAsync(channel.Id, role.Id, args).ConfigureAwait(false);
}
public static async Task RemovePermissionOverwriteAsync(IGuildChannel channel, DiscordRestClient client,
IUser user)
{
await client.ApiClient.DeleteChannelPermissionAsync(channel.Id, user.Id).ConfigureAwait(false);
}
public static async Task RemovePermissionOverwriteAsync(IGuildChannel channel, DiscordRestClient client,
IRole role)
{
await client.ApiClient.DeleteChannelPermissionAsync(channel.Id, role.Id).ConfigureAwait(false);
}
//Users
public static async Task<RestGuildUser> GetUserAsync(IGuildChannel channel, DiscordRestClient client,
ulong id)
{
var model = await client.ApiClient.GetGuildMemberAsync(channel.GuildId, id);
if (model == null)
return null;
var user = RestGuildUser.Create(client, model);
if (!user.GetPermissions(channel).ReadMessages)
return null;
return user;
}
public static IAsyncEnumerable<IReadOnlyCollection<RestGuildUser>> GetUsersAsync(IGuildChannel channel, DiscordRestClient client,
ulong? froUserId = null, uint? limit = DiscordConfig.MaxUsersPerBatch)
{
return new PagedAsyncEnumerable<RestGuildUser>(
DiscordConfig.MaxUsersPerBatch,
async (info, ct) =>
{
var args = new GetGuildMembersParams
{
Limit = info.PageSize
};
if (info.Position != null)
args.AfterUserId = info.Position.Value;
var models = await client.ApiClient.GetGuildMembersAsync(channel.GuildId, args);
return models.Select(x => RestGuildUser.Create(client, x)).ToImmutableArray(); ;
},
nextPage: (info, lastPage) =>
{
info.Position = lastPage.Max(x => x.Id);
if (lastPage.Count != DiscordConfig.MaxMessagesPerBatch)
info.Remaining = 0;
},
start: froUserId,
count: limit
);
}
//Typing
public static IDisposable EnterTypingState(IChannel channel, DiscordRestClient client)
{
throw new NotImplementedException(); //TODO: Impl
}
}
}

View File

@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Model = Discord.API.Channel;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestDMChannel : RestEntity<ulong>, IDMChannel, IUpdateable
{
public RestUser Recipient { get; }
public IReadOnlyCollection<RestUser> Users => ImmutableArray.Create(Discord.CurrentUser, Recipient);
internal RestDMChannel(DiscordRestClient discord, ulong id)
: base(discord, id)
{
}
internal static RestDMChannel Create(DiscordRestClient discord, Model model)
{
var entity = new RestDMChannel(discord, model.Id);
entity.Update(model);
return entity;
}
internal void Update(Model model)
{
Recipient.Update(model.Recipients.Value[0]);
}
public async Task UpdateAsync()
=> Update(await ChannelHelper.GetAsync(this, Discord));
public Task CloseAsync()
=> ChannelHelper.DeleteAsync(this, Discord);
public RestUser GetUser(ulong id)
{
if (id == Recipient.Id)
return Recipient;
else if (id == Discord.CurrentUser.Id)
return Discord.CurrentUser;
else
return null;
}
public Task<RestMessage> GetMessageAsync(ulong id)
=> ChannelHelper.GetMessageAsync(this, Discord, id);
public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch)
=> ChannelHelper.GetMessagesAsync(this, Discord, limit: limit);
public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch)
=> ChannelHelper.GetMessagesAsync(this, Discord, fromMessageId, dir, limit);
public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch)
=> ChannelHelper.GetMessagesAsync(this, Discord, fromMessage.Id, dir, limit);
public Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync()
=> ChannelHelper.GetPinnedMessagesAsync(this, Discord);
public Task<RestUserMessage> SendMessageAsync(string text, bool isTTS)
=> ChannelHelper.SendMessageAsync(this, Discord, text, isTTS);
public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS)
=> ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS);
public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS)
=> ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS);
public Task DeleteMessagesAsync(IEnumerable<IMessage> messages)
=> ChannelHelper.DeleteMessagesAsync(this, Discord, messages);
public IDisposable EnterTypingState()
=> ChannelHelper.EnterTypingState(this, Discord);
public override string ToString() => $"@{Recipient}";
private string DebuggerDisplay => $"@{Recipient} ({Id}, DM)";
//IDMChannel
IUser IDMChannel.Recipient => Recipient;
//IPrivateChannel
IReadOnlyCollection<IUser> IPrivateChannel.Recipients => ImmutableArray.Create<IUser>(Recipient);
//IMessageChannel
IReadOnlyCollection<IMessage> IMessageChannel.CachedMessages => ImmutableArray.Create<IMessage>();
IMessage IMessageChannel.GetCachedMessage(ulong id) => null;
async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id)
=> await GetMessageAsync(id);
IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(int limit)
=> GetMessagesAsync(limit);
IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(ulong fromMessageId, Direction dir, int limit)
=> GetMessagesAsync(fromMessageId, dir, limit);
async Task<IReadOnlyCollection<IMessage>> IMessageChannel.GetPinnedMessagesAsync()
=> await GetPinnedMessagesAsync().ConfigureAwait(false);
async Task<IUserMessage> IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS)
=> await SendFileAsync(filePath, text, isTTS);
async Task<IUserMessage> IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS)
=> await SendFileAsync(stream, filename, text, isTTS);
async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS)
=> await SendMessageAsync(text, isTTS);
IDisposable IMessageChannel.EnterTypingState()
=> EnterTypingState();
//IChannel
IReadOnlyCollection<IUser> IChannel.CachedUsers => Users;
IUser IChannel.GetCachedUser(ulong id)
=> GetUser(id);
Task<IUser> IChannel.GetUserAsync(ulong id)
=> Task.FromResult<IUser>(GetUser(id));
IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync()
=> ImmutableArray.Create<IReadOnlyCollection<IUser>>().ToAsyncEnumerable();
}
}

View File

@@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Model = Discord.API.Channel;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestGroupChannel : RestEntity<ulong>, IGroupChannel, IUpdateable
{
private string _iconId;
private ImmutableDictionary<ulong, RestGroupUser> _users;
public string Name { get; private set; }
public IReadOnlyCollection<RestGroupUser> Users => _users.ToReadOnlyCollection();
public IReadOnlyCollection<RestGroupUser> Recipients
=> _users.Select(x => x.Value).Where(x => x.Id != Discord.CurrentUser.Id).ToReadOnlyCollection(() => _users.Count - 1);
internal RestGroupChannel(DiscordRestClient discord, ulong id)
: base(discord, id)
{
}
internal static RestGroupChannel Create(DiscordRestClient discord, Model model)
{
var entity = new RestGroupChannel(discord, model.Id);
entity.Update(model);
return entity;
}
internal void Update(Model model)
{
if (model.Name.IsSpecified)
Name = model.Name.Value;
if (model.Icon.IsSpecified)
_iconId = model.Icon.Value;
if (model.Recipients.IsSpecified)
UpdateUsers(model.Recipients.Value);
}
internal virtual void UpdateUsers(API.User[] models)
{
var users = ImmutableDictionary.CreateBuilder<ulong, RestGroupUser>();
for (int i = 0; i < models.Length; i++)
users[models[i].Id] = RestGroupUser.Create(Discord, models[i]);
_users = users.ToImmutable();
}
public async Task UpdateAsync()
=> Update(await ChannelHelper.GetAsync(this, Discord));
public Task LeaveAsync()
=> ChannelHelper.DeleteAsync(this, Discord);
public IUser GetUser(ulong id)
{
RestGroupUser user;
if (_users.TryGetValue(id, out user))
return user;
return null;
}
public Task<RestMessage> GetMessageAsync(ulong id)
=> ChannelHelper.GetMessageAsync(this, Discord, id);
public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch)
=> ChannelHelper.GetMessagesAsync(this, Discord, limit: limit);
public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch)
=> ChannelHelper.GetMessagesAsync(this, Discord, fromMessageId, dir, limit);
public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch)
=> ChannelHelper.GetMessagesAsync(this, Discord, fromMessage.Id, dir, limit);
public Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync()
=> ChannelHelper.GetPinnedMessagesAsync(this, Discord);
public Task<RestUserMessage> SendMessageAsync(string text, bool isTTS)
=> ChannelHelper.SendMessageAsync(this, Discord, text, isTTS);
public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS)
=> ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS);
public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS)
=> ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS);
public Task DeleteMessagesAsync(IEnumerable<IMessage> messages)
=> ChannelHelper.DeleteMessagesAsync(this, Discord, messages);
public IDisposable EnterTypingState()
=> ChannelHelper.EnterTypingState(this, Discord);
//IPrivateChannel
IReadOnlyCollection<IUser> IPrivateChannel.Recipients => Recipients;
//IMessageChannel
IReadOnlyCollection<IMessage> IMessageChannel.CachedMessages => ImmutableArray.Create<IMessage>();
IMessage IMessageChannel.GetCachedMessage(ulong id)
=> null;
async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id)
=> await GetMessageAsync(id);
IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(int limit)
=> GetMessagesAsync(limit);
IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(ulong fromMessageId, Direction dir, int limit)
=> GetMessagesAsync(fromMessageId, dir, limit);
async Task<IReadOnlyCollection<IMessage>> IMessageChannel.GetPinnedMessagesAsync()
=> await GetPinnedMessagesAsync();
async Task<IUserMessage> IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS)
=> await SendFileAsync(filePath, text, isTTS);
async Task<IUserMessage> IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS)
=> await SendFileAsync(stream, filename, text, isTTS);
async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS)
=> await SendMessageAsync(text, isTTS);
IDisposable IMessageChannel.EnterTypingState()
=> EnterTypingState();
//IChannel
IReadOnlyCollection<IUser> IChannel.CachedUsers => Users;
IUser IChannel.GetCachedUser(ulong id)
=> GetUser(id);
Task<IUser> IChannel.GetUserAsync(ulong id)
=> Task.FromResult(GetUser(id));
IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync()
=> ImmutableArray.Create<IReadOnlyCollection<IUser>>(Users).ToAsyncEnumerable();
}
}

View File

@@ -0,0 +1,158 @@
using Discord.API.Rest;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Model = Discord.API.Channel;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public abstract class RestGuildChannel : RestEntity<ulong>, IGuildChannel, IUpdateable
{
private ImmutableArray<Overwrite> _overwrites;
public IReadOnlyCollection<Overwrite> PermissionOverwrites => _overwrites;
public ulong GuildId { get; }
public string Name { get; private set; }
public int Position { get; private set; }
internal RestGuildChannel(DiscordRestClient discord, ulong id, ulong guildId)
: base(discord, id)
{
GuildId = guildId;
}
internal static RestGuildChannel Create(DiscordRestClient discord, Model model)
{
switch (model.Type)
{
case ChannelType.Text:
return RestTextChannel.Create(discord, model);
case ChannelType.Voice:
return RestVoiceChannel.Create(discord, model);
default:
throw new InvalidOperationException("Unknown guild channel type");
}
}
internal virtual void Update(Model model)
{
Name = model.Name.Value;
Position = model.Position.Value;
var overwrites = model.PermissionOverwrites.Value;
var newOverwrites = ImmutableArray.CreateBuilder<Overwrite>(overwrites.Length);
for (int i = 0; i < overwrites.Length; i++)
newOverwrites.Add(new Overwrite(overwrites[i]));
_overwrites = newOverwrites.ToImmutable();
}
public async Task UpdateAsync()
=> Update(await ChannelHelper.GetAsync(this, Discord));
public Task ModifyAsync(Action<ModifyGuildChannelParams> func)
=> ChannelHelper.ModifyAsync(this, Discord, func);
public Task DeleteAsync()
=> ChannelHelper.DeleteAsync(this, Discord);
public OverwritePermissions? GetPermissionOverwrite(IUser user)
{
for (int i = 0; i < _overwrites.Length; i++)
{
if (_overwrites[i].TargetId == user.Id)
return _overwrites[i].Permissions;
}
return null;
}
public OverwritePermissions? GetPermissionOverwrite(IRole role)
{
for (int i = 0; i < _overwrites.Length; i++)
{
if (_overwrites[i].TargetId == role.Id)
return _overwrites[i].Permissions;
}
return null;
}
public async Task AddPermissionOverwriteAsync(IUser user, OverwritePermissions perms)
{
await ChannelHelper.AddPermissionOverwriteAsync(this, Discord, user, perms).ConfigureAwait(false);
_overwrites = _overwrites.Add(new Overwrite(new API.Overwrite { Allow = perms.AllowValue, Deny = perms.DenyValue, TargetId = user.Id, TargetType = PermissionTarget.User }));
}
public async Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions perms)
{
await ChannelHelper.AddPermissionOverwriteAsync(this, Discord, role, perms).ConfigureAwait(false);
_overwrites.Add(new Overwrite(new API.Overwrite { Allow = perms.AllowValue, Deny = perms.DenyValue, TargetId = role.Id, TargetType = PermissionTarget.Role }));
}
public async Task RemovePermissionOverwriteAsync(IUser user)
{
await ChannelHelper.RemovePermissionOverwriteAsync(this, Discord, user).ConfigureAwait(false);
for (int i = 0; i < _overwrites.Length; i++)
{
if (_overwrites[i].TargetId == user.Id)
{
_overwrites = _overwrites.RemoveAt(i);
return;
}
}
}
public async Task RemovePermissionOverwriteAsync(IRole role)
{
await ChannelHelper.RemovePermissionOverwriteAsync(this, Discord, role).ConfigureAwait(false);
for (int i = 0; i < _overwrites.Length; i++)
{
if (_overwrites[i].TargetId == role.Id)
{
_overwrites = _overwrites.RemoveAt(i);
return;
}
}
}
public async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync()
=> await ChannelHelper.GetInvitesAsync(this, Discord);
public async Task<RestInviteMetadata> CreateInviteAsync(int? maxAge = 3600, int? maxUses = null, bool isTemporary = true)
=> await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary);
//IGuildChannel
async Task<IReadOnlyCollection<IInviteMetadata>> IGuildChannel.GetInvitesAsync()
=> await GetInvitesAsync();
async Task<IInviteMetadata> IGuildChannel.CreateInviteAsync(int? maxAge, int? maxUses, bool isTemporary)
=> await CreateInviteAsync(maxAge, maxUses, isTemporary);
OverwritePermissions? IGuildChannel.GetPermissionOverwrite(IRole role)
=> GetPermissionOverwrite(role);
OverwritePermissions? IGuildChannel.GetPermissionOverwrite(IUser user)
=> GetPermissionOverwrite(user);
async Task IGuildChannel.AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions)
=> await AddPermissionOverwriteAsync(role, permissions);
async Task IGuildChannel.AddPermissionOverwriteAsync(IUser user, OverwritePermissions permissions)
=> await AddPermissionOverwriteAsync(user, permissions);
async Task IGuildChannel.RemovePermissionOverwriteAsync(IRole role)
=> await RemovePermissionOverwriteAsync(role);
async Task IGuildChannel.RemovePermissionOverwriteAsync(IUser user)
=> await RemovePermissionOverwriteAsync(user);
IReadOnlyCollection<IGuildUser> IGuildChannel.CachedUsers
=> ImmutableArray.Create<IGuildUser>();
IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> IGuildChannel.GetUsersAsync()
=> ImmutableArray.Create<IReadOnlyCollection<IGuildUser>>().ToAsyncEnumerable(); //Overriden in Text/Voice //TODO: Does this actually override?
Task<IGuildUser> IGuildChannel.GetUserAsync(ulong id)
=> Task.FromResult<IGuildUser>(null); //Overriden in Text/Voice //TODO: Does this actually override?
IGuildUser IGuildChannel.GetCachedUser(ulong id)
=> null;
//IChannel
IReadOnlyCollection<IUser> IChannel.CachedUsers
=> ImmutableArray.Create<IUser>();
IUser IChannel.GetCachedUser(ulong id)
=> null;
IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync()
=> ImmutableArray.Create<IReadOnlyCollection<IUser>>().ToAsyncEnumerable(); //Overriden in Text/Voice //TODO: Does this actually override?
Task<IUser> IChannel.GetUserAsync(ulong id)
=> Task.FromResult<IUser>(null); //Overriden in Text/Voice //TODO: Does this actually override?
}
}

View File

@@ -0,0 +1,98 @@
using Discord.API.Rest;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Model = Discord.API.Channel;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestTextChannel : RestGuildChannel, ITextChannel
{
public string Topic { get; private set; }
public string Mention => MentionUtils.MentionChannel(Id);
internal RestTextChannel(DiscordRestClient discord, ulong id, ulong guildId)
: base(discord, id, guildId)
{
}
internal new static RestTextChannel Create(DiscordRestClient discord, Model model)
{
var entity = new RestTextChannel(discord, model.Id, model.GuildId.Value);
entity.Update(model);
return entity;
}
internal override void Update(Model model)
{
base.Update(model);
Topic = model.Topic.Value;
}
public Task ModifyAsync(Action<ModifyTextChannelParams> func)
=> ChannelHelper.ModifyAsync(this, Discord, func);
public Task<RestGuildUser> GetUserAsync(ulong id)
=> ChannelHelper.GetUserAsync(this, Discord, id);
public IAsyncEnumerable<IReadOnlyCollection<RestGuildUser>> GetUsersAsync()
=> ChannelHelper.GetUsersAsync(this, Discord);
public Task<RestMessage> GetMessageAsync(ulong id)
=> ChannelHelper.GetMessageAsync(this, Discord, id);
public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch)
=> ChannelHelper.GetMessagesAsync(this, Discord, limit: limit);
public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch)
=> ChannelHelper.GetMessagesAsync(this, Discord, fromMessageId, dir, limit);
public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch)
=> ChannelHelper.GetMessagesAsync(this, Discord, fromMessage.Id, dir, limit);
public Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync()
=> ChannelHelper.GetPinnedMessagesAsync(this, Discord);
public Task<RestUserMessage> SendMessageAsync(string text, bool isTTS)
=> ChannelHelper.SendMessageAsync(this, Discord, text, isTTS);
public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS)
=> ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS);
public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS)
=> ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS);
public Task DeleteMessagesAsync(IEnumerable<IMessage> messages)
=> ChannelHelper.DeleteMessagesAsync(this, Discord, messages);
public IDisposable EnterTypingState()
=> ChannelHelper.EnterTypingState(this, Discord);
//IGuildChannel
async Task<IGuildUser> IGuildChannel.GetUserAsync(ulong id)
=> await GetUserAsync(id);
IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> IGuildChannel.GetUsersAsync()
=> GetUsersAsync();
//IMessageChannel
IReadOnlyCollection<IMessage> IMessageChannel.CachedMessages
=> ImmutableArray.Create<IMessage>();
IMessage IMessageChannel.GetCachedMessage(ulong id)
=> null;
async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id)
=> await GetMessageAsync(id);
IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(int limit)
=> GetMessagesAsync(limit);
IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(ulong fromMessageId, Direction dir, int limit)
=> GetMessagesAsync(fromMessageId, dir, limit);
async Task<IReadOnlyCollection<IMessage>> IMessageChannel.GetPinnedMessagesAsync()
=> await GetPinnedMessagesAsync();
async Task<IUserMessage> IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS)
=> await SendFileAsync(filePath, text, isTTS);
async Task<IUserMessage> IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS)
=> await SendFileAsync(stream, filename, text, isTTS);
async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS)
=> await SendMessageAsync(text, isTTS);
IDisposable IMessageChannel.EnterTypingState()
=> EnterTypingState();
}
}

View File

@@ -0,0 +1,49 @@
using Discord.API.Rest;
using Discord.Audio;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Model = Discord.API.Channel;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestVoiceChannel : RestGuildChannel, IVoiceChannel
{
public int Bitrate { get; private set; }
public int UserLimit { get; private set; }
internal RestVoiceChannel(DiscordRestClient discord, ulong id, ulong guildId)
: base(discord, id, guildId)
{
}
internal new static RestVoiceChannel Create(DiscordRestClient discord, Model model)
{
var entity = new RestVoiceChannel(discord, model.Id, model.GuildId.Value);
entity.Update(model);
return entity;
}
internal override void Update(Model model)
{
base.Update(model);
Bitrate = model.Bitrate.Value;
UserLimit = model.UserLimit.Value;
}
public Task ModifyAsync(Action<ModifyVoiceChannelParams> func)
=> ChannelHelper.ModifyAsync(this, Discord, func);
//IVoiceChannel
Task<IAudioClient> IVoiceChannel.ConnectAsync() { throw new NotSupportedException(); }
//IGuildChannel
Task<IGuildUser> IGuildChannel.GetUserAsync(ulong id)
=> Task.FromResult<IGuildUser>(null);
IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> IGuildChannel.GetUsersAsync()
=> ImmutableArray.Create<IReadOnlyCollection<IGuildUser>>().ToAsyncEnumerable();
}
}

View File

@@ -0,0 +1,183 @@
using Discord.API.Rest;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Model = Discord.API.Guild;
using EmbedModel = Discord.API.GuildEmbed;
using RoleModel = Discord.API.Role;
using System.Linq;
using System.Collections.Immutable;
namespace Discord.Rest
{
internal static class GuildHelper
{
//General
public static async Task<Model> ModifyAsync(IGuild guild, DiscordRestClient client,
Action<ModifyGuildParams> func)
{
if (func == null) throw new NullReferenceException(nameof(func));
var args = new ModifyGuildParams();
func(args);
if (args.Splash.IsSpecified && guild.SplashId != null)
args.Splash = new API.Image(guild.SplashId);
if (args.Icon.IsSpecified && guild.IconId != null)
args.Icon = new API.Image(guild.IconId);
return await client.ApiClient.ModifyGuildAsync(guild.Id, args).ConfigureAwait(false);
}
public static async Task<EmbedModel> ModifyEmbedAsync(IGuild guild, DiscordRestClient client,
Action<ModifyGuildEmbedParams> func)
{
if (func == null) throw new NullReferenceException(nameof(func));
var args = new ModifyGuildEmbedParams();
func(args);
return await client.ApiClient.ModifyGuildEmbedAsync(guild.Id, args).ConfigureAwait(false);
}
public static async Task ModifyChannelsAsync(IGuild guild, DiscordRestClient client,
IEnumerable<ModifyGuildChannelsParams> args)
{
await client.ApiClient.ModifyGuildChannelsAsync(guild.Id, args).ConfigureAwait(false);
}
public static async Task<IReadOnlyCollection<RoleModel>> ModifyRolesAsync(IGuild guild, DiscordRestClient client,
IEnumerable<ModifyGuildRolesParams> args)
{
return await client.ApiClient.ModifyGuildRolesAsync(guild.Id, args).ConfigureAwait(false);
}
public static async Task LeaveAsync(IGuild guild, DiscordRestClient client)
{
await client.ApiClient.LeaveGuildAsync(guild.Id).ConfigureAwait(false);
}
public static async Task DeleteAsync(IGuild guild, DiscordRestClient client)
{
await client.ApiClient.DeleteGuildAsync(guild.Id).ConfigureAwait(false);
}
//Bans
public static async Task<IReadOnlyCollection<RestBan>> GetBansAsync(IGuild guild, DiscordRestClient client)
{
var models = await client.ApiClient.GetGuildBansAsync(guild.Id);
return models.Select(x => RestBan.Create(client, x)).ToImmutableArray();
}
public static async Task AddBanAsync(IGuild guild, DiscordRestClient client,
ulong userId, int pruneDays)
{
var args = new CreateGuildBanParams { DeleteMessageDays = pruneDays };
await client.ApiClient.CreateGuildBanAsync(guild.Id, userId, args);
}
public static async Task RemoveBanAsync(IGuild guild, DiscordRestClient client,
ulong userId)
{
await client.ApiClient.RemoveGuildBanAsync(guild.Id, userId);
}
//Channels
public static async Task<RestGuildChannel> GetChannelAsync(IGuild guild, DiscordRestClient client,
ulong id)
{
var model = await client.ApiClient.GetChannelAsync(guild.Id, id).ConfigureAwait(false);
if (model != null)
return RestGuildChannel.Create(client, model);
return null;
}
public static async Task<IReadOnlyCollection<RestGuildChannel>> GetChannelsAsync(IGuild guild, DiscordRestClient client)
{
var models = await client.ApiClient.GetGuildChannelsAsync(guild.Id).ConfigureAwait(false);
return models.Select(x => RestGuildChannel.Create(client, x)).ToImmutableArray();
}
public static async Task<RestTextChannel> CreateTextChannelAsync(IGuild guild, DiscordRestClient client,
string name)
{
if (name == null) throw new ArgumentNullException(nameof(name));
var args = new CreateGuildChannelParams(name, ChannelType.Text);
var model = await client.ApiClient.CreateGuildChannelAsync(guild.Id, args).ConfigureAwait(false);
return RestTextChannel.Create(client, model);
}
public static async Task<RestVoiceChannel> CreateVoiceChannelAsync(IGuild guild, DiscordRestClient client,
string name)
{
if (name == null) throw new ArgumentNullException(nameof(name));
var args = new CreateGuildChannelParams(name, ChannelType.Voice);
var model = await client.ApiClient.CreateGuildChannelAsync(guild.Id, args).ConfigureAwait(false);
return RestVoiceChannel.Create(client, model);
}
//Integrations
public static async Task<IReadOnlyCollection<RestGuildIntegration>> GetIntegrationsAsync(IGuild guild, DiscordRestClient client)
{
var models = await client.ApiClient.GetGuildIntegrationsAsync(guild.Id).ConfigureAwait(false);
return models.Select(x => RestGuildIntegration.Create(client, x)).ToImmutableArray();
}
public static async Task<RestGuildIntegration> CreateIntegrationAsync(IGuild guild, DiscordRestClient client,
ulong id, string type)
{
var args = new CreateGuildIntegrationParams(id, type);
var model = await client.ApiClient.CreateGuildIntegrationAsync(guild.Id, args).ConfigureAwait(false);
return RestGuildIntegration.Create(client, model);
}
//Invites
public static async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(IGuild guild, DiscordRestClient client)
{
var models = await client.ApiClient.GetGuildInvitesAsync(guild.Id).ConfigureAwait(false);
return models.Select(x => RestInviteMetadata.Create(client, x)).ToImmutableArray();
}
//Roles
public static async Task<RestRole> CreateRoleAsync(IGuild guild, DiscordRestClient client,
string name, GuildPermissions? permissions = null, Color? color = null, bool isHoisted = false)
{
if (name == null) throw new ArgumentNullException(nameof(name));
var model = await client.ApiClient.CreateGuildRoleAsync(guild.Id).ConfigureAwait(false);
var role = RestRole.Create(client, model);
await role.ModifyAsync(x =>
{
x.Name = name;
x.Permissions = (permissions ?? role.Permissions).RawValue;
x.Color = (color ?? Color.Default).RawValue;
x.Hoist = isHoisted;
}).ConfigureAwait(false);
return role;
}
//Users
public static async Task<RestGuildUser> GetUserAsync(IGuild guild, DiscordRestClient client,
ulong id)
{
var model = await client.ApiClient.GetGuildMemberAsync(guild.Id, id).ConfigureAwait(false);
if (model != null)
return RestGuildUser.Create(client, model);
return null;
}
public static async Task<RestGuildUser> GetCurrentUserAsync(IGuild guild, DiscordRestClient client)
{
return await GetUserAsync(guild, client, client.CurrentUser.Id).ConfigureAwait(false);
}
public static async Task<IReadOnlyCollection<RestGuildUser>> GetUsersAsync(IGuild guild, DiscordRestClient client)
{
var args = new GetGuildMembersParams();
var models = await client.ApiClient.GetGuildMembersAsync(guild.Id, args).ConfigureAwait(false);
return models.Select(x => RestGuildUser.Create(client, x)).ToImmutableArray();
}
public static async Task<int> PruneUsersAsync(IGuild guild, DiscordRestClient client,
int days = 30, bool simulate = false)
{
var args = new GuildPruneParams(days);
GetGuildPruneCountResponse model;
if (simulate)
model = await client.ApiClient.GetGuildPruneCountAsync(guild.Id, args).ConfigureAwait(false);
else
model = await client.ApiClient.BeginGuildPruneAsync(guild.Id, args).ConfigureAwait(false);
return model.Pruned;
}
}
}

View File

@@ -0,0 +1,27 @@
using System.Diagnostics;
using Model = Discord.API.Ban;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestBan : IBan
{
public RestUser User { get; }
public string Reason { get; }
internal RestBan(RestUser user, string reason)
{
User = user;
Reason = reason;
}
internal static RestBan Create(DiscordRestClient client, Model model)
{
return new RestBan(RestUser.Create(client, model.User), model.Reason);
}
public override string ToString() => User.ToString();
private string DebuggerDisplay => $"{User}: {Reason}";
IUser IBan.User => User;
}
}

View File

@@ -0,0 +1,212 @@
using System.Diagnostics;
using System.Collections.Immutable;
using Discord.Audio;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Discord.API.Rest;
using Model = Discord.API.Guild;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestGuild : RestEntity<ulong>, IGuild, IUpdateable
{
private ImmutableDictionary<ulong, RestRole> _roles;
private ImmutableArray<Emoji> _emojis;
private ImmutableArray<string> _features;
public string Name { get; private set; }
public int AFKTimeout { get; private set; }
public bool IsEmbeddable { get; private set; }
public VerificationLevel VerificationLevel { get; private set; }
public MfaLevel MfaLevel { get; private set; }
public DefaultMessageNotifications DefaultMessageNotifications { get; private set; }
public ulong? AFKChannelId { get; private set; }
public ulong? EmbedChannelId { get; private set; }
public ulong OwnerId { get; private set; }
public string VoiceRegionId { get; private set; }
public string IconId { get; private set; }
public string SplashId { get; private set; }
public ulong DefaultChannelId => Id;
public string IconUrl => API.CDN.GetGuildIconUrl(Id, IconId);
public string SplashUrl => API.CDN.GetGuildSplashUrl(Id, SplashId);
public RestRole EveryoneRole => GetRole(Id);
public IReadOnlyCollection<RestRole> Roles => _roles.ToReadOnlyCollection();
public IReadOnlyCollection<Emoji> Emojis => _emojis;
public IReadOnlyCollection<string> Features => _features;
internal RestGuild(DiscordRestClient client, ulong id)
: base(client, id)
{
}
internal static RestGuild Create(DiscordRestClient discord, Model model)
{
var entity = new RestGuild(discord, model.Id);
entity.Update(model);
return entity;
}
internal void Update(Model model)
{
AFKChannelId = model.AFKChannelId;
EmbedChannelId = model.EmbedChannelId;
AFKTimeout = model.AFKTimeout;
IsEmbeddable = model.EmbedEnabled;
IconId = model.Icon;
Name = model.Name;
OwnerId = model.OwnerId;
VoiceRegionId = model.Region;
SplashId = model.Splash;
VerificationLevel = model.VerificationLevel;
MfaLevel = model.MfaLevel;
DefaultMessageNotifications = model.DefaultMessageNotifications;
if (model.Emojis != null)
{
var emojis = ImmutableArray.CreateBuilder<Emoji>(model.Emojis.Length);
for (int i = 0; i < model.Emojis.Length; i++)
emojis.Add(Emoji.Create(model.Emojis[i]));
_emojis = emojis.ToImmutableArray();
}
else
_emojis = ImmutableArray.Create<Emoji>();
if (model.Features != null)
_features = model.Features.ToImmutableArray();
else
_features = ImmutableArray.Create<string>();
var roles = ImmutableDictionary.CreateBuilder<ulong, RestRole>();
if (model.Roles != null)
{
for (int i = 0; i < model.Roles.Length; i++)
roles[model.Roles[i].Id] = RestRole.Create(Discord, model.Roles[i]);
}
_roles = roles.ToImmutable();
}
//General
public async Task UpdateAsync()
=> Update(await Discord.ApiClient.GetGuildAsync(Id));
public Task DeleteAsync()
=> GuildHelper.DeleteAsync(this, Discord);
public Task ModifyAsync(Action<ModifyGuildParams> func)
=> GuildHelper.ModifyAsync(this, Discord, func);
public Task ModifyEmbedAsync(Action<ModifyGuildEmbedParams> func)
=> GuildHelper.ModifyEmbedAsync(this, Discord, func);
public Task ModifyChannelsAsync(IEnumerable<ModifyGuildChannelsParams> args)
=> GuildHelper.ModifyChannelsAsync(this, Discord, args);
public Task ModifyRolesAsync(IEnumerable<ModifyGuildRolesParams> args)
=> GuildHelper.ModifyRolesAsync(this, Discord, args);
public Task LeaveAsync()
=> GuildHelper.LeaveAsync(this, Discord);
//Bans
public Task<IReadOnlyCollection<RestBan>> GetBansAsync()
=> GuildHelper.GetBansAsync(this, Discord);
public Task AddBanAsync(IUser user, int pruneDays = 0)
=> GuildHelper.AddBanAsync(this, Discord, user.Id, pruneDays);
public Task AddBanAsync(ulong userId, int pruneDays = 0)
=> GuildHelper.AddBanAsync(this, Discord, userId, pruneDays);
public Task RemoveBanAsync(IUser user)
=> GuildHelper.RemoveBanAsync(this, Discord, user.Id);
public Task RemoveBanAsync(ulong userId)
=> GuildHelper.RemoveBanAsync(this, Discord, userId);
//Channels
public Task<IReadOnlyCollection<RestGuildChannel>> GetChannelsAsync()
=> GuildHelper.GetChannelsAsync(this, Discord);
public Task<RestGuildChannel> GetChannelAsync(ulong id)
=> GuildHelper.GetChannelAsync(this, Discord, id);
public Task<RestTextChannel> CreateTextChannelAsync(string name)
=> GuildHelper.CreateTextChannelAsync(this, Discord, name);
public Task<RestVoiceChannel> CreateVoiceChannelAsync(string name)
=> GuildHelper.CreateVoiceChannelAsync(this, Discord, name);
//Integrations
public Task<IReadOnlyCollection<RestGuildIntegration>> GetIntegrationsAsync()
=> GuildHelper.GetIntegrationsAsync(this, Discord);
public Task<RestGuildIntegration> CreateIntegrationAsync(ulong id, string type)
=> GuildHelper.CreateIntegrationAsync(this, Discord, id, type);
//Invites
public Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync()
=> GuildHelper.GetInvitesAsync(this, Discord);
//Roles
public RestRole GetRole(ulong id)
{
RestRole value;
if (_roles.TryGetValue(id, out value))
return value;
return null;
}
public async Task<IRole> CreateRoleAsync(string name, GuildPermissions? permissions = default(GuildPermissions?), Color? color = default(Color?), bool isHoisted = false)
{
var role = await GuildHelper.CreateRoleAsync(this, Discord, name, permissions, color, isHoisted);
_roles = _roles.Add(role.Id, role);
return role;
}
//Users
public Task<IReadOnlyCollection<RestGuildUser>> GetUsersAsync()
=> GuildHelper.GetUsersAsync(this, Discord);
public Task<RestGuildUser> GetUserAsync(ulong id)
=> GuildHelper.GetUserAsync(this, Discord, id);
public Task<RestGuildUser> GetCurrentUserAsync()
=> GuildHelper.GetUserAsync(this, Discord, Discord.CurrentUser.Id);
public Task<int> PruneUsersAsync(int days = 30, bool simulate = false)
=> GuildHelper.PruneUsersAsync(this, Discord, days, simulate);
//IGuild
bool IGuild.Available => true;
IAudioClient IGuild.AudioClient => null;
IReadOnlyCollection<IGuildUser> IGuild.CachedUsers => ImmutableArray.Create<IGuildUser>();
IRole IGuild.EveryoneRole => EveryoneRole;
IReadOnlyCollection<IRole> IGuild.Roles => Roles;
async Task<IReadOnlyCollection<IBan>> IGuild.GetBansAsync()
=> await GetBansAsync();
async Task<IReadOnlyCollection<IGuildChannel>> IGuild.GetChannelsAsync()
=> await GetChannelsAsync();
async Task<IGuildChannel> IGuild.GetChannelAsync(ulong id)
=> await GetChannelAsync(id);
IGuildChannel IGuild.GetCachedChannel(ulong id)
=> null;
async Task<ITextChannel> IGuild.CreateTextChannelAsync(string name)
=> await CreateTextChannelAsync(name);
async Task<IVoiceChannel> IGuild.CreateVoiceChannelAsync(string name)
=> await CreateVoiceChannelAsync(name);
async Task<IReadOnlyCollection<IGuildIntegration>> IGuild.GetIntegrationsAsync()
=> await GetIntegrationsAsync();
async Task<IGuildIntegration> IGuild.CreateIntegrationAsync(ulong id, string type)
=> await CreateIntegrationAsync(id, type);
async Task<IReadOnlyCollection<IInviteMetadata>> IGuild.GetInvitesAsync()
=> await GetInvitesAsync();
IRole IGuild.GetRole(ulong id)
=> GetRole(id);
async Task<IReadOnlyCollection<IGuildUser>> IGuild.GetUsersAsync()
=> await GetUsersAsync();
async Task<IGuildUser> IGuild.GetUserAsync(ulong id)
=> await GetUserAsync(id);
IGuildUser IGuild.GetCachedUser(ulong id)
=> null;
async Task<IGuildUser> IGuild.GetCurrentUserAsync()
=> await GetCurrentUserAsync();
Task IGuild.DownloadUsersAsync() { throw new NotSupportedException(); }
}
}

View File

@@ -0,0 +1,25 @@
using System.Diagnostics;
using Model = Discord.API.GuildEmbed;
namespace Discord
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public struct RestGuildEmbed
{
public bool IsEnabled { get; private set; }
public ulong? ChannelId { get; private set; }
internal RestGuildEmbed(bool isEnabled, ulong? channelId)
{
ChannelId = channelId;
IsEnabled = isEnabled;
}
internal static RestGuildEmbed Create(Model model)
{
return new RestGuildEmbed(model.Enabled, model.ChannelId);
}
public override string ToString() => ChannelId?.ToString();
private string DebuggerDisplay => $"{ChannelId} ({(IsEnabled ? "Enabled" : "Disabled")})";
}
}

View File

@@ -0,0 +1,77 @@
using Discord.API.Rest;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Model = Discord.API.Integration;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestGuildIntegration : RestEntity<ulong>, IGuildIntegration
{
private long _syncedAtTicks;
public string Name { get; private set; }
public string Type { get; private set; }
public bool IsEnabled { get; private set; }
public bool IsSyncing { get; private set; }
public ulong ExpireBehavior { get; private set; }
public ulong ExpireGracePeriod { get; private set; }
public ulong GuildId { get; private set; }
public ulong RoleId { get; private set; }
public RestUser User { get; private set; }
public IntegrationAccount Account { get; private set; }
public DateTimeOffset SyncedAt => DateTimeUtils.FromTicks(_syncedAtTicks);
internal RestGuildIntegration(DiscordRestClient discord, ulong id)
: base(discord, id)
{
}
internal static RestGuildIntegration Create(DiscordRestClient discord, Model model)
{
var entity = new RestGuildIntegration(discord, model.Id);
entity.Update(model);
return entity;
}
public void Update(Model model)
{
Name = model.Name;
Type = model.Type;
IsEnabled = model.Enabled;
IsSyncing = model.Syncing;
ExpireBehavior = model.ExpireBehavior;
ExpireGracePeriod = model.ExpireGracePeriod;
_syncedAtTicks = model.SyncedAt.UtcTicks;
RoleId = model.RoleId;
User = RestUser.Create(Discord, model.User);
}
public async Task DeleteAsync()
{
await Discord.ApiClient.DeleteGuildIntegrationAsync(GuildId, Id).ConfigureAwait(false);
}
public async Task ModifyAsync(Action<ModifyGuildIntegrationParams> func)
{
if (func == null) throw new NullReferenceException(nameof(func));
var args = new ModifyGuildIntegrationParams();
func(args);
var model = await Discord.ApiClient.ModifyGuildIntegrationAsync(GuildId, Id, args).ConfigureAwait(false);
Update(model);
}
public async Task SyncAsync()
{
await Discord.ApiClient.SyncGuildIntegrationAsync(GuildId, Id).ConfigureAwait(false);
}
public override string ToString() => Name;
private string DebuggerDisplay => $"{Name} ({Id}{(IsEnabled ? ", Enabled" : "")})";
IUser IGuildIntegration.User => User;
}
}

View File

@@ -0,0 +1,49 @@
using System.Diagnostics;
using System.Threading.Tasks;
using Model = Discord.API.UserGuild;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestUserGuild : RestEntity<ulong>, ISnowflakeEntity, IUserGuild
{
private string _iconId;
public string Name { get; private set; }
public bool IsOwner { get; private set; }
public GuildPermissions Permissions { get; private set; }
public string IconUrl => API.CDN.GetGuildIconUrl(Id, _iconId);
internal RestUserGuild(DiscordRestClient discord, ulong id)
: base(discord, id)
{
}
internal static RestUserGuild Create(DiscordRestClient discord, Model model)
{
var entity = new RestUserGuild(discord, model.Id);
entity.Update(model);
return entity;
}
public void Update(Model model)
{
_iconId = model.Icon;
IsOwner = model.Owner;
Name = model.Name;
Permissions = new GuildPermissions(model.Permissions);
}
public async Task LeaveAsync()
{
await Discord.ApiClient.LeaveGuildAsync(Id).ConfigureAwait(false);
}
public async Task DeleteAsync()
{
await Discord.ApiClient.DeleteGuildAsync(Id).ConfigureAwait(false);
}
public override string ToString() => Name;
private string DebuggerDisplay => $"{Name} ({Id}{(IsOwner ? ", Owned" : "")})";
}
}

View File

@@ -0,0 +1,38 @@
using Discord.Rest;
using System.Diagnostics;
using Model = Discord.API.VoiceRegion;
namespace Discord
{
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class RestVoiceRegion : RestEntity<string>, IVoiceRegion
{
public string Name { get; private set; }
public bool IsVip { get; private set; }
public bool IsOptimal { get; private set; }
public string SampleHostname { get; private set; }
public int SamplePort { get; private set; }
internal RestVoiceRegion(DiscordRestClient client, string id)
: base(client, id)
{
}
internal static RestVoiceRegion Create(DiscordRestClient client, Model model)
{
var entity = new RestVoiceRegion(client, model.Id);
entity.Update(model);
return entity;
}
internal void Update(Model model)
{
Name = model.Name;
IsVip = model.IsVip;
IsOptimal = model.IsOptimal;
SampleHostname = model.SampleHostname;
SamplePort = model.SamplePort;
}
public override string ToString() => Name;
private string DebuggerDisplay => $"{Name} ({Id}{(IsVip ? ", VIP" : "")}{(IsOptimal ? ", Optimal" : "")})";
}
}

View File

@@ -0,0 +1,21 @@
using System.Threading.Tasks;
using Model = Discord.API.Invite;
namespace Discord.Rest
{
internal static class InviteHelper
{
public static async Task<Model> GetAsync(IInvite invite, DiscordRestClient client)
{
return await client.ApiClient.GetInviteAsync(invite.Code).ConfigureAwait(false);
}
public static async Task AcceptAsync(IInvite invite, DiscordRestClient client)
{
await client.ApiClient.AcceptInviteAsync(invite.Code).ConfigureAwait(false);
}
public static async Task DeleteAsync(IInvite invite, DiscordRestClient client)
{
await client.ApiClient.DeleteInviteAsync(invite.Code).ConfigureAwait(false);
}
}
}

View File

@@ -0,0 +1,50 @@
using System.Diagnostics;
using System.Threading.Tasks;
using Model = Discord.API.Invite;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestInvite : RestEntity<string>, IInvite, IUpdateable
{
public string ChannelName { get; private set; }
public string GuildName { get; private set; }
public ulong ChannelId { get; private set; }
public ulong GuildId { get; private set; }
public string Code => Id;
public string Url => $"{DiscordConfig.InviteUrl}/{Code}";
internal RestInvite(DiscordRestClient discord, string id)
: base(discord, id)
{
}
internal static RestInvite Create(DiscordRestClient discord, Model model)
{
var entity = new RestInvite(discord, model.Code);
entity.Update(model);
return entity;
}
internal void Update(Model model)
{
GuildId = model.Guild.Id;
ChannelId = model.Channel.Id;
GuildName = model.Guild.Name;
ChannelName = model.Channel.Name;
}
public async Task UpdateAsync()
=> Update(await InviteHelper.GetAsync(this, Discord).ConfigureAwait(false));
public Task DeleteAsync()
=> InviteHelper.DeleteAsync(this, Discord);
public Task AcceptAsync()
=> InviteHelper.AcceptAsync(this, Discord);
public override string ToString() => Url;
private string DebuggerDisplay => $"{Url} ({GuildName} / {ChannelName})";
string IEntity<string>.Id => Code;
}
}

View File

@@ -0,0 +1,45 @@
using System;
using System.Diagnostics;
using Model = Discord.API.InviteMetadata;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestInviteMetadata : RestInvite, IInviteMetadata
{
private long _createdAtTicks;
public bool IsRevoked { get; private set; }
public bool IsTemporary { get; private set; }
public int? MaxAge { get; private set; }
public int? MaxUses { get; private set; }
public int Uses { get; private set; }
public RestUser Inviter { get; private set; }
public DateTimeOffset CreatedAt => DateTimeUtils.FromTicks(_createdAtTicks);
internal RestInviteMetadata(DiscordRestClient discord, string id)
: base(discord, id)
{
}
internal static RestInviteMetadata Create(DiscordRestClient discord, Model model)
{
var entity = new RestInviteMetadata(discord, model.Code);
entity.Update(model);
return entity;
}
internal void Update(Model model)
{
base.Update(model);
Inviter = RestUser.Create(Discord, model.Inviter);
IsRevoked = model.Revoked;
IsTemporary = model.Temporary;
MaxAge = model.MaxAge != 0 ? model.MaxAge : (int?)null;
MaxUses = model.MaxUses;
Uses = model.Uses;
_createdAtTicks = model.CreatedAt.UtcTicks;
}
IUser IInviteMetadata.Inviter => Inviter;
}
}

View File

@@ -0,0 +1,33 @@
using Discord.API.Rest;
using System;
using System.Threading.Tasks;
namespace Discord.Rest
{
internal static class MessageHelper
{
public static async Task GetAsync(IMessage msg, DiscordRestClient client)
{
await client.ApiClient.GetChannelMessageAsync(msg.ChannelId, msg.Id);
}
public static async Task ModifyAsync(IMessage msg, DiscordRestClient client, Action<ModifyMessageParams> func)
{
var args = new ModifyMessageParams();
func(args);
await client.ApiClient.ModifyMessageAsync(msg.ChannelId, msg.Id, args);
}
public static async Task DeleteAsync(IMessage msg, DiscordRestClient client)
{
await client.ApiClient.DeleteMessageAsync(msg.ChannelId, msg.Id);
}
public static async Task PinAsync(IMessage msg, DiscordRestClient client)
{
await client.ApiClient.AddPinAsync(msg.ChannelId, msg.Id);
}
public static async Task UnpinAsync(IMessage msg, DiscordRestClient client)
{
await client.ApiClient.RemovePinAsync(msg.ChannelId, msg.Id);
}
}
}

View File

@@ -0,0 +1,32 @@
using Model = Discord.API.Attachment;
namespace Discord
{
public class RestAttachment : IAttachment
{
public ulong Id { get; }
public string Filename { get; }
public string Url { get; }
public string ProxyUrl { get; }
public int Size { get; }
public int? Height { get; }
public int? Width { get; }
internal RestAttachment(ulong id, string filename, string url, string proxyUrl, int size, int? height, int? width)
{
Id = id;
Filename = filename;
Url = url;
ProxyUrl = proxyUrl;
Size = size;
Height = height;
Width = width;
}
internal static RestAttachment Create(Model model)
{
return new RestAttachment(model.Id, model.Filename, model.Url, model.ProxyUrl, model.Size,
model.Height.IsSpecified ? model.Height.Value : (int?)null,
model.Width.IsSpecified ? model.Width.Value : (int?)null);
}
}
}

View File

@@ -0,0 +1,30 @@
using Model = Discord.API.Embed;
namespace Discord
{
public class RestEmbed : IEmbed
{
public string Description { get; }
public string Url { get; }
public string Title { get; }
public string Type { get; }
public EmbedProvider? Provider { get; }
public EmbedThumbnail? Thumbnail { get; }
internal RestEmbed(string type, string title, string description, string url, EmbedProvider? provider, EmbedThumbnail? thumbnail)
{
Type = type;
Title = title;
Description = description;
Url = url;
Provider = provider;
Thumbnail = thumbnail;
}
internal static RestEmbed Create(Model model)
{
return new RestEmbed(model.Type, model.Title, model.Description, model.Url,
model.Provider.IsSpecified ? EmbedProvider.Create(model.Provider.Value) : (EmbedProvider?)null,
model.Thumbnail.IsSpecified ? EmbedThumbnail.Create(model.Thumbnail.Value) : (EmbedThumbnail?)null);
}
}
}

View File

@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Threading.Tasks;
using Model = Discord.API.Message;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public abstract class RestMessage : RestEntity<ulong>, IMessage, IUpdateable
{
private long _timestampTicks;
public ulong ChannelId { get; }
public IUser Author { get; }
public string Content { get; private set; }
public virtual bool IsTTS => false;
public virtual bool IsPinned => false;
public virtual DateTimeOffset? EditedTimestamp => null;
public virtual IReadOnlyCollection<IAttachment> Attachments => ImmutableArray.Create<IAttachment>();
public virtual IReadOnlyCollection<IEmbed> Embeds => ImmutableArray.Create<IEmbed>();
public virtual IReadOnlyCollection<ulong> MentionedChannelIds => ImmutableArray.Create<ulong>();
public virtual IReadOnlyCollection<IRole> MentionedRoles => ImmutableArray.Create<IRole>();
public virtual IReadOnlyCollection<IUser> MentionedUsers => ImmutableArray.Create<IUser>();
public DateTimeOffset Timestamp => DateTimeUtils.FromTicks(_timestampTicks);
internal RestMessage(DiscordRestClient discord, ulong id, ulong channelId)
: base(discord, id)
{
ChannelId = channelId;
}
internal static RestMessage Create(DiscordRestClient discord, Model model)
{
if (model.Type == MessageType.Default)
return RestUserMessage.Create(discord, model);
else
return RestSystemMessage.Create(discord, model);
}
internal virtual void Update(Model model)
{
if (model.Timestamp.IsSpecified)
_timestampTicks = model.Timestamp.Value.UtcTicks;
if (model.Content.IsSpecified)
Content = model.Content.Value;
}
public async Task UpdateAsync()
{
var model = await Discord.ApiClient.GetChannelMessageAsync(ChannelId, Id).ConfigureAwait(false);
Update(model);
}
MessageType IMessage.Type => MessageType.Default;
}
}

View File

@@ -0,0 +1,28 @@
using System.Diagnostics;
using Model = Discord.API.Message;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestSystemMessage : RestMessage, ISystemMessage
{
public MessageType Type { get; private set; }
internal RestSystemMessage(DiscordRestClient discord, ulong id, ulong channelId)
: base(discord, id, channelId)
{
}
internal new static RestSystemMessage Create(DiscordRestClient discord, Model model)
{
var entity = new RestSystemMessage(discord, model.Id, model.ChannelId);
entity.Update(model);
return entity;
}
internal override void Update(Model model)
{
base.Update(model);
Type = model.Type;
}
}
}

View File

@@ -0,0 +1,135 @@
using Discord.API.Rest;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Model = Discord.API.Message;
using Discord.API;
using System.Collections.Generic;
using System.Collections.Immutable;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestUserMessage : RestMessage, IUserMessage
{
private bool _isMentioningEveryone, _isTTS, _isPinned;
private long? _editedTimestampTicks;
private ImmutableArray<RestAttachment> _attachments;
private ImmutableArray<RestEmbed> _embeds;
private ImmutableArray<ulong> _mentionedChannelIds;
private ImmutableArray<RestRole> _mentionedRoles;
private ImmutableArray<RestUser> _mentionedUsers;
public override bool IsTTS => _isTTS;
public override bool IsPinned => _isPinned;
public override DateTimeOffset? EditedTimestamp => DateTimeUtils.FromTicks(_editedTimestampTicks);
public override IReadOnlyCollection<IAttachment> Attachments => _attachments;
public override IReadOnlyCollection<IEmbed> Embeds => _embeds;
public override IReadOnlyCollection<ulong> MentionedChannelIds => _mentionedChannelIds;
public override IReadOnlyCollection<IRole> MentionedRoles => _mentionedRoles;
public override IReadOnlyCollection<IUser> MentionedUsers => _mentionedUsers;
internal RestUserMessage(DiscordRestClient discord, ulong id, ulong channelId)
: base(discord, id, channelId)
{
}
internal new static RestUserMessage Create(DiscordRestClient discord, Model model)
{
var entity = new RestUserMessage(discord, model.Id, model.ChannelId);
entity.Update(model);
return entity;
}
internal override void Update(Model model)
{
base.Update(model);
if (model.IsTextToSpeech.IsSpecified)
_isTTS = model.IsTextToSpeech.Value;
if (model.Pinned.IsSpecified)
_isPinned = model.Pinned.Value;
if (model.EditedTimestamp.IsSpecified)
_editedTimestampTicks = model.EditedTimestamp.Value?.UtcTicks;
if (model.MentionEveryone.IsSpecified)
_isMentioningEveryone = model.MentionEveryone.Value;
if (model.Attachments.IsSpecified)
{
var value = model.Attachments.Value;
if (value.Length > 0)
{
var attachments = ImmutableArray.CreateBuilder<RestAttachment>(value.Length);
for (int i = 0; i < value.Length; i++)
attachments.Add(RestAttachment.Create(value[i]));
_attachments = attachments.ToImmutable();
}
else
_attachments = ImmutableArray.Create<RestAttachment>();
}
if (model.Embeds.IsSpecified)
{
var value = model.Embeds.Value;
if (value.Length > 0)
{
var embeds = ImmutableArray.CreateBuilder<RestEmbed>(value.Length);
for (int i = 0; i < value.Length; i++)
embeds.Add(RestEmbed.Create(value[i]));
_embeds = embeds.ToImmutable();
}
else
_embeds = ImmutableArray.Create<RestEmbed>();
}
ImmutableArray<RestUser> mentions = ImmutableArray.Create<RestUser>();
if (model.Mentions.IsSpecified)
{
var value = model.Mentions.Value;
if (value.Length > 0)
{
var newMentions = ImmutableArray.CreateBuilder<RestUser>(value.Length);
for (int i = 0; i < value.Length; i++)
newMentions.Add(RestUser.Create(Discord, value[i]));
mentions = newMentions.ToImmutable();
}
}
if (model.Content.IsSpecified)
{
var text = model.Content.Value;
_mentionedUsers = MentionsHelper.GetUserMentions(text, null, mentions);
_mentionedChannelIds = MentionsHelper.GetChannelMentions(text, null);
_mentionedRoles = MentionsHelper.GetRoleMentions<RestRole>(text, null);
model.Content = text;
}
}
public Task ModifyAsync(Action<ModifyMessageParams> func)
=> MessageHelper.ModifyAsync(this, Discord, func);
public Task DeleteAsync()
=> MessageHelper.DeleteAsync(this, Discord);
public Task PinAsync()
=> MessageHelper.PinAsync(this, Discord);
public Task UnpinAsync()
=> MessageHelper.UnpinAsync(this, Discord);
public string Resolve(UserMentionHandling userHandling = UserMentionHandling.Name, ChannelMentionHandling channelHandling = ChannelMentionHandling.Name,
RoleMentionHandling roleHandling = RoleMentionHandling.Name, EveryoneMentionHandling everyoneHandling = EveryoneMentionHandling.Ignore)
=> Resolve(Content, userHandling, channelHandling, roleHandling, everyoneHandling);
public string Resolve(int startIndex, int length, UserMentionHandling userHandling = UserMentionHandling.Name, ChannelMentionHandling channelHandling = ChannelMentionHandling.Name,
RoleMentionHandling roleHandling = RoleMentionHandling.Name, EveryoneMentionHandling everyoneHandling = EveryoneMentionHandling.Ignore)
=> Resolve(Content.Substring(startIndex, length), userHandling, channelHandling, roleHandling, everyoneHandling);
public string Resolve(string text, UserMentionHandling userHandling, ChannelMentionHandling channelHandling,
RoleMentionHandling roleHandling, EveryoneMentionHandling everyoneHandling)
{
text = MentionsHelper.ResolveUserMentions(text, null, MentionedUsers, userHandling);
text = MentionsHelper.ResolveChannelMentions(text, null, channelHandling);
text = MentionsHelper.ResolveRoleMentions(text, MentionedRoles, roleHandling);
text = MentionsHelper.ResolveEveryoneMentions(text, everyoneHandling);
return text;
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Threading.Tasks;
using Model = Discord.API.Application;
namespace Discord.Rest
{
public class RestApplication : RestEntity<ulong>, IApplication
{
protected string _iconId;
public string Name { get; private set; }
public string Description { get; private set; }
public string[] RPCOrigins { get; private set; }
public ulong Flags { get; private set; }
public IUser Owner { get; private set; }
public string IconUrl => API.CDN.GetApplicationIconUrl(Id, _iconId);
internal RestApplication(DiscordRestClient discord, ulong id)
: base(discord, id)
{
}
internal static RestApplication Create(DiscordRestClient discord, Model model)
{
var entity = new RestApplication(discord, model.Id);
entity.Update(model);
return entity;
}
internal void Update(Model model)
{
Description = model.Description;
RPCOrigins = model.RPCOrigins;
Name = model.Name;
Flags = model.Flags;
Owner = RestUser.Create(Discord, model.Owner);
_iconId = model.Icon;
}
public async Task UpdateAsync()
{
var response = await Discord.ApiClient.GetMyApplicationAsync().ConfigureAwait(false);
if (response.Id != Id)
throw new InvalidOperationException("Unable to update this object from a different application token.");
Update(response);
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
namespace Discord.Rest
{
public abstract class RestEntity<T> : IEntity<T>
where T : IEquatable<T>
{
public T Id { get; }
public DiscordRestClient Discord { get; }
public RestEntity(DiscordRestClient discord, T id)
{
Discord = discord;
Id = id;
}
IDiscordClient IEntity<T>.Discord => Discord;
}
}

View File

@@ -0,0 +1,52 @@
using Discord.API.Rest;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Model = Discord.API.Role;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestRole : RestEntity<ulong>, IRole
{
public RestGuild Guild { get; }
public Color Color { get; private set; }
public bool IsHoisted { get; private set; }
public bool IsManaged { get; private set; }
public string Name { get; private set; }
public GuildPermissions Permissions { get; private set; }
public int Position { get; private set; }
public bool IsEveryone => Id == Guild.Id;
public string Mention => MentionUtils.MentionRole(Id);
internal RestRole(DiscordRestClient discord, ulong id)
: base(discord, id)
{
}
internal static RestRole Create(DiscordRestClient discord, Model model)
{
var entity = new RestRole(discord, model.Id);
entity.Update(model);
return entity;
}
internal void Update(Model model)
{
Name = model.Name;
IsHoisted = model.Hoist;
IsManaged = model.Managed;
Position = model.Position;
Color = new Color(model.Color);
Permissions = new GuildPermissions(model.Permissions);
}
public Task ModifyAsync(Action<ModifyGuildRoleParams> func)
=> RoleHelper.ModifyAsync(this, Discord, func);
public Task DeleteAsync()
=> RoleHelper.DeleteAsync(this, Discord);
//IRole
IGuild IRole.Guild => Guild;
}
}

View File

@@ -0,0 +1,22 @@
using Discord.API.Rest;
using System;
using System.Threading.Tasks;
namespace Discord.Rest
{
internal static class RoleHelper
{
//General
public static async Task DeleteAsync(IRole role, DiscordRestClient client)
{
await client.ApiClient.DeleteGuildRoleAsync(role.Guild.Id, role.Id).ConfigureAwait(false);
}
public static async Task ModifyAsync(IRole role, DiscordRestClient client,
Action<ModifyGuildRoleParams> func)
{
var args = new ModifyGuildRoleParams();
func(args);
await client.ApiClient.ModifyGuildRoleAsync(role.Guild.Id, role.Id, args);
}
}
}

View File

@@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Model = Discord.API.Connection;
namespace Discord
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestConnection : IConnection
{
public string Id { get; }
public string Type { get; }
public string Name { get; }
public bool IsRevoked { get; }
public IReadOnlyCollection<ulong> IntegrationIds { get; }
internal RestConnection(string id, string type, string name, bool isRevoked, IReadOnlyCollection<ulong> integrationIds)
{
Id = id;
Type = type;
Name = name;
IsRevoked = isRevoked;
IntegrationIds = integrationIds;
}
internal static RestConnection Create(Model model)
{
return new RestConnection(model.Id, model.Type, model.Name, model.Revoked, model.Integrations.ToImmutableArray());
}
public override string ToString() => Name;
private string DebuggerDisplay => $"{Name} ({Id}, Type = {Type}{(IsRevoked ? ", Revoked" : "")})";
}
}

View File

@@ -0,0 +1,29 @@
using System.Diagnostics;
using Model = Discord.API.User;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestGroupUser : RestUser, IGroupUser
{
internal RestGroupUser(DiscordRestClient discord, ulong id)
: base(discord, id)
{
}
internal new static RestGroupUser Create(DiscordRestClient discord, Model model)
{
var entity = new RestGroupUser(discord, model.Id);
entity.Update(model);
return entity;
}
//IVoiceState
bool IVoiceState.IsDeafened => false;
bool IVoiceState.IsMuted => false;
bool IVoiceState.IsSelfDeafened => false;
bool IVoiceState.IsSelfMuted => false;
bool IVoiceState.IsSuppressed => false;
IVoiceChannel IVoiceState.VoiceChannel => null;
string IVoiceState.VoiceSessionId => null;
}
}

View File

@@ -0,0 +1,74 @@
using Discord.API.Rest;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Threading.Tasks;
using Model = Discord.API.GuildMember;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestGuildUser : RestUser, IGuildUser, IUpdateable
{
private long? _joinedAtTicks;
private ImmutableArray<ulong> _roleIds;
public string Nickname { get; private set; }
public ulong GuildId { get; private set; }
public IReadOnlyCollection<ulong> RoleIds => _roleIds;
public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks);
internal RestGuildUser(DiscordRestClient discord, ulong id)
: base(discord, id)
{
}
internal static RestGuildUser Create(DiscordRestClient discord, Model model)
{
var entity = new RestGuildUser(discord, model.User.Id);
entity.Update(model);
return entity;
}
internal void Update(Model model)
{
_joinedAtTicks = model.JoinedAt.UtcTicks;
if (model.Nick.IsSpecified)
Nickname = model.Nick.Value;
UpdateRoles(model.Roles);
}
private void UpdateRoles(ulong[] roleIds)
{
var roles = ImmutableArray.CreateBuilder<ulong>(roleIds.Length + 1);
roles.Add(GuildId);
for (int i = 0; i < roleIds.Length; i++)
roles.Add(roleIds[i]);
_roleIds = roles.ToImmutable();
}
public override async Task UpdateAsync()
=> Update(await UserHelper.GetAsync(this, Discord));
public Task ModifyAsync(Action<ModifyGuildMemberParams> func)
=> UserHelper.ModifyAsync(this, Discord, func);
public Task KickAsync()
=> UserHelper.KickAsync(this, Discord);
public ChannelPermissions GetPermissions(IGuildChannel channel)
{
throw new NotImplementedException(); //TODO: Impl
}
//IGuildUser
IReadOnlyCollection<ulong> IGuildUser.RoleIds => RoleIds;
//IVoiceState
bool IVoiceState.IsDeafened => false;
bool IVoiceState.IsMuted => false;
bool IVoiceState.IsSelfDeafened => false;
bool IVoiceState.IsSelfMuted => false;
bool IVoiceState.IsSuppressed => false;
IVoiceChannel IVoiceState.VoiceChannel => null;
string IVoiceState.VoiceSessionId => null;
}
}

View File

@@ -0,0 +1,45 @@
using Discord.API.Rest;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Model = Discord.API.User;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestSelfUser : RestUser, ISelfUser
{
public string Email { get; private set; }
public bool IsVerified { get; private set; }
public bool IsMfaEnabled { get; private set; }
internal RestSelfUser(DiscordRestClient discord, ulong id)
: base(discord, id)
{
}
internal new static RestSelfUser Create(DiscordRestClient discord, Model model)
{
var entity = new RestSelfUser(discord, model.Id);
entity.Update(model);
return entity;
}
internal override void Update(Model model)
{
base.Update(model);
if (model.Email.IsSpecified)
Email = model.Email.Value;
if (model.Verified.IsSpecified)
IsVerified = model.Verified.Value;
if (model.MfaEnabled.IsSpecified)
IsMfaEnabled = model.MfaEnabled.Value;
}
public override async Task UpdateAsync()
=> Update(await UserHelper.GetAsync(this, Discord));
public Task ModifyAsync(Action<ModifyCurrentUserParams> func)
=> UserHelper.ModifyAsync(this, Discord, func);
Task ISelfUser.ModifyStatusAsync(Action<ModifyPresenceParams> func) { throw new NotSupportedException(); }
}
}

View File

@@ -0,0 +1,51 @@
using System.Diagnostics;
using System.Threading.Tasks;
using Model = Discord.API.User;
namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestUser : RestEntity<ulong>, IUser, IUpdateable
{
public bool IsBot { get; private set; }
public string Username { get; private set; }
public ushort DiscriminatorValue { get; private set; }
public string AvatarId { get; private set; }
public string AvatarUrl => API.CDN.GetUserAvatarUrl(Id, AvatarId);
public string Discriminator => DiscriminatorValue.ToString("D4");
public string Mention => MentionUtils.MentionUser(Id);
public virtual Game? Game => null;
public virtual UserStatus Status => UserStatus.Unknown;
internal RestUser(DiscordRestClient discord, ulong id)
: base(discord, id)
{
}
internal static RestUser Create(DiscordRestClient discord, Model model)
{
var entity = new RestUser(discord, model.Id);
entity.Update(model);
return entity;
}
internal virtual void Update(Model model)
{
if (model.Avatar.IsSpecified)
AvatarId = model.Avatar.Value;
if (model.Discriminator.IsSpecified)
DiscriminatorValue = ushort.Parse(model.Discriminator.Value);
if (model.Bot.IsSpecified)
IsBot = model.Bot.Value;
if (model.Username.IsSpecified)
Username = model.Username.Value;
}
public virtual async Task UpdateAsync()
=> Update(await UserHelper.GetAsync(this, Discord));
public Task<IDMChannel> CreateDMChannelAsync()
=> UserHelper.CreateDMChannelAsync(this, Discord);
IDMChannel IUser.GetCachedDMChannel() => null;
}
}

View File

@@ -0,0 +1,53 @@
using Discord.API.Rest;
using System.Threading.Tasks;
using Model = Discord.API.User;
using MemberModel = Discord.API.GuildMember;
using System;
namespace Discord.Rest
{
internal static class UserHelper
{
public static async Task<Model> GetAsync(IUser user, DiscordRestClient client)
{
return await client.ApiClient.GetUserAsync(user.Id);
}
public static async Task<Model> GetAsync(ISelfUser user, DiscordRestClient client)
{
var model = await client.ApiClient.GetMyUserAsync();
if (model.Id != user.Id)
throw new InvalidOperationException("Unable to update this object using a different token.");
return model;
}
public static async Task<MemberModel> GetAsync(IGuildUser user, DiscordRestClient client)
{
return await client.ApiClient.GetGuildMemberAsync(user.GuildId, user.Id);
}
public static async Task ModifyAsync(ISelfUser user, DiscordRestClient client, Action<ModifyCurrentUserParams> func)
{
if (user.Id != client.CurrentUser.Id)
throw new InvalidOperationException("Unable to modify this object using a different token.");
var args = new ModifyCurrentUserParams();
func(args);
await client.ApiClient.ModifySelfAsync(args);
}
public static async Task ModifyAsync(IGuildUser user, DiscordRestClient client, Action<ModifyGuildMemberParams> func)
{
var args = new ModifyGuildMemberParams();
func(args);
await client.ApiClient.ModifyGuildMemberAsync(user.GuildId, user.Id, args);
}
public static async Task KickAsync(IGuildUser user, DiscordRestClient client)
{
await client.ApiClient.RemoveGuildMemberAsync(user.GuildId, user.Id);
}
public static async Task<IDMChannel> CreateDMChannelAsync(IUser user, DiscordRestClient client)
{
var args = new CreateDMChannelParams(user.Id);
return RestDMChannel.Create(client, await client.ApiClient.CreateDMChannelAsync(args));
}
}
}

View File

@@ -0,0 +1,19 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Discord.Net.Rest")]
[assembly: AssemblyTrademark("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("bfc6dc28-0351-4573-926a-d4124244c04f")]

View File

@@ -0,0 +1,39 @@
{
"version": "1.0.0-*",
"buildOptions": {
"compile": {
"include": [ "../Discord.Net.Utils/**.cs" ]
},
"define": [ "REST" ]
},
"configurations": {
"Release": {
"buildOptions": {
"define": [ "RELEASE" ],
"nowarn": [ "CS1573", "CS1591" ],
"optimize": true,
"warningsAsErrors": true,
"xmlDoc": true
}
}
},
"dependencies": {
"Discord.Net.Core": {
"target": "project"
},
"NETStandard.Library": "1.6.0"
},
"frameworks": {
"netstandard1.3": {
"imports": [
"dotnet5.4",
"dnxcore50",
"portable-net45+win8"
]
}
}
}