@@ -1,5 +1,5 @@ | |||
{ | |||
"version": "0.8.1-beta2", | |||
"version": "0.9.0-alpha1", | |||
"description": "A Discord.Net extension adding basic command support.", | |||
"authors": [ "RogueException" ], | |||
"tags": [ "discord", "discordapp" ], | |||
@@ -13,10 +13,10 @@ | |||
"warningsAsErrors": true | |||
}, | |||
"dependencies": { | |||
"Discord.Net": "0.8.1-beta2" | |||
"Discord.Net": "0.9.0-alpha1" | |||
}, | |||
"frameworks": { | |||
"net45": { }, | |||
"dotnet5.4": { } | |||
} | |||
"frameworks": { | |||
"net45": { }, | |||
"dotnet5.4": { } | |||
} | |||
} |
@@ -1,5 +1,5 @@ | |||
{ | |||
"version": "0.8.1-beta2", | |||
"version": "0.9.0-alpha1", | |||
"description": "A Discord.Net extension adding basic plugin support.", | |||
"authors": [ "RogueException" ], | |||
"tags": [ "discord", "discordapp" ], | |||
@@ -13,11 +13,11 @@ | |||
"warningsAsErrors": true | |||
}, | |||
"dependencies": { | |||
"Discord.Net": "0.8.1-beta2", | |||
"Discord.Net.Commands": "0.8.1-beta2" | |||
"Discord.Net": "0.9.0-alpha1", | |||
"Discord.Net.Commands": "0.9.0-alpha1" | |||
}, | |||
"frameworks": { | |||
"net45": { }, | |||
"dotnet5.4": { } | |||
} | |||
"frameworks": { | |||
"net45": { }, | |||
"dotnet5.4": { } | |||
} | |||
} |
@@ -16,14 +16,14 @@ namespace Discord | |||
{ | |||
public static readonly string Version = DiscordClient.Version; | |||
private readonly DiscordAPIClientConfig _config; | |||
private readonly DiscordConfig _config; | |||
internal RestClient RestClient => _rest; | |||
private readonly RestClient _rest; | |||
public DiscordAPIClient(DiscordAPIClientConfig config = null) | |||
public DiscordAPIClient(DiscordConfig config = null) | |||
{ | |||
_config = config ?? new DiscordAPIClientConfig(); | |||
_config = config ?? new DiscordConfig(); | |||
_rest = new RestClient(_config); | |||
} | |||
@@ -1,52 +0,0 @@ | |||
using System; | |||
using System.Net; | |||
namespace Discord | |||
{ | |||
public enum LogSeverity : byte | |||
{ | |||
Error = 1, | |||
Warning = 2, | |||
Info = 3, | |||
Verbose = 4, | |||
Debug = 5 | |||
} | |||
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 LogSeverity LogLevel { get { return _logLevel; } set { SetValue(ref _logLevel, value); } } | |||
private LogSeverity _logLevel = LogSeverity.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; | |||
//Internals | |||
internal static readonly string UserAgent = $"Discord.Net/{DiscordClient.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; | |||
} | |||
} | |||
} |
@@ -45,16 +45,6 @@ namespace Discord | |||
Channel = channel; | |||
} | |||
} | |||
public class UserIsSpeakingEventArgs : UserChannelEventArgs | |||
{ | |||
public bool IsSpeaking { get; } | |||
public UserIsSpeakingEventArgs(User user, Channel channel, bool isSpeaking) | |||
: base(user, channel) | |||
{ | |||
IsSpeaking = isSpeaking; | |||
} | |||
} | |||
public class BanEventArgs : EventArgs | |||
{ | |||
public long UserId { get; } | |||
@@ -70,8 +70,8 @@ namespace Discord | |||
private bool _wasDisconnectUnexpected; | |||
/// <summary> Returns the configuration object used to make this client. Note that this object cannot be edited directly - to change the configuration of this client, use the DiscordClient(DiscordClientConfig config) constructor. </summary> | |||
public DiscordClientConfig Config => _config; | |||
private readonly DiscordClientConfig _config; | |||
public DiscordConfig Config => _config; | |||
private readonly DiscordConfig _config; | |||
/// <summary> Returns the current connection state of this client. </summary> | |||
public DiscordClientState State => (DiscordClientState)_state; | |||
@@ -110,9 +110,9 @@ namespace Discord | |||
} | |||
/// <summary> Initializes a new instance of the DiscordClient class. </summary> | |||
public DiscordClient(DiscordClientConfig config = null) | |||
public DiscordClient(DiscordConfig config = null) | |||
{ | |||
_config = config ?? new DiscordClientConfig(); | |||
_config = config ?? new DiscordConfig(); | |||
_config.Lock(); | |||
_rand = new Random(); | |||
@@ -133,7 +133,7 @@ namespace Discord | |||
_cacheLock = new object(); | |||
_channels = new Channels(this, _cacheLock); | |||
_users = new Users(this, _cacheLock); | |||
_messages = new Messages(this, _cacheLock, Config.MessageCacheLength > 0); | |||
_messages = new Messages(this, _cacheLock, Config.MessageCacheSize > 0); | |||
_roles = new Roles(this, _cacheLock); | |||
_servers = new Servers(this, _cacheLock); | |||
_globalUsers = new GlobalUsers(this, _cacheLock); | |||
@@ -259,7 +259,8 @@ namespace Discord | |||
private DataWebSocket CreateWebSocket() | |||
{ | |||
var socket = new DataWebSocket(this, _log.CreateLogger("WebSocket")); | |||
var socket = new DataWebSocket(_config, _log.CreateLogger("WebSocket")); | |||
var settings = new JsonSerializerSettings(); | |||
socket.Connected += (s, e) => | |||
{ | |||
if (_state == (int)DiscordClientState.Connecting) | |||
@@ -290,7 +291,6 @@ namespace Discord | |||
try | |||
{ | |||
var response = await _api.Login(email, password) | |||
.Timeout(_config.APITimeout) | |||
.ConfigureAwait(false); | |||
token = response.Token; | |||
if (_config.LogLevel >= LogSeverity.Verbose) | |||
@@ -311,7 +311,7 @@ namespace Discord | |||
await Disconnect().ConfigureAwait(false); | |||
_api.Token = token; | |||
var gatewayResponse = await _api.Gateway().Timeout(_config.APITimeout).ConfigureAwait(false); | |||
var gatewayResponse = await _api.Gateway().ConfigureAwait(false); | |||
string gateway = gatewayResponse.Url; | |||
if (_config.LogLevel >= LogSeverity.Verbose) | |||
_logger.Log(LogSeverity.Verbose, $"Websocket endpoint: {gateway}"); | |||
@@ -400,7 +400,7 @@ namespace Discord | |||
{ | |||
List<Task> tasks = new List<Task>(); | |||
tasks.Add(_cancelToken.Wait()); | |||
if (Config.UseMessageQueue) | |||
if (_config.UseMessageQueue) | |||
tasks.Add(MessageQueueLoop()); | |||
Task[] tasksArray = tasks.ToArray(); | |||
@@ -1,47 +0,0 @@ | |||
namespace Discord | |||
{ | |||
public class DiscordClientConfig : DiscordAPIClientConfig | |||
{ | |||
/// <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; | |||
/// <summary> Gets or sets the time (in milliseconds) to wait after an unexpected disconnect before reconnecting. </summary> | |||
public int ReconnectDelay { get { return _reconnectDelay; } set { SetValue(ref _reconnectDelay, value); } } | |||
private int _reconnectDelay = 1000; | |||
/// <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> 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); } } | |||
private int _webSocketInterval = 100; | |||
/// <summary> Gets or sets the number of messages per channel that should be kept in cache. Setting this to zero disables the message cache entirely. </summary> | |||
public int MessageCacheLength { get { return _messageCacheLength; } set { SetValue(ref _messageCacheLength, value); } } | |||
private int _messageCacheLength = 100; | |||
//Experimental Features | |||
/// <summary> (Experimental) Instructs Discord to not send send information about offline users, for servers with more than 50 users. </summary> | |||
public bool UseLargeThreshold { get { return _useLargeThreshold; } set { SetValue(ref _useLargeThreshold, value); } } | |||
private bool _useLargeThreshold = false; | |||
//Experimental Features | |||
/// <summary> (Experimental) Enables or disables the internal message queue. This will allow SendMessage to return immediately and handle messages internally. Messages will set the IsQueued and HasFailed properties to show their progress. </summary> | |||
public bool UseMessageQueue { get { return _useMessageQueue; } set { SetValue(ref _useMessageQueue, value); } } | |||
private bool _useMessageQueue = false; | |||
/// <summary> Gets or sets the time (in milliseconds) to wait when the message queue is empty before checking again. </summary> | |||
public int MessageQueueInterval { get { return _messageQueueInterval; } set { SetValue(ref _messageQueueInterval, value); } } | |||
private int _messageQueueInterval = 100; | |||
/// <summary> (Experimental) Maintains the LastActivity property for users, showing when they last made an action (sent message, joined server, typed, etc). </summary> | |||
public bool TrackActivity { get { return _trackActivity; } set { SetValue(ref _trackActivity, value); } } | |||
private bool _trackActivity = true; | |||
/// <summary> (Experimental) Acknowledges all incoming messages so that they appear read. </summary> | |||
public bool AckMessages { get { return _ackMessages; } set { SetValue(ref _ackMessages, value); } } | |||
private bool _ackMessages = false; | |||
public new DiscordClientConfig Clone() | |||
{ | |||
var config = MemberwiseClone() as DiscordClientConfig; | |||
config._isLocked = false; | |||
return config; | |||
} | |||
} | |||
} |
@@ -124,7 +124,7 @@ namespace Discord | |||
} | |||
//Local Cache | |||
if (client.Config.MessageCacheLength > 0) | |||
if (client.Config.MessageCacheSize > 0) | |||
_messages = new ConcurrentDictionary<long, Message>(); | |||
} | |||
internal override bool LoadReferences() | |||
@@ -174,7 +174,7 @@ namespace Discord | |||
internal void AddMessage(Message message) | |||
{ | |||
//Race conditions are okay here - it just means the queue will occasionally go higher than the requested cache size, and fixed later. | |||
var cacheLength = _client.Config.MessageCacheLength; | |||
var cacheLength = _client.Config.MessageCacheSize; | |||
if (cacheLength > 0) | |||
{ | |||
var oldestIds = _messages.Where(x => x.Value.Timestamp < message.Timestamp).Select(x => x.Key).OrderBy(x => x).Take(_messages.Count - cacheLength); | |||
@@ -10,11 +10,11 @@ namespace Discord.Net.Rest | |||
{ | |||
internal sealed partial class RestClient | |||
{ | |||
private readonly DiscordAPIClientConfig _config; | |||
private readonly DiscordConfig _config; | |||
private readonly IRestEngine _engine; | |||
private CancellationToken _cancelToken; | |||
public RestClient(DiscordAPIClientConfig config) | |||
public RestClient(DiscordConfig config) | |||
{ | |||
_config = config; | |||
#if !DOTNET5_4 | |||
@@ -3,7 +3,6 @@ using Discord.API; | |||
using RestSharp; | |||
using System; | |||
using System.IO; | |||
using System.Net; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
@@ -11,22 +10,22 @@ namespace Discord.Net.Rest | |||
{ | |||
internal sealed class RestSharpEngine : IRestEngine | |||
{ | |||
private readonly DiscordAPIClientConfig _config; | |||
private readonly DiscordConfig _config; | |||
private readonly RestSharp.RestClient _client; | |||
public RestSharpEngine(DiscordAPIClientConfig config) | |||
public RestSharpEngine(DiscordConfig config) | |||
{ | |||
_config = config; | |||
_client = new RestSharp.RestClient(Endpoints.BaseApi) | |||
{ | |||
PreAuthenticate = false, | |||
ReadWriteTimeout = _config.APITimeout, | |||
UserAgent = DiscordAPIClientConfig.UserAgent | |||
ReadWriteTimeout = _config.RestTimeout, | |||
UserAgent = config.UserAgent | |||
}; | |||
if (_config.ProxyUrl != null) | |||
/*if (_config.ProxyUrl != null) | |||
_client.Proxy = new WebProxy(_config.ProxyUrl, true, new string[0], _config.ProxyCredentials); | |||
else | |||
_client.Proxy = null; | |||
else*/ | |||
_client.Proxy = null; | |||
_client.RemoveDefaultParameter("Accept"); | |||
_client.AddDefaultHeader("accept", "*/*"); | |||
_client.AddDefaultHeader("accept-encoding", "gzip,deflate"); | |||
@@ -26,8 +26,8 @@ namespace Discord.Net.WebSockets | |||
public string SessionId => _sessionId; | |||
private string _sessionId; | |||
public DataWebSocket(DiscordClient client, Logger logger) | |||
: base(client, logger) | |||
public DataWebSocket(DiscordConfig config, Logger logger) | |||
: base(config, logger) | |||
{ | |||
} | |||
@@ -39,7 +39,7 @@ namespace Discord.Net.WebSockets | |||
LoginCommand msg = new LoginCommand(); | |||
msg.Payload.Token = token; | |||
msg.Payload.Properties["$device"] = "Discord.Net"; | |||
if (_client.Config.UseLargeThreshold) | |||
if (_config.UseLargeThreshold) | |||
msg.Payload.LargeThreshold = 100; | |||
msg.Payload.Compress = true; | |||
QueueMessage(msg); | |||
@@ -61,7 +61,7 @@ namespace Discord.Net.WebSockets | |||
try | |||
{ | |||
var cancelToken = ParentCancelToken.Value; | |||
await Task.Delay(_client.Config.ReconnectDelay, cancelToken).ConfigureAwait(false); | |||
await Task.Delay(_config.ReconnectDelay, cancelToken).ConfigureAwait(false); | |||
while (!cancelToken.IsCancellationRequested) | |||
{ | |||
try | |||
@@ -74,7 +74,7 @@ namespace Discord.Net.WebSockets | |||
{ | |||
_logger.Log(LogSeverity.Error, $"Reconnect failed", ex); | |||
//Net is down? We can keep trying to reconnect until the user runs Disconnect() | |||
await Task.Delay(_client.Config.FailedReconnectDelay, cancelToken).ConfigureAwait(false); | |||
await Task.Delay(_config.FailedReconnectDelay, cancelToken).ConfigureAwait(false); | |||
} | |||
} | |||
} | |||
@@ -16,7 +16,7 @@ namespace Discord.Net.WebSockets | |||
public partial class DataWebSocket | |||
{ | |||
internal event EventHandler<WebSocketEventEventArgs> ReceivedEvent; | |||
public event EventHandler<WebSocketEventEventArgs> ReceivedEvent; | |||
private void RaiseReceivedEvent(string type, JToken payload) | |||
{ | |||
if (ReceivedEvent != null) | |||
@@ -21,14 +21,14 @@ namespace Discord.Net.WebSockets | |||
public abstract partial class WebSocket | |||
{ | |||
protected readonly IWebSocketEngine _engine; | |||
protected readonly DiscordClient _client; | |||
protected readonly DiscordConfig _config; | |||
protected readonly ManualResetEventSlim _connectedEvent; | |||
protected ExceptionDispatchInfo _disconnectReason; | |||
protected bool _wasDisconnectUnexpected; | |||
protected WebSocketState _disconnectState; | |||
protected int _loginTimeout, _heartbeatInterval; | |||
protected int _heartbeatInterval; | |||
private DateTime _lastHeartbeat; | |||
private Task _runTask; | |||
@@ -66,19 +66,18 @@ namespace Discord.Net.WebSockets | |||
Disconnected(this, new DisconnectedEventArgs(wasUnexpected, error)); | |||
} | |||
public WebSocket(DiscordClient client, Logger logger) | |||
public WebSocket(DiscordConfig config, Logger logger) | |||
{ | |||
_client = client; | |||
_config = config; | |||
_logger = logger; | |||
_loginTimeout = client.Config.ConnectionTimeout; | |||
_cancelToken = new CancellationToken(true); | |||
_connectedEvent = new ManualResetEventSlim(false); | |||
#if !DOTNET5_4 | |||
_engine = new WebSocketSharpEngine(this, client.Config, _logger); | |||
_engine = new WebSocketSharpEngine(this, _config, _logger); | |||
#else | |||
//_engine = new BuiltInWebSocketEngine(this, client.Config, _logger); | |||
//_engine = new BuiltInWebSocketEngine(this, _config, _logger); | |||
#endif | |||
_engine.BinaryMessage += (s, e) => | |||
{ | |||
@@ -10,7 +10,7 @@ namespace Discord.Net.WebSockets | |||
{ | |||
internal class WebSocketSharpEngine : IWebSocketEngine | |||
{ | |||
private readonly DiscordClientConfig _config; | |||
private readonly DiscordConfig _config; | |||
private readonly Logger _logger; | |||
private readonly ConcurrentQueue<string> _sendQueue; | |||
private readonly WebSocket _parent; | |||
@@ -29,7 +29,7 @@ namespace Discord.Net.WebSockets | |||
TextMessage(this, new WebSocketTextMessageEventArgs(msg)); | |||
} | |||
internal WebSocketSharpEngine(WebSocket parent, DiscordClientConfig config, Logger logger) | |||
internal WebSocketSharpEngine(WebSocket parent, DiscordConfig config, Logger logger) | |||
{ | |||
_parent = parent; | |||
_config = config; | |||
@@ -42,8 +42,9 @@ namespace Discord.Net.WebSockets | |||
_webSocket = new WSSharpWebSocket(host); | |||
_webSocket.EmitOnPing = false; | |||
_webSocket.EnableRedirection = true; | |||
_webSocket.Compression = WebSocketSharp.CompressionMethod.Deflate; | |||
_webSocket.SetProxy(_config.ProxyUrl, _config.ProxyCredentials?.UserName, _config.ProxyCredentials?.Password); | |||
_webSocket.Compression = WebSocketSharp.CompressionMethod.Deflate; | |||
_webSocket.SetProxy(null, null, null); //Disable | |||
//_webSocket.SetProxy(_config.ProxyUrl, _config.ProxyCredentials?.UserName, _config.ProxyCredentials?.Password); | |||
_webSocket.OnMessage += (s, e) => | |||
{ | |||
if (e.IsBinary) | |||
@@ -1,5 +1,5 @@ | |||
{ | |||
"version": "0.8.1-beta2", | |||
"version": "0.9.0-alpha1", | |||
"description": "An unofficial .Net API wrapper for the Discord client.", | |||
"authors": [ | |||
"RogueException" | |||