Added WebSocketSharp support and fixed Mono issues

This commit is contained in:
RogueException
2015-10-01 18:27:40 -03:00
parent 7c246274d7
commit 9c9884c1ae
9 changed files with 130 additions and 23 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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)
{

View File

@@ -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...

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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"