| @@ -9,10 +9,12 @@ | |||||
| - User | - User | ||||
| - Voice | - Voice | ||||
| - Webhook | - Webhook | ||||
| - Ratelimiter with refit | |||||
| - Gateway | - Gateway | ||||
| - Models | - Models | ||||
| - Client | - Client | ||||
| - Socket | - Socket | ||||
| - use token | |||||
| * Receive | * Receive | ||||
| * Compression | * Compression | ||||
| - Voice (long) | - Voice (long) | ||||
| @@ -24,8 +26,11 @@ | |||||
| - Emoji | - Emoji | ||||
| - Guild | - Guild | ||||
| - User | - User | ||||
| - Utilities | |||||
| - Token Validation (port from @ChrisJ) | |||||
| - Tests | - Tests | ||||
| - Unit test Gateway stability / deadlockability? | - Unit test Gateway stability / deadlockability? | ||||
| - Port ChrisJ's token validator tests | |||||
| - Extensions | - Extensions | ||||
| - Commands | - Commands | ||||
| ? design - use finite's or quahu's | ? design - use finite's or quahu's | ||||
| @@ -7,4 +7,14 @@ | |||||
| <RootNamespace>Discord</RootNamespace> | <RootNamespace>Discord</RootNamespace> | ||||
| </PropertyGroup> | </PropertyGroup> | ||||
| <ItemGroup> | |||||
| <PackageReference Include="refit" Version="5.0.23" /> | |||||
| <PackageReference Include="System.Text.Json" Version="4.7.0" /> | |||||
| </ItemGroup> | |||||
| <ItemGroup> | |||||
| <Folder Include="Entities\" /> | |||||
| <Folder Include="..\..\..\..\..\%2540discord\%2540next\Discord.Net\src\Discord.Net\Rest\Requests\" /> | |||||
| </ItemGroup> | |||||
| </Project> | </Project> | ||||
| @@ -1,25 +1,20 @@ | |||||
| using Discord.Rest; | using Discord.Rest; | ||||
| using Discord.Socket; | using Discord.Socket; | ||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Text; | |||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| internal class DiscordClient : IDiscordClient | internal class DiscordClient : IDiscordClient | ||||
| { | { | ||||
| public DiscordRestApi Rest => _restApi; | |||||
| public DiscordGatewayApi Gateway => _gatewayApi; | |||||
| public DiscordRestApi Rest { get; } | |||||
| public DiscordGatewayApi Gateway { get; } | |||||
| private readonly DiscordConfig _config; | private readonly DiscordConfig _config; | ||||
| private readonly DiscordRestApi _restApi; | |||||
| private readonly DiscordGatewayApi _gatewayApi; | |||||
| public DiscordClient(DiscordConfig config, DiscordRestApi restApi, DiscordGatewayApi gatewayApi) | public DiscordClient(DiscordConfig config, DiscordRestApi restApi, DiscordGatewayApi gatewayApi) | ||||
| { | { | ||||
| _config = config; | _config = config; | ||||
| _restApi = restApi; | |||||
| _gatewayApi = gatewayApi; | |||||
| Rest = restApi; | |||||
| Gateway = gatewayApi; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -27,7 +27,9 @@ namespace Discord | |||||
| /// The URI to use when connecting to the gateway. If specified, this will override the URI Discord instructs us to use. | /// The URI to use when connecting to the gateway. If specified, this will override the URI Discord instructs us to use. | ||||
| /// </summary> | /// </summary> | ||||
| public Uri? GatewayUri = null; | public Uri? GatewayUri = null; | ||||
| /// <summary> | |||||
| /// SocketFactory gets or sets how a WebSocket will be created. | |||||
| /// </summary> | |||||
| public SocketFactory SocketFactory { get; set; } = DefaultSocketFactory.Create; | public SocketFactory SocketFactory { get; set; } = DefaultSocketFactory.Create; | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,7 +1,4 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| using System.Net.Http.Headers; | |||||
| using Discord.Rest; | using Discord.Rest; | ||||
| using Discord.Socket; | using Discord.Socket; | ||||
| @@ -9,10 +6,15 @@ namespace Discord | |||||
| { | { | ||||
| internal interface IDiscordClient | internal interface IDiscordClient | ||||
| { | { | ||||
| static IDiscordClient Create(DiscordConfig config) | |||||
| static IDiscordClient Create(string token, DiscordConfig? config = default) | |||||
| { | { | ||||
| var rest = new DiscordRestApi(config); | |||||
| var gateway = new DiscordGatewayApi(config); | |||||
| config = config ?? new DiscordConfig(); | |||||
| // todo: validate token | |||||
| var tokenHeader = AuthenticationHeaderValue.Parse(token); | |||||
| var rest = new DiscordRestApi(config, tokenHeader); | |||||
| var gateway = new DiscordGatewayApi(config, token); | |||||
| return new DiscordClient(config, rest, gateway); | return new DiscordClient(config, rest, gateway); | ||||
| } | } | ||||
| @@ -0,0 +1,23 @@ | |||||
| using System.Net.Http; | |||||
| using System.Net.Http.Headers; | |||||
| using System.Threading; | |||||
| using System.Threading.Tasks; | |||||
| namespace Discord.Rest | |||||
| { | |||||
| internal sealed class DiscordHttpClientHandler : HttpClientHandler | |||||
| { | |||||
| private readonly AuthenticationHeaderValue _token; | |||||
| public DiscordHttpClientHandler(AuthenticationHeaderValue token) | |||||
| { | |||||
| _token = token; | |||||
| } | |||||
| protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) | |||||
| { | |||||
| request.Headers.Authorization = _token; | |||||
| return base.SendAsync(request, cancellationToken); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -2,6 +2,7 @@ using System.Text.Json; | |||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| using Refit; | using Refit; | ||||
| using Discord.Rest.Models; | using Discord.Rest.Models; | ||||
| using System.Net.Http.Headers; | |||||
| // This is essentially a reimplementation of Wumpus.Net.Rest | // This is essentially a reimplementation of Wumpus.Net.Rest | ||||
| namespace Discord.Rest | namespace Discord.Rest | ||||
| @@ -10,7 +11,7 @@ namespace Discord.Rest | |||||
| { | { | ||||
| private readonly IDiscordRestApi _api; | private readonly IDiscordRestApi _api; | ||||
| public DiscordRestApi(DiscordConfig config) | |||||
| public DiscordRestApi(DiscordConfig config, AuthenticationHeaderValue token) | |||||
| { | { | ||||
| var jsonOptions = new JsonSerializerOptions(); | var jsonOptions = new JsonSerializerOptions(); | ||||
| var refitSettings = new RefitSettings | var refitSettings = new RefitSettings | ||||
| @@ -1,11 +1,8 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.IO; | using System.IO; | ||||
| using System.Net.Http; | using System.Net.Http; | ||||
| using System.Net.Http.Headers; | using System.Net.Http.Headers; | ||||
| using System.Text; | using System.Text; | ||||
| using System.Text.Json; | using System.Text.Json; | ||||
| using System.Text.Json.Serialization; | |||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| using Refit; | using Refit; | ||||
| @@ -6,18 +6,23 @@ namespace Discord.Socket | |||||
| { | { | ||||
| public class DiscordGatewayApi | public class DiscordGatewayApi | ||||
| { | { | ||||
| static readonly Uri DefaultGatewayUri = new Uri("wss://gateway.discord.gg"); | |||||
| private readonly DiscordConfig _config; | |||||
| private readonly string _token; | |||||
| ISocket Socket { get; set; } | |||||
| public ISocket Socket { get; set; } | |||||
| public DiscordGatewayApi(DiscordConfig config) | |||||
| public DiscordGatewayApi(DiscordConfig config, string token) | |||||
| { | { | ||||
| _config = config; | |||||
| _token = token; | |||||
| Socket = config.SocketFactory(OnAborted, OnPacket); | Socket = config.SocketFactory(OnAborted, OnPacket); | ||||
| } | } | ||||
| public async Task ConnectAsync(Uri? gatewayUri) | public async Task ConnectAsync(Uri? gatewayUri) | ||||
| { | { | ||||
| await Socket.ConnectAsync(gatewayUri ?? DefaultGatewayUri, CancellationToken.None).ConfigureAwait(false); | |||||
| var baseUri = _config.GatewayUri ?? (gatewayUri ?? DiscordConfig.DefaultGatewayUri); | |||||
| await Socket.ConnectAsync(baseUri, CancellationToken.None).ConfigureAwait(false); | |||||
| } | } | ||||
| public void OnAborted(Exception error) | public void OnAborted(Exception error) | ||||
| @@ -88,6 +88,8 @@ namespace Discord.Socket.Providers | |||||
| } | } | ||||
| State = SocketState.Open; | State = SocketState.Open; | ||||
| _receiveTask = ReceiveAsync(); | |||||
| // TODO: this should not be expected to fail | // TODO: this should not be expected to fail | ||||
| _stateLock.Release(); | _stateLock.Release(); | ||||
| openLock.Dispose(); | openLock.Dispose(); | ||||