| @@ -25,10 +25,15 @@ namespace Discord.API | |||||
| private readonly IRestClient _restClient; | private readonly IRestClient _restClient; | ||||
| private readonly CancellationToken _cancelToken; | private readonly CancellationToken _cancelToken; | ||||
| private readonly JsonSerializer _serializer; | private readonly JsonSerializer _serializer; | ||||
| public TokenType AuthTokenType { get; private set; } | |||||
| public IRestClient RestClient { get; private set; } | |||||
| public IRequestQueue RequestQueue { get; private set; } | |||||
| internal DiscordRawClient(RestClientProvider restClientProvider, CancellationToken cancelToken, TokenType authTokenType, string authToken) | internal DiscordRawClient(RestClientProvider restClientProvider, CancellationToken cancelToken, TokenType authTokenType, string authToken) | ||||
| { | { | ||||
| _cancelToken = cancelToken; | _cancelToken = cancelToken; | ||||
| AuthTokenType = authTokenType; | |||||
| switch (authTokenType) | switch (authTokenType) | ||||
| { | { | ||||
| @@ -11,8 +11,6 @@ namespace Discord | |||||
| int AFKTimeout { get; } | int AFKTimeout { get; } | ||||
| /// <summary> Returns true if this guild is embeddable (e.g. widget) </summary> | /// <summary> Returns true if this guild is embeddable (e.g. widget) </summary> | ||||
| bool IsEmbeddable { get; } | bool IsEmbeddable { get; } | ||||
| /// <summary> Returns true if the current user owns this guild. </summary> | |||||
| bool IsOwner { get; } | |||||
| /// <summary> Gets the name of this guild. </summary> | /// <summary> Gets the name of this guild. </summary> | ||||
| string Name { get; } | string Name { get; } | ||||
| int VerificationLevel { get; } | int VerificationLevel { get; } | ||||
| @@ -9,8 +9,6 @@ namespace Discord | |||||
| { | { | ||||
| /// <summary> Gets the time of this message's last edit, if any. </summary> | /// <summary> Gets the time of this message's last edit, if any. </summary> | ||||
| DateTime? EditedTimestamp { get; } | DateTime? EditedTimestamp { get; } | ||||
| /// <summary> Returns true if this message originated from the logged-in account. </summary> | |||||
| bool IsAuthor { get; } | |||||
| /// <summary> Returns true if this message was sent as a text-to-speech message. </summary> | /// <summary> Returns true if this message was sent as a text-to-speech message. </summary> | ||||
| bool IsTTS { get; } | bool IsTTS { get; } | ||||
| /// <summary> Returns the original, unprocessed text for this message. </summary> | /// <summary> Returns the original, unprocessed text for this message. </summary> | ||||
| @@ -12,8 +12,6 @@ namespace Discord | |||||
| ushort Discriminator { get; } | ushort Discriminator { get; } | ||||
| /// <summary> Returns true if this user is a bot account. </summary> | /// <summary> Returns true if this user is a bot account. </summary> | ||||
| bool IsBot { get; } | bool IsBot { get; } | ||||
| /// <summary> Returns true is this user is the current logged-in account. </summary> | |||||
| bool IsCurrentUser { get; } | |||||
| /// <summary> Gets the current status of this user. </summary> | /// <summary> Gets the current status of this user. </summary> | ||||
| UserStatus Status { get; } | UserStatus Status { get; } | ||||
| /// <summary> Gets the username for this user. </summary> | /// <summary> Gets the username for this user. </summary> | ||||
| @@ -1,15 +1,18 @@ | |||||
| using Discord.API; | using Discord.API; | ||||
| using Discord.Net.Rest; | |||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.IO; | using System.IO; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| //TODO: Add docstrings | |||||
| public interface IDiscordClient | public interface IDiscordClient | ||||
| { | { | ||||
| ISelfUser CurrentUser { get; } | |||||
| TokenType AuthTokenType { get; } | |||||
| DiscordRawClient BaseClient { get; } | DiscordRawClient BaseClient { get; } | ||||
| //IMessageQueue MessageQueue { get; } | |||||
| IRestClient RestClient { get; } | |||||
| IRequestQueue RequestQueue { get; } | |||||
| Task Login(TokenType tokenType, string token); | Task Login(TokenType tokenType, string token); | ||||
| Task Logout(); | Task Logout(); | ||||
| @@ -4,6 +4,7 @@ using System.Threading.Tasks; | |||||
| namespace Discord.Net.Rest | namespace Discord.Net.Rest | ||||
| { | { | ||||
| //TODO: Add docstrings | |||||
| public interface IRestClient | public interface IRestClient | ||||
| { | { | ||||
| void SetHeader(string key, string value); | void SetHeader(string key, string value); | ||||
| @@ -2,6 +2,7 @@ using System.Threading.Tasks; | |||||
| namespace Discord.Net.Rest | namespace Discord.Net.Rest | ||||
| { | { | ||||
| //TODO: Add docstrings | |||||
| public interface IRequestQueue | public interface IRequestQueue | ||||
| { | { | ||||
| Task Clear(GlobalBucket type); | Task Clear(GlobalBucket type); | ||||
| @@ -1,11 +1,13 @@ | |||||
| using Discord.API.Rest; | using Discord.API.Rest; | ||||
| using Discord.Logging; | using Discord.Logging; | ||||
| using Discord.Net; | |||||
| using Discord.Net.Rest; | using Discord.Net.Rest; | ||||
| using Newtonsoft.Json.Linq; | using Newtonsoft.Json.Linq; | ||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.IO; | using System.IO; | ||||
| using System.Linq; | using System.Linq; | ||||
| using System.Net; | |||||
| using System.Threading; | using System.Threading; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| @@ -22,10 +24,14 @@ namespace Discord.Rest | |||||
| private CancellationTokenSource _cancelTokenSource; | private CancellationTokenSource _cancelTokenSource; | ||||
| private bool _isDisposed; | private bool _isDisposed; | ||||
| private string _userAgent; | private string _userAgent; | ||||
| private SelfUser _currentUser; | |||||
| public bool IsLoggedIn { get; private set; } | public bool IsLoggedIn { get; private set; } | ||||
| internal API.DiscordRawClient BaseClient { get; private set; } | |||||
| internal SelfUser CurrentUser { get; private set; } | |||||
| public API.DiscordRawClient BaseClient { get; private set; } | |||||
| public TokenType AuthTokenType => BaseClient.AuthTokenType; | |||||
| public IRestClient RestClient => BaseClient.RestClient; | |||||
| public IRequestQueue RequestQueue => BaseClient.RequestQueue; | |||||
| public DiscordClient(DiscordConfig config = null) | public DiscordClient(DiscordConfig config = null) | ||||
| { | { | ||||
| @@ -64,9 +70,13 @@ namespace Discord.Rest | |||||
| //MessageQueue = new MessageQueue(RestClient, _restLogger); | //MessageQueue = new MessageQueue(RestClient, _restLogger); | ||||
| //await MessageQueue.Start(_cancelTokenSource.Token).ConfigureAwait(false); | //await MessageQueue.Start(_cancelTokenSource.Token).ConfigureAwait(false); | ||||
| var currentUser = await BaseClient.GetCurrentUser().ConfigureAwait(false); | |||||
| CurrentUser = new SelfUser(this, currentUser); | |||||
| try | |||||
| { | |||||
| var currentUser = await BaseClient.GetCurrentUser().ConfigureAwait(false); | |||||
| _currentUser = new SelfUser(this, currentUser); | |||||
| } | |||||
| catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.Unauthorized && tokenType == TokenType.Bearer) { } //Ignore 401 if Bearer doesnt have identity | |||||
| _cancelTokenSource = cancelTokenSource; | _cancelTokenSource = cancelTokenSource; | ||||
| IsLoggedIn = true; | IsLoggedIn = true; | ||||
| @@ -173,25 +183,25 @@ namespace Discord.Rest | |||||
| return new PublicUser(this, model); | return new PublicUser(this, model); | ||||
| return null; | return null; | ||||
| } | } | ||||
| public async Task<IUser> GetUser(string username, ushort discriminator) | |||||
| public async Task<User> GetUser(string username, ushort discriminator) | |||||
| { | { | ||||
| var model = await BaseClient.GetUser(username, discriminator).ConfigureAwait(false); | var model = await BaseClient.GetUser(username, discriminator).ConfigureAwait(false); | ||||
| if (model != null) | if (model != null) | ||||
| return new PublicUser(this, model); | return new PublicUser(this, model); | ||||
| return null; | return null; | ||||
| } | } | ||||
| public async Task<ISelfUser> GetCurrentUser() | |||||
| public async Task<SelfUser> GetCurrentUser() | |||||
| { | { | ||||
| var currentUser = CurrentUser; | |||||
| if (currentUser == null) | |||||
| var user = _currentUser; | |||||
| if (user == null) | |||||
| { | { | ||||
| var model = await BaseClient.GetCurrentUser().ConfigureAwait(false); | var model = await BaseClient.GetCurrentUser().ConfigureAwait(false); | ||||
| currentUser = new SelfUser(this, model); | |||||
| CurrentUser = currentUser; | |||||
| user = new SelfUser(this, model); | |||||
| _currentUser = user; | |||||
| } | } | ||||
| return currentUser; | |||||
| return user; | |||||
| } | } | ||||
| public async Task<IEnumerable<IUser>> QueryUsers(string query, int limit) | |||||
| public async Task<IEnumerable<User>> QueryUsers(string query, int limit) | |||||
| { | { | ||||
| var models = await BaseClient.QueryUsers(query, limit).ConfigureAwait(false); | var models = await BaseClient.QueryUsers(query, limit).ConfigureAwait(false); | ||||
| return models.Select(x => new PublicUser(this, x)); | return models.Select(x => new PublicUser(this, x)); | ||||
| @@ -225,7 +235,6 @@ namespace Discord.Rest | |||||
| public void Dispose() => Dispose(true); | public void Dispose() => Dispose(true); | ||||
| API.DiscordRawClient IDiscordClient.BaseClient => BaseClient; | API.DiscordRawClient IDiscordClient.BaseClient => BaseClient; | ||||
| ISelfUser IDiscordClient.CurrentUser => CurrentUser; | |||||
| async Task<IChannel> IDiscordClient.GetChannel(ulong id) | async Task<IChannel> IDiscordClient.GetChannel(ulong id) | ||||
| => await GetChannel(id).ConfigureAwait(false); | => await GetChannel(id).ConfigureAwait(false); | ||||
| @@ -243,6 +252,10 @@ namespace Discord.Rest | |||||
| => await CreateGuild(name, region, jpegIcon).ConfigureAwait(false); | => await CreateGuild(name, region, jpegIcon).ConfigureAwait(false); | ||||
| async Task<IUser> IDiscordClient.GetUser(ulong id) | async Task<IUser> IDiscordClient.GetUser(ulong id) | ||||
| => await GetUser(id).ConfigureAwait(false); | => await GetUser(id).ConfigureAwait(false); | ||||
| async Task<IUser> IDiscordClient.GetUser(string username, ushort discriminator) | |||||
| => await GetUser(username, discriminator).ConfigureAwait(false); | |||||
| async Task<ISelfUser> IDiscordClient.GetCurrentUser() | |||||
| => await GetCurrentUser().ConfigureAwait(false); | |||||
| async Task<IEnumerable<IUser>> IDiscordClient.QueryUsers(string query, int limit) | async Task<IEnumerable<IUser>> IDiscordClient.QueryUsers(string query, int limit) | ||||
| => await QueryUsers(query, limit).ConfigureAwait(false); | => await QueryUsers(query, limit).ConfigureAwait(false); | ||||
| async Task<IEnumerable<IVoiceRegion>> IDiscordClient.GetVoiceRegions() | async Task<IEnumerable<IVoiceRegion>> IDiscordClient.GetVoiceRegions() | ||||
| @@ -20,8 +20,6 @@ namespace Discord.Rest | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public DateTime CreatedAt => DateTimeHelper.FromSnowflake(Id); | public DateTime CreatedAt => DateTimeHelper.FromSnowflake(Id); | ||||
| /// <inheritdoc /> | |||||
| public IEnumerable<IUser> Users => ImmutableArray.Create<IUser>(Discord.CurrentUser, Recipient); | |||||
| internal DMChannel(DiscordClient discord, Model model) | internal DMChannel(DiscordClient discord, Model model) | ||||
| { | { | ||||
| @@ -39,20 +37,23 @@ namespace Discord.Rest | |||||
| } | } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public IUser GetUser(ulong id) | |||||
| public async Task<IUser> GetUser(ulong id) | |||||
| { | { | ||||
| var currentUser = await Discord.GetCurrentUser().ConfigureAwait(false); | |||||
| if (id == Recipient.Id) | if (id == Recipient.Id) | ||||
| return Recipient; | return Recipient; | ||||
| else if (id == Discord.CurrentUser.Id) | |||||
| return Discord.CurrentUser; | |||||
| else if (id == currentUser.Id) | |||||
| return currentUser; | |||||
| else | else | ||||
| return null; | return null; | ||||
| } | } | ||||
| public IEnumerable<IUser> GetUsers() | |||||
| /// <inheritdoc /> | |||||
| public async Task<IEnumerable<IUser>> GetUsers() | |||||
| { | { | ||||
| return ImmutableArray.Create<IUser>(Discord.CurrentUser, Recipient); | |||||
| var currentUser = await Discord.GetCurrentUser().ConfigureAwait(false); | |||||
| return ImmutableArray.Create<IUser>(currentUser, Recipient); | |||||
| } | } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public async Task<IEnumerable<Message>> GetMessages(int limit = DiscordConfig.MaxMessagesPerBatch) | public async Task<IEnumerable<Message>> GetMessages(int limit = DiscordConfig.MaxMessagesPerBatch) | ||||
| { | { | ||||
| @@ -124,10 +125,10 @@ namespace Discord.Rest | |||||
| IDMUser IDMChannel.Recipient => Recipient; | IDMUser IDMChannel.Recipient => Recipient; | ||||
| Task<IEnumerable<IUser>> IChannel.GetUsers() | |||||
| => Task.FromResult(GetUsers()); | |||||
| Task<IUser> IChannel.GetUser(ulong id) | |||||
| => Task.FromResult(GetUser(id)); | |||||
| async Task<IEnumerable<IUser>> IChannel.GetUsers() | |||||
| => await GetUsers().ConfigureAwait(false); | |||||
| async Task<IUser> IChannel.GetUser(ulong id) | |||||
| => await GetUser(id).ConfigureAwait(false); | |||||
| Task<IMessage> IMessageChannel.GetMessage(ulong id) | Task<IMessage> IMessageChannel.GetMessage(ulong id) | ||||
| => throw new NotSupportedException(); | => throw new NotSupportedException(); | ||||
| async Task<IEnumerable<IMessage>> IMessageChannel.GetMessages(int limit) | async Task<IEnumerable<IMessage>> IMessageChannel.GetMessages(int limit) | ||||
| @@ -46,8 +46,6 @@ namespace Discord.Rest | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public DateTime CreatedAt => DateTimeHelper.FromSnowflake(Id); | public DateTime CreatedAt => DateTimeHelper.FromSnowflake(Id); | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public bool IsOwner => OwnerId == Discord.CurrentUser.Id; | |||||
| /// <inheritdoc /> | |||||
| public string IconUrl => API.CDN.GetGuildIconUrl(Id, _iconId); | public string IconUrl => API.CDN.GetGuildIconUrl(Id, _iconId); | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public string SplashUrl => API.CDN.GetGuildSplashUrl(Id, _splashId); | public string SplashUrl => API.CDN.GetGuildSplashUrl(Id, _splashId); | ||||
| @@ -157,15 +155,11 @@ namespace Discord.Rest | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public async Task Leave() | public async Task Leave() | ||||
| { | { | ||||
| if (IsOwner) | |||||
| throw new InvalidOperationException("Unable to leave a guild the current user owns."); | |||||
| await Discord.BaseClient.LeaveGuild(Id).ConfigureAwait(false); | await Discord.BaseClient.LeaveGuild(Id).ConfigureAwait(false); | ||||
| } | } | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public async Task Delete() | public async Task Delete() | ||||
| { | { | ||||
| if (!IsOwner) | |||||
| throw new InvalidOperationException("Unable to delete a guild the current user does not own."); | |||||
| await Discord.BaseClient.DeleteGuild(Id).ConfigureAwait(false); | await Discord.BaseClient.DeleteGuild(Id).ConfigureAwait(false); | ||||
| } | } | ||||
| @@ -317,7 +311,8 @@ namespace Discord.Rest | |||||
| /// <summary> Gets a the current user. </summary> | /// <summary> Gets a the current user. </summary> | ||||
| public async Task<GuildUser> GetCurrentUser() | public async Task<GuildUser> GetCurrentUser() | ||||
| { | { | ||||
| return await GetUser(Discord.CurrentUser.Id).ConfigureAwait(false); | |||||
| var currentUser = await Discord.GetCurrentUser().ConfigureAwait(false); | |||||
| return await GetUser(currentUser.Id).ConfigureAwait(false); | |||||
| } | } | ||||
| public async Task<int> PruneUsers(int days = 30, bool simulate = false) | public async Task<int> PruneUsers(int days = 30, bool simulate = false) | ||||
| { | { | ||||
| @@ -41,8 +41,6 @@ namespace Discord.Rest | |||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public DateTime CreatedAt => DateTimeHelper.FromSnowflake(Id); | public DateTime CreatedAt => DateTimeHelper.FromSnowflake(Id); | ||||
| /// <inheritdoc /> | |||||
| public bool IsAuthor => Discord.CurrentUser.Id == Author.Id; | |||||
| internal DiscordClient Discord => (Channel as TextChannel)?.Discord ?? (Channel as DMChannel).Discord; | internal DiscordClient Discord => (Channel as TextChannel)?.Discord ?? (Channel as DMChannel).Discord; | ||||
| internal Message(IMessageChannel channel, Model model) | internal Message(IMessageChannel channel, Model model) | ||||
| @@ -84,7 +84,7 @@ namespace Discord.Rest | |||||
| var args = new ModifyGuildMemberParams(); | var args = new ModifyGuildMemberParams(); | ||||
| func(args); | func(args); | ||||
| bool isCurrentUser = IsCurrentUser; | |||||
| bool isCurrentUser = (await Discord.GetCurrentUser().ConfigureAwait(false)).Id == Id; | |||||
| if (isCurrentUser && args.Nickname.IsSpecified) | if (isCurrentUser && args.Nickname.IsSpecified) | ||||
| { | { | ||||
| var nickArgs = new ModifyCurrentUserNickParams | var nickArgs = new ModifyCurrentUserNickParams | ||||
| @@ -92,6 +92,7 @@ namespace Discord.Rest | |||||
| Nickname = args.Nickname.Value | Nickname = args.Nickname.Value | ||||
| }; | }; | ||||
| await Discord.BaseClient.ModifyCurrentUserNick(Guild.Id, nickArgs).ConfigureAwait(false); | await Discord.BaseClient.ModifyCurrentUserNick(Guild.Id, nickArgs).ConfigureAwait(false); | ||||
| args.Nickname = new API.Optional<string>(); //Remove | |||||
| } | } | ||||
| if (!isCurrentUser || args.Deaf.IsSpecified || args.Mute.IsSpecified || args.Roles.IsSpecified) | if (!isCurrentUser || args.Deaf.IsSpecified || args.Mute.IsSpecified || args.Roles.IsSpecified) | ||||
| @@ -28,8 +28,6 @@ namespace Discord.Rest | |||||
| public string Mention => MentionHelper.Mention(this, false); | public string Mention => MentionHelper.Mention(this, false); | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| public string NicknameMention => MentionHelper.Mention(this, true); | public string NicknameMention => MentionHelper.Mention(this, true); | ||||
| /// <inheritdoc /> | |||||
| public bool IsCurrentUser => Id == Discord.CurrentUser.Id; | |||||
| internal User(Model model) | internal User(Model model) | ||||
| { | { | ||||