* feature: add DiscordSocketRestClient this resolves #803. Users can access a DiscordSocketRestClient from the new `DiscordSocketClient.Rest` property. DiscordSocketRestClient is a wrapper over DiscordRestClient with certain state-modifying methods, such as Login/Logout disabled, to prevent users from breaking the client state. DiscordSocketRestClient uses the same API client as the DiscordSocketClient, allowing for shared ratelimiting - meaning users can now force HTTP requests without needing to wory about running into 429s. * fix: disallow users from bypassing shadowed logintags/2.0
| @@ -65,7 +65,7 @@ namespace Discord.Rest | |||||
| } | } | ||||
| finally { _stateLock.Release(); } | finally { _stateLock.Release(); } | ||||
| } | } | ||||
| private async Task LoginInternalAsync(TokenType tokenType, string token, bool validateToken) | |||||
| internal virtual async Task LoginInternalAsync(TokenType tokenType, string token, bool validateToken) | |||||
| { | { | ||||
| if (_isFirstLogin) | if (_isFirstLogin) | ||||
| { | { | ||||
| @@ -118,7 +118,7 @@ namespace Discord.Rest | |||||
| } | } | ||||
| finally { _stateLock.Release(); } | finally { _stateLock.Release(); } | ||||
| } | } | ||||
| private async Task LogoutInternalAsync() | |||||
| internal virtual async Task LogoutInternalAsync() | |||||
| { | { | ||||
| if (LoginState == LoginState.LoggedOut) return; | if (LoginState == LoginState.LoggedOut) return; | ||||
| LoginState = LoginState.LoggingOut; | LoginState = LoginState.LoggingOut; | ||||
| @@ -24,6 +24,8 @@ namespace Discord.Rest | |||||
| /// </summary> | /// </summary> | ||||
| /// <param name="config">The configuration to be used with the client.</param> | /// <param name="config">The configuration to be used with the client.</param> | ||||
| public DiscordRestClient(DiscordRestConfig config) : base(config, CreateApiClient(config)) { } | public DiscordRestClient(DiscordRestConfig config) : base(config, CreateApiClient(config)) { } | ||||
| // used for socket client rest access | |||||
| internal DiscordRestClient(DiscordRestConfig config, API.DiscordRestApiClient api) : base(config, api) { } | |||||
| private static API.DiscordRestApiClient CreateApiClient(DiscordRestConfig config) | private static API.DiscordRestApiClient CreateApiClient(DiscordRestConfig config) | ||||
| => new API.DiscordRestApiClient(config.RestClientProvider, DiscordRestConfig.UserAgent); | => new API.DiscordRestApiClient(config.RestClientProvider, DiscordRestConfig.UserAgent); | ||||
| @@ -42,9 +42,10 @@ namespace Discord.WebSocket | |||||
| private int _nextAudioId; | private int _nextAudioId; | ||||
| private DateTimeOffset? _statusSince; | private DateTimeOffset? _statusSince; | ||||
| private RestApplication _applicationInfo; | private RestApplication _applicationInfo; | ||||
| private bool _isDisposed; | private bool _isDisposed; | ||||
| /// <summary> Provides access to a REST-only client with a shared state from this client. </summary> | |||||
| public DiscordSocketRestClient Rest { get; } | |||||
| /// <summary> Gets the shard of of this client. </summary> | /// <summary> Gets the shard of of this client. </summary> | ||||
| public int ShardId { get; } | public int ShardId { get; } | ||||
| /// <summary> Gets the current connection state of this client. </summary> | /// <summary> Gets the current connection state of this client. </summary> | ||||
| @@ -128,6 +129,7 @@ namespace Discord.WebSocket | |||||
| AlwaysDownloadUsers = config.AlwaysDownloadUsers; | AlwaysDownloadUsers = config.AlwaysDownloadUsers; | ||||
| HandlerTimeout = config.HandlerTimeout; | HandlerTimeout = config.HandlerTimeout; | ||||
| State = new ClientState(0, 0); | State = new ClientState(0, 0); | ||||
| Rest = new DiscordSocketRestClient(config, ApiClient); | |||||
| _heartbeatTimes = new ConcurrentQueue<long>(); | _heartbeatTimes = new ConcurrentQueue<long>(); | ||||
| _stateLock = new SemaphoreSlim(1, 1); | _stateLock = new SemaphoreSlim(1, 1); | ||||
| @@ -0,0 +1,20 @@ | |||||
| using System; | |||||
| using System.Threading.Tasks; | |||||
| using Discord.Rest; | |||||
| namespace Discord.WebSocket | |||||
| { | |||||
| public class DiscordSocketRestClient : DiscordRestClient | |||||
| { | |||||
| internal DiscordSocketRestClient(DiscordRestConfig config, API.DiscordRestApiClient api) : base(config, api) { } | |||||
| public new Task LoginAsync(TokenType tokenType, string token, bool validateToken = true) | |||||
| => throw new NotSupportedException("The Socket REST wrapper cannot be used to log in or out."); | |||||
| internal override Task LoginInternalAsync(TokenType tokenType, string token, bool validateToken) | |||||
| => throw new NotSupportedException("The Socket REST wrapper cannot be used to log in or out."); | |||||
| public new Task LogoutAsync() | |||||
| => throw new NotSupportedException("The Socket REST wrapper cannot be used to log in or out."); | |||||
| internal override Task LogoutInternalAsync() | |||||
| => throw new NotSupportedException("The Socket REST wrapper cannot be used to log in or out."); | |||||
| } | |||||
| } | |||||