diff --git a/src/Discord.Net/API/DiscordRestApiClient.cs b/src/Discord.Net/API/DiscordRestApiClient.cs index cd64df50a..0d0b22c25 100644 --- a/src/Discord.Net/API/DiscordRestApiClient.cs +++ b/src/Discord.Net/API/DiscordRestApiClient.cs @@ -152,30 +152,30 @@ namespace Discord.API //REST public Task SendAsync(string method, string endpoint, - GlobalBucket bucket = GlobalBucket.GeneralRest, RequestOptions options = null) - => SendInternalAsync(method, endpoint, null, true, BucketGroup.Global, (int)bucket, 0, options); + GlobalBucket bucket = GlobalBucket.GeneralRest, bool ignoreState = false, RequestOptions options = null) + => SendInternalAsync(method, endpoint, null, true, BucketGroup.Global, (int)bucket, 0, ignoreState, options); public Task SendAsync(string method, string endpoint, object payload, - GlobalBucket bucket = GlobalBucket.GeneralRest, RequestOptions options = null) - => SendInternalAsync(method, endpoint, payload, true, BucketGroup.Global, (int)bucket, 0, options); + GlobalBucket bucket = GlobalBucket.GeneralRest, bool ignoreState = false, RequestOptions options = null) + => SendInternalAsync(method, endpoint, payload, true, BucketGroup.Global, (int)bucket, 0, ignoreState, options); public async Task SendAsync(string method, string endpoint, - GlobalBucket bucket = GlobalBucket.GeneralRest, RequestOptions options = null) where TResponse : class - => DeserializeJson(await SendInternalAsync(method, endpoint, null, false, BucketGroup.Global, (int)bucket, 0, options).ConfigureAwait(false)); + GlobalBucket bucket = GlobalBucket.GeneralRest, bool ignoreState = false, RequestOptions options = null) where TResponse : class + => DeserializeJson(await SendInternalAsync(method, endpoint, null, false, BucketGroup.Global, (int)bucket, 0, ignoreState, options).ConfigureAwait(false)); public async Task SendAsync(string method, string endpoint, object payload, GlobalBucket bucket = - GlobalBucket.GeneralRest, RequestOptions options = null) where TResponse : class - => DeserializeJson(await SendInternalAsync(method, endpoint, payload, false, BucketGroup.Global, (int)bucket, 0, options).ConfigureAwait(false)); + GlobalBucket.GeneralRest, bool ignoreState = false, RequestOptions options = null) where TResponse : class + => DeserializeJson(await SendInternalAsync(method, endpoint, payload, false, BucketGroup.Global, (int)bucket, 0, ignoreState, options).ConfigureAwait(false)); public Task SendAsync(string method, string endpoint, - GuildBucket bucket, ulong guildId, RequestOptions options = null) - => SendInternalAsync(method, endpoint, null, true, BucketGroup.Guild, (int)bucket, guildId, options); + GuildBucket bucket, ulong guildId, bool ignoreState = false, RequestOptions options = null) + => SendInternalAsync(method, endpoint, null, true, BucketGroup.Guild, (int)bucket, guildId, ignoreState, options); public Task SendAsync(string method, string endpoint, object payload, - GuildBucket bucket, ulong guildId, RequestOptions options = null) - => SendInternalAsync(method, endpoint, payload, true, BucketGroup.Guild, (int)bucket, guildId, options); + GuildBucket bucket, ulong guildId, bool ignoreState = false, RequestOptions options = null) + => SendInternalAsync(method, endpoint, payload, true, BucketGroup.Guild, (int)bucket, guildId, ignoreState, options); public async Task SendAsync(string method, string endpoint, - GuildBucket bucket, ulong guildId, RequestOptions options = null) where TResponse : class - => DeserializeJson(await SendInternalAsync(method, endpoint, null, false, BucketGroup.Guild, (int)bucket, guildId, options).ConfigureAwait(false)); + GuildBucket bucket, ulong guildId, bool ignoreState = false, RequestOptions options = null) where TResponse : class + => DeserializeJson(await SendInternalAsync(method, endpoint, null, false, BucketGroup.Guild, (int)bucket, guildId, ignoreState, options).ConfigureAwait(false)); public async Task SendAsync(string method, string endpoint, object payload, - GuildBucket bucket, ulong guildId, RequestOptions options = null) where TResponse : class - => DeserializeJson(await SendInternalAsync(method, endpoint, payload, false, BucketGroup.Guild, (int)bucket, guildId, options).ConfigureAwait(false)); + GuildBucket bucket, ulong guildId, bool ignoreState = false, RequestOptions options = null) where TResponse : class + => DeserializeJson(await SendInternalAsync(method, endpoint, payload, false, BucketGroup.Guild, (int)bucket, guildId, ignoreState, options).ConfigureAwait(false)); //REST - Multipart public Task SendMultipartAsync(string method, string endpoint, IReadOnlyDictionary multipartArgs, @@ -194,8 +194,11 @@ namespace Discord.API //Core private async Task SendInternalAsync(string method, string endpoint, object payload, bool headerOnly, - BucketGroup group, int bucketId, ulong guildId, RequestOptions options = null) + BucketGroup group, int bucketId, ulong guildId, bool ignoreState, RequestOptions options = null) { + if (!ignoreState) + CheckState(); + var stopwatch = Stopwatch.StartNew(); string json = null; if (payload != null) @@ -211,6 +214,8 @@ namespace Discord.API private async Task SendMultipartInternalAsync(string method, string endpoint, IReadOnlyDictionary multipartArgs, bool headerOnly, BucketGroup group, int bucketId, ulong guildId, RequestOptions options = null) { + CheckState(); + var stopwatch = Stopwatch.StartNew(); var responseStream = await RequestQueue.SendAsync(new RestRequest(_restClient, method, endpoint, multipartArgs, headerOnly, options), group, bucketId, guildId).ConfigureAwait(false); int bytes = headerOnly ? 0 : (int)responseStream.Length; @@ -1039,6 +1044,11 @@ namespace Discord.API } //Helpers + protected void CheckState() + { + if (LoginState != LoginState.LoggedIn) + throw new InvalidOperationException("Client is not logged in."); + } protected static double ToMilliseconds(Stopwatch stopwatch) => Math.Round((double)stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0, 2); protected string SerializeJson(object value) { diff --git a/src/Discord.Net/API/DiscordRpcAPIClient.cs b/src/Discord.Net/API/DiscordRpcAPIClient.cs index dccad0b03..37a2aa5a6 100644 --- a/src/Discord.Net/API/DiscordRpcAPIClient.cs +++ b/src/Discord.Net/API/DiscordRpcAPIClient.cs @@ -140,7 +140,7 @@ namespace Discord.API internal override async Task ConnectInternalAsync() { /*if (LoginState != LoginState.LoggedIn) - throw new InvalidOperationException("You must log in before connecting.");*/ + throw new InvalidOperationException("Client is not logged in.");*/ ConnectionState = ConnectionState.Connecting; try @@ -207,17 +207,20 @@ namespace Discord.API //Core public Task SendRpcAsync(string cmd, object payload, GlobalBucket bucket = GlobalBucket.GeneralRpc, - Optional evt = default(Optional), RequestOptions options = null) + Optional evt = default(Optional), bool ignoreState = false, RequestOptions options = null) where TResponse : class - => SendRpcAsyncInternal(cmd, payload, BucketGroup.Global, (int)bucket, 0, evt, options); + => SendRpcAsyncInternal(cmd, payload, BucketGroup.Global, (int)bucket, 0, evt, ignoreState, options); public Task SendRpcAsync(string cmd, object payload, GuildBucket bucket, ulong guildId, - Optional evt = default(Optional), RequestOptions options = null) + Optional evt = default(Optional), bool ignoreState = false, RequestOptions options = null) where TResponse : class - => SendRpcAsyncInternal(cmd, payload, BucketGroup.Guild, (int)bucket, guildId, evt, options); + => SendRpcAsyncInternal(cmd, payload, BucketGroup.Guild, (int)bucket, guildId, evt, ignoreState, options); private async Task SendRpcAsyncInternal(string cmd, object payload, BucketGroup group, int bucketId, ulong guildId, - Optional evt, RequestOptions options) + Optional evt, bool ignoreState, RequestOptions options) where TResponse : class { + if (!ignoreState) + CheckState(); + byte[] bytes = null; var guid = Guid.NewGuid(); payload = new API.Rpc.RpcMessage { Cmd = cmd, Event = evt, Args = payload, Nonce = guid }; @@ -242,7 +245,7 @@ namespace Discord.API { AccessToken = _authToken }; - return await SendRpcAsync("AUTHENTICATE", msg, options: options).ConfigureAwait(false); + return await SendRpcAsync("AUTHENTICATE", msg, ignoreState: true, options: options).ConfigureAwait(false); } public async Task SendAuthorizeAsync(string[] scopes, string rpcToken = null, RequestOptions options = null) { @@ -256,7 +259,7 @@ namespace Discord.API options = new RequestOptions(); if (options.Timeout == null) options.Timeout = 60000; //This requires manual input on the user's end, lets give them more time - return await SendRpcAsync("AUTHORIZE", msg, options: options).ConfigureAwait(false); + return await SendRpcAsync("AUTHORIZE", msg, ignoreState: true, options: options).ConfigureAwait(false); } public async Task SendGetGuildsAsync(RequestOptions options = null) diff --git a/src/Discord.Net/API/DiscordSocketApiClient.cs b/src/Discord.Net/API/DiscordSocketApiClient.cs index 83347607b..2d2579273 100644 --- a/src/Discord.Net/API/DiscordSocketApiClient.cs +++ b/src/Discord.Net/API/DiscordSocketApiClient.cs @@ -159,6 +159,8 @@ namespace Discord.API private async Task SendGatewayInternalAsync(GatewayOpCode opCode, object payload, BucketGroup group, int bucketId, ulong guildId, RequestOptions options) { + CheckState(); + //TODO: Add ETF byte[] bytes = null; payload = new WebSocketMessage { Operation = (int)opCode, Payload = payload }; diff --git a/src/Discord.Net/WebSocket/DiscordSocketClient.cs b/src/Discord.Net/WebSocket/DiscordSocketClient.cs index 171b79406..8502272b9 100644 --- a/src/Discord.Net/WebSocket/DiscordSocketClient.cs +++ b/src/Discord.Net/WebSocket/DiscordSocketClient.cs @@ -144,7 +144,7 @@ namespace Discord.WebSocket private async Task ConnectInternalAsync(bool isReconnecting) { if (LoginState != LoginState.LoggedIn) - throw new InvalidOperationException("You must log in before connecting."); + throw new InvalidOperationException("Client is not logged in."); if (!isReconnecting && _reconnectCancelToken != null && !_reconnectCancelToken.IsCancellationRequested) _reconnectCancelToken.Cancel();