From a75c9f6c8f6cf658d508ba0a1378dc451c1777d3 Mon Sep 17 00:00:00 2001 From: Kharkunov Eugene Date: Wed, 10 Apr 2024 13:45:27 +0300 Subject: [PATCH] Use builtin Emscripten webscoket implementation for html5. Update .gitignore. --- .gitignore | 3 +- websocket/ext.manifest | 7 + websocket/include/emscripten/websocket.h | 136 ------- websocket/lib/web/library_websocket.js | 448 ----------------------- websocket/src/websocket.h | 2 +- 5 files changed, 10 insertions(+), 586 deletions(-) delete mode 100644 websocket/include/emscripten/websocket.h delete mode 100644 websocket/lib/web/library_websocket.js diff --git a/.gitignore b/.gitignore index 7d5711e..4411e3a 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ Thumbs.db builtins lws_source lws_build -*.profraw \ No newline at end of file +*.profraw +*.der \ No newline at end of file diff --git a/websocket/ext.manifest b/websocket/ext.manifest index 523ed73..d2a7b63 100644 --- a/websocket/ext.manifest +++ b/websocket/ext.manifest @@ -6,3 +6,10 @@ platforms: context: includes: ["upload/websocket/include/wslay"] defines: ["HAVE_CONFIG_H"] + + wasm-web: + context: + linkFlags: ["-lwebsocket.js"] + js-web: + context: + linkFlags: ["-lwebsocket.js"] \ No newline at end of file diff --git a/websocket/include/emscripten/websocket.h b/websocket/include/emscripten/websocket.h deleted file mode 100644 index a87a987..0000000 --- a/websocket/include/emscripten/websocket.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2018 The Emscripten Authors. All rights reserved. - * Emscripten is available under two separate licenses, the MIT license and the - * University of Illinois/NCSA Open Source License. Both these licenses can be - * found in the LICENSE file. - */ - -#pragma once - -#include -#include - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define EMSCRIPTEN_WEBSOCKET_T int - -// Returns the WebSocket.readyState field into readyState. readyState must not be a null pointer. -EMSCRIPTEN_RESULT emscripten_websocket_get_ready_state(EMSCRIPTEN_WEBSOCKET_T socket, unsigned short *readyState); - -// Returns the WebSocket.bufferedAmount field into bufferedAmount. bufferedAmount must not be a null pointer. -EMSCRIPTEN_RESULT emscripten_websocket_get_buffered_amount(EMSCRIPTEN_WEBSOCKET_T socket, unsigned long long *bufferedAmount); - -// Writes the WebSocket.url field as a UTF-8 string to the memory area pointed by url. The memory area must contain at least urlLength bytes of free space. If this memory area cannot -// fit the url string, it will be truncated. Call emscripten_websocket_get_url_length() to determine how large memory area will be required to store the url. -// url must not be a null pointer. -EMSCRIPTEN_RESULT emscripten_websocket_get_url(EMSCRIPTEN_WEBSOCKET_T socket, char *url, int urlLength); -// Returns the byte length needed to store WebSocket.url string in Wasm heap. This length can be passed to emscripten_websocket_get_url as it includes the null byte in the count. -// urlLength must not be a null pointer. -EMSCRIPTEN_RESULT emscripten_websocket_get_url_length(EMSCRIPTEN_WEBSOCKET_T socket, int *urlLength); - -// Similar to emscripten_websocket_get_url(), but returns WebSocket.extensions field instead. -EMSCRIPTEN_RESULT emscripten_websocket_get_extensions(EMSCRIPTEN_WEBSOCKET_T socket, char *extensions, int extensionsLength); -EMSCRIPTEN_RESULT emscripten_websocket_get_extensions_length(EMSCRIPTEN_WEBSOCKET_T socket, int *extensionsLength); - -// Similar to emscripten_websocket_get_url(), but returns WebSocket.protocol field instead. -EMSCRIPTEN_RESULT emscripten_websocket_get_protocol(EMSCRIPTEN_WEBSOCKET_T socket, char *protocol, int protocolLength); -EMSCRIPTEN_RESULT emscripten_websocket_get_protocol_length(EMSCRIPTEN_WEBSOCKET_T socket, int *protocolLength); - -typedef struct EmscriptenWebSocketOpenEvent { - EMSCRIPTEN_WEBSOCKET_T socket; -} EmscriptenWebSocketOpenEvent; - -typedef EM_BOOL (*em_websocket_open_callback_func)(int eventType, const EmscriptenWebSocketOpenEvent *websocketEvent, void *userData); -EMSCRIPTEN_RESULT emscripten_websocket_set_onopen_callback_on_thread(EMSCRIPTEN_WEBSOCKET_T socket, void *userData, em_websocket_open_callback_func callback, pthread_t targetThread); - -typedef struct EmscriptenWebSocketMessageEvent { - EMSCRIPTEN_WEBSOCKET_T socket; - uint8_t *data; - uint32_t numBytes; - EM_BOOL isText; -} EmscriptenWebSocketMessageEvent; - -typedef EM_BOOL (*em_websocket_message_callback_func)(int eventType, const EmscriptenWebSocketMessageEvent *websocketEvent, void *userData); -EMSCRIPTEN_RESULT emscripten_websocket_set_onmessage_callback_on_thread(EMSCRIPTEN_WEBSOCKET_T socket, void *userData, em_websocket_message_callback_func callback, pthread_t targetThread); - -typedef struct EmscriptenWebSocketErrorEvent { - EMSCRIPTEN_WEBSOCKET_T socket; -} EmscriptenWebSocketErrorEvent; - -typedef EM_BOOL (*em_websocket_error_callback_func)(int eventType, const EmscriptenWebSocketErrorEvent *websocketEvent, void *userData); -EMSCRIPTEN_RESULT emscripten_websocket_set_onerror_callback_on_thread(EMSCRIPTEN_WEBSOCKET_T socket, void *userData, em_websocket_error_callback_func callback, pthread_t targetThread); - -typedef struct EmscriptenWebSocketCloseEvent { - EMSCRIPTEN_WEBSOCKET_T socket; - EM_BOOL wasClean; - unsigned short code; - char reason[512]; // WebSockets spec enforces this can be max 123 characters, so as UTF-8 at most 123*4 bytes < 512. -} EmscriptenWebSocketCloseEvent; - -typedef EM_BOOL (*em_websocket_close_callback_func)(int eventType, const EmscriptenWebSocketCloseEvent *websocketEvent, void *userData); -EMSCRIPTEN_RESULT emscripten_websocket_set_onclose_callback_on_thread(EMSCRIPTEN_WEBSOCKET_T socket, void *userData, em_websocket_close_callback_func callback, pthread_t targetThread); - -#define emscripten_websocket_set_onopen_callback(socket, userData, callback) emscripten_websocket_set_onopen_callback_on_thread( (socket), (userData), (callback), EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD) -#define emscripten_websocket_set_onerror_callback(socket, userData, callback) emscripten_websocket_set_onerror_callback_on_thread( (socket), (userData), (callback), EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD) -#define emscripten_websocket_set_onclose_callback(socket, userData, callback) emscripten_websocket_set_onclose_callback_on_thread( (socket), (userData), (callback), EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD) -#define emscripten_websocket_set_onmessage_callback(socket, userData, callback) emscripten_websocket_set_onmessage_callback_on_thread((socket), (userData), (callback), EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD) - -typedef struct EmscriptenWebSocketCreateAttributes { - // The target URL to connect to. This string can point to a stack local variable, the string is read immediately at a call to emscripten_websocket_new(). - const char *url; - // A comma-separated list of protocol strings. Set to e.g. "binary,base64" to create a WebSocket connection with two supported protocols "binary" and "base64". - // Be careful to avoid leading and trailing spaces, e.g. "binary, base64" may not be interpreted properly. - // This string can point to a stack local variable, the string is read immediately at a call to emscripten_websocket_new(). - 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. - // If you want to share the created EMSCRIPTEN_WEBSOCKET_T structure across multiple threads, or are running your own main loop in the - // pthread that you create the socket, set createOnMainThread to true. If the created WebSocket only needs to be accessible on the thread - // that created it, and the creating thread is an event based thread (meaning it regularly yields back to the browser event loop), then - // it is more efficient to set this to false. - EM_BOOL createOnMainThread; -} EmscriptenWebSocketCreateAttributes; - -//extern void emscripten_websocket_init_create_attributes(EmscriptenWebSocketCreateAttributes *attributes); -#define emscripten_websocket_init_create_attributes(attributes) do { memset((attributes), 0, sizeof(EmscriptenWebSocketCreateAttributes)); } while(0) - -// Returns true if WebSockets are supported by the current browser -EM_BOOL emscripten_websocket_is_supported(void); - -// Creates a new WebSocket and connects it to the given remote host. -// If the return value of this function is > 0, the function has succeeded and the return value represents a handle to the WebSocket object. -// If the return value of this function is < 0, then the function has failed, and the return value can be interpreted as a EMSCRIPTEN_RESULT code -// representing the cause of the failure. If the function returns 0, then the call has failed with an unknown reason (build with -s WEBSOCKET_DEBUG=1 for more information) -EMSCRIPTEN_WEBSOCKET_T emscripten_websocket_new(EmscriptenWebSocketCreateAttributes *createAttributes); - -// Sends the given string of null-delimited UTF8 encoded text data to the connected server. -EMSCRIPTEN_RESULT emscripten_websocket_send_utf8_text(EMSCRIPTEN_WEBSOCKET_T socket, const char *textData); - -// Sends the given block of raw memory data out to the connected server. -EMSCRIPTEN_RESULT emscripten_websocket_send_binary(EMSCRIPTEN_WEBSOCKET_T socket, void *binaryData, uint32_t dataLength); - -// Closes the specified WebSocket. N.B.: the meaning of "closing" a WebSocket means "eager read/lazy write"-closing the socket. That is, all still -// pending untransferred outbound bytes will continue to transfer out, but after calling close on the socket, any pending bytes still in the process -// of being received will never be available. See https://html.spec.whatwg.org/multipage/web-sockets.html#dom-websocket-sclose -// After calling close(), it is no longer possible to send() on the WebSocket to send more bytes. -EMSCRIPTEN_RESULT emscripten_websocket_close(EMSCRIPTEN_WEBSOCKET_T socket, unsigned short code, const char *reason); - -// Releases the given WebSocket object and all associated allocated memory for garbage collection. This effectively frees the socket handle, after calling -// this function the given handle no longer exists. -EMSCRIPTEN_RESULT emscripten_websocket_delete(EMSCRIPTEN_WEBSOCKET_T socket); - -// This function close()s and releases all created WebSocket connections for the current thread. You can call this at application exit time to enforce -// teardown of all active sockets, although it is optional. When a pthread terminates, it will call this function to delete all active connections bound to -// that specific pthread (sockets created with createOnMainThread=false). Any WebSockets created by a pthread with createOnMainThread=true will remain alive -// even after the pthread quits, although be warned that if the target thread that was registered to handle events for a given WebSocket quits, then those -// events will stop from being delivered altogether. -void emscripten_websocket_deinitialize(void); - -#ifdef __cplusplus -} // ~extern "C" -#endif diff --git a/websocket/lib/web/library_websocket.js b/websocket/lib/web/library_websocket.js deleted file mode 100644 index 4994a6e..0000000 --- a/websocket/lib/web/library_websocket.js +++ /dev/null @@ -1,448 +0,0 @@ -/** - * @license - * Copyright 2018 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ - -var LibraryWebSocket = { - $WS: { - sockets: [null], - socketEvent: null - }, - - emscripten_websocket_get_ready_state__deps: ['$WS'], - emscripten_websocket_get_ready_state__proxy: 'sync', - emscripten_websocket_get_ready_state__sig: 'iii', - emscripten_websocket_get_ready_state: function(socketId, readyState) { - var socket = WS.sockets[socketId]; - if (!socket) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_get_ready_state(): Invalid socket ID ' + socketId + ' specified!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } - - {{{ makeSetValue('readyState', '0', 'socket.readyState', 'i16') }}}; - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; - }, - - emscripten_websocket_get_buffered_amount__deps: ['$WS'], - emscripten_websocket_get_buffered_amount__proxy: 'sync', - emscripten_websocket_get_buffered_amount__sig: 'iii', - emscripten_websocket_get_buffered_amount: function(socketId, bufferedAmount) { - var socket = WS.sockets[socketId]; - if (!socket) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_get_buffered_amount(): Invalid socket ID ' + socketId + ' specified!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } - - {{{ makeSetValue('bufferedAmount', '0', 'socket.bufferedAmount', 'i64') }}}; - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; - }, - - emscripten_websocket_get_extensions__deps: ['$WS'], - emscripten_websocket_get_extensions__proxy: 'sync', - emscripten_websocket_get_extensions__sig: 'iiii', - emscripten_websocket_get_extensions: function(socketId, extensions, extensionsLength) { - var socket = WS.sockets[socketId]; - if (!socket) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_get_extensions(): Invalid socket ID ' + socketId + ' specified!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } - if (!extensions) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; - stringToUTF8(socket.extensions, extensions, extensionsLength); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; - }, - - emscripten_websocket_get_extensions_length__deps: ['$WS'], - emscripten_websocket_get_extensions_length__proxy: 'sync', - emscripten_websocket_get_extensions_length__sig: 'iii', - emscripten_websocket_get_extensions_length: function(socketId, extensionsLength) { - var socket = WS.sockets[socketId]; - if (!socket) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_get_extensions_length(): Invalid socket ID ' + socketId + ' specified!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } - if (!extensionsLength) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; - {{{ makeSetValue('extensionsLength', '0', 'lengthBytesUTF8(socket.extensions)+1', 'i32') }}}; - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; - }, - - emscripten_websocket_get_protocol__deps: ['$WS'], - emscripten_websocket_get_protocol__proxy: 'sync', - emscripten_websocket_get_protocol__sig: 'iiii', - emscripten_websocket_get_protocol: function(socketId, protocol, protocolLength) { - var socket = WS.sockets[socketId]; - if (!socket) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_get_protocol(): Invalid socket ID ' + socketId + ' specified!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } - if (!protocol) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; - stringToUTF8(socket.protocol, protocol, protocolLength); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; - }, - - emscripten_websocket_get_protocol_length__deps: ['$WS'], - emscripten_websocket_get_protocol_length__proxy: 'sync', - emscripten_websocket_get_protocol_length__sig: 'iii', - emscripten_websocket_get_protocol_length: function(socketId, protocolLength) { - var socket = WS.sockets[socketId]; - if (!socket) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_get_protocol_length(): Invalid socket ID ' + socketId + ' specified!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } - if (!protocolLength) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; - {{{ makeSetValue('protocolLength', '0', 'lengthBytesUTF8(socket.protocol)+1', 'i32') }}}; - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; - }, - - emscripten_websocket_get_url__deps: ['$WS'], - emscripten_websocket_get_url__proxy: 'sync', - emscripten_websocket_get_url__sig: 'iiii', - emscripten_websocket_get_url: function(socketId, url, urlLength) { - var socket = WS.sockets[socketId]; - if (!socket) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_get_url(): Invalid socket ID ' + socketId + ' specified!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } - if (!url) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; - stringToUTF8(socket.url, url, urlLength); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; - }, - - emscripten_websocket_get_url_length__deps: ['$WS'], - 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]; - if (!socket) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_get_url_length(): Invalid socket ID ' + socketId + ' specified!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } - if (!urlLength) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; - {{{ makeSetValue('urlLength', '0', 'lengthBytesUTF8(socket.url)+1', 'i32') }}}; - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; - }, - - emscripten_websocket_set_onopen_callback_on_thread__deps: ['$WS'], - emscripten_websocket_set_onopen_callback_on_thread__proxy: 'sync', - emscripten_websocket_set_onopen_callback_on_thread__sig: 'iiiii', - emscripten_websocket_set_onopen_callback_on_thread: function(socketId, userData, callbackFunc, thread) { -// TODO: -// if (thread == {{{ cDefine('EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD') }}} || -// (thread == _pthread_self()) return emscripten_websocket_set_onopen_callback_on_calling_thread(socketId, userData, callbackFunc); - - if (!WS.socketEvent) WS.socketEvent = _malloc(1024); // TODO: sizeof(EmscriptenWebSocketCloseEvent), which is the largest event struct - - var socket = WS.sockets[socketId]; - if (!socket) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_set_onopen_callback(): Invalid socket ID ' + socketId + ' specified!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } - -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_set_onopen_callback(socketId='+socketId+',userData='+userData+',callbackFunc='+callbackFunc+')'); -#endif - socket.onopen = function(e) { -#if WEBSOCKET_DEBUG - console.error('websocket event "open": socketId='+socketId+',userData='+userData+',callbackFunc='+callbackFunc+')'); -#endif - HEAPU32[WS.socketEvent>>2] = socketId; - {{{ makeDynCall('iiii', 'callbackFunc') }}}(0/*TODO*/, WS.socketEvent, userData); - } - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; - }, - - emscripten_websocket_set_onerror_callback_on_thread__deps: ['$WS'], - emscripten_websocket_set_onerror_callback_on_thread__proxy: 'sync', - emscripten_websocket_set_onerror_callback_on_thread__sig: 'iiiii', - emscripten_websocket_set_onerror_callback_on_thread: function(socketId, userData, callbackFunc, thread) { - if (!WS.socketEvent) WS.socketEvent = _malloc(1024); // TODO: sizeof(EmscriptenWebSocketCloseEvent), which is the largest event struct - - var socket = WS.sockets[socketId]; - if (!socket) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_set_onerror_callback(): Invalid socket ID ' + socketId + ' specified!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } - -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_set_onerror_callback(socketId='+socketId+',userData='+userData+',callbackFunc='+callbackFunc+')'); -#endif - socket.onerror = function(e) { -#if WEBSOCKET_DEBUG - console.error('websocket event "error": socketId='+socketId+',userData='+userData+',callbackFunc='+callbackFunc+')'); -#endif - HEAPU32[WS.socketEvent>>2] = socketId; - {{{ makeDynCall('iiii', 'callbackFunc') }}}(0/*TODO*/, WS.socketEvent, userData); - } - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; - }, - - emscripten_websocket_set_onclose_callback_on_thread__deps: ['$WS'], - emscripten_websocket_set_onclose_callback_on_thread__proxy: 'sync', - emscripten_websocket_set_onclose_callback_on_thread__sig: 'iiiii', - emscripten_websocket_set_onclose_callback_on_thread: function(socketId, userData, callbackFunc, thread) { - if (!WS.socketEvent) WS.socketEvent = _malloc(1024); // TODO: sizeof(EmscriptenWebSocketCloseEvent), which is the largest event struct - - var socket = WS.sockets[socketId]; - if (!socket) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_set_onclose_callback(): Invalid socket ID ' + socketId + ' specified!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } - -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_set_onclose_callback(socketId='+socketId+',userData='+userData+',callbackFunc='+callbackFunc+')'); -#endif - socket.onclose = function(e) { -#if WEBSOCKET_DEBUG - console.error('websocket event "close": socketId='+socketId+',userData='+userData+',callbackFunc='+callbackFunc+')'); -#endif - HEAPU32[WS.socketEvent>>2] = socketId; - HEAPU32[(WS.socketEvent+4)>>2] = e.wasClean; - HEAPU32[(WS.socketEvent+8)>>2] = e.code; - stringToUTF8(e.reason, HEAPU32[(WS.socketEvent+10)>>2], 512); - {{{ makeDynCall('iiii', 'callbackFunc') }}}(0/*TODO*/, WS.socketEvent, userData); - } - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; - }, - - emscripten_websocket_set_onmessage_callback_on_thread__deps: ['$WS'], - emscripten_websocket_set_onmessage_callback_on_thread__proxy: 'sync', - emscripten_websocket_set_onmessage_callback_on_thread__sig: 'iiiii', - emscripten_websocket_set_onmessage_callback_on_thread: function(socketId, userData, callbackFunc, thread) { - if (!WS.socketEvent) WS.socketEvent = _malloc(1024); // TODO: sizeof(EmscriptenWebSocketCloseEvent), which is the largest event struct - - var socket = WS.sockets[socketId]; - if (!socket) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_set_onmessage_callback(): Invalid socket ID ' + socketId + ' specified!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } - -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_set_onmessage_callback(socketId='+socketId+',userData='+userData+',callbackFunc='+callbackFunc+')'); -#endif - socket.onmessage = function(e) { -#if WEBSOCKET_DEBUG == 2 - console.error('websocket event "message": socketId='+socketId+',userData='+userData+',callbackFunc='+callbackFunc+')'); -#endif - HEAPU32[WS.socketEvent>>2] = socketId; - if (typeof e.data === 'string') { - var len = lengthBytesUTF8(e.data)+1; - var buf = _malloc(len); - stringToUTF8(e.data, buf, len); -#if WEBSOCKET_DEBUG - var s = (e.data.length < 256) ? e.data : (e.data.substr(0, 256) + ' (' + (e.data.length-256) + ' more characters)'); - console.error('WebSocket onmessage, received data: "' + e.data + '", ' + e.data.length + ' chars, ' + len + ' bytes encoded as UTF-8: "' + s + '"'); -#endif - HEAPU32[(WS.socketEvent+12)>>2] = 1; // text data - } else { - var len = e.data.byteLength; - var buf = _malloc(len); - HEAP8.set(new Uint8Array(e.data), buf); -#if WEBSOCKET_DEBUG - var s = 'WebSocket onmessage, received data: ' + len + ' bytes of binary:'; - for(var i = 0; i < Math.min(len, 256); ++i) s += ' ' + HEAPU8[buf+i].toString(16); - s += ', "'; - for(var i = 0; i < Math.min(len, 256); ++i) s += (HEAPU8[buf+i] >= 32 && HEAPU8[buf+i] <= 127) ? String.fromCharCode(HEAPU8[buf+i]) : '\uFFFD'; - s += '"'; - if (len > 256) s + ' ... (' + (len - 256) + ' more bytes)'; - - console.error(s); -#endif - HEAPU32[(WS.socketEvent+12)>>2] = 0; // binary data - } - HEAPU32[(WS.socketEvent+4)>>2] = buf; - HEAPU32[(WS.socketEvent+8)>>2] = len; - {{{ makeDynCall('iiii', 'callbackFunc') }}}(0/*TODO*/, WS.socketEvent, userData); - _free(buf); - } - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; - }, - - emscripten_websocket_new__deps: ['$WS'], - emscripten_websocket_new__proxy: 'sync', - emscripten_websocket_new__sig: 'ii', - emscripten_websocket_new: function(createAttributes) { - if (typeof WebSocket === 'undefined') { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_new(): WebSocket API is not supported by current browser)'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; - } - if (!createAttributes) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_new(): Missing required "createAttributes" function parameter!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; - } - - var createAttrs = createAttributes>>2; - var url = UTF8ToString(HEAP32[createAttrs]); - var protocols = HEAP32[createAttrs+1]; - // TODO: Add support for createOnMainThread==false; currently all WebSocket connections are created on the main thread. - // var createOnMainThread = HEAP32[createAttrs+2]; - - var socket = protocols ? new WebSocket(url, UTF8ToString(protocols).split(',')) : new WebSocket(url); - // We always marshal received WebSocket data back to Wasm, so enable receiving the data as arraybuffers for easy marshalling. - socket.binaryType = 'arraybuffer'; - // TODO: While strictly not necessary, this ID would be good to be unique across all threads to avoid confusion. - var socketId = WS.sockets.length; - WS.sockets[socketId] = socket; - -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_new(url='+url+', protocols=' + (protocols?UTF8ToString(protocols).split(','):'null') + '): created socket ID ' + socketId + ')'); -#endif - return socketId; - }, - - emscripten_websocket_send_utf8_text__deps: ['$WS'], - emscripten_websocket_send_utf8_text__proxy: 'sync', - emscripten_websocket_send_utf8_text__sig: 'iii', - emscripten_websocket_send_utf8_text: function(socketId, textData) { - var socket = WS.sockets[socketId]; - if (!socket) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_send_utf8_text(): Invalid socket ID ' + socketId + ' specified!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } - - var str = UTF8ToString(textData); -#if WEBSOCKET_DEBUG == 2 - console.error('emscripten_websocket_send_utf8_text(socketId='+socketId+',textData='+ str.length + ' chars, "' + str +'")'); -#else -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_send_utf8_text(socketId='+socketId+',textData='+ str.length + ' chars, "' + ((str.length > 8) ? (str.substring(0,8) + '...') : str) + '")'); -#endif -#endif - socket.send(str); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; - }, - - emscripten_websocket_send_binary__deps: ['$WS'], - emscripten_websocket_send_binary__proxy: 'sync', - emscripten_websocket_send_binary__sig: 'iiii', - emscripten_websocket_send_binary: function(socketId, binaryData, dataLength) { - var socket = WS.sockets[socketId]; - if (!socket) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_send_binary(): Invalid socket ID ' + socketId + ' specified!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } - -#if WEBSOCKET_DEBUG - var s = 'data: ' + dataLength + ' bytes of binary:'; - for(var i = 0; i < Math.min(dataLength, 256); ++i) s += ' '+ HEAPU8[binaryData+i].toString(16); - s += ', "'; - for(var i = 0; i < Math.min(dataLength, 256); ++i) s += (HEAPU8[binaryData+i] >= 32 && HEAPU8[binaryData+i] <= 127) ? String.fromCharCode(HEAPU8[binaryData+i]) : '\uFFFD'; - s += '"'; - if (dataLength > 256) s + ' ... (' + (dataLength - 256) + ' more bytes)'; - - console.error('emscripten_websocket_send_binary(socketId='+socketId+',binaryData='+binaryData+ ',dataLength='+dataLength+'), ' + s); -#endif -#if USE_PTHREADS - // TODO: This is temporary to cast a shared Uint8Array to a non-shared Uint8Array. This could be removed if WebSocket API is improved - // to allow passing in views to SharedArrayBuffers - socket.send(new Uint8Array({{{ makeHEAPView('U8', 'binaryData', 'binaryData+dataLength') }}})); -#else - socket.send({{{ makeHEAPView('U8', 'binaryData', 'binaryData+dataLength') }}}); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; - }, - - emscripten_websocket_close__deps: ['$WS'], - emscripten_websocket_close__proxy: 'sync', - emscripten_websocket_close__sig: 'iiii', - emscripten_websocket_close: function(socketId, code, reason) { - var socket = WS.sockets[socketId]; - if (!socket) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_close(): Invalid socket ID ' + socketId + ' specified!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } - - var reasonStr = reason ? UTF8ToString(reason) : undefined; -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_close(socketId='+socketId+',code='+code+',reason='+reasonStr+')'); -#endif - // According to WebSocket specification, only close codes that are recognized have integer values - // 1000-4999, with 3000-3999 and 4000-4999 denoting user-specified close codes: - // https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#Status_codes - // Therefore be careful to call the .close() function with exact number and types of parameters. - // Coerce code==0 to undefined, since Wasm->JS call can only marshal integers, and 0 is not allowed. - if (reason) socket.close(code || undefined, UTF8ToString(reason)); - else if (code) socket.close(code); - else socket.close(); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; - }, - - emscripten_websocket_delete__deps: ['$WS'], - emscripten_websocket_delete__proxy: 'sync', - emscripten_websocket_delete__sig: 'ii', - emscripten_websocket_delete: function(socketId) { - var socket = WS.sockets[socketId]; - if (!socket) { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_delete(): Invalid socket ID ' + socketId + ' specified!'); -#endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; - } - -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_delete(socketId='+socketId+')'); -#endif - socket.onopen = socket.onerror = socket.onclose = socket.onmessage = null; - delete WS.sockets[socket]; - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; - }, - - emscripten_websocket_is_supported__proxy: 'sync', - emscripten_websocket_is_supported__sig: 'i', - emscripten_websocket_is_supported: function() { - return typeof WebSocket !== 'undefined'; - }, - - emscripten_websocket_deinitialize__deps: ['$WS'], - emscripten_websocket_deinitialize__proxy: 'sync', - emscripten_websocket_deinitialize__sig: 'v', - emscripten_websocket_deinitialize__deps: ['emscripten_websocket_delete'], - emscripten_websocket_deinitialize: function() { -#if WEBSOCKET_DEBUG - console.error('emscripten_websocket_deinitialize()'); -#endif - for(var i in WS.sockets) { - var socket = WS.sockets[i]; - if (socket) { - socket.close(); - _emscripten_websocket_delete(i); - } - } - WS.sockets = []; - } -} - -mergeInto(LibraryManager.library, LibraryWebSocket); diff --git a/websocket/src/websocket.h b/websocket/src/websocket.h index 55517af..cd7d1cb 100644 --- a/websocket/src/websocket.h +++ b/websocket/src/websocket.h @@ -16,7 +16,7 @@ #endif #if defined(__EMSCRIPTEN__) -#include "emscripten/websocket.h" +#include #endif #include