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