@@ -38,6 +38,7 @@ namespace Discord.API | |||
public TokenType AuthTokenType { get; private set; } | |||
public User CurrentUser { get; private set; } | |||
public RequestQueue RequestQueue { get; private set; } | |||
internal bool FetchCurrentUser { get; set; } | |||
public DiscordRestApiClient(RestClientProvider restClientProvider, string userAgent, JsonSerializer serializer = null, RequestQueue requestQueue = null) | |||
{ | |||
@@ -45,6 +46,7 @@ namespace Discord.API | |||
_userAgent = userAgent; | |||
_serializer = serializer ?? new JsonSerializer { ContractResolver = new DiscordContractResolver() }; | |||
RequestQueue = requestQueue; | |||
FetchCurrentUser = true; | |||
_stateLock = new SemaphoreSlim(1, 1); | |||
@@ -113,7 +115,8 @@ namespace Discord.API | |||
_authToken = token; | |||
_restClient.SetHeader("authorization", GetPrefixedToken(AuthTokenType, _authToken)); | |||
CurrentUser = await GetMyUserAsync(new RequestOptions { IgnoreState = true }); | |||
if (FetchCurrentUser) | |||
CurrentUser = await GetMyUserAsync(new RequestOptions { IgnoreState = true }); | |||
LoginState = LoginState.LoggedIn; | |||
} | |||
@@ -8,6 +8,7 @@ using Newtonsoft.Json; | |||
using Newtonsoft.Json.Linq; | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.IO.Compression; | |||
using System.Text; | |||
@@ -67,13 +68,16 @@ namespace Discord.API | |||
public ConnectionState ConnectionState { get; private set; } | |||
public DiscordRpcApiClient(string clientId, string userAgent, string origin, RestClientProvider restClientProvider, WebSocketProvider webSocketProvider, JsonSerializer serializer = null, RequestQueue requestQueue = null) | |||
public DiscordRpcApiClient(string clientId, string userAgent, string origin, RestClientProvider restClientProvider, WebSocketProvider webSocketProvider, | |||
JsonSerializer serializer = null, RequestQueue requestQueue = null) | |||
: base(restClientProvider, userAgent, serializer, requestQueue) | |||
{ | |||
_connectionLock = new SemaphoreSlim(1, 1); | |||
_clientId = clientId; | |||
_origin = origin; | |||
FetchCurrentUser = false; | |||
_requestQueue = requestQueue ?? new RequestQueue(); | |||
_requests = new ConcurrentDictionary<Guid, RpcRequest>(); | |||
@@ -169,7 +173,7 @@ namespace Discord.API | |||
if (!success) | |||
throw new Exception("Unable to connect to the RPC server."); | |||
SetBaseUrl($"https://{uuid}.discordapp.io:{port}/"); | |||
ConnectionState = ConnectionState.Connected; | |||
} | |||
@@ -209,7 +213,6 @@ namespace Discord.API | |||
public async Task<TResponse> SendRpcAsync<TResponse>(string cmd, object payload, Optional<string> evt = default(Optional<string>), RequestOptions options = null) | |||
where TResponse : class | |||
{ | |||
options.IgnoreState = false; | |||
return await SendRpcAsyncInternal<TResponse>(cmd, payload, evt, options).ConfigureAwait(false); | |||
} | |||
private async Task<TResponse> SendRpcAsyncInternal<TResponse>(string cmd, object payload, Optional<string> evt, RequestOptions options) | |||
@@ -246,7 +249,7 @@ namespace Discord.API | |||
options.IgnoreState = true; | |||
return await SendRpcAsync<AuthenticateResponse>("AUTHENTICATE", msg, options: options).ConfigureAwait(false); | |||
} | |||
public async Task<AuthorizeResponse> SendAuthorizeAsync(string[] scopes, string rpcToken = null, RequestOptions options = null) | |||
public async Task<AuthorizeResponse> SendAuthorizeAsync(IReadOnlyCollection<string> scopes, string rpcToken = null, RequestOptions options = null) | |||
{ | |||
options = RequestOptions.CreateOrClone(options); | |||
var msg = new AuthorizeParams | |||
@@ -1,5 +1,6 @@ | |||
#pragma warning disable CS1591 | |||
using Newtonsoft.Json; | |||
using System.Collections.Generic; | |||
namespace Discord.API.Rpc | |||
{ | |||
@@ -8,7 +9,7 @@ namespace Discord.API.Rpc | |||
[JsonProperty("client_id")] | |||
public string ClientId { get; set; } | |||
[JsonProperty("scopes")] | |||
public string[] Scopes { get; set; } | |||
public IReadOnlyCollection<string> Scopes { get; set; } | |||
[JsonProperty("rpc_token")] | |||
public Optional<string> RpcToken { get; set; } | |||
} | |||
@@ -42,18 +42,18 @@ namespace Discord.Rpc | |||
private readonly AsyncEvent<Func<Task>> _voiceStateUpdatedEvent = new AsyncEvent<Func<Task>>(); | |||
//Messages | |||
public event Func<ulong, IMessage, Task> MessageReceived | |||
public event Func<RpcMessage, Task> MessageReceived | |||
{ | |||
add { _messageReceivedEvent.Add(value); } | |||
remove { _messageReceivedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<ulong, IMessage, Task>> _messageReceivedEvent = new AsyncEvent<Func<ulong, IMessage, Task>>(); | |||
public event Func<ulong, IMessage, Task> MessageUpdated | |||
private readonly AsyncEvent<Func<RpcMessage, Task>> _messageReceivedEvent = new AsyncEvent<Func<RpcMessage, Task>>(); | |||
public event Func<RpcMessage, Task> MessageUpdated | |||
{ | |||
add { _messageUpdatedEvent.Add(value); } | |||
remove { _messageUpdatedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<ulong, IMessage, Task>> _messageUpdatedEvent = new AsyncEvent<Func<ulong, IMessage, Task>>(); | |||
private readonly AsyncEvent<Func<RpcMessage, Task>> _messageUpdatedEvent = new AsyncEvent<Func<RpcMessage, Task>>(); | |||
public event Func<ulong, ulong, Task> MessageDeleted | |||
{ | |||
add { _messageDeletedEvent.Add(value); } | |||
@@ -6,6 +6,8 @@ using Discord.Rest; | |||
using Newtonsoft.Json; | |||
using Newtonsoft.Json.Linq; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Collections.Immutable; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
@@ -22,11 +24,15 @@ namespace Discord.Rpc | |||
private bool _canReconnect; | |||
public ConnectionState ConnectionState { get; private set; } | |||
public IReadOnlyCollection<string> Scopes { get; private set; } | |||
public DateTimeOffset TokenExpiresAt { get; private set; } | |||
//From DiscordRpcConfig | |||
internal int ConnectionTimeout { get; private set; } | |||
public new API.DiscordRpcApiClient ApiClient => base.ApiClient as API.DiscordRpcApiClient; | |||
public new RestSelfUser CurrentUser { get { return base.CurrentUser as RestSelfUser; } private set { base.CurrentUser = value; } } | |||
public RestApplication CurrentApplication { get; private set; } | |||
/// <summary> Creates a new RPC discord client. </summary> | |||
public DiscordRpcClient(string clientId, string origin) | |||
@@ -58,6 +64,7 @@ namespace Discord.Rpc | |||
await _rpcLogger.WarningAsync($"Connection Closed").ConfigureAwait(false); | |||
}; | |||
} | |||
private static API.DiscordRpcApiClient CreateApiClient(string clientId, string origin, DiscordRpcConfig config) | |||
=> new API.DiscordRpcApiClient(clientId, DiscordRestConfig.UserAgent, origin, config.RestClientProvider, config.WebSocketProvider, requestQueue: new RequestQueue()); | |||
@@ -286,19 +293,21 @@ namespace Discord.Rpc | |||
{ | |||
await _rpcLogger.DebugAsync("Received Dispatch (READY)").ConfigureAwait(false); | |||
var data = (payload.Value as JToken).ToObject<ReadyEvent>(_serializer); | |||
var cancelToken = _cancelToken; | |||
RequestOptions options = new RequestOptions | |||
{ | |||
//CancellationToken = _cancelToken //TODO: Implement | |||
}; | |||
var _ = Task.Run(async () => | |||
{ | |||
try | |||
{ | |||
RequestOptions options = new RequestOptions | |||
{ | |||
//CancellationToken = cancelToken //TODO: Implement | |||
}; | |||
if (LoginState != LoginState.LoggedOut) | |||
await ApiClient.SendAuthenticateAsync(options).ConfigureAwait(false); //Has bearer | |||
var response = await ApiClient.SendAuthenticateAsync(options).ConfigureAwait(false); | |||
CurrentUser = RestSelfUser.Create(this, response.User); | |||
CurrentApplication = RestApplication.Create(this, response.Application); | |||
Scopes = response.Scopes; | |||
TokenExpiresAt = response.Expires; | |||
var __ = _connectTask.TrySetResultAsync(true); //Signal the .Connect() call to complete | |||
await _rpcLogger.InfoAsync("Ready").ConfigureAwait(false); | |||
@@ -361,20 +370,20 @@ namespace Discord.Rpc | |||
//Messages | |||
case "MESSAGE_CREATE": | |||
{ | |||
/*await _rpcLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false); | |||
await _rpcLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false); | |||
var data = (payload.Value as JToken).ToObject<MessageEvent>(_serializer); | |||
var msg = new RpcMessage(this, data.Message); | |||
var msg = RpcMessage.Create(this, data.ChannelId, data.Message); | |||
await _messageReceivedEvent.InvokeAsync(data.ChannelId, msg).ConfigureAwait(false);*/ | |||
await _messageReceivedEvent.InvokeAsync(msg).ConfigureAwait(false); | |||
} | |||
break; | |||
case "MESSAGE_UPDATE": | |||
{ | |||
/*await _rpcLogger.DebugAsync("Received Dispatch (MESSAGE_UPDATE)").ConfigureAwait(false); | |||
await _rpcLogger.DebugAsync("Received Dispatch (MESSAGE_UPDATE)").ConfigureAwait(false); | |||
var data = (payload.Value as JToken).ToObject<MessageEvent>(_serializer); | |||
var msg = new RpcMessage(this, data.Message); | |||
var msg = RpcMessage.Create(this, data.ChannelId, data.Message); | |||
await _messageUpdatedEvent.InvokeAsync(data.ChannelId, msg).ConfigureAwait(false);*/ | |||
await _messageUpdatedEvent.InvokeAsync(msg).ConfigureAwait(false); | |||
} | |||
break; | |||
case "MESSAGE_DELETE": | |||
@@ -9,7 +9,7 @@ namespace Discord.Rpc | |||
public const int PortRangeStart = 6463; | |||
public const int PortRangeEnd = 6472; | |||
/// <summary> Gets or sets the time, in milliseconds, to wait for a connection to complete before aborting. </summary> | |||
public int ConnectionTimeout { get; set; } = 30000; | |||