Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/mono/wasm/runtime/web-socket.ts')
-rw-r--r--src/mono/wasm/runtime/web-socket.ts484
1 files changed, 190 insertions, 294 deletions
diff --git a/src/mono/wasm/runtime/web-socket.ts b/src/mono/wasm/runtime/web-socket.ts
index caaa9bd3930..feeebf0f449 100644
--- a/src/mono/wasm/runtime/web-socket.ts
+++ b/src/mono/wasm/runtime/web-socket.ts
@@ -1,19 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-import { mono_wasm_new_root, mono_wasm_new_external_root } from "./roots";
-import { setI32 } from "./memory";
import { prevent_timer_throttling } from "./scheduling";
import { Queue } from "./queue";
-import { PromiseControl, _create_cancelable_promise } from "./cancelable-promise";
-import { mono_array_root_to_js_array, _wrap_delegate_root_as_function } from "./cs-to-js";
-import { mono_wasm_get_jsobj_from_js_handle, mono_wasm_get_js_handle } from "./gc-handles";
-import { _wrap_js_thenable_as_task_root } from "./js-to-cs";
-import { wrap_error_root } from "./method-calls";
-import { conv_string_root } from "./strings";
-import { JSHandle, MonoArray, MonoObject, MonoString, MonoObjectRef } from "./types";
-import { Module } from "./imports";
-import { Int32Ptr, VoidPtr } from "./types/emscripten";
+import { PromiseControl, create_cancelable_promise } from "./cancelable-promise";
+import { mono_assert } from "./types";
+import { ArraySegment, IDisposable } from "./marshal";
const wasm_ws_pending_send_buffer = Symbol.for("wasm ws_pending_send_buffer");
const wasm_ws_pending_send_buffer_offset = Symbol.for("wasm ws_pending_send_buffer_offset");
@@ -30,302 +22,210 @@ let _text_encoder_utf8: TextEncoder | undefined = undefined;
const ws_send_buffer_blocking_threshold = 65536;
const emptyBuffer = new Uint8Array();
-export function mono_wasm_web_socket_open_ref(uri_address: MonoObjectRef, subProtocols: MonoObjectRef, on_close: MonoObjectRef, web_socket_js_handle: Int32Ptr, thenable_js_handle: Int32Ptr, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
- const result_root = mono_wasm_new_external_root<MonoObject>(result_address);
- const uri_root = mono_wasm_new_external_root<MonoString>(uri_address);
- const sub_root = mono_wasm_new_external_root<MonoArray>(subProtocols);
- const on_close_root = mono_wasm_new_root();
- on_close_root.copy_from_address(on_close);
- try {
- const js_uri = conv_string_root(uri_root);
- if (!js_uri) {
- wrap_error_root(is_exception, "ERR12: Invalid uri '" + uri_root.value + "'", result_root);
- return;
- }
+export function ws_wasm_create(uri: string, sub_protocols: string[] | null, onClosed: (code: number, reason: string) => void): WebSocketExtension {
+ mono_assert(uri && typeof uri === "string", () => `ERR12: Invalid uri ${typeof uri}`);
+
+ const ws = new globalThis.WebSocket(uri, sub_protocols || undefined) as WebSocketExtension;
+ const { promise_control: open_promise_control } = create_cancelable_promise();
+
+ ws[wasm_ws_pending_receive_event_queue] = new Queue();
+ ws[wasm_ws_pending_receive_promise_queue] = new Queue();
+ ws[wasm_ws_pending_open_promise] = open_promise_control;
+ ws[wasm_ws_pending_send_promises] = [];
+ ws[wasm_ws_pending_close_promises] = [];
+ ws.binaryType = "arraybuffer";
+ const local_on_open = () => {
+ if (ws[wasm_ws_is_aborted]) return;
+ open_promise_control.resolve(ws);
+ prevent_timer_throttling();
+ };
+ const local_on_message = (ev: MessageEvent) => {
+ if (ws[wasm_ws_is_aborted]) return;
+ _mono_wasm_web_socket_on_message(ws, ev);
+ prevent_timer_throttling();
+ };
+ const local_on_close = (ev: CloseEvent) => {
+ ws.removeEventListener("message", local_on_message);
+ if (ws[wasm_ws_is_aborted]) return;
+ if (onClosed) onClosed(ev.code, ev.reason);
+
+ // this reject would not do anything if there was already "open" before it.
+ open_promise_control.reject(ev.reason);
- const js_subs = mono_array_root_to_js_array(sub_root);
-
- const js_on_close = _wrap_delegate_root_as_function(on_close_root)!;
-
- const ws = new globalThis.WebSocket(js_uri, <any>js_subs) as WebSocketExtension;
- const { promise, promise_control: open_promise_control } = _create_cancelable_promise();
-
- ws[wasm_ws_pending_receive_event_queue] = new Queue();
- ws[wasm_ws_pending_receive_promise_queue] = new Queue();
- ws[wasm_ws_pending_open_promise] = open_promise_control;
- ws[wasm_ws_pending_send_promises] = [];
- ws[wasm_ws_pending_close_promises] = [];
- ws.binaryType = "arraybuffer";
- const local_on_open = () => {
- if (ws[wasm_ws_is_aborted]) return;
- open_promise_control.resolve(null);
- prevent_timer_throttling();
- };
- const local_on_message = (ev: MessageEvent) => {
- if (ws[wasm_ws_is_aborted]) return;
- _mono_wasm_web_socket_on_message(ws, ev);
- prevent_timer_throttling();
- };
- const local_on_close = (ev: CloseEvent) => {
- ws.removeEventListener("message", local_on_message);
- if (ws[wasm_ws_is_aborted]) return;
- js_on_close(ev.code, ev.reason);
-
- // this reject would not do anything if there was already "open" before it.
- open_promise_control.reject(ev.reason);
-
- for (const close_promise_control of ws[wasm_ws_pending_close_promises]) {
- close_promise_control.resolve();
- }
+ for (const close_promise_control of ws[wasm_ws_pending_close_promises]) {
+ close_promise_control.resolve();
+ }
- // send close to any pending receivers, to wake them
- const receive_promise_queue = ws[wasm_ws_pending_receive_promise_queue];
- receive_promise_queue.drain((receive_promise_control) => {
- const response_ptr = receive_promise_control.response_ptr;
- setI32(<any>response_ptr + 0, 0);// count
- setI32(<any>response_ptr + 4, 2);// type:close
- setI32(<any>response_ptr + 8, 1);// end_of_message: true
- receive_promise_control.resolve(null);
- });
- };
- const local_on_error = (ev: any) => {
- open_promise_control.reject(ev.message);
- };
- ws.addEventListener("message", local_on_message);
- ws.addEventListener("open", local_on_open, { once: true });
- ws.addEventListener("close", local_on_close, { once: true });
- ws.addEventListener("error", local_on_error, { once: true });
- const ws_js_handle = mono_wasm_get_js_handle(ws);
- Module.setValue(web_socket_js_handle, <any>ws_js_handle, "i32");
-
- const { then_js_handle } = _wrap_js_thenable_as_task_root(promise, result_root);
- // task_ptr above is not rooted, we need to return it to mono without any intermediate mono call which could cause GC
- Module.setValue(thenable_js_handle, <any>then_js_handle, "i32");
- }
- catch (ex) {
- wrap_error_root(is_exception, ex, result_root);
- }
- finally {
- result_root.release();
- uri_root.release();
- sub_root.release();
- on_close_root.release();
- }
+ // send close to any pending receivers, to wake them
+ const receive_promise_queue = ws[wasm_ws_pending_receive_promise_queue];
+ receive_promise_queue.drain((receive_promise_control) => {
+
+ const response = new Int32Array([
+ 0,// count
+ 2, // type:close
+ 1]);// end_of_message: true
+ receive_promise_control.responseView.set(response);
+ receive_promise_control.resolve(null);
+ });
+ };
+ const local_on_error = (ev: any) => {
+ open_promise_control.reject(ev.message || "WebSocket error");
+ };
+ ws.addEventListener("message", local_on_message);
+ ws.addEventListener("open", local_on_open, { once: true });
+ ws.addEventListener("close", local_on_close, { once: true });
+ ws.addEventListener("error", local_on_error, { once: true });
+
+ return ws;
}
-export function mono_wasm_web_socket_send(webSocket_js_handle: JSHandle, buffer_ptr: VoidPtr, offset: number, length: number, message_type: number, end_of_message: boolean, thenable_js_handle: Int32Ptr, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
- const result_root = mono_wasm_new_external_root<MonoObject>(result_address);
- try {
- const ws = mono_wasm_get_jsobj_from_js_handle(webSocket_js_handle);
- if (!ws)
- throw new Error("ERR17: Invalid JS object handle " + webSocket_js_handle);
+export function ws_wasm_open(ws: WebSocketExtension): Promise<void> | null {
+ mono_assert(!!ws, "ERR17: expected ws instance");
+ const open_promise_control = ws[wasm_ws_pending_open_promise];
+ return open_promise_control.promise;
+}
- if (ws.readyState != WebSocket.OPEN) {
- throw new Error("InvalidState: The WebSocket is not connected.");
- }
+export function ws_wasm_send(ws: WebSocketExtension, bufferView: ArraySegment, message_type: number, end_of_message: boolean): Promise<void> | null {
+ mono_assert(!!ws, "ERR17: expected ws instance");
- const whole_buffer = _mono_wasm_web_socket_send_buffering(ws, buffer_ptr, offset, length, message_type, end_of_message);
+ const whole_buffer = _mono_wasm_web_socket_send_buffering(ws, bufferView, message_type, end_of_message);
- if (!end_of_message || !whole_buffer) {
- result_root.clear(); // we are done buffering synchronously, no promise
- return;
- }
- _mono_wasm_web_socket_send_and_wait(ws, whole_buffer, thenable_js_handle, result_address);
- }
- catch (ex) {
- wrap_error_root(is_exception, ex, result_root);
- }
- finally {
- result_root.release();
+ if (!end_of_message || !whole_buffer) {
+ return null;
}
+
+ return _mono_wasm_web_socket_send_and_wait(ws, whole_buffer, bufferView);
}
-export function mono_wasm_web_socket_receive(webSocket_js_handle: JSHandle, buffer_ptr: VoidPtr, offset: number, length: number, response_ptr: VoidPtr, thenable_js_handle: Int32Ptr, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
- const result_root = mono_wasm_new_external_root<MonoObject>(result_address);
+export function ws_wasm_receive(ws: WebSocketExtension, bufferView: ArraySegment, responseView: ArraySegment): Promise<void> | null {
+ mono_assert(!!ws, "ERR18: expected ws instance");
- try {
- const ws = mono_wasm_get_jsobj_from_js_handle(webSocket_js_handle);
- if (!ws)
- throw new Error("ERR18: Invalid JS object handle " + webSocket_js_handle);
- const receive_event_queue = ws[wasm_ws_pending_receive_event_queue];
- const receive_promise_queue = ws[wasm_ws_pending_receive_promise_queue];
+ const receive_event_queue = ws[wasm_ws_pending_receive_event_queue];
+ const receive_promise_queue = ws[wasm_ws_pending_receive_promise_queue];
- const readyState = ws.readyState;
- if (readyState != WebSocket.OPEN && readyState != WebSocket.CLOSING) {
- throw new Error("InvalidState: The WebSocket is not connected.");
- }
+ const readyState = ws.readyState;
+ if (readyState != WebSocket.OPEN && readyState != WebSocket.CLOSING) {
+ throw new Error("InvalidState: The WebSocket is not connected.");
+ }
- if (receive_event_queue.getLength()) {
- if (receive_promise_queue.getLength() != 0) {
- throw new Error("ERR20: Invalid WS state");// assert
- }
- // finish synchronously
- _mono_wasm_web_socket_receive_buffering(receive_event_queue, buffer_ptr, offset, length, response_ptr);
+ if (receive_event_queue.getLength()) {
+ mono_assert(receive_promise_queue.getLength() == 0, "ERR20: Invalid WS state");
- Module.setValue(thenable_js_handle, 0, "i32");
- result_root.clear();
- return;
- }
- const { promise, promise_control } = _create_cancelable_promise(undefined, undefined);
- const receive_promise_control = promise_control as ReceivePromiseControl;
- receive_promise_control.buffer_ptr = buffer_ptr;
- receive_promise_control.buffer_offset = offset;
- receive_promise_control.buffer_length = length;
- receive_promise_control.response_ptr = response_ptr;
- receive_promise_queue.enqueue(receive_promise_control);
-
- const { then_js_handle } = _wrap_js_thenable_as_task_root(promise, result_root);
- // task_ptr above is not rooted, we need to return it to mono without any intermediate mono call which could cause GC
- Module.setValue(thenable_js_handle, <any>then_js_handle, "i32");
- }
- catch (ex) {
- wrap_error_root(is_exception, ex, result_root);
- }
- finally {
- result_root.release();
+ // finish synchronously
+ _mono_wasm_web_socket_receive_buffering(receive_event_queue, bufferView, responseView);
+
+ return null;
}
-}
+ const { promise, promise_control } = create_cancelable_promise(undefined, undefined);
+ const receive_promise_control = promise_control as ReceivePromiseControl;
+ receive_promise_control.bufferView = bufferView;
+ receive_promise_control.responseView = responseView;
+ receive_promise_queue.enqueue(receive_promise_control);
-export function mono_wasm_web_socket_close_ref(webSocket_js_handle: JSHandle, code: number, reason: MonoObjectRef, wait_for_close_received: boolean, thenable_js_handle: Int32Ptr, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
- const result_root = mono_wasm_new_external_root<MonoObject>(result_address);
- const reason_root = mono_wasm_new_external_root<MonoString>(reason);
- try {
- const ws = mono_wasm_get_jsobj_from_js_handle(webSocket_js_handle);
- if (!ws)
- throw new Error("ERR19: Invalid JS object handle " + webSocket_js_handle);
+ return promise;
+}
- if (ws.readyState == WebSocket.CLOSED) {
- result_root.clear();
- return;
- }
+export function ws_wasm_close(ws: WebSocketExtension, code: number, reason: string | null, wait_for_close_received: boolean): Promise<void> | null {
+ mono_assert(!!ws, "ERR19: expected ws instance");
- const js_reason = conv_string_root(reason_root);
- if (wait_for_close_received) {
- const { promise, promise_control } = _create_cancelable_promise();
- ws[wasm_ws_pending_close_promises].push(promise_control);
+ if (ws.readyState == WebSocket.CLOSED) {
+ return null;
+ }
- if (typeof (js_reason) === "string") {
- ws.close(code, js_reason);
- } else {
- ws.close(code);
- }
+ if (wait_for_close_received) {
+ const { promise, promise_control } = create_cancelable_promise();
+ ws[wasm_ws_pending_close_promises].push(promise_control);
- const { then_js_handle } = _wrap_js_thenable_as_task_root(promise, result_root);
- // task_ptr above is not rooted, we need to return it to mono without any intermediate mono call which could cause GC
- Module.setValue(thenable_js_handle, <any>then_js_handle, "i32");
- }
- else {
- if (!mono_wasm_web_socket_close_warning) {
- mono_wasm_web_socket_close_warning = true;
- console.warn("WARNING: Web browsers do not support closing the output side of a WebSocket. CloseOutputAsync has closed the socket and discarded any incoming messages.");
- }
- if (typeof (js_reason) === "string") {
- ws.close(code, js_reason);
- } else {
- ws.close(code);
- }
- Module.setValue(thenable_js_handle, 0, "i32");
- result_root.clear();
+ if (typeof reason === "string") {
+ ws.close(code, reason);
+ } else {
+ ws.close(code);
}
+ return promise;
}
- catch (ex) {
- wrap_error_root(is_exception, ex, result_root);
- }
- finally {
- result_root.release();
- reason_root.release();
- }
-}
-
-export function mono_wasm_web_socket_abort(webSocket_js_handle: JSHandle, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
- const result_root = mono_wasm_new_external_root<MonoObject>(result_address);
- try {
- const ws = mono_wasm_get_jsobj_from_js_handle(webSocket_js_handle) as WebSocketExtension;
- if (!ws)
- throw new Error("ERR18: Invalid JS object handle " + webSocket_js_handle);
-
- ws[wasm_ws_is_aborted] = true;
- const open_promise_control = ws[wasm_ws_pending_open_promise];
- if (open_promise_control) {
- open_promise_control.reject("OperationCanceledException");
- }
- for (const close_promise_control of ws[wasm_ws_pending_close_promises]) {
- close_promise_control.reject("OperationCanceledException");
+ else {
+ if (!mono_wasm_web_socket_close_warning) {
+ mono_wasm_web_socket_close_warning = true;
+ console.warn("WARNING: Web browsers do not support closing the output side of a WebSocket. CloseOutputAsync has closed the socket and discarded any incoming messages.");
}
- for (const send_promise_control of ws[wasm_ws_pending_send_promises]) {
- send_promise_control.reject("OperationCanceledException");
+ if (typeof reason === "string") {
+ ws.close(code, reason);
+ } else {
+ ws.close(code);
}
+ return null;
+ }
+}
- ws[wasm_ws_pending_receive_promise_queue].drain(receive_promise_control => {
- receive_promise_control.reject("OperationCanceledException");
- });
-
- // this is different from Managed implementation
- ws.close(1000, "Connection was aborted.");
+export function ws_wasm_abort(ws: WebSocketExtension): void {
+ mono_assert(!!ws, "ERR18: expected ws instance");
- result_root.clear();
+ ws[wasm_ws_is_aborted] = true;
+ const open_promise_control = ws[wasm_ws_pending_open_promise];
+ if (open_promise_control) {
+ open_promise_control.reject("OperationCanceledException");
}
- catch (ex) {
- wrap_error_root(is_exception, ex, result_root);
+ for (const close_promise_control of ws[wasm_ws_pending_close_promises]) {
+ close_promise_control.reject("OperationCanceledException");
}
- finally {
- result_root.release();
+ for (const send_promise_control of ws[wasm_ws_pending_send_promises]) {
+ send_promise_control.reject("OperationCanceledException");
}
+
+ ws[wasm_ws_pending_receive_promise_queue].drain(receive_promise_control => {
+ receive_promise_control.reject("OperationCanceledException");
+ });
+
+ // this is different from Managed implementation
+ ws.close(1000, "Connection was aborted.");
}
-function _mono_wasm_web_socket_send_and_wait(ws: WebSocketExtension, buffer: Uint8Array | string, thenable_js_handle: Int32Ptr, result_address: MonoObjectRef): void {
- const result_root = mono_wasm_new_external_root<MonoObject>(result_address);
- try {
- // send and return promise
- ws.send(buffer);
- ws[wasm_ws_pending_send_buffer] = null;
-
- // if the remaining send buffer is small, we don't block so that the throughput doesn't suffer.
- // Otherwise we block so that we apply some backpresure to the application sending large data.
- // this is different from Managed implementation
- if (ws.bufferedAmount < ws_send_buffer_blocking_threshold) {
- result_root.clear();
- return;
- }
+function _mono_wasm_web_socket_send_and_wait(ws: WebSocketExtension, buffer: Uint8Array | string, managedBuffer: IDisposable): Promise<void> | null {
+ // send and return promise
+ ws.send(buffer);
+ managedBuffer.dispose();
+ ws[wasm_ws_pending_send_buffer] = null;
+
+ // if the remaining send buffer is small, we don't block so that the throughput doesn't suffer.
+ // Otherwise we block so that we apply some backpresure to the application sending large data.
+ // this is different from Managed implementation
+ if (ws.bufferedAmount < ws_send_buffer_blocking_threshold) {
+ return null;
+ }
- // block the promise/task until the browser passed the buffer to OS
- const { promise, promise_control } = _create_cancelable_promise();
- const pending = ws[wasm_ws_pending_send_promises];
- pending.push(promise_control);
+ // block the promise/task until the browser passed the buffer to OS
+ const { promise, promise_control } = create_cancelable_promise();
+ const pending = ws[wasm_ws_pending_send_promises];
+ pending.push(promise_control);
- let nextDelay = 1;
- const polling_check = () => {
- // was it all sent yet ?
- if (ws.bufferedAmount === 0) {
- promise_control.resolve(null);
- }
- else if (ws.readyState != WebSocket.OPEN) {
- // only reject if the data were not sent
- // bufferedAmount does not reset to zero once the connection closes
- promise_control.reject("InvalidState: The WebSocket is not connected.");
- }
- else if (!promise_control.isDone) {
- globalThis.setTimeout(polling_check, nextDelay);
- // exponentially longer delays, up to 1000ms
- nextDelay = Math.min(nextDelay * 1.5, 1000);
- return;
- }
- // remove from pending
- const index = pending.indexOf(promise_control);
- if (index > -1) {
- pending.splice(index, 1);
- }
- };
+ let nextDelay = 1;
+ const polling_check = () => {
+ // was it all sent yet ?
+ if (ws.bufferedAmount === 0) {
+ promise_control.resolve(null);
+ }
+ else if (ws.readyState != WebSocket.OPEN) {
+ // only reject if the data were not sent
+ // bufferedAmount does not reset to zero once the connection closes
+ promise_control.reject("InvalidState: The WebSocket is not connected.");
+ }
+ else if (!promise_control.isDone) {
+ globalThis.setTimeout(polling_check, nextDelay);
+ // exponentially longer delays, up to 1000ms
+ nextDelay = Math.min(nextDelay * 1.5, 1000);
+ return;
+ }
+ // remove from pending
+ const index = pending.indexOf(promise_control);
+ if (index > -1) {
+ pending.splice(index, 1);
+ }
+ };
- globalThis.setTimeout(polling_check, 0);
+ globalThis.setTimeout(polling_check, 0);
- const { then_js_handle } = _wrap_js_thenable_as_task_root(promise, result_root);
- // task_ptr above is not rooted, we need to return it to mono without any intermediate mono call which could cause GC
- Module.setValue(thenable_js_handle, <any>then_js_handle, "i32");
- } finally {
- result_root.release();
- }
+ return promise;
}
function _mono_wasm_web_socket_on_message(ws: WebSocketExtension, event: MessageEvent) {
@@ -361,36 +261,37 @@ function _mono_wasm_web_socket_on_message(ws: WebSocketExtension, event: Message
while (promise_queue.getLength() && event_queue.getLength()) {
const promise_control = promise_queue.dequeue()!;
_mono_wasm_web_socket_receive_buffering(event_queue,
- promise_control.buffer_ptr, promise_control.buffer_offset, promise_control.buffer_length,
- promise_control.response_ptr);
+ promise_control.bufferView, promise_control.responseView);
promise_control.resolve(null);
}
prevent_timer_throttling();
}
-function _mono_wasm_web_socket_receive_buffering(event_queue: Queue<any>, buffer_ptr: VoidPtr, buffer_offset: number, buffer_length: number, response_ptr: VoidPtr) {
+function _mono_wasm_web_socket_receive_buffering(event_queue: Queue<any>, bufferView: ArraySegment, responseView: ArraySegment) {
const event = event_queue.peek();
- const count = Math.min(buffer_length, event.data.length - event.offset);
+ const count = Math.min(bufferView.length, event.data.length - event.offset);
if (count > 0) {
- const targetView = Module.HEAPU8.subarray(<any>buffer_ptr + buffer_offset, <any>buffer_ptr + buffer_offset + buffer_length);
const sourceView = event.data.subarray(event.offset, event.offset + count);
- targetView.set(sourceView, 0);
+ bufferView.set(sourceView, 0);
event.offset += count;
}
const end_of_message = event.data.length === event.offset ? 1 : 0;
if (end_of_message) {
event_queue.dequeue();
}
- setI32(<any>response_ptr + 0, count);
- setI32(<any>response_ptr + 4, event.type);
- setI32(<any>response_ptr + 8, end_of_message);
+
+ const response = new Int32Array([count, event.type, end_of_message]);
+ responseView.set(response);
+
+ bufferView.dispose();
+ responseView.dispose();
}
-function _mono_wasm_web_socket_send_buffering(ws: WebSocketExtension, buffer_ptr: VoidPtr, buffer_offset: number, length: number, message_type: number, end_of_message: boolean): Uint8Array | string | null {
+function _mono_wasm_web_socket_send_buffering(ws: WebSocketExtension, bufferView: ArraySegment, message_type: number, end_of_message: boolean): Uint8Array | string | null {
let buffer = ws[wasm_ws_pending_send_buffer];
let offset = 0;
- const message_ptr = <any>buffer_ptr + buffer_offset;
+ const length = bufferView.length;
if (buffer) {
offset = ws[wasm_ws_pending_send_buffer_offset];
@@ -398,15 +299,14 @@ function _mono_wasm_web_socket_send_buffering(ws: WebSocketExtension, buffer_ptr
message_type = ws[wasm_ws_pending_send_buffer_type];
// if not empty message, append to existing buffer
if (length !== 0) {
- const view = Module.HEAPU8.subarray(message_ptr, message_ptr + length);
if (offset + length > buffer.length) {
const newbuffer = new Uint8Array((offset + length + 50) * 1.5); // exponential growth
newbuffer.set(buffer, 0);// copy previous buffer
- newbuffer.set(view, offset);// append copy at the end
+ bufferView.copyTo(newbuffer.subarray(offset));// append copy at the end
ws[wasm_ws_pending_send_buffer] = buffer = newbuffer;
}
else {
- buffer.set(view, offset);// append copy at the end
+ bufferView.copyTo(buffer.subarray(offset));// append copy at the end
}
offset += length;
ws[wasm_ws_pending_send_buffer_offset] = offset;
@@ -415,8 +315,7 @@ function _mono_wasm_web_socket_send_buffering(ws: WebSocketExtension, buffer_ptr
else if (!end_of_message) {
// create new buffer
if (length !== 0) {
- const view = Module.HEAPU8.subarray(message_ptr, message_ptr + length);
- buffer = new Uint8Array(view); // copy
+ buffer = <Uint8Array>bufferView.slice(); // copy
offset = length;
ws[wasm_ws_pending_send_buffer_offset] = offset;
ws[wasm_ws_pending_send_buffer] = buffer;
@@ -424,10 +323,9 @@ function _mono_wasm_web_socket_send_buffering(ws: WebSocketExtension, buffer_ptr
ws[wasm_ws_pending_send_buffer_type] = message_type;
}
else {
- // use the buffer only localy
if (length !== 0) {
- const memoryView = Module.HEAPU8.subarray(message_ptr, message_ptr + length);
- buffer = memoryView; // send will make a copy
+ // we could use the unsafe view, because it will be immediately used in ws.send()
+ buffer = <Uint8Array>bufferView._unsafe_create_view();
offset = length;
}
}
@@ -469,10 +367,8 @@ type WebSocketExtension = WebSocket & {
}
type ReceivePromiseControl = PromiseControl & {
- response_ptr: VoidPtr
- buffer_ptr: VoidPtr
- buffer_offset: number
- buffer_length: number
+ bufferView: ArraySegment,
+ responseView: ArraySegment
}
type Message = {