@@ -59,6 +59,9 @@ | |||
<Reference Include="RestSharp, Version=105.2.3.0, Culture=neutral, PublicKeyToken=null"> | |||
<HintPath>..\..\..\DiscordBot\packages\RestSharp.105.2.3\lib\net45\RestSharp.dll</HintPath> | |||
</Reference> | |||
<Reference Include="websocket-sharp, Version=1.0.2.36589, Culture=neutral, PublicKeyToken=5660b08a1845a91e"> | |||
<HintPath>..\..\..\DiscordBot\packages\WebSocketSharp.1.0.3-rc9\lib\websocket-sharp.dll</HintPath> | |||
</Reference> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Content Include="lib\libopus.so" /> | |||
@@ -241,6 +244,9 @@ | |||
<Compile Include="..\Discord.Net\WebSockets\WebSocket.Events.cs"> | |||
<Link>WebSockets\WebSocket.Events.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\WebSockets\WebSocket.WebSocketSharp.cs"> | |||
<Link>WebSockets\WebSocket.WebSocketSharp.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\WebSockets\WebSocketMessage.cs"> | |||
<Link>WebSockets\WebSocketMessage.cs</Link> | |||
</Compile> | |||
@@ -2,4 +2,5 @@ | |||
<packages> | |||
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" /> | |||
<package id="RestSharp" version="105.2.3" targetFramework="net45" /> | |||
<package id="WebSocketSharp" version="1.0.3-rc9" targetFramework="net45" /> | |||
</packages> |
@@ -40,7 +40,7 @@ namespace Discord.WebSockets.Data | |||
{ | |||
try | |||
{ | |||
var cancelToken = ParentCancelToken; | |||
var cancelToken = ParentCancelToken.Value; | |||
await Task.Delay(_client.Config.ReconnectDelay, cancelToken).ConfigureAwait(false); | |||
while (!cancelToken.IsCancellationRequested) | |||
{ | |||
@@ -85,7 +85,7 @@ namespace Discord.WebSockets.Voice | |||
{ | |||
try | |||
{ | |||
var cancelToken = ParentCancelToken; | |||
var cancelToken = ParentCancelToken.Value; | |||
await Task.Delay(_client.Config.ReconnectDelay, cancelToken).ConfigureAwait(false); | |||
while (!cancelToken.IsCancellationRequested) | |||
{ | |||
@@ -127,7 +127,8 @@ namespace Discord.WebSockets.Voice | |||
{ | |||
#if USE_THREAD | |||
_sendThread = new Thread(new ThreadStart(() => SendVoiceAsync(_cancelToken))); | |||
_sendThread.Start(); | |||
_sendThread.IsBackground = true; | |||
_sendThread.Start(); | |||
#else | |||
tasks.Add(SendVoiceAsync()); | |||
#endif | |||
@@ -138,6 +139,7 @@ namespace Discord.WebSockets.Voice | |||
if ((_client.Config.VoiceMode & DiscordVoiceMode.Incoming) != 0) | |||
{ | |||
_receiveThread = new Thread(new ThreadStart(() => ReceiveVoiceAsync(_cancelToken))); | |||
_sendThread.IsBackground = true; | |||
_receiveThread.Start(); | |||
} | |||
else //Dont make an OS thread if we only want to capture one packet... | |||
@@ -1,4 +1,5 @@ | |||
using Discord.Helpers; | |||
#if DNXCORE50 | |||
using Discord.Helpers; | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.ComponentModel; | |||
@@ -16,7 +17,7 @@ namespace Discord.WebSockets | |||
private const int SendChunkSize = 4096; | |||
private const int HR_TIMEOUT = -2147012894; | |||
private readonly ConcurrentQueue<byte[]> _sendQueue; | |||
private readonly ConcurrentQueue<string> _sendQueue; | |||
private readonly int _sendInterval; | |||
private ClientWebSocket _webSocket; | |||
@@ -30,7 +31,7 @@ namespace Discord.WebSockets | |||
public BuiltInWebSocketEngine(int sendInterval) | |||
{ | |||
_sendInterval = sendInterval; | |||
_sendQueue = new ConcurrentQueue<byte[]>(); | |||
_sendQueue = new ConcurrentQueue<string>(); | |||
} | |||
public Task Connect(string host, CancellationToken cancelToken) | |||
@@ -42,7 +43,7 @@ namespace Discord.WebSockets | |||
public Task Disconnect() | |||
{ | |||
byte[] ignored; | |||
string ignored; | |||
while (_sendQueue.TryDequeue(out ignored)) { } | |||
_webSocket.Dispose(); | |||
_webSocket = new ClientWebSocket(); | |||
@@ -107,12 +108,13 @@ namespace Discord.WebSockets | |||
{ | |||
try | |||
{ | |||
byte[] bytes; | |||
while (_webSocket.State == State.Open && !cancelToken.IsCancellationRequested) | |||
{ | |||
while (_sendQueue.TryDequeue(out bytes)) | |||
string json; | |||
while (_sendQueue.TryDequeue(out json)) | |||
{ | |||
var frameCount = (int)Math.Ceiling((double)bytes.Length / SendChunkSize); | |||
byte[] bytes = Encoding.UTF8.GetBytes(json); | |||
int frameCount = (int)Math.Ceiling((double)bytes.Length / SendChunkSize); | |||
int offset = 0; | |||
for (var i = 0; i < frameCount; i++, offset += SendChunkSize) | |||
@@ -142,9 +144,10 @@ namespace Discord.WebSockets | |||
}); | |||
} | |||
public void QueueMessage(byte[] message) | |||
public void QueueMessage(string message) | |||
{ | |||
_sendQueue.Enqueue(message); | |||
} | |||
} | |||
} | |||
} | |||
#endif |
@@ -0,0 +1,88 @@ | |||
#if !DNXCORE50 | |||
using Discord.Helpers; | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
using WSSharpNWebSocket = WebSocketSharp.WebSocket; | |||
namespace Discord.WebSockets | |||
{ | |||
public class WSSharpWebSocketEngine : IWebSocketEngine | |||
{ | |||
private readonly ConcurrentQueue<string> _sendQueue; | |||
private readonly int _sendInterval; | |||
private readonly string _userAgent; | |||
private readonly WebSocket _parent; | |||
private WSSharpNWebSocket _webSocket; | |||
public event EventHandler<WebSocketMessageEventArgs> ProcessMessage; | |||
private void RaiseProcessMessage(string msg) | |||
{ | |||
if (ProcessMessage != null) | |||
ProcessMessage(this, new WebSocketMessageEventArgs(msg)); | |||
} | |||
internal WSSharpWebSocketEngine(WebSocket parent, string userAgent, int sendInterval) | |||
{ | |||
_parent = parent; | |||
_userAgent = userAgent; | |||
_sendInterval = sendInterval; | |||
_sendQueue = new ConcurrentQueue<string>(); | |||
} | |||
public Task Connect(string host, CancellationToken cancelToken) | |||
{ | |||
_webSocket = new WSSharpNWebSocket(host); | |||
_webSocket.EmitOnPing = false; | |||
_webSocket.EnableRedirection = true; | |||
_webSocket.Compression = WebSocketSharp.CompressionMethod.None; | |||
_webSocket.OnMessage += (s, e) => RaiseProcessMessage(e.Data); | |||
_webSocket.OnError += (s, e) => _parent.RaiseOnLog(LogMessageSeverity.Error, $"Websocket Error: {e.Message}"); | |||
_webSocket.Connect(); | |||
return TaskHelper.CompletedTask; | |||
} | |||
public Task Disconnect() | |||
{ | |||
string ignored; | |||
while (_sendQueue.TryDequeue(out ignored)) { } | |||
_webSocket.Close(); | |||
return TaskHelper.CompletedTask; | |||
} | |||
public Task[] GetTasks(CancellationToken cancelToken) | |||
{ | |||
return new Task[] | |||
{ | |||
SendAsync(cancelToken) | |||
}; | |||
} | |||
private Task SendAsync(CancellationToken cancelToken) | |||
{ | |||
return Task.Run(async () => | |||
{ | |||
try | |||
{ | |||
while (_webSocket.IsAlive && !cancelToken.IsCancellationRequested) | |||
{ | |||
string json; | |||
while (_sendQueue.TryDequeue(out json)) | |||
_webSocket.Send(json); | |||
await Task.Delay(_sendInterval, cancelToken).ConfigureAwait(false); | |||
} | |||
} | |||
catch (OperationCanceledException) { } | |||
}); | |||
} | |||
public void QueueMessage(string message) | |||
{ | |||
_sendQueue.Enqueue(message); | |||
} | |||
} | |||
} | |||
#endif |
@@ -28,7 +28,7 @@ namespace Discord.WebSockets | |||
Task Connect(string host, CancellationToken cancelToken); | |||
Task Disconnect(); | |||
void QueueMessage(byte[] message); | |||
void QueueMessage(string message); | |||
Task[] GetTasks(CancellationToken cancelToken); | |||
} | |||
@@ -47,7 +47,7 @@ namespace Discord.WebSockets | |||
private DateTime _lastHeartbeat; | |||
private Task _runTask; | |||
public CancellationToken ParentCancelToken { get; set; } | |||
public CancellationToken? ParentCancelToken { get; set; } | |||
public CancellationToken CancelToken => _cancelToken; | |||
private CancellationTokenSource _cancelTokenSource; | |||
protected CancellationToken _cancelToken; | |||
@@ -61,11 +61,16 @@ namespace Discord.WebSockets | |||
{ | |||
_client = client; | |||
_logLevel = client.Config.LogLevel; | |||
_loginTimeout = client.Config.ConnectionTimeout; | |||
_cancelToken = new CancellationToken(true); | |||
_connectedEvent = new ManualResetEventSlim(false); | |||
#if DNXCORE50 | |||
_engine = new BuiltInWebSocketEngine(client.Config.WebSocketInterval); | |||
#else | |||
_engine = new WSSharpWebSocketEngine(this, client.Config.UserAgent, client.Config.WebSocketInterval); | |||
#endif | |||
_engine.ProcessMessage += async (s, e) => | |||
{ | |||
if (_logLevel >= LogMessageSeverity.Debug) | |||
@@ -84,10 +89,11 @@ namespace Discord.WebSockets | |||
await Disconnect().ConfigureAwait(false); | |||
_cancelTokenSource = new CancellationTokenSource(); | |||
if (ParentCancelToken != null) | |||
_cancelToken = CancellationTokenSource.CreateLinkedTokenSource(_cancelTokenSource.Token, ParentCancelToken).Token; | |||
else | |||
_cancelToken = _cancelTokenSource.Token; | |||
if (ParentCancelToken == null) | |||
throw new InvalidOperationException("Parent cancel token was never set."); | |||
_cancelToken = CancellationTokenSource.CreateLinkedTokenSource(_cancelTokenSource.Token, ParentCancelToken.Value).Token; | |||
/*else | |||
_cancelToken = _cancelTokenSource.Token;*/ | |||
_lastHeartbeat = DateTime.UtcNow; | |||
await _engine.Connect(Host, _cancelToken).ConfigureAwait(false); | |||
@@ -198,8 +204,7 @@ namespace Discord.WebSockets | |||
string json = JsonConvert.SerializeObject(message); | |||
if (_logLevel >= LogMessageSeverity.Debug) | |||
RaiseOnLog(LogMessageSeverity.Debug, $"Out: " + json); | |||
var bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message)); | |||
_engine.QueueMessage(bytes); | |||
_engine.QueueMessage(json); | |||
} | |||
private Task HeartbeatAsync(CancellationToken cancelToken) | |||
@@ -27,7 +27,8 @@ | |||
"frameworks": { | |||
"net45": { | |||
"dependencies": { | |||
"RestSharp": "105.2.3" | |||
"RestSharp": "105.2.3", | |||
"WebSocketSharp": "1.0.3-rc9" | |||
}, | |||
"frameworkAssemblies": { | |||
"System.Net.Http": "4.0.0.0" | |||
@@ -35,7 +36,8 @@ | |||
}, | |||
"dnx451": { | |||
"dependencies": { | |||
"RestSharp": "105.2.3" | |||
"RestSharp": "105.2.3", | |||
"WebSocketSharp": "1.0.3-rc9" | |||
}, | |||
"frameworkAssemblies": { | |||
"System.Net.Http": "4.0.0.0" | |||
@@ -1,5 +1,5 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
<PropertyGroup> | |||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |||