statianzo / Fleck

C# Websocket Implementation
MIT License
2.29k stars 583 forks source link

.OnMessage behaving differently to .OnBinary #244

Open harrystuart opened 6 years ago

harrystuart commented 6 years ago

Essentially, the client sends an initial text message to the websocket, then it writes all subsequent data to the websocket as a binary stream of 640 byte messages. I am trying to await a Task<> in the .OnBinary() method, however, for some reason, the code doesn't seem to execute as expected. It seems as if subsequent lines of code in the .OnBinary() method are not executed either. Oddly, everything functions perfectly when put in the .OnMessage() method. Leading me to believe that due to the fact that my client is only causing .OnMessage() to trigger once, and it triggers .OnBinary many times a second, the code "freaks out" and the Task<> is not awaited. I have no explanation for this and it seems illogical. Nonetheless, the issue is present and I was hoping someone would know a work around. An example is below:

            socket.OnMessage = async message =>
            {
                MySynchronousMethod(); // This line executes once
            };
            socket.OnBinary = async binary =>
            {
                MySynchronousMethod(); // This line executes many times a second
            };
            socket.OnMessage = async message =>
            {
                await streamingCall.WriteAsync(); // awaits a Task<>
                MySynchronousMethod(); // This line DOES execute
            };
            socket.OnBinary = async binary =>
            {
                await streamingCall.WriteAsync(); // awaits a Task<>
                MySynchronousMethod(); // This line DOES NOT execute
            };

I have tried .GetAwaiter().GetResults() with no success and it seems like MySynchronousMethod() is not executed in the above situations, even if I try testing with an asyncrhonous method with and without being awaited.

statianzo commented 6 years ago

Not sure how Fleck would be interfering with the async result. All it does is invoke the Action callback for each frame type:

https://github.com/statianzo/Fleck/blob/master/src/Fleck/Handlers/Hybi13Handler.cs#L145-L156

For testing, what happens if you await something other than streamingCall.WriteAsync()? If it calls MySynchronousMethod in that case, it would seem streamingCall.WriteAsync isn't resolving.

harrystuart commented 6 years ago

I figured out how to fix this. streamingCall.WriteAsync() is only allowed to be called ONCE. So if I have:

         socket.OnBinary = async binary =>
        {
            await streamingCall.WriteAsync(); // awaits a Task<>
            MySynchronousMethod(); // This line DOES NOT execute
        };

How do I execute streamingCall.WriteAsync() on the first .OnBinary() event, and then execute MySynchronousMethod() on all SUBSEQUENT .OnBinary() events? For context, streamingCall.WriteAsync() initialises an external API and MySynchronousMethod() sends the binary data to that API after it's been initialised. Therefore, I also need to make sure that streamingCall.WriteAsync() has been awaited (fully executed) BEFORE MySynchronousMethod() begins getting called. If I lose a bit of binary data in doing so, it isn't an issue.