private async Task ConnectAsyncJavaScript(Uri uri, CancellationToken cancellationToken) { var tcsConnect = new TaskCompletionSource <bool> (); // For Abort/Dispose. Calling Abort on the request at any point will close the connection. cts.Token.Register(AbortRequest); // Wrap the cancellationToken in a using so that it can be disposed of whether // we successfully connected or failed trying. // Otherwise any timeout/cancellation would apply to the full session. // In the failure case we need to release the references and dispose of the objects. using (cancellationToken.Register(() => tcsConnect.TrySetCanceled())) { try { Core.Array subProtocols = null; if (Options.RequestedSubProtocols.Count > 0) { subProtocols = new Core.Array(); foreach (var item in Options.RequestedSubProtocols) { subProtocols.Push(item); } } innerWebSocket = new HostObject("WebSocket", uri.ToString(), subProtocols); subProtocols?.Dispose(); // Setup the onError callback onError = new Action <JSObject> ((errorEvt) => { errorEvt.Dispose(); }); // Attach the onError callback innerWebSocket.SetObjectProperty("onerror", onError); // Setup the onClose callback onClose = new Action <JSObject> ((closeEvt) => { innerWebSocketCloseStatus = (WebSocketCloseStatus)closeEvt.GetObjectProperty("code"); innerWebSocketCloseStatusDescription = closeEvt.GetObjectProperty("reason")?.ToString(); var mess = new ReceivePayload(WebSocketHelpers.EmptyPayload, WebSocketMessageType.Close); receiveMessageQueue.BufferPayload(mess); if (!tcsConnect.Task.IsCanceled && !tcsConnect.Task.IsCompleted && !tcsConnect.Task.IsFaulted) { tcsConnect.SetException(new WebSocketException(WebSocketError.NativeError)); } else { tcsClose?.SetResult(true); } closeEvt.Dispose(); }); // Attach the onClose callback innerWebSocket.SetObjectProperty("onclose", onClose); // Setup the onOpen callback onOpen = new Action <JSObject> ((evt) => { if (!cancellationToken.IsCancellationRequested) { // Change internal state to 'connected' to enable the other methods if (Interlocked.CompareExchange(ref state, connected, connecting) != connecting) { // Aborted/Disposed during connect. throw new ObjectDisposedException(GetType().FullName); } tcsConnect.SetResult(true); } evt.Dispose(); }); // Attach the onOpen callback innerWebSocket.SetObjectProperty("onopen", onOpen); // Setup the onMessage callback onMessage = new Action <JSObject> ((messageEvent) => { ThrowIfNotConnected(); // get the events "data" var eventData = messageEvent.GetObjectProperty("data"); // If the messageEvent's data property is marshalled as a JSObject then we are dealing with // binary data if (eventData is JSObject) { // TODO: Handle ArrayBuffer binary type but have only seen 'blob' so far without // changing the default websocket binary type manually. if (innerWebSocket.GetObjectProperty("binaryType").ToString() == "blob") { Action <JSObject> loadend = null; // Create a new "FileReader" object using (var reader = new HostObject("FileReader")) { loadend = new Action <JSObject> ((loadEvent) => { using (var target = (JSObject)loadEvent.GetObjectProperty("target")) { if ((int)target.GetObjectProperty("readyState") == 2) { using (var binResult = (ArrayBuffer)target.GetObjectProperty("result")) { var mess = new ReceivePayload(binResult, WebSocketMessageType.Binary); receiveMessageQueue.BufferPayload(mess); Runtime.FreeObject(loadend); } } } loadEvent.Dispose(); }); reader.Invoke("addEventListener", "loadend", loadend); using (var blobData = (JSObject)messageEvent.GetObjectProperty("data")) reader.Invoke("readAsArrayBuffer", blobData); } } else { throw new NotImplementedException($"WebSocket bynary type '{innerWebSocket.GetObjectProperty ("binaryType").ToString ()}' not supported."); } } else if (eventData is string) { var mess = new ReceivePayload(Encoding.UTF8.GetBytes(((string)eventData).ToString()), WebSocketMessageType.Text); receiveMessageQueue.BufferPayload(mess); } messageEvent.Dispose(); }); // Attach the onMessage callaback innerWebSocket.SetObjectProperty("onmessage", onMessage); await tcsConnect.Task; } catch (Exception wse) { ConnectExceptionCleanup(); WebSocketException wex = new WebSocketException("WebSocket connection failure.", wse); throw wex; } } }