diff --git a/src/Discord.Net.Net45/Discord.Net.csproj b/src/Discord.Net.Net45/Discord.Net.csproj
index 703014726..11f2c1766 100644
--- a/src/Discord.Net.Net45/Discord.Net.csproj
+++ b/src/Discord.Net.Net45/Discord.Net.csproj
@@ -151,6 +151,9 @@
DiscordAPIClient.cs
+
+ DiscordAPIClientConfig.cs
+
DiscordClient.API.cs
diff --git a/src/Discord.Net/DiscordAPIClient.cs b/src/Discord.Net/DiscordAPIClient.cs
index 81a50114e..975b9aa6d 100644
--- a/src/Discord.Net/DiscordAPIClient.cs
+++ b/src/Discord.Net/DiscordAPIClient.cs
@@ -11,12 +11,15 @@ namespace Discord
/// A lightweight wrapper around the Discord API.
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;
diff --git a/src/Discord.Net/DiscordAPIClientConfig.cs b/src/Discord.Net/DiscordAPIClientConfig.cs
new file mode 100644
index 000000000..0fde36c2c
--- /dev/null
+++ b/src/Discord.Net/DiscordAPIClientConfig.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Net;
+using System.Reflection;
+
+namespace Discord
+{
+ public class DiscordAPIClientConfig
+ {
+ /// 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.
+ public LogMessageSeverity LogLevel { get { return _logLevel; } set { SetValue(ref _logLevel, value); } }
+ private LogMessageSeverity _logLevel = LogMessageSeverity.Info;
+
+ /// Max time (in milliseconds) to wait for an API request to complete.
+ public int APITimeout { get { return _apiTimeout; } set { SetValue(ref _apiTimeout, value); } }
+ private int _apiTimeout = 10000;
+
+ /// The proxy to user for API and WebSocket connections.
+ public string ProxyUrl { get { return _proxyUrl; } set { SetValue(ref _proxyUrl, value); } }
+ private string _proxyUrl = null;
+ /// The credentials to use for this proxy.
+ 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(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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs
index d402ed573..8a2709a8d 100644
--- a/src/Discord.Net/DiscordClient.cs
+++ b/src/Discord.Net/DiscordClient.cs
@@ -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();
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);
diff --git a/src/Discord.Net/DiscordClientConfig.cs b/src/Discord.Net/DiscordClientConfig.cs
index 6396b5c82..e5f2cdbac 100644
--- a/src/Discord.Net/DiscordClientConfig.cs
+++ b/src/Discord.Net/DiscordClientConfig.cs
@@ -25,7 +25,7 @@
public new DiscordClientConfig Clone()
{
- var config = this.MemberwiseClone() as DiscordClientConfig;
+ var config = MemberwiseClone() as DiscordClientConfig;
config._isLocked = false;
return config;
}
diff --git a/src/Discord.Net/DiscordWebSocketClientConfig.cs b/src/Discord.Net/DiscordWebSocketClientConfig.cs
index b788b3a7b..601ad8c21 100644
--- a/src/Discord.Net/DiscordWebSocketClientConfig.cs
+++ b/src/Discord.Net/DiscordWebSocketClientConfig.cs
@@ -12,12 +12,8 @@ namespace Discord
Both = Outgoing | Incoming
}
- public class DiscordWebSocketClientConfig
+ public class DiscordWebSocketClientConfig : DiscordAPIClientConfig
{
- /// 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.
- public LogMessageSeverity LogLevel { get { return _logLevel; } set { SetValue(ref _logLevel, value); } }
- private LogMessageSeverity _logLevel = LogMessageSeverity.Info;
-
/// Max time in milliseconds to wait for DiscordClient to connect and initialize.
public int ConnectionTimeout { get { return _connectionTimeout; } set { SetValue(ref _connectionTimeout, value); } }
private int _connectionTimeout = 30000;
@@ -27,9 +23,6 @@ namespace Discord
/// Gets or sets the time (in milliseconds) to wait after an reconnect fails before retrying.
public int FailedReconnectDelay { get { return _failedReconnectDelay; } set { SetValue(ref _failedReconnectDelay, value); } }
private int _failedReconnectDelay = 10000;
- /// Max time (in milliseconds) to wait for an API request to complete.
- public int APITimeout { get { return _apiTimeout; } set { SetValue(ref _apiTimeout, value); } }
- private int _apiTimeout = 10000;
/// Gets or sets the time (in milliseconds) to wait when the websocket's message queue is empty before checking again.
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
- {
- 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(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()
+ public new DiscordWebSocketClientConfig Clone()
{
- var config = this.MemberwiseClone() as DiscordClientConfig;
+ var config = MemberwiseClone() as DiscordWebSocketClientConfig;
config._isLocked = false;
return config;
}
diff --git a/src/Discord.Net/Net/RestClient.SharpRest.cs b/src/Discord.Net/Net/RestClient.SharpRest.cs
index 31e4f4925..1a9955233 100644
--- a/src/Discord.Net/Net/RestClient.SharpRest.cs
+++ b/src/Discord.Net/Net/RestClient.SharpRest.cs
@@ -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)
{
diff --git a/src/Discord.Net/Net/RestClient.cs b/src/Discord.Net/Net/RestClient.cs
index c956728c9..e8fa94db7 100644
--- a/src/Discord.Net/Net/RestClient.cs
+++ b/src/Discord.Net/Net/RestClient.cs
@@ -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);
diff --git a/src/Discord.Net/Net/WebSocket.WebSocketSharp.cs b/src/Discord.Net/Net/WebSocket.WebSocketSharp.cs
index f245dd24e..7a0ac2c30 100644
--- a/src/Discord.Net/Net/WebSocket.WebSocketSharp.cs
+++ b/src/Discord.Net/Net/WebSocket.WebSocketSharp.cs
@@ -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 _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();
}
@@ -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) { }
diff --git a/src/Discord.Net/Net/WebSocket.cs b/src/Discord.Net/Net/WebSocket.cs
index 2bb8dfc71..75bfb136c 100644
--- a/src/Discord.Net/Net/WebSocket.cs
+++ b/src/Discord.Net/Net/WebSocket.cs
@@ -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)