Added Proxy support, split DiscordWebSocketClientConfig into DiscordAPIClientConfig
This commit is contained in:
@@ -151,6 +151,9 @@
|
||||
<Compile Include="..\Discord.Net\DiscordAPIClient.cs">
|
||||
<Link>DiscordAPIClient.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Discord.Net\DiscordAPIClientConfig.cs">
|
||||
<Link>DiscordAPIClientConfig.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Discord.Net\DiscordClient.API.cs">
|
||||
<Link>DiscordClient.API.cs</Link>
|
||||
</Compile>
|
||||
|
||||
@@ -11,12 +11,15 @@ namespace Discord
|
||||
/// <summary> A lightweight wrapper around the Discord API. </summary>
|
||||
public class DiscordAPIClient
|
||||
{
|
||||
private readonly DiscordAPIClientConfig _config;
|
||||
|
||||
internal RestClient RestClient => _rest;
|
||||
private readonly RestClient _rest;
|
||||
|
||||
public DiscordAPIClient(LogMessageSeverity logLevel, string userAgent, int timeout)
|
||||
public DiscordAPIClient(DiscordAPIClientConfig config = null)
|
||||
{
|
||||
_rest = new RestClient(logLevel, userAgent, timeout);
|
||||
_config = config ?? new DiscordAPIClientConfig();
|
||||
_rest = new RestClient(_config);
|
||||
}
|
||||
|
||||
private string _token;
|
||||
|
||||
50
src/Discord.Net/DiscordAPIClientConfig.cs
Normal file
50
src/Discord.Net/DiscordAPIClientConfig.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
public class DiscordAPIClientConfig
|
||||
{
|
||||
/// <summary> Specifies the minimum log level severity that will be sent to the LogMessage event. Warning: setting this to debug will really hurt performance but should help investigate any internal issues. </summary>
|
||||
public LogMessageSeverity LogLevel { get { return _logLevel; } set { SetValue(ref _logLevel, value); } }
|
||||
private LogMessageSeverity _logLevel = LogMessageSeverity.Info;
|
||||
|
||||
/// <summary> Max time (in milliseconds) to wait for an API request to complete. </summary>
|
||||
public int APITimeout { get { return _apiTimeout; } set { SetValue(ref _apiTimeout, value); } }
|
||||
private int _apiTimeout = 10000;
|
||||
|
||||
/// <summary> The proxy to user for API and WebSocket connections. </summary>
|
||||
public string ProxyUrl { get { return _proxyUrl; } set { SetValue(ref _proxyUrl, value); } }
|
||||
private string _proxyUrl = null;
|
||||
/// <summary> The credentials to use for this proxy. </summary>
|
||||
public NetworkCredential ProxyCredentials { get { return _proxyCredentials; } set { SetValue(ref _proxyCredentials, value); } }
|
||||
private NetworkCredential _proxyCredentials = null;
|
||||
|
||||
internal string UserAgent
|
||||
{
|
||||
get
|
||||
{
|
||||
string version = typeof(DiscordClientConfig).GetTypeInfo().Assembly.GetName().Version.ToString(2);
|
||||
return $"Discord.Net/{version} (https://github.com/RogueException/Discord.Net)";
|
||||
}
|
||||
}
|
||||
|
||||
//Lock
|
||||
protected bool _isLocked;
|
||||
internal void Lock() { _isLocked = true; }
|
||||
protected void SetValue<T>(ref T storage, T value)
|
||||
{
|
||||
if (_isLocked)
|
||||
throw new InvalidOperationException("Unable to modify a discord client's configuration after it has been created.");
|
||||
storage = value;
|
||||
}
|
||||
|
||||
public DiscordAPIClientConfig Clone()
|
||||
{
|
||||
var config = MemberwiseClone() as DiscordAPIClientConfig;
|
||||
config._isLocked = false;
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ namespace Discord
|
||||
: base(config ?? new DiscordClientConfig())
|
||||
{
|
||||
_rand = new Random();
|
||||
_api = new DiscordAPIClient(_config.LogLevel, _config.UserAgent, _config.APITimeout);
|
||||
_api = new DiscordAPIClient(_config);
|
||||
if (Config.UseMessageQueue)
|
||||
_pendingMessages = new ConcurrentQueue<Message>();
|
||||
if (Config.EnableVoiceMultiserver)
|
||||
@@ -765,7 +765,6 @@ namespace Discord
|
||||
{
|
||||
var config = _config.Clone();
|
||||
config.LogLevel = _config.LogLevel;// (LogMessageSeverity)Math.Min((int)_config.LogLevel, (int)LogMessageSeverity.Warning);
|
||||
config.EnableVoiceMultiserver = false;
|
||||
config.VoiceOnly = true;
|
||||
config.VoiceClientId = unchecked(++_nextVoiceClientId);
|
||||
return new DiscordWebSocketClient(config, serverId);
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
public new DiscordClientConfig Clone()
|
||||
{
|
||||
var config = this.MemberwiseClone() as DiscordClientConfig;
|
||||
var config = MemberwiseClone() as DiscordClientConfig;
|
||||
config._isLocked = false;
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -12,12 +12,8 @@ namespace Discord
|
||||
Both = Outgoing | Incoming
|
||||
}
|
||||
|
||||
public class DiscordWebSocketClientConfig
|
||||
public class DiscordWebSocketClientConfig : DiscordAPIClientConfig
|
||||
{
|
||||
/// <summary> Specifies the minimum log level severity that will be sent to the LogMessage event. Warning: setting this to debug will really hurt performance but should help investigate any internal issues. </summary>
|
||||
public LogMessageSeverity LogLevel { get { return _logLevel; } set { SetValue(ref _logLevel, value); } }
|
||||
private LogMessageSeverity _logLevel = LogMessageSeverity.Info;
|
||||
|
||||
/// <summary> Max time in milliseconds to wait for DiscordClient to connect and initialize. </summary>
|
||||
public int ConnectionTimeout { get { return _connectionTimeout; } set { SetValue(ref _connectionTimeout, value); } }
|
||||
private int _connectionTimeout = 30000;
|
||||
@@ -27,9 +23,6 @@ namespace Discord
|
||||
/// <summary> Gets or sets the time (in milliseconds) to wait after an reconnect fails before retrying. </summary>
|
||||
public int FailedReconnectDelay { get { return _failedReconnectDelay; } set { SetValue(ref _failedReconnectDelay, value); } }
|
||||
private int _failedReconnectDelay = 10000;
|
||||
/// <summary> Max time (in milliseconds) to wait for an API request to complete. </summary>
|
||||
public int APITimeout { get { return _apiTimeout; } set { SetValue(ref _apiTimeout, value); } }
|
||||
private int _apiTimeout = 10000;
|
||||
|
||||
/// <summary> Gets or sets the time (in milliseconds) to wait when the websocket's message queue is empty before checking again. </summary>
|
||||
public int WebSocketInterval { get { return _webSocketInterval; } set { SetValue(ref _webSocketInterval, value); } }
|
||||
@@ -54,28 +47,9 @@ namespace Discord
|
||||
|
||||
internal virtual bool EnableVoice => _voiceMode != DiscordVoiceMode.Disabled;
|
||||
|
||||
internal string UserAgent
|
||||
public new DiscordWebSocketClientConfig Clone()
|
||||
{
|
||||
get
|
||||
{
|
||||
string version = typeof(DiscordClientConfig).GetTypeInfo().Assembly.GetName().Version.ToString(2);
|
||||
return $"Discord.Net/{version} (https://github.com/RogueException/Discord.Net)";
|
||||
}
|
||||
}
|
||||
|
||||
//Lock
|
||||
protected bool _isLocked;
|
||||
internal void Lock() { _isLocked = true; }
|
||||
protected void SetValue<T>(ref T storage, T value)
|
||||
{
|
||||
if (_isLocked)
|
||||
throw new InvalidOperationException("Unable to modify a discord client's configuration after it has been created.");
|
||||
storage = value;
|
||||
}
|
||||
|
||||
public DiscordClientConfig Clone()
|
||||
{
|
||||
var config = this.MemberwiseClone() as DiscordClientConfig;
|
||||
var config = MemberwiseClone() as DiscordWebSocketClientConfig;
|
||||
config._isLocked = false;
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Discord.API;
|
||||
using RestSharp;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -11,18 +12,19 @@ namespace Discord.Net
|
||||
{
|
||||
private RestSharp.RestClient _client;
|
||||
|
||||
partial void Initialize(string userAgent, int timeout)
|
||||
partial void Initialize()
|
||||
{
|
||||
_client = new RestSharp.RestClient(Endpoints.BaseApi)
|
||||
{
|
||||
PreAuthenticate = false
|
||||
PreAuthenticate = false,
|
||||
Proxy = new WebProxy(_config.ProxyUrl, true, new string[0], _config.ProxyCredentials),
|
||||
ReadWriteTimeout = _config.APITimeout,
|
||||
UserAgent = _config.UserAgent
|
||||
};
|
||||
_client.RemoveDefaultParameter("Accept");
|
||||
_client.AddDefaultHeader("accept", "*/*");
|
||||
_client.AddDefaultHeader("accept-encoding", "gzip,deflate");
|
||||
_client.UserAgent = userAgent;
|
||||
_client.ReadWriteTimeout = timeout;
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetToken(string token)
|
||||
{
|
||||
|
||||
@@ -10,15 +10,15 @@ namespace Discord.Net
|
||||
{
|
||||
internal partial class RestClient
|
||||
{
|
||||
private readonly LogMessageSeverity _logLevel;
|
||||
private readonly DiscordAPIClientConfig _config;
|
||||
private CancellationToken _cancelToken;
|
||||
|
||||
public RestClient(LogMessageSeverity logLevel, string userAgent, int timeout)
|
||||
public RestClient(DiscordAPIClientConfig config)
|
||||
{
|
||||
_logLevel = logLevel;
|
||||
Initialize(userAgent, timeout);
|
||||
_config = config;
|
||||
Initialize();
|
||||
}
|
||||
partial void Initialize(string userAgent, int timeout);
|
||||
partial void Initialize();
|
||||
|
||||
//DELETE
|
||||
private static readonly HttpMethod _delete = HttpMethod.Delete;
|
||||
@@ -90,7 +90,7 @@ namespace Discord.Net
|
||||
if (content != null)
|
||||
requestJson = JsonConvert.SerializeObject(content);
|
||||
|
||||
if (_logLevel >= LogMessageSeverity.Verbose)
|
||||
if (_config.LogLevel >= LogMessageSeverity.Verbose)
|
||||
stopwatch = Stopwatch.StartNew();
|
||||
|
||||
string responseJson = await SendInternal(method, path, requestJson, _cancelToken).ConfigureAwait(false);
|
||||
@@ -100,10 +100,10 @@ namespace Discord.Net
|
||||
throw new Exception("API check failed: Response is not empty.");
|
||||
#endif
|
||||
|
||||
if (_logLevel >= LogMessageSeverity.Verbose)
|
||||
if (_config.LogLevel >= LogMessageSeverity.Verbose)
|
||||
{
|
||||
stopwatch.Stop();
|
||||
if (content != null && _logLevel >= LogMessageSeverity.Debug)
|
||||
if (content != null && _config.LogLevel >= LogMessageSeverity.Debug)
|
||||
{
|
||||
if (path.StartsWith(Endpoints.Auth))
|
||||
RaiseOnRequest(method, path, "[Hidden]", stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerMillisecond);
|
||||
@@ -129,7 +129,7 @@ namespace Discord.Net
|
||||
{
|
||||
Stopwatch stopwatch = null;
|
||||
|
||||
if (_logLevel >= LogMessageSeverity.Verbose)
|
||||
if (_config.LogLevel >= LogMessageSeverity.Verbose)
|
||||
stopwatch = Stopwatch.StartNew();
|
||||
|
||||
string responseJson = await SendFileInternal(method, path, filePath, _cancelToken).ConfigureAwait(false);
|
||||
@@ -139,10 +139,10 @@ namespace Discord.Net
|
||||
throw new Exception("API check failed: Response is not empty.");
|
||||
#endif
|
||||
|
||||
if (_logLevel >= LogMessageSeverity.Verbose)
|
||||
if (_config.LogLevel >= LogMessageSeverity.Verbose)
|
||||
{
|
||||
stopwatch.Stop();
|
||||
if (_logLevel >= LogMessageSeverity.Debug)
|
||||
if (_config.LogLevel >= LogMessageSeverity.Debug)
|
||||
RaiseOnRequest(method, path, filePath, stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerMillisecond);
|
||||
else
|
||||
RaiseOnRequest(method, path, null, stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerMillisecond);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using WSSharpNWebSocket = WebSocketSharp.WebSocket;
|
||||
@@ -9,9 +10,8 @@ namespace Discord.Net
|
||||
{
|
||||
internal class WSSharpWebSocketEngine : IWebSocketEngine
|
||||
{
|
||||
private readonly DiscordWebSocketClientConfig _config;
|
||||
private readonly ConcurrentQueue<string> _sendQueue;
|
||||
private readonly int _sendInterval;
|
||||
private readonly string _userAgent;
|
||||
private readonly WebSocket _parent;
|
||||
private WSSharpNWebSocket _webSocket;
|
||||
|
||||
@@ -22,11 +22,10 @@ namespace Discord.Net
|
||||
ProcessMessage(this, new WebSocketMessageEventArgs(msg));
|
||||
}
|
||||
|
||||
internal WSSharpWebSocketEngine(WebSocket parent, string userAgent, int sendInterval)
|
||||
internal WSSharpWebSocketEngine(WebSocket parent, DiscordWebSocketClientConfig config)
|
||||
{
|
||||
_parent = parent;
|
||||
_userAgent = userAgent;
|
||||
_sendInterval = sendInterval;
|
||||
_config = config;
|
||||
_sendQueue = new ConcurrentQueue<string>();
|
||||
}
|
||||
|
||||
@@ -35,7 +34,8 @@ namespace Discord.Net
|
||||
_webSocket = new WSSharpNWebSocket(host);
|
||||
_webSocket.EmitOnPing = false;
|
||||
_webSocket.EnableRedirection = true;
|
||||
_webSocket.Compression = WebSocketSharp.CompressionMethod.None;
|
||||
_webSocket.Compression = WebSocketSharp.CompressionMethod.None;
|
||||
_webSocket.SetProxy(_config.ProxyUrl, _config.ProxyCredentials.UserName, _config.ProxyCredentials.Password);
|
||||
_webSocket.OnMessage += (s, e) => RaiseProcessMessage(e.Data);
|
||||
_webSocket.OnError += async (s, e) =>
|
||||
{
|
||||
@@ -77,6 +77,7 @@ namespace Discord.Net
|
||||
|
||||
private Task SendAsync(CancellationToken cancelToken)
|
||||
{
|
||||
var sendInterval = _config.WebSocketInterval;
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
@@ -86,7 +87,7 @@ namespace Discord.Net
|
||||
string json;
|
||||
while (_sendQueue.TryDequeue(out json))
|
||||
_webSocket.Send(json);
|
||||
await Task.Delay(_sendInterval, cancelToken).ConfigureAwait(false);
|
||||
await Task.Delay(sendInterval, cancelToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace Discord.Net
|
||||
_cancelToken = new CancellationToken(true);
|
||||
_connectedEvent = new ManualResetEventSlim(false);
|
||||
|
||||
_engine = new WSSharpWebSocketEngine(this, client.Config.UserAgent, client.Config.WebSocketInterval);
|
||||
_engine = new WSSharpWebSocketEngine(this, client.Config);
|
||||
_engine.ProcessMessage += async (s, e) =>
|
||||
{
|
||||
if (_logLevel >= LogMessageSeverity.Debug)
|
||||
|
||||
Reference in New Issue
Block a user