| @@ -25,10 +25,15 @@ namespace Discord.API | |||
| private readonly IRestClient _restClient; | |||
| private readonly CancellationToken _cancelToken; | |||
| 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) | |||
| { | |||
| _cancelToken = cancelToken; | |||
| AuthTokenType = authTokenType; | |||
| switch (authTokenType) | |||
| { | |||
| @@ -11,8 +11,6 @@ namespace Discord | |||
| int AFKTimeout { get; } | |||
| /// <summary> Returns true if this guild is embeddable (e.g. widget) </summary> | |||
| 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> | |||
| string Name { get; } | |||
| int VerificationLevel { get; } | |||
| @@ -9,8 +9,6 @@ namespace Discord | |||
| { | |||
| /// <summary> Gets the time of this message's last edit, if any. </summary> | |||
| 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> | |||
| bool IsTTS { get; } | |||
| /// <summary> Returns the original, unprocessed text for this message. </summary> | |||
| @@ -12,8 +12,6 @@ namespace Discord | |||
| ushort Discriminator { get; } | |||
| /// <summary> Returns true if this user is a bot account. </summary> | |||
| 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> | |||
| UserStatus Status { get; } | |||
| /// <summary> Gets the username for this user. </summary> | |||
| @@ -1,15 +1,18 @@ | |||
| using Discord.API; | |||
| using Discord.Net.Rest; | |||
| using System.Collections.Generic; | |||
| using System.IO; | |||
| using System.Threading.Tasks; | |||
| namespace Discord | |||
| { | |||
| //TODO: Add docstrings | |||
| public interface IDiscordClient | |||
| { | |||
| ISelfUser CurrentUser { get; } | |||
| TokenType AuthTokenType { get; } | |||
| DiscordRawClient BaseClient { get; } | |||
| //IMessageQueue MessageQueue { get; } | |||
| IRestClient RestClient { get; } | |||
| IRequestQueue RequestQueue { get; } | |||
| Task Login(TokenType tokenType, string token); | |||
| Task Logout(); | |||
| @@ -4,6 +4,7 @@ using System.Threading.Tasks; | |||
| namespace Discord.Net.Rest | |||
| { | |||
| //TODO: Add docstrings | |||
| public interface IRestClient | |||
| { | |||
| void SetHeader(string key, string value); | |||
| @@ -2,6 +2,7 @@ using System.Threading.Tasks; | |||
| namespace Discord.Net.Rest | |||
| { | |||
| //TODO: Add docstrings | |||
| public interface IRequestQueue | |||
| { | |||
| Task Clear(GlobalBucket type); | |||
| @@ -1,11 +1,13 @@ | |||
| using Discord.API.Rest; | |||
| using Discord.Logging; | |||
| using Discord.Net; | |||
| using Discord.Net.Rest; | |||
| using Newtonsoft.Json.Linq; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.IO; | |||
| using System.Linq; | |||
| using System.Net; | |||
| using System.Threading; | |||
| using System.Threading.Tasks; | |||
| @@ -22,10 +24,14 @@ namespace Discord.Rest | |||
| private CancellationTokenSource _cancelTokenSource; | |||
| private bool _isDisposed; | |||
| private string _userAgent; | |||
| private SelfUser _currentUser; | |||
| 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) | |||
| { | |||
| @@ -64,9 +70,13 @@ namespace Discord.Rest | |||
| //MessageQueue = new MessageQueue(RestClient, _restLogger); | |||
| //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; | |||
| IsLoggedIn = true; | |||
| @@ -173,25 +183,25 @@ namespace Discord.Rest | |||
| return new PublicUser(this, model); | |||
| 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); | |||
| if (model != null) | |||
| return new PublicUser(this, model); | |||
| 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); | |||
| 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); | |||
| return models.Select(x => new PublicUser(this, x)); | |||
| @@ -225,7 +235,6 @@ namespace Discord.Rest | |||
| public void Dispose() => Dispose(true); | |||
| API.DiscordRawClient IDiscordClient.BaseClient => BaseClient; | |||
| ISelfUser IDiscordClient.CurrentUser => CurrentUser; | |||
| async Task<IChannel> IDiscordClient.GetChannel(ulong id) | |||
| => await GetChannel(id).ConfigureAwait(false); | |||
| @@ -243,6 +252,10 @@ namespace Discord.Rest | |||
| => await CreateGuild(name, region, jpegIcon).ConfigureAwait(false); | |||
| async Task<IUser> IDiscordClient.GetUser(ulong id) | |||
| => 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) | |||
| => await QueryUsers(query, limit).ConfigureAwait(false); | |||
| async Task<IEnumerable<IVoiceRegion>> IDiscordClient.GetVoiceRegions() | |||
| @@ -20,8 +20,6 @@ namespace Discord.Rest | |||
| /// <inheritdoc /> | |||
| public DateTime CreatedAt => DateTimeHelper.FromSnowflake(Id); | |||
| /// <inheritdoc /> | |||
| public IEnumerable<IUser> Users => ImmutableArray.Create<IUser>(Discord.CurrentUser, Recipient); | |||
| internal DMChannel(DiscordClient discord, Model model) | |||
| { | |||
| @@ -39,20 +37,23 @@ namespace Discord.Rest | |||
| } | |||
| /// <inheritdoc /> | |||
| public IUser GetUser(ulong id) | |||
| public async Task<IUser> GetUser(ulong id) | |||
| { | |||
| var currentUser = await Discord.GetCurrentUser().ConfigureAwait(false); | |||
| if (id == Recipient.Id) | |||
| return Recipient; | |||
| else if (id == Discord.CurrentUser.Id) | |||
| return Discord.CurrentUser; | |||
| else if (id == currentUser.Id) | |||
| return currentUser; | |||
| else | |||
| 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 /> | |||
| public async Task<IEnumerable<Message>> GetMessages(int limit = DiscordConfig.MaxMessagesPerBatch) | |||
| { | |||
| @@ -124,10 +125,10 @@ namespace Discord.Rest | |||
| 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) | |||
| => throw new NotSupportedException(); | |||
| async Task<IEnumerable<IMessage>> IMessageChannel.GetMessages(int limit) | |||
| @@ -46,8 +46,6 @@ namespace Discord.Rest | |||
| /// <inheritdoc /> | |||
| public DateTime CreatedAt => DateTimeHelper.FromSnowflake(Id); | |||
| /// <inheritdoc /> | |||
| public bool IsOwner => OwnerId == Discord.CurrentUser.Id; | |||
| /// <inheritdoc /> | |||
| public string IconUrl => API.CDN.GetGuildIconUrl(Id, _iconId); | |||
| /// <inheritdoc /> | |||
| public string SplashUrl => API.CDN.GetGuildSplashUrl(Id, _splashId); | |||
| @@ -157,15 +155,11 @@ namespace Discord.Rest | |||
| /// <inheritdoc /> | |||
| 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); | |||
| } | |||
| /// <inheritdoc /> | |||
| 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); | |||
| } | |||
| @@ -317,7 +311,8 @@ namespace Discord.Rest | |||
| /// <summary> Gets a the current user. </summary> | |||
| 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) | |||
| { | |||
| @@ -41,8 +41,6 @@ namespace Discord.Rest | |||
| /// <inheritdoc /> | |||
| 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 Message(IMessageChannel channel, Model model) | |||
| @@ -84,7 +84,7 @@ namespace Discord.Rest | |||
| var args = new ModifyGuildMemberParams(); | |||
| func(args); | |||
| bool isCurrentUser = IsCurrentUser; | |||
| bool isCurrentUser = (await Discord.GetCurrentUser().ConfigureAwait(false)).Id == Id; | |||
| if (isCurrentUser && args.Nickname.IsSpecified) | |||
| { | |||
| var nickArgs = new ModifyCurrentUserNickParams | |||
| @@ -92,6 +92,7 @@ namespace Discord.Rest | |||
| Nickname = args.Nickname.Value | |||
| }; | |||
| 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) | |||
| @@ -28,8 +28,6 @@ namespace Discord.Rest | |||
| public string Mention => MentionHelper.Mention(this, false); | |||
| /// <inheritdoc /> | |||
| public string NicknameMention => MentionHelper.Mention(this, true); | |||
| /// <inheritdoc /> | |||
| public bool IsCurrentUser => Id == Discord.CurrentUser.Id; | |||
| internal User(Model model) | |||
| { | |||