Write to websocket asynchronously, plus fix thread-safety issues #60
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This fixes #3 and obsoletes #54. Additionally some thread-safety issues have been fixed so that all game-reading code happens from within the game thread. These two things have been done in separate commits. (I would have made them separate PRs except that my commit for the threading fixes depended on my async-send change.)
In https://github.com/opl-/beatsaber-http-status/issues/3#issuecomment-817007287, I theorized that the Send call inside of HTTPServer.StatusBroadcastBehavior.OnStatusChange was the cause of stuttering while using the mod. I tested this by adding some timing around the send call:
I got results like this:
Original Results
This is all within the main game thread, so the synchronous IO is regularly causing stuttering. (At 90fps, each frame has 11ms to happen, so blocking the main thread for an extra 40+ms regularly is pretty bad.) (I also did some timing around other parts of OnStatusChange and the rest of it was just zeroes.)
After the first commit, the results look perfect like this:
Fixed Results
The asynchronous send fix properly queues up writes to the websocket.
Next, I noticed that HTTPServer would directly read from the StatusManager in response to web requests and websocket events even though StatusManager was written to from the main game thread. I made the code thread-safe by making sure that all access to StatusManager happened through the game thread.
(I did consider an alternate solution: It would be possible to make it so that StatusManager.EmitStatusUpdate wrote all of its results to a single volatile property, and then HTTPServer could read this volatile property when handling requests and websocket events, but this would have been a bigger change for negligible benefit that would make the code harder to evolve. In comparison, the change to just read from StatusManager within the game thread is a very small drop-in fix.)