Implemented support for RPC responses and errors, fixed several bugs
This commit is contained in:
@@ -71,16 +71,21 @@ namespace Discord.API
|
|||||||
zlib.CopyTo(decompressed);
|
zlib.CopyTo(decompressed);
|
||||||
decompressed.Position = 0;
|
decompressed.Position = 0;
|
||||||
using (var reader = new StreamReader(decompressed))
|
using (var reader = new StreamReader(decompressed))
|
||||||
|
using (var jsonReader = new JsonTextReader(reader))
|
||||||
{
|
{
|
||||||
var msg = JsonConvert.DeserializeObject<WebSocketMessage>(reader.ReadToEnd());
|
var msg = _serializer.Deserialize<WebSocketMessage>(jsonReader);
|
||||||
await _receivedGatewayEvent.InvokeAsync((GatewayOpCode)msg.Operation, msg.Sequence, msg.Type, msg.Payload).ConfigureAwait(false);
|
await _receivedGatewayEvent.InvokeAsync((GatewayOpCode)msg.Operation, msg.Sequence, msg.Type, msg.Payload).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
_gatewayClient.TextMessage += async text =>
|
_gatewayClient.TextMessage += async text =>
|
||||||
{
|
{
|
||||||
var msg = JsonConvert.DeserializeObject<WebSocketMessage>(text);
|
using (var reader = new StringReader(text))
|
||||||
|
using (var jsonReader = new JsonTextReader(reader))
|
||||||
|
{
|
||||||
|
var msg = _serializer.Deserialize<WebSocketMessage>(jsonReader);
|
||||||
await _receivedGatewayEvent.InvokeAsync((GatewayOpCode)msg.Operation, msg.Sequence, msg.Type, msg.Payload).ConfigureAwait(false);
|
await _receivedGatewayEvent.InvokeAsync((GatewayOpCode)msg.Operation, msg.Sequence, msg.Type, msg.Payload).ConfigureAwait(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
_gatewayClient.Closed += async ex =>
|
_gatewayClient.Closed += async ex =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,21 +1,16 @@
|
|||||||
using Discord.API.Gateway;
|
using Discord.API.Rpc;
|
||||||
using Discord.API.Rest;
|
using Discord.Logging;
|
||||||
using Discord.API.Rpc;
|
|
||||||
using Discord.Net;
|
|
||||||
using Discord.Net.Converters;
|
using Discord.Net.Converters;
|
||||||
using Discord.Net.Queue;
|
using Discord.Net.Queue;
|
||||||
using Discord.Net.Rest;
|
|
||||||
using Discord.Net.WebSockets;
|
using Discord.Net.WebSockets;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Immutable;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -24,16 +19,46 @@ namespace Discord.API
|
|||||||
{
|
{
|
||||||
public class DiscordRpcApiClient : IDisposable
|
public class DiscordRpcApiClient : IDisposable
|
||||||
{
|
{
|
||||||
|
private abstract class RpcRequest
|
||||||
|
{
|
||||||
|
public abstract Task SetResultAsync(JToken data, JsonSerializer serializer);
|
||||||
|
public abstract Task SetExceptionAsync(JToken data, JsonSerializer serializer);
|
||||||
|
}
|
||||||
|
private class RpcRequest<T> : RpcRequest
|
||||||
|
{
|
||||||
|
public TaskCompletionSource<T> Promise { get; set; }
|
||||||
|
|
||||||
|
public RpcRequest(RequestOptions options)
|
||||||
|
{
|
||||||
|
Promise = new TaskCompletionSource<T>();
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await Task.Delay(options?.Timeout ?? 15000).ConfigureAwait(false);
|
||||||
|
Promise.TrySetCanceled(); //Doesn't need to be async, we're already in a separate task
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public override Task SetResultAsync(JToken data, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
return Promise.TrySetResultAsync(data.ToObject<T>(serializer));
|
||||||
|
}
|
||||||
|
public override Task SetExceptionAsync(JToken data, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
var error = data.ToObject<ErrorEvent>(serializer);
|
||||||
|
return Promise.TrySetExceptionAsync(new RpcException(error.Code, error.Message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private object _eventLock = new object();
|
private object _eventLock = new object();
|
||||||
|
|
||||||
public event Func<string, Task> SentRpcMessage { add { _sentRpcMessageEvent.Add(value); } remove { _sentRpcMessageEvent.Remove(value); } }
|
public event Func<string, Task> SentRpcMessage { add { _sentRpcMessageEvent.Add(value); } remove { _sentRpcMessageEvent.Remove(value); } }
|
||||||
private readonly AsyncEvent<Func<string, Task>> _sentRpcMessageEvent = new AsyncEvent<Func<string, Task>>();
|
private readonly AsyncEvent<Func<string, Task>> _sentRpcMessageEvent = new AsyncEvent<Func<string, Task>>();
|
||||||
|
|
||||||
public event Func<string, string, object, string, Task> ReceivedRpcEvent { add { _receivedRpcEvent.Add(value); } remove { _receivedRpcEvent.Remove(value); } }
|
public event Func<string, Optional<string>, Optional<object>, Task> ReceivedRpcEvent { add { _receivedRpcEvent.Add(value); } remove { _receivedRpcEvent.Remove(value); } }
|
||||||
private readonly AsyncEvent<Func<string, string, object, string, Task>> _receivedRpcEvent = new AsyncEvent<Func<string, string, object, string, Task>>();
|
private readonly AsyncEvent<Func<string, Optional<string>, Optional<object>, Task>> _receivedRpcEvent = new AsyncEvent<Func<string, Optional<string>, Optional<object>, Task>>();
|
||||||
public event Func<Exception, Task> Disconnected { add { _disconnectedEvent.Add(value); } remove { _disconnectedEvent.Remove(value); } }
|
public event Func<Exception, Task> Disconnected { add { _disconnectedEvent.Add(value); } remove { _disconnectedEvent.Remove(value); } }
|
||||||
private readonly AsyncEvent<Func<Exception, Task>> _disconnectedEvent = new AsyncEvent<Func<Exception, Task>>();
|
private readonly AsyncEvent<Func<Exception, Task>> _disconnectedEvent = new AsyncEvent<Func<Exception, Task>>();
|
||||||
|
|
||||||
|
private readonly ConcurrentDictionary<Guid, RpcRequest> _requests;
|
||||||
private readonly RequestQueue _requestQueue;
|
private readonly RequestQueue _requestQueue;
|
||||||
private readonly JsonSerializer _serializer;
|
private readonly JsonSerializer _serializer;
|
||||||
private readonly IWebSocketClient _webSocketClient;
|
private readonly IWebSocketClient _webSocketClient;
|
||||||
@@ -41,22 +66,26 @@ namespace Discord.API
|
|||||||
private readonly string _clientId;
|
private readonly string _clientId;
|
||||||
private CancellationTokenSource _loginCancelToken, _connectCancelToken;
|
private CancellationTokenSource _loginCancelToken, _connectCancelToken;
|
||||||
private string _authToken;
|
private string _authToken;
|
||||||
|
private string _origin;
|
||||||
private bool _isDisposed;
|
private bool _isDisposed;
|
||||||
|
|
||||||
public LoginState LoginState { get; private set; }
|
public LoginState LoginState { get; private set; }
|
||||||
public ConnectionState ConnectionState { get; private set; }
|
public ConnectionState ConnectionState { get; private set; }
|
||||||
|
|
||||||
public DiscordRpcApiClient(string clientId, WebSocketProvider webSocketProvider, JsonSerializer serializer = null, RequestQueue requestQueue = null)
|
public DiscordRpcApiClient(string clientId, string origin, WebSocketProvider webSocketProvider, JsonSerializer serializer = null, RequestQueue requestQueue = null)
|
||||||
{
|
{
|
||||||
_connectionLock = new SemaphoreSlim(1, 1);
|
_connectionLock = new SemaphoreSlim(1, 1);
|
||||||
_clientId = clientId;
|
_clientId = clientId;
|
||||||
|
_origin = origin;
|
||||||
|
|
||||||
_requestQueue = requestQueue ?? new RequestQueue();
|
_requestQueue = requestQueue ?? new RequestQueue();
|
||||||
|
_requests = new ConcurrentDictionary<Guid, RpcRequest>();
|
||||||
|
|
||||||
if (webSocketProvider != null)
|
if (webSocketProvider != null)
|
||||||
{
|
{
|
||||||
_webSocketClient = webSocketProvider();
|
_webSocketClient = webSocketProvider();
|
||||||
//_gatewayClient.SetHeader("user-agent", DiscordConfig.UserAgent); (Causes issues in .Net 4.6+)
|
//_webSocketClient.SetHeader("user-agent", DiscordConfig.UserAgent); (Causes issues in .Net 4.6+)
|
||||||
|
_webSocketClient.SetHeader("origin", _origin);
|
||||||
_webSocketClient.BinaryMessage += async (data, index, count) =>
|
_webSocketClient.BinaryMessage += async (data, index, count) =>
|
||||||
{
|
{
|
||||||
using (var compressed = new MemoryStream(data, index + 2, count - 2))
|
using (var compressed = new MemoryStream(data, index + 2, count - 2))
|
||||||
@@ -66,16 +95,25 @@ namespace Discord.API
|
|||||||
zlib.CopyTo(decompressed);
|
zlib.CopyTo(decompressed);
|
||||||
decompressed.Position = 0;
|
decompressed.Position = 0;
|
||||||
using (var reader = new StreamReader(decompressed))
|
using (var reader = new StreamReader(decompressed))
|
||||||
|
using (var jsonReader = new JsonTextReader(reader))
|
||||||
{
|
{
|
||||||
var msg = JsonConvert.DeserializeObject<RpcMessage>(reader.ReadToEnd());
|
var msg = _serializer.Deserialize<RpcMessage>(jsonReader);
|
||||||
await _receivedRpcEvent.InvokeAsync(msg.Cmd, msg.Event, msg.Data, msg.Nonce).ConfigureAwait(false);
|
await _receivedRpcEvent.InvokeAsync(msg.Cmd, msg.Event, msg.Data).ConfigureAwait(false);
|
||||||
|
if (msg.Nonce.IsSpecified && msg.Nonce.Value.HasValue)
|
||||||
|
ProcessMessage(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
_webSocketClient.TextMessage += async text =>
|
_webSocketClient.TextMessage += async text =>
|
||||||
{
|
{
|
||||||
var msg = JsonConvert.DeserializeObject<RpcMessage>(text);
|
using (var reader = new StringReader(text))
|
||||||
await _receivedRpcEvent.InvokeAsync(msg.Cmd, msg.Event, msg.Data, msg.Nonce).ConfigureAwait(false);
|
using (var jsonReader = new JsonTextReader(reader))
|
||||||
|
{
|
||||||
|
var msg = _serializer.Deserialize<RpcMessage>(jsonReader);
|
||||||
|
await _receivedRpcEvent.InvokeAsync(msg.Cmd, msg.Event, msg.Data).ConfigureAwait(false);
|
||||||
|
if (msg.Nonce.IsSpecified && msg.Nonce.Value.HasValue)
|
||||||
|
ProcessMessage(msg);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
_webSocketClient.Closed += async ex =>
|
_webSocketClient.Closed += async ex =>
|
||||||
{
|
{
|
||||||
@@ -100,18 +138,18 @@ namespace Discord.API
|
|||||||
}
|
}
|
||||||
public void Dispose() => Dispose(true);
|
public void Dispose() => Dispose(true);
|
||||||
|
|
||||||
public async Task LoginAsync(TokenType tokenType, string token, RequestOptions options = null)
|
public async Task LoginAsync(TokenType tokenType, string token, bool upgrade = false, RequestOptions options = null)
|
||||||
{
|
{
|
||||||
await _connectionLock.WaitAsync().ConfigureAwait(false);
|
await _connectionLock.WaitAsync().ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await LoginInternalAsync(tokenType, token, options).ConfigureAwait(false);
|
await LoginInternalAsync(tokenType, token, upgrade, options).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
finally { _connectionLock.Release(); }
|
finally { _connectionLock.Release(); }
|
||||||
}
|
}
|
||||||
private async Task LoginInternalAsync(TokenType tokenType, string token, RequestOptions options = null)
|
private async Task LoginInternalAsync(TokenType tokenType, string token, bool upgrade = false, RequestOptions options = null)
|
||||||
{
|
{
|
||||||
if (LoginState != LoginState.LoggedOut)
|
if (!upgrade && LoginState != LoginState.LoggedOut)
|
||||||
await LogoutInternalAsync().ConfigureAwait(false);
|
await LogoutInternalAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
if (tokenType != TokenType.Bearer)
|
if (tokenType != TokenType.Bearer)
|
||||||
@@ -233,39 +271,155 @@ namespace Discord.API
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Core
|
//Core
|
||||||
public Task SendRpcAsync(string cmd, object payload, GlobalBucket bucket = GlobalBucket.GeneralRpc, RequestOptions options = null)
|
public Task<TResponse> SendRpcAsync<TResponse>(string cmd, object payload, GlobalBucket bucket = GlobalBucket.GeneralRpc,
|
||||||
=> SendRpcAsyncInternal(cmd, payload, BucketGroup.Global, (int)bucket, 0, options);
|
Optional<string> evt = default(Optional<string>), RequestOptions options = null)
|
||||||
public Task SendRpcAsync(string cmd, object payload, GuildBucket bucket, ulong guildId, RequestOptions options = null)
|
where TResponse : class
|
||||||
=> SendRpcAsyncInternal(cmd, payload, BucketGroup.Guild, (int)bucket, guildId, options);
|
=> SendRpcAsyncInternal<TResponse>(cmd, payload, BucketGroup.Global, (int)bucket, 0, evt, options);
|
||||||
private async Task SendRpcAsyncInternal(string cmd, object payload,
|
public Task<TResponse> SendRpcAsync<TResponse>(string cmd, object payload, GuildBucket bucket, ulong guildId,
|
||||||
BucketGroup group, int bucketId, ulong guildId, RequestOptions options)
|
Optional<string> evt = default(Optional<string>), RequestOptions options = null)
|
||||||
|
where TResponse : class
|
||||||
|
=> SendRpcAsyncInternal<TResponse>(cmd, payload, BucketGroup.Guild, (int)bucket, guildId, evt, options);
|
||||||
|
private async Task<TResponse> SendRpcAsyncInternal<TResponse>(string cmd, object payload, BucketGroup group, int bucketId, ulong guildId,
|
||||||
|
Optional<string> evt, RequestOptions options)
|
||||||
|
where TResponse : class
|
||||||
{
|
{
|
||||||
//TODO: Add Nonce to pair sent requests with responses
|
|
||||||
byte[] bytes = null;
|
byte[] bytes = null;
|
||||||
payload = new RpcMessage { Cmd = cmd, Args = payload, Nonce = Guid.NewGuid().ToString() };
|
var guid = Guid.NewGuid();
|
||||||
|
payload = new RpcMessage { Cmd = cmd, Event = evt, Args = payload, Nonce = guid };
|
||||||
if (payload != null)
|
if (payload != null)
|
||||||
bytes = Encoding.UTF8.GetBytes(SerializeJson(payload));
|
{
|
||||||
|
var json = SerializeJson(payload);
|
||||||
|
bytes = Encoding.UTF8.GetBytes(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
var requestTracker = new RpcRequest<TResponse>(options);
|
||||||
|
_requests[guid] = requestTracker;
|
||||||
|
|
||||||
await _requestQueue.SendAsync(new WebSocketRequest(_webSocketClient, bytes, true, options), group, bucketId, guildId).ConfigureAwait(false);
|
await _requestQueue.SendAsync(new WebSocketRequest(_webSocketClient, bytes, true, options), group, bucketId, guildId).ConfigureAwait(false);
|
||||||
await _sentRpcMessageEvent.InvokeAsync(cmd).ConfigureAwait(false);
|
await _sentRpcMessageEvent.InvokeAsync(cmd).ConfigureAwait(false);
|
||||||
|
return await requestTracker.Promise.Task.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Rpc
|
//Rpc
|
||||||
public async Task SendAuthenticateAsync(RequestOptions options = null)
|
public async Task<AuthenticateResponse> SendAuthenticateAsync(RequestOptions options = null)
|
||||||
{
|
{
|
||||||
var msg = new AuthenticateParams()
|
var msg = new AuthenticateParams()
|
||||||
{
|
{
|
||||||
AccessToken = _authToken
|
AccessToken = _authToken
|
||||||
};
|
};
|
||||||
await SendRpcAsync("AUTHENTICATE", msg, options: options).ConfigureAwait(false);
|
return await SendRpcAsync<AuthenticateResponse>("AUTHENTICATE", msg, options: options).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
public async Task SendAuthorizeAsync(string[] scopes, RequestOptions options = null)
|
public async Task<AuthorizeResponse> SendAuthorizeAsync(string[] scopes, RequestOptions options = null)
|
||||||
{
|
{
|
||||||
var msg = new AuthorizeParams()
|
var msg = new AuthorizeParams()
|
||||||
{
|
{
|
||||||
ClientId = _clientId,
|
ClientId = _clientId,
|
||||||
Scopes = scopes
|
Scopes = scopes
|
||||||
};
|
};
|
||||||
await SendRpcAsync("AUTHORIZE", msg, options: options).ConfigureAwait(false);
|
if (options == null)
|
||||||
|
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<AuthorizeResponse>("AUTHORIZE", msg, options: options).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<GetGuildsResponse> SendGetGuildsAsync(RequestOptions options = null)
|
||||||
|
{
|
||||||
|
return await SendRpcAsync<GetGuildsResponse>("GET_GUILDS", null, options: options).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
public async Task<RpcGuild> SendGetGuildAsync(ulong guildId, RequestOptions options = null)
|
||||||
|
{
|
||||||
|
var msg = new GetGuildParams
|
||||||
|
{
|
||||||
|
GuildId = guildId
|
||||||
|
};
|
||||||
|
return await SendRpcAsync<RpcGuild>("GET_GUILD", msg, options: options).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
public async Task<GetChannelsResponse> SendGetChannelsAsync(ulong guildId, RequestOptions options = null)
|
||||||
|
{
|
||||||
|
var msg = new GetChannelsParams
|
||||||
|
{
|
||||||
|
GuildId = guildId
|
||||||
|
};
|
||||||
|
return await SendRpcAsync<GetChannelsResponse>("GET_CHANNELS", msg, options: options).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
public async Task<RpcChannel> SendGetChannelAsync(ulong channelId, RequestOptions options = null)
|
||||||
|
{
|
||||||
|
var msg = new GetChannelParams
|
||||||
|
{
|
||||||
|
ChannelId = channelId
|
||||||
|
};
|
||||||
|
return await SendRpcAsync<RpcChannel>("GET_CHANNEL", msg, options: options).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SetLocalVolumeResponse> SendSetLocalVolumeAsync(int volume, RequestOptions options = null)
|
||||||
|
{
|
||||||
|
var msg = new SetLocalVolumeParams
|
||||||
|
{
|
||||||
|
Volume = volume
|
||||||
|
};
|
||||||
|
return await SendRpcAsync<SetLocalVolumeResponse>("SET_LOCAL_VOLUME", msg, options: options).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
public async Task<RpcChannel> SendSelectVoiceChannelAsync(ulong channelId, RequestOptions options = null)
|
||||||
|
{
|
||||||
|
var msg = new SelectVoiceChannelParams
|
||||||
|
{
|
||||||
|
ChannelId = channelId
|
||||||
|
};
|
||||||
|
return await SendRpcAsync<RpcChannel>("SELECT_VOICE_CHANNEL", msg, options: options).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SubscriptionResponse> SendChannelSubscribeAsync(string evt, ulong channelId, RequestOptions options = null)
|
||||||
|
{
|
||||||
|
var msg = new ChannelSubscriptionParams
|
||||||
|
{
|
||||||
|
ChannelId = channelId
|
||||||
|
};
|
||||||
|
return await SendRpcAsync<SubscriptionResponse>("SUBSCRIBE", msg, evt: evt, options: options).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
public async Task<SubscriptionResponse> SendChannelUnsubscribeAsync(string evt, ulong channelId, RequestOptions options = null)
|
||||||
|
{
|
||||||
|
var msg = new ChannelSubscriptionParams
|
||||||
|
{
|
||||||
|
ChannelId = channelId
|
||||||
|
};
|
||||||
|
return await SendRpcAsync<SubscriptionResponse>("UNSUBSCRIBE", msg, evt: evt, options: options).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SubscriptionResponse> SendGuildSubscribeAsync(string evt, ulong guildId, RequestOptions options = null)
|
||||||
|
{
|
||||||
|
var msg = new GuildSubscriptionParams
|
||||||
|
{
|
||||||
|
GuildId = guildId
|
||||||
|
};
|
||||||
|
return await SendRpcAsync<SubscriptionResponse>("SUBSCRIBE", msg, evt: evt, options: options).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
public async Task<SubscriptionResponse> SendGuildUnsubscribeAsync(string evt, ulong guildId, RequestOptions options = null)
|
||||||
|
{
|
||||||
|
var msg = new GuildSubscriptionParams
|
||||||
|
{
|
||||||
|
GuildId = guildId
|
||||||
|
};
|
||||||
|
return await SendRpcAsync<SubscriptionResponse>("UNSUBSCRIBE", msg, evt: evt, options: options).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ProcessMessage(RpcMessage msg)
|
||||||
|
{
|
||||||
|
RpcRequest requestTracker;
|
||||||
|
if (_requests.TryGetValue(msg.Nonce.Value.Value, out requestTracker))
|
||||||
|
{
|
||||||
|
if (msg.Event.GetValueOrDefault("") == "ERROR")
|
||||||
|
{
|
||||||
|
var _ = requestTracker.SetExceptionAsync(msg.Data.GetValueOrDefault() as JToken, _serializer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var _ = requestTracker.SetResultAsync(msg.Data.GetValueOrDefault() as JToken, _serializer);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Helpers
|
//Helpers
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace Discord.API.Rpc
|
|||||||
[JsonProperty("id")]
|
[JsonProperty("id")]
|
||||||
public ulong Id { get; set; }
|
public ulong Id { get; set; }
|
||||||
[JsonProperty("rpc_origins")]
|
[JsonProperty("rpc_origins")]
|
||||||
public string RpcOrigins { get; set; }
|
public string[] RpcOrigins { get; set; }
|
||||||
[JsonProperty("name")]
|
[JsonProperty("name")]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System;
|
|||||||
|
|
||||||
namespace Discord.API.Rpc
|
namespace Discord.API.Rpc
|
||||||
{
|
{
|
||||||
public class AuthenticateEvent
|
public class AuthenticateResponse
|
||||||
{
|
{
|
||||||
[JsonProperty("application")]
|
[JsonProperty("application")]
|
||||||
public Application Application { get; set; }
|
public Application Application { get; set; }
|
||||||
@@ -3,7 +3,7 @@ using System;
|
|||||||
|
|
||||||
namespace Discord.API.Rpc
|
namespace Discord.API.Rpc
|
||||||
{
|
{
|
||||||
public class AuthorizeEvent
|
public class AuthorizeResponse
|
||||||
{
|
{
|
||||||
[JsonProperty("code")]
|
[JsonProperty("code")]
|
||||||
public string Code { get; set; }
|
public string Code { get; set; }
|
||||||
10
src/Discord.Net/API/Rpc/ChannelSubscriptionParams.cs
Normal file
10
src/Discord.Net/API/Rpc/ChannelSubscriptionParams.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class ChannelSubscriptionParams
|
||||||
|
{
|
||||||
|
[JsonProperty("channel_id")]
|
||||||
|
public ulong ChannelId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Discord.Net/API/Rpc/GetChannelParams.cs
Normal file
10
src/Discord.Net/API/Rpc/GetChannelParams.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class GetChannelParams
|
||||||
|
{
|
||||||
|
[JsonProperty("channel_id")]
|
||||||
|
public ulong ChannelId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Discord.Net/API/Rpc/GetChannelsParams.cs
Normal file
10
src/Discord.Net/API/Rpc/GetChannelsParams.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class GetChannelsParams
|
||||||
|
{
|
||||||
|
[JsonProperty("guild_id")]
|
||||||
|
public ulong GuildId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Discord.Net/API/Rpc/GetChannelsResponse.cs
Normal file
10
src/Discord.Net/API/Rpc/GetChannelsResponse.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class GetChannelsResponse
|
||||||
|
{
|
||||||
|
[JsonProperty("channels")]
|
||||||
|
public RpcChannel[] Channels { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Discord.Net/API/Rpc/GetGuildParams.cs
Normal file
10
src/Discord.Net/API/Rpc/GetGuildParams.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class GetGuildParams
|
||||||
|
{
|
||||||
|
[JsonProperty("guild_id")]
|
||||||
|
public ulong GuildId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/Discord.Net/API/Rpc/GetGuildsParams.cs
Normal file
11
src/Discord.Net/API/Rpc/GetGuildsParams.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class GetGuildsParams
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Discord.Net/API/Rpc/GetGuildsResponse.cs
Normal file
10
src/Discord.Net/API/Rpc/GetGuildsResponse.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class GetGuildsResponse
|
||||||
|
{
|
||||||
|
[JsonProperty("guilds")]
|
||||||
|
public RpcUserGuild[] Guilds { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Discord.Net/API/Rpc/GuildSubscriptionParams.cs
Normal file
10
src/Discord.Net/API/Rpc/GuildSubscriptionParams.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class GuildSubscriptionParams
|
||||||
|
{
|
||||||
|
[JsonProperty("guild_id")]
|
||||||
|
public ulong GuildId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/Discord.Net/API/Rpc/MessageEvent.cs
Normal file
11
src/Discord.Net/API/Rpc/MessageEvent.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class MessageEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Discord.Net/API/Rpc/RpcChannel.cs
Normal file
10
src/Discord.Net/API/Rpc/RpcChannel.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class RpcChannel : Channel
|
||||||
|
{
|
||||||
|
[JsonProperty("voice_states")]
|
||||||
|
public VoiceState[] VoiceStates { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/Discord.Net/API/Rpc/RpcGuild.cs
Normal file
12
src/Discord.Net/API/Rpc/RpcGuild.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class RpcGuild : Guild
|
||||||
|
{
|
||||||
|
[JsonProperty("online")]
|
||||||
|
public int Online { get; set; }
|
||||||
|
[JsonProperty("members")]
|
||||||
|
public GuildMember[] Members { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Discord.API.Rpc
|
namespace Discord.API.Rpc
|
||||||
{
|
{
|
||||||
@@ -7,11 +8,11 @@ namespace Discord.API.Rpc
|
|||||||
[JsonProperty("cmd")]
|
[JsonProperty("cmd")]
|
||||||
public string Cmd { get; set; }
|
public string Cmd { get; set; }
|
||||||
[JsonProperty("nonce")]
|
[JsonProperty("nonce")]
|
||||||
public string Nonce { get; set; }
|
public Optional<Guid?> Nonce { get; set; }
|
||||||
[JsonProperty("evt")]
|
[JsonProperty("evt")]
|
||||||
public string Event { get; set; }
|
public Optional<string> Event { get; set; }
|
||||||
[JsonProperty("data")]
|
[JsonProperty("data")]
|
||||||
public object Data { get; set; }
|
public Optional<object> Data { get; set; }
|
||||||
[JsonProperty("args")]
|
[JsonProperty("args")]
|
||||||
public object Args { get; set; }
|
public object Args { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/Discord.Net/API/Rpc/RpcUserGuild.cs
Normal file
12
src/Discord.Net/API/Rpc/RpcUserGuild.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class RpcUserGuild
|
||||||
|
{
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public ulong Id { get; set; }
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Discord.Net/API/Rpc/SelectVoiceChannelParams.cs
Normal file
10
src/Discord.Net/API/Rpc/SelectVoiceChannelParams.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class SelectVoiceChannelParams
|
||||||
|
{
|
||||||
|
[JsonProperty("channel_id")]
|
||||||
|
public ulong? ChannelId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Discord.Net/API/Rpc/SetLocalVolumeParams.cs
Normal file
10
src/Discord.Net/API/Rpc/SetLocalVolumeParams.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class SetLocalVolumeParams
|
||||||
|
{
|
||||||
|
[JsonProperty("volume")]
|
||||||
|
public int Volume { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/Discord.Net/API/Rpc/SetLocalVolumeResponse.cs
Normal file
12
src/Discord.Net/API/Rpc/SetLocalVolumeResponse.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class SetLocalVolumeResponse
|
||||||
|
{
|
||||||
|
[JsonProperty("user_id")]
|
||||||
|
public ulong UserId { get; set; }
|
||||||
|
[JsonProperty("volume")]
|
||||||
|
public int Volume { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/Discord.Net/API/Rpc/SpeakingEvent.cs
Normal file
11
src/Discord.Net/API/Rpc/SpeakingEvent.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class SpeakingEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Discord.Net/API/Rpc/SubscriptionResponse.cs
Normal file
10
src/Discord.Net/API/Rpc/SubscriptionResponse.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class SubscriptionResponse
|
||||||
|
{
|
||||||
|
[JsonProperty("evt")]
|
||||||
|
public string Event { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/Discord.Net/API/Rpc/VoiceStateEvent.cs
Normal file
11
src/Discord.Net/API/Rpc/VoiceStateEvent.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Discord.API.Rpc
|
||||||
|
{
|
||||||
|
public class VoiceStateEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -314,7 +314,7 @@ namespace Discord
|
|||||||
private async Task WriteInitialLog()
|
private async Task WriteInitialLog()
|
||||||
{
|
{
|
||||||
if (this is DiscordSocketClient)
|
if (this is DiscordSocketClient)
|
||||||
await _clientLogger.InfoAsync($"DiscordSocketClient v{DiscordConfig.Version} (API v{DiscordConfig.APIVersion}, {DiscordConfig.GatewayEncoding})").ConfigureAwait(false);
|
await _clientLogger.InfoAsync($"DiscordSocketClient v{DiscordConfig.Version} (API v{DiscordConfig.APIVersion}, {DiscordSocketConfig.GatewayEncoding})").ConfigureAwait(false);
|
||||||
else if (this is DiscordRpcClient)
|
else if (this is DiscordRpcClient)
|
||||||
await _clientLogger.InfoAsync($"DiscordRpcClient v{DiscordConfig.Version} (API v{DiscordConfig.APIVersion}, RPC API v{DiscordRpcConfig.RpcAPIVersion})").ConfigureAwait(false);
|
await _clientLogger.InfoAsync($"DiscordRpcClient v{DiscordConfig.Version} (API v{DiscordConfig.APIVersion}, RPC API v{DiscordRpcConfig.RpcAPIVersion})").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using Discord.Net.Converters;
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -48,7 +47,7 @@ namespace Discord
|
|||||||
public ConnectionState ConnectionState { get; private set; }
|
public ConnectionState ConnectionState { get; private set; }
|
||||||
|
|
||||||
/// <summary> Creates a new RPC discord client. </summary>
|
/// <summary> Creates a new RPC discord client. </summary>
|
||||||
public DiscordRpcClient(string clientId) : this(new DiscordRpcConfig(clientId)) { }
|
public DiscordRpcClient(string clientId, string origin) : this(new DiscordRpcConfig(clientId, origin)) { }
|
||||||
/// <summary> Creates a new RPC discord client. </summary>
|
/// <summary> Creates a new RPC discord client. </summary>
|
||||||
public DiscordRpcClient(DiscordRpcConfig config)
|
public DiscordRpcClient(DiscordRpcConfig config)
|
||||||
{
|
{
|
||||||
@@ -67,7 +66,7 @@ namespace Discord
|
|||||||
e.ErrorContext.Handled = true;
|
e.ErrorContext.Handled = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
ApiClient = new API.DiscordRpcApiClient(config.ClientId, config.WebSocketProvider);
|
ApiClient = new API.DiscordRpcApiClient(config.ClientId, config.Origin, config.WebSocketProvider);
|
||||||
ApiClient.SentRpcMessage += async opCode => await _rpcLogger.DebugAsync($"Sent {opCode}").ConfigureAwait(false);
|
ApiClient.SentRpcMessage += async opCode => await _rpcLogger.DebugAsync($"Sent {opCode}").ConfigureAwait(false);
|
||||||
ApiClient.ReceivedRpcEvent += ProcessMessageAsync;
|
ApiClient.ReceivedRpcEvent += ProcessMessageAsync;
|
||||||
ApiClient.Disconnected += async ex =>
|
ApiClient.Disconnected += async ex =>
|
||||||
@@ -198,11 +197,6 @@ namespace Discord
|
|||||||
await ApiClient.ConnectAsync().ConfigureAwait(false);
|
await ApiClient.ConnectAsync().ConfigureAwait(false);
|
||||||
await _connectedEvent.InvokeAsync().ConfigureAwait(false);
|
await _connectedEvent.InvokeAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
/*if (_sessionId != null)
|
|
||||||
await ApiClient.SendResumeAsync(_sessionId, _lastSeq).ConfigureAwait(false);
|
|
||||||
else
|
|
||||||
await ApiClient.SendIdentifyAsync().ConfigureAwait(false);*/
|
|
||||||
|
|
||||||
await _connectTask.Task.ConfigureAwait(false);
|
await _connectTask.Task.ConfigureAwait(false);
|
||||||
|
|
||||||
ConnectionState = ConnectionState.Connected;
|
ConnectionState = ConnectionState.Connected;
|
||||||
@@ -301,25 +295,40 @@ namespace Discord
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessMessageAsync(string cmd, string evnt, object payload, string nonce)
|
private async Task ProcessMessageAsync(string cmd, Optional<string> evnt, Optional<object> payload)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
case "DISPATCH":
|
case "DISPATCH":
|
||||||
switch (evnt)
|
switch (evnt.Value)
|
||||||
{
|
{
|
||||||
//Connection
|
//Connection
|
||||||
case "READY":
|
case "READY":
|
||||||
{
|
{
|
||||||
await _rpcLogger.DebugAsync("Received Dispatch (READY)").ConfigureAwait(false);
|
await _rpcLogger.DebugAsync("Received Dispatch (READY)").ConfigureAwait(false);
|
||||||
var data = (payload as JToken).ToObject<ReadyEvent>(_serializer);
|
var data = (payload.Value as JToken).ToObject<ReadyEvent>(_serializer);
|
||||||
|
var cancelToken = _cancelToken;
|
||||||
|
|
||||||
if (_scopes != null)
|
var _ = Task.Run(async () =>
|
||||||
await ApiClient.SendAuthorizeAsync(_scopes).ConfigureAwait(false); //No bearer
|
{
|
||||||
else
|
RequestOptions options = new RequestOptions
|
||||||
await ApiClient.SendAuthenticateAsync().ConfigureAwait(false); //Has bearer
|
{
|
||||||
|
//CancellationToken = cancelToken //TODO: Implement
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_scopes != null) //No bearer
|
||||||
|
{
|
||||||
|
var authorizeData = await ApiClient.SendAuthorizeAsync(_scopes, options).ConfigureAwait(false);
|
||||||
|
await ApiClient.LoginAsync(TokenType.Bearer, authorizeData.Code, options).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var authenticateData = await ApiClient.SendAuthenticateAsync(options).ConfigureAwait(false); //Has bearer
|
||||||
|
|
||||||
|
var __ = _connectTask.TrySetResultAsync(true); //Signal the .Connect() call to complete
|
||||||
|
await _rpcLogger.InfoAsync("Ready").ConfigureAwait(false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -329,32 +338,15 @@ namespace Discord
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "AUTHORIZE":
|
|
||||||
{
|
|
||||||
await _rpcLogger.DebugAsync("Received AUTHORIZE").ConfigureAwait(false);
|
|
||||||
var data = (payload as JToken).ToObject<AuthorizeEvent>(_serializer);
|
|
||||||
await ApiClient.LoginAsync(TokenType.Bearer, data.Code).ConfigureAwait(false);
|
|
||||||
await ApiClient.SendAuthenticateAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "AUTHENTICATE":
|
|
||||||
{
|
|
||||||
await _rpcLogger.DebugAsync("Received AUTHENTICATE").ConfigureAwait(false);
|
|
||||||
var data = (payload as JToken).ToObject<AuthenticateEvent>(_serializer);
|
|
||||||
|
|
||||||
var _ = _connectTask.TrySetResultAsync(true); //Signal the .Connect() call to complete
|
/*default:
|
||||||
await _rpcLogger.InfoAsync("Ready").ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
await _rpcLogger.WarningAsync($"Unknown OpCode ({cmd})").ConfigureAwait(false);
|
await _rpcLogger.WarningAsync($"Unknown OpCode ({cmd})").ConfigureAwait(false);
|
||||||
return;
|
return;*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await _rpcLogger.ErrorAsync($"Error handling {cmd}{(evnt != null ? $" ({evnt})" : "")}", ex).ConfigureAwait(false);
|
await _rpcLogger.ErrorAsync($"Error handling {cmd}{(evnt.IsSpecified ? $" ({evnt})" : "")}", ex).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,16 @@ namespace Discord
|
|||||||
public const int PortRangeStart = 6463;
|
public const int PortRangeStart = 6463;
|
||||||
public const int PortRangeEnd = 6472;
|
public const int PortRangeEnd = 6472;
|
||||||
|
|
||||||
public DiscordRpcConfig(string clientId)
|
public DiscordRpcConfig(string clientId, string origin)
|
||||||
{
|
{
|
||||||
ClientId = clientId;
|
ClientId = clientId;
|
||||||
|
Origin = origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Gets or sets the Discord client/application id used for this RPC connection. </summary>
|
/// <summary> Gets or sets the Discord client/application id used for this RPC connection. </summary>
|
||||||
public string ClientId { get; set; }
|
public string ClientId { get; set; }
|
||||||
|
/// <summary> Gets or sets the origin used for this RPC connection. </summary>
|
||||||
|
public string Origin { get; set; }
|
||||||
|
|
||||||
/// <summary> Gets or sets the provider used to generate new websocket connections. </summary>
|
/// <summary> Gets or sets the provider used to generate new websocket connections. </summary>
|
||||||
public WebSocketProvider WebSocketProvider { get; set; } = () => new DefaultWebSocketClient();
|
public WebSocketProvider WebSocketProvider { get; set; } = () => new DefaultWebSocketClient();
|
||||||
|
|||||||
8
src/Discord.Net/Entities/Rpc/IRemoteUserGuild.cs
Normal file
8
src/Discord.Net/Entities/Rpc/IRemoteUserGuild.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Discord.Entities.Rpc
|
||||||
|
{
|
||||||
|
public interface IRemoteUserGuild : ISnowflakeEntity
|
||||||
|
{
|
||||||
|
/// <summary> Gets the name of this guild. </summary>
|
||||||
|
string Name { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/Discord.Net/Entities/Rpc/RemoteUserGuild.cs
Normal file
29
src/Discord.Net/Entities/Rpc/RemoteUserGuild.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using Model = Discord.API.Rpc.RpcUserGuild;
|
||||||
|
|
||||||
|
namespace Discord.Entities.Rpc
|
||||||
|
{
|
||||||
|
internal class RemoteUserGuild : IRemoteUserGuild, ISnowflakeEntity
|
||||||
|
{
|
||||||
|
public ulong Id { get; }
|
||||||
|
public DiscordRestClient Discord { get; }
|
||||||
|
public string Name { get; private set; }
|
||||||
|
|
||||||
|
public DateTimeOffset CreatedAt => DateTimeUtils.FromSnowflake(Id);
|
||||||
|
|
||||||
|
public RemoteUserGuild(DiscordRestClient discord, Model model)
|
||||||
|
{
|
||||||
|
Id = model.Id;
|
||||||
|
Discord = discord;
|
||||||
|
Update(model, UpdateSource.Creation);
|
||||||
|
}
|
||||||
|
public void Update(Model model, UpdateSource source)
|
||||||
|
{
|
||||||
|
if (source == UpdateSource.Rest) return;
|
||||||
|
|
||||||
|
Name = model.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IEntity<ulong>.IsAttached => false;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/Discord.Net/Net/RpcException.cs
Normal file
17
src/Discord.Net/Net/RpcException.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Discord
|
||||||
|
{
|
||||||
|
public class RpcException : Exception
|
||||||
|
{
|
||||||
|
public int ErrorCode { get; }
|
||||||
|
public string Reason { get; }
|
||||||
|
|
||||||
|
public RpcException(int errorCode, string reason = null)
|
||||||
|
: base($"The server sent error {errorCode}{(reason != null ? $": \"{reason}\"" : "")}")
|
||||||
|
{
|
||||||
|
ErrorCode = errorCode;
|
||||||
|
Reason = reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user