Added Proxy support, split DiscordWebSocketClientConfig into DiscordAPIClientConfig
This commit is contained in:
@@ -151,6 +151,9 @@
|
|||||||
<Compile Include="..\Discord.Net\DiscordAPIClient.cs">
|
<Compile Include="..\Discord.Net\DiscordAPIClient.cs">
|
||||||
<Link>DiscordAPIClient.cs</Link>
|
<Link>DiscordAPIClient.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\Discord.Net\DiscordAPIClientConfig.cs">
|
||||||
|
<Link>DiscordAPIClientConfig.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\Discord.Net\DiscordClient.API.cs">
|
<Compile Include="..\Discord.Net\DiscordClient.API.cs">
|
||||||
<Link>DiscordClient.API.cs</Link>
|
<Link>DiscordClient.API.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|||||||
@@ -11,12 +11,15 @@ namespace Discord
|
|||||||
/// <summary> A lightweight wrapper around the Discord API. </summary>
|
/// <summary> A lightweight wrapper around the Discord API. </summary>
|
||||||
public class DiscordAPIClient
|
public class DiscordAPIClient
|
||||||
{
|
{
|
||||||
|
private readonly DiscordAPIClientConfig _config;
|
||||||
|
|
||||||
internal RestClient RestClient => _rest;
|
internal RestClient RestClient => _rest;
|
||||||
private readonly 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;
|
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())
|
: base(config ?? new DiscordClientConfig())
|
||||||
{
|
{
|
||||||
_rand = new Random();
|
_rand = new Random();
|
||||||
_api = new DiscordAPIClient(_config.LogLevel, _config.UserAgent, _config.APITimeout);
|
_api = new DiscordAPIClient(_config);
|
||||||
if (Config.UseMessageQueue)
|
if (Config.UseMessageQueue)
|
||||||
_pendingMessages = new ConcurrentQueue<Message>();
|
_pendingMessages = new ConcurrentQueue<Message>();
|
||||||
if (Config.EnableVoiceMultiserver)
|
if (Config.EnableVoiceMultiserver)
|
||||||
@@ -765,7 +765,6 @@ namespace Discord
|
|||||||
{
|
{
|
||||||
var config = _config.Clone();
|
var config = _config.Clone();
|
||||||
config.LogLevel = _config.LogLevel;// (LogMessageSeverity)Math.Min((int)_config.LogLevel, (int)LogMessageSeverity.Warning);
|
config.LogLevel = _config.LogLevel;// (LogMessageSeverity)Math.Min((int)_config.LogLevel, (int)LogMessageSeverity.Warning);
|
||||||
config.EnableVoiceMultiserver = false;
|
|
||||||
config.VoiceOnly = true;
|
config.VoiceOnly = true;
|
||||||
config.VoiceClientId = unchecked(++_nextVoiceClientId);
|
config.VoiceClientId = unchecked(++_nextVoiceClientId);
|
||||||
return new DiscordWebSocketClient(config, serverId);
|
return new DiscordWebSocketClient(config, serverId);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
public new DiscordClientConfig Clone()
|
public new DiscordClientConfig Clone()
|
||||||
{
|
{
|
||||||
var config = this.MemberwiseClone() as DiscordClientConfig;
|
var config = MemberwiseClone() as DiscordClientConfig;
|
||||||
config._isLocked = false;
|
config._isLocked = false;
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,12 +12,8 @@ namespace Discord
|
|||||||
Both = Outgoing | Incoming
|
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>
|
/// <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); } }
|
public int ConnectionTimeout { get { return _connectionTimeout; } set { SetValue(ref _connectionTimeout, value); } }
|
||||||
private int _connectionTimeout = 30000;
|
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>
|
/// <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); } }
|
public int FailedReconnectDelay { get { return _failedReconnectDelay; } set { SetValue(ref _failedReconnectDelay, value); } }
|
||||||
private int _failedReconnectDelay = 10000;
|
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>
|
/// <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); } }
|
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 virtual bool EnableVoice => _voiceMode != DiscordVoiceMode.Disabled;
|
||||||
|
|
||||||
internal string UserAgent
|
public new DiscordWebSocketClientConfig Clone()
|
||||||
{
|
{
|
||||||
get
|
var config = MemberwiseClone() as DiscordWebSocketClientConfig;
|
||||||
{
|
|
||||||
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;
|
|
||||||
config._isLocked = false;
|
config._isLocked = false;
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Discord.API;
|
using Discord.API;
|
||||||
using RestSharp;
|
using RestSharp;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -11,18 +12,19 @@ namespace Discord.Net
|
|||||||
{
|
{
|
||||||
private RestSharp.RestClient _client;
|
private RestSharp.RestClient _client;
|
||||||
|
|
||||||
partial void Initialize(string userAgent, int timeout)
|
partial void Initialize()
|
||||||
{
|
{
|
||||||
_client = new RestSharp.RestClient(Endpoints.BaseApi)
|
_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.RemoveDefaultParameter("Accept");
|
||||||
_client.AddDefaultHeader("accept", "*/*");
|
_client.AddDefaultHeader("accept", "*/*");
|
||||||
_client.AddDefaultHeader("accept-encoding", "gzip,deflate");
|
_client.AddDefaultHeader("accept-encoding", "gzip,deflate");
|
||||||
_client.UserAgent = userAgent;
|
}
|
||||||
_client.ReadWriteTimeout = timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void SetToken(string token)
|
internal void SetToken(string token)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ namespace Discord.Net
|
|||||||
{
|
{
|
||||||
internal partial class RestClient
|
internal partial class RestClient
|
||||||
{
|
{
|
||||||
private readonly LogMessageSeverity _logLevel;
|
private readonly DiscordAPIClientConfig _config;
|
||||||
private CancellationToken _cancelToken;
|
private CancellationToken _cancelToken;
|
||||||
|
|
||||||
public RestClient(LogMessageSeverity logLevel, string userAgent, int timeout)
|
public RestClient(DiscordAPIClientConfig config)
|
||||||
{
|
{
|
||||||
_logLevel = logLevel;
|
_config = config;
|
||||||
Initialize(userAgent, timeout);
|
Initialize();
|
||||||
}
|
}
|
||||||
partial void Initialize(string userAgent, int timeout);
|
partial void Initialize();
|
||||||
|
|
||||||
//DELETE
|
//DELETE
|
||||||
private static readonly HttpMethod _delete = HttpMethod.Delete;
|
private static readonly HttpMethod _delete = HttpMethod.Delete;
|
||||||
@@ -90,7 +90,7 @@ namespace Discord.Net
|
|||||||
if (content != null)
|
if (content != null)
|
||||||
requestJson = JsonConvert.SerializeObject(content);
|
requestJson = JsonConvert.SerializeObject(content);
|
||||||
|
|
||||||
if (_logLevel >= LogMessageSeverity.Verbose)
|
if (_config.LogLevel >= LogMessageSeverity.Verbose)
|
||||||
stopwatch = Stopwatch.StartNew();
|
stopwatch = Stopwatch.StartNew();
|
||||||
|
|
||||||
string responseJson = await SendInternal(method, path, requestJson, _cancelToken).ConfigureAwait(false);
|
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.");
|
throw new Exception("API check failed: Response is not empty.");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (_logLevel >= LogMessageSeverity.Verbose)
|
if (_config.LogLevel >= LogMessageSeverity.Verbose)
|
||||||
{
|
{
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
if (content != null && _logLevel >= LogMessageSeverity.Debug)
|
if (content != null && _config.LogLevel >= LogMessageSeverity.Debug)
|
||||||
{
|
{
|
||||||
if (path.StartsWith(Endpoints.Auth))
|
if (path.StartsWith(Endpoints.Auth))
|
||||||
RaiseOnRequest(method, path, "[Hidden]", stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerMillisecond);
|
RaiseOnRequest(method, path, "[Hidden]", stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerMillisecond);
|
||||||
@@ -129,7 +129,7 @@ namespace Discord.Net
|
|||||||
{
|
{
|
||||||
Stopwatch stopwatch = null;
|
Stopwatch stopwatch = null;
|
||||||
|
|
||||||
if (_logLevel >= LogMessageSeverity.Verbose)
|
if (_config.LogLevel >= LogMessageSeverity.Verbose)
|
||||||
stopwatch = Stopwatch.StartNew();
|
stopwatch = Stopwatch.StartNew();
|
||||||
|
|
||||||
string responseJson = await SendFileInternal(method, path, filePath, _cancelToken).ConfigureAwait(false);
|
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.");
|
throw new Exception("API check failed: Response is not empty.");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (_logLevel >= LogMessageSeverity.Verbose)
|
if (_config.LogLevel >= LogMessageSeverity.Verbose)
|
||||||
{
|
{
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
if (_logLevel >= LogMessageSeverity.Debug)
|
if (_config.LogLevel >= LogMessageSeverity.Debug)
|
||||||
RaiseOnRequest(method, path, filePath, stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerMillisecond);
|
RaiseOnRequest(method, path, filePath, stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerMillisecond);
|
||||||
else
|
else
|
||||||
RaiseOnRequest(method, path, null, stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerMillisecond);
|
RaiseOnRequest(method, path, null, stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerMillisecond);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using WSSharpNWebSocket = WebSocketSharp.WebSocket;
|
using WSSharpNWebSocket = WebSocketSharp.WebSocket;
|
||||||
@@ -9,9 +10,8 @@ namespace Discord.Net
|
|||||||
{
|
{
|
||||||
internal class WSSharpWebSocketEngine : IWebSocketEngine
|
internal class WSSharpWebSocketEngine : IWebSocketEngine
|
||||||
{
|
{
|
||||||
|
private readonly DiscordWebSocketClientConfig _config;
|
||||||
private readonly ConcurrentQueue<string> _sendQueue;
|
private readonly ConcurrentQueue<string> _sendQueue;
|
||||||
private readonly int _sendInterval;
|
|
||||||
private readonly string _userAgent;
|
|
||||||
private readonly WebSocket _parent;
|
private readonly WebSocket _parent;
|
||||||
private WSSharpNWebSocket _webSocket;
|
private WSSharpNWebSocket _webSocket;
|
||||||
|
|
||||||
@@ -22,11 +22,10 @@ namespace Discord.Net
|
|||||||
ProcessMessage(this, new WebSocketMessageEventArgs(msg));
|
ProcessMessage(this, new WebSocketMessageEventArgs(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal WSSharpWebSocketEngine(WebSocket parent, string userAgent, int sendInterval)
|
internal WSSharpWebSocketEngine(WebSocket parent, DiscordWebSocketClientConfig config)
|
||||||
{
|
{
|
||||||
_parent = parent;
|
_parent = parent;
|
||||||
_userAgent = userAgent;
|
_config = config;
|
||||||
_sendInterval = sendInterval;
|
|
||||||
_sendQueue = new ConcurrentQueue<string>();
|
_sendQueue = new ConcurrentQueue<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +35,7 @@ namespace Discord.Net
|
|||||||
_webSocket.EmitOnPing = false;
|
_webSocket.EmitOnPing = false;
|
||||||
_webSocket.EnableRedirection = true;
|
_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.OnMessage += (s, e) => RaiseProcessMessage(e.Data);
|
||||||
_webSocket.OnError += async (s, e) =>
|
_webSocket.OnError += async (s, e) =>
|
||||||
{
|
{
|
||||||
@@ -77,6 +77,7 @@ namespace Discord.Net
|
|||||||
|
|
||||||
private Task SendAsync(CancellationToken cancelToken)
|
private Task SendAsync(CancellationToken cancelToken)
|
||||||
{
|
{
|
||||||
|
var sendInterval = _config.WebSocketInterval;
|
||||||
return Task.Run(async () =>
|
return Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -86,7 +87,7 @@ namespace Discord.Net
|
|||||||
string json;
|
string json;
|
||||||
while (_sendQueue.TryDequeue(out json))
|
while (_sendQueue.TryDequeue(out json))
|
||||||
_webSocket.Send(json);
|
_webSocket.Send(json);
|
||||||
await Task.Delay(_sendInterval, cancelToken).ConfigureAwait(false);
|
await Task.Delay(sendInterval, cancelToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException) { }
|
catch (OperationCanceledException) { }
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ namespace Discord.Net
|
|||||||
_cancelToken = new CancellationToken(true);
|
_cancelToken = new CancellationToken(true);
|
||||||
_connectedEvent = new ManualResetEventSlim(false);
|
_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) =>
|
_engine.ProcessMessage += async (s, e) =>
|
||||||
{
|
{
|
||||||
if (_logLevel >= LogMessageSeverity.Debug)
|
if (_logLevel >= LogMessageSeverity.Debug)
|
||||||
|
|||||||
Reference in New Issue
Block a user