Confused about DispatchMessageQueue() and different order of OnClose/OnMessage in the latest version
Hi, I recently updated to the latest version and I realized OnMessage is not being called anymore. I've spent several hours debugging and, by mistake, discovered this DispatchMessageQueue() method, which is not called by anyone. Did I just have a very old version where this method was automatically called? I don't find the text "DispatchMessageQueue" anywhere throughout any of the involved projects, so it means in my last version it was called automatically, internally. I really looked among your release notes before upgrading and such a breaking change wasn't mentioned anywhere.. Was my version just an ancient one (like before 1.0.0)? Just trying to understand what happened. Very useful library, BTW. Thanks!
Also, I'm getting some messages in a different order. Specifically, it seems that previously I was able to disconnect and reconnect a player and sync any lost messages (which I cache locally on both the server and the client), and now I receive a disconnect event a bit sooner than expected (and I suppose there might be other subtle differences). This is a hefty process that I didn't want to ever dive into again, as it took ages to design properly.
I suppose several other things changed, not only when OnMessage() is called, as I also tried to call OnMessage manually, to closely match the old way, but issues still happen. This is the older code of Receive():
public async Task Receive()
{
ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[8192]);
while (m_Socket.State == System.Net.WebSockets.WebSocketState.Open)
{
WebSocketReceiveResult result = null;
using (var ms = new MemoryStream())
{
do
{
result = await m_Socket.ReceiveAsync(buffer, CancellationToken.None);
ms.Write(buffer.Array, buffer.Offset, result.Count);
}
while (!result.EndOfMessage);
ms.Seek(0, SeekOrigin.Begin);
if (result.MessageType == WebSocketMessageType.Text)
{
OnMessage?.Invoke(ms.ToArray());
//using (var reader = new StreamReader(ms, Encoding.UTF8))
//{
// string message = reader.ReadToEnd();
// OnMessage?.Invoke(this, new MessageEventArgs(message));
//}
}
else if (result.MessageType == WebSocketMessageType.Binary)
{
OnMessage?.Invoke(ms.ToArray());
}
else if (result.MessageType == WebSocketMessageType.Close)
{
await Close();
OnClose?.Invoke(WebSocketHelpers.ParseCloseCodeEnum((int)result.CloseStatus));
break;
}
}
}
}
and this is the current one in this repo:
public async Task Receive()
{
WebSocketCloseCode closeCode = WebSocketCloseCode.Abnormal;
await new WaitForBackgroundThread();
ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[8192]);
try
{
while (m_Socket.State == System.Net.WebSockets.WebSocketState.Open)
{
WebSocketReceiveResult result = null;
using (var ms = new MemoryStream())
{
do
{
result = await m_Socket.ReceiveAsync(buffer, m_CancellationToken);
ms.Write(buffer.Array, buffer.Offset, result.Count);
}
while (!result.EndOfMessage);
ms.Seek(0, SeekOrigin.Begin);
if (result.MessageType == WebSocketMessageType.Text)
{
lock (IncomingMessageLock)
{
m_MessageList.Add(ms.ToArray());
}
//using (var reader = new StreamReader(ms, Encoding.UTF8))
//{
// string message = reader.ReadToEnd();
// OnMessage?.Invoke(this, new MessageEventArgs(message));
//}
}
else if (result.MessageType == WebSocketMessageType.Binary)
{
lock (IncomingMessageLock)
{
m_MessageList.Add(ms.ToArray());
}
}
else if (result.MessageType == WebSocketMessageType.Close)
{
await Close();
closeCode = WebSocketHelpers.ParseCloseCodeEnum((int)result.CloseStatus);
break;
}
}
}
}
catch (Exception)
{
m_TokenSource.Cancel();
}
finally
{
await new WaitForUpdate();
OnClose?.Invoke(closeCode);
}
}
Is there any obvious change that could lead to my issue? I'd be really grateful for any direction, as I have very different usages of this plugin in my project and they all relied on the older behavior. Specifically, the gameplay module has around 100 game events that depend on the "correct" order of OnMessage/OnClose etc. I imagine a solution would invove either me changing the code in my logic, or changing something in the plugin itself. Anything that could help me track the issue is highly appreciated!
Hi @tfgstudios, this change on the library has been introduced since this PR https://github.com/endel/NativeWebSocket/pull/11, IIRC this new threading mechanism was due to extra unnecessary delays happening on the previous implementation when receiving messages.
I think you are right regarding the order of "close" and message events that differ after this release. The await Close(); is triggered immediately when parsing incoming message, whereas binary and text messages are enqueued for the next "queue dispatch". So if a "close" happens to be received along with other messages, it will fire first.
I've flagged this issue as a bug, please let me know if you have any luck fixing this!
Hey, I was only able to fix it on the user side. There were other issues (Unity's own ones) in the play, so I'm not sure which fixed which. Based on your comment, this still remains a bug, albeit it doesn't affect my specific case anymore. What I can say is this plugin is very useful and thanks for it! I hope it'll remain actual in the next years