Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Emscripten WebSockets API #7670

Merged
merged 1 commit into from
Jan 16, 2019

Conversation

juj
Copy link
Collaborator

@juj juj commented Dec 14, 2018

Adds Emscripten WebSockets API: direct bare WebSockets support exposed to C code in multithreading aware manner. A C integer handle represents the WebSocket connection, and it can be shared across threads. Still slightly experimental, a number of TODOs left, but may be useful to others.

(One TODO in particular is backproxying - currently WebSocket events will all be dispatched on the main browser thread, and not the requested thread)

Copy link
Member

@kripken kripken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few early comments.

What do you think about writing new libraries like these in a more SDL2 manner, that is, in C (or C++), and use EM_ASM/EM_JS for the necessary JS parts?

emscripten_websocket_get_url_length__proxy: 'sync',
emscripten_websocket_get_url_length__sig: 'iii',
emscripten_websocket_get_url_length: function(socketId, urlLength) {
var socket = WS.sockets[socketId];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could have a WS.get(id) helper that contains the debug ifdef (could also pass the function name in there, optionally).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would regress on release mode code size, because the if (!socket) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; part would still need to be in the caller side. So while it would reduce duplication of the #if WEBSOCKET_DEBUG part, it would make the code larger by creating a redundant function. (var socket = WS.sockets[socketId]; minifies probably to exact same length as var socket = WS.get(socketId);, but the function approach would have an extra WS: { get: function(socketId) { return this.sockets[socketId]; } } part to it.

Ideal solution to avoid code duplication here would be to use macros:

#if WEBSOCKET_DEBUG
#define WS_GET(socketId, name) WS.sockets[socketId]; \
    if (!socket) { \
      console.error(name + '(): Invalid socket ID ' + socketId + ' specified!'); \
      return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; \
    }
#else
#define WS_GET(socketId, name) WS.sockets[socketId]; \
    if (!socket) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}};
#endif

and then in all parts, use `var socket = WS_GET(socketId);`. (But that would require support for full C preprocessing)


emscripten_websocket_get_url_length__proxy: 'sync',
emscripten_websocket_get_url_length__sig: 'iii',
emscripten_websocket_get_url_length: function(socketId, urlLength) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

urlLength is not used anywhere?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I'll update that.

@juj
Copy link
Collaborator Author

juj commented Dec 19, 2018

What do you think about writing new libraries like these in a more SDL2 manner, that is, in C (or C++), and use EM_ASM/EM_JS for the necessary JS parts?

Using EM_ASM/EM_JS is a bad practice that generates poor code compared to JS libraries. I definitely do like implementing as much as possible in C/C++ code, but none of these functions lend well to being implemented in C/C++ code, because they access the WebSocket object that is JavaScript state. Note how the other PR #7672 builds on top of this in a way that #7672 does not have any JS code in it.

@kripken
Copy link
Member

kripken commented Dec 19, 2018

What do you mean by poor code? It's true that EM_ASMs are looked up by an integer id, so metadce/closure/etc. can't optimize out unused ones. But EM_JS emits a proper function for each one, which is fully optimizable. Is there something else poor there?

For the library here, though, yeah, maybe it's fine either way, since as you said it's almost all JS API glue code. I wonder though if more wouldn't be needed eventually even here?

@juj
Copy link
Collaborator Author

juj commented Jan 7, 2019

What do you mean by poor code? It's true that EM_ASMs are looked up by an integer id, so metadce/closure/etc. can't optimize out unused ones.

Yeah, that is what I referred to here. The array lookup is worse compared to having each function written out in full.

But EM_JS emits a proper function for each one, which is fully optimizable. Is there something else poor there?

EM_JS() has a limitation that it cannot proxy, so it will need proxying support added to it first. I admit I have not looked at the codegen of EM_JS() that close if there are other differences. One drawback is that the JS code would then live in a .c or a .cpp file, which would throw off IDEs completely, the current .js library files with some #ifs confuse IDEs a little bit less and give mostly working syntax highlighting at least.

@juj juj force-pushed the emscripten_websockets branch 2 times, most recently from 39c7364 to 0baccda Compare January 7, 2019 17:45
@juj
Copy link
Collaborator Author

juj commented Jan 7, 2019

Updated to add test to sockets suite.

@juj juj force-pushed the emscripten_websockets branch 2 times, most recently from cf89066 to aa421c2 Compare January 10, 2019 10:16
@juj
Copy link
Collaborator Author

juj commented Jan 11, 2019

This is now ready for a second review pass to merge?

@juj
Copy link
Collaborator Author

juj commented Jan 15, 2019

Ping @kripken, I wish this would be able to merge soon, it is becoming a bit urgent.

@kripken
Copy link
Member

kripken commented Jan 15, 2019

Got it, reading now.

EM_JS() has a limitation that it cannot proxy, so it will need proxying support added to it first.

Hmm, they do expand into JS library functions, so the proxying support we have there could work, if they were marked as such - seems like that could be done.

Copy link
Member

@kripken kripken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm with some minor comments.

We don't run websockets tests on CI - does the new test pass for you? We should really get at least a subset of them running on CI - like maybe even just starting with your new test here, if it's robust enough (many of the old ones are not, sadly), please look into that later when you can.

@@ -361,6 +361,9 @@ var WEBSOCKET_SUBPROTOCOL = 'binary';
// Print out debugging information from our OpenAL implementation.
var OPENAL_DEBUG = 0;

// If 1, prints out debugging related to WebSockets calls. If 2, traces bytes communicated via the socket.
var WEBSOCKET_DEBUG = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this only works with the new library, correct, and not the old sockets code? may be worth documenting that here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check, adjusted the comment to refer to emscripten/websocket.h.

const char *url;
const char **protocols;

// If true, the created socket will reside on the main browser thread. If false, the created socket is bound to the calling thread.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these docs should be moved to the emscripten.h area under site/. Can leave for a followup though, not urgent.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants