Search Unity

WebSockets on JSLIB not raising any data

Discussion in 'Web' started by Katori, Dec 14, 2018.

  1. Katori

    Katori

    Joined:
    Nov 30, 2009
    Posts:
    60
    Hi, I am trying to send a byte array to C# from JavaScript without using SendMessage. Here is the relevant Unity part:
    Code (CSharp):
    1. [DllImport("__Internal")]
    2.     private static extern int SocketCreate (string url, MessageRecvCallback action, ConnectedCallback ConnectedAction, DisconnectedCallback DisconnectedAction, ErrorCallback ErrorAction);
    3.  
    4. public void Connect()
    5.     {
    6.         m_NativeRef = SocketCreate (mUrl.ToString(), MsgRcvdCallback, CtdCallback, DisctdCallback, ErrorCbk);
    7.     }
    8.  
    9. public delegate void MessageRecvCallback(System.IntPtr ptr, System.IntPtr Length);
    10.  
    11. [MonoPInvokeCallback(typeof(MessageRecvCallback))]
    12.     public static void MsgRcvdCallback(System.IntPtr ptr, System.IntPtr Length)
    13.     {
    14.         int ReadLength = Length.ToInt32();
    15.         byte[] msg = new byte[ReadLength];
    16.         Debug.Log("Got data of: " + ReadLength);
    17.         Marshal.Copy(ptr, msg, 0, ReadLength);
    18.         OnClientData.Invoke(msg);
    19.     }
    20.  
    21.     public delegate void ConnectedCallback();
    22.  
    23.     [MonoPInvokeCallback(typeof(ConnectedCallback))]
    24.     public static void CtdCallback()
    25.     {
    26.         OnClientConnect.Invoke();
    27.     }
    28.  
    29.     public delegate void DisconnectedCallback();
    30.  
    31.     [MonoPInvokeCallback(typeof(DisconnectedCallback))]
    32.     public static void DisctdCallback()
    33.     {
    34.         OnClientDisconnect.Invoke();
    35.     }
    36.  
    37.     public delegate void ErrorCallback();
    38.  
    39.     [MonoPInvokeCallback(typeof(ErrorCallback))]
    40.     public static void ErrorCbk()
    41.     {
    42.         OnClientError.Invoke(new System.Exception());
    43.     }
    44.  
    And here is the JSLIB part:
    Code (JavaScript):
    1. var LibraryWebSockets = {
    2. $webSocketInstances: [],
    3.  
    4. SocketCreate: function(url, MsgRcvd, ConnectedCallback, DisconnectedCallback, ErrorCallback)
    5. {
    6.     var str = Pointer_stringify(url);
    7.     var socket = {
    8.         socket: new WebSocket(str),
    9.         buffer: new Uint8Array(0),
    10.         error: null
    11.     }
    12.  
    13.     socket.socket.binaryType = 'arraybuffer';
    14.  
    15.     socket.socket.onopen = function(e){
    16.         Runtime.dynCall('v', ConnectedCallback, 0);
    17.     };
    18.  
    19.     socket.socket.onmessage = function (e) {
    20.         // Todo: handle other data types?
    21.         console.log("received data");
    22.         if (e.data instanceof Blob)
    23.         {
    24.             var reader = new FileReader();
    25.             reader.addEventListener("loadend", function() {
    26.                 var array = new Uint8Array(reader.result);
    27.  
    28.                 var dataBytes = array.length * array.BYTES_PER_ELEMENT;
    29.                 var dataPtr = Module._malloc(dataBytes);
    30.                 var dataHeap = new Uint8Array(Module.HEAPU8.buffer, dataPtr, dataBytes);
    31.                 dataHeap.set(array);
    32.  
    33.                 var args = [dataPtr, dataBytes];
    34.                 console.log("calling native code");
    35.                 Runtime.dynCall('vii', MsgRcvd, args);
    36.             });
    37.             reader.readAsArrayBuffer(e.data);
    38.         }
    39.         else if (e.data instanceof ArrayBuffer)
    40.         {
    41.             var array = new Uint8Array(e.data);
    42.            
    43.             var dataBytes = array.length * array.BYTES_PER_ELEMENT;
    44.                 var dataPtr = Module._malloc(dataBytes);
    45.                 var dataHeap = new Uint8Array(Module.HEAPU8.buffer, dataPtr, dataBytes);
    46.                 dataHeap.set(array);
    47.  
    48.                 var args = [dataPtr, dataBytes];
    49.                 console.log("calling native code");
    50.                 Runtime.dynCall('vii', MsgRcvd, args);
    51.         }
    52.         else if(typeof e.data === "string") {
    53.             var reader = new FileReader();
    54.             reader.addEventListener("loadend", function() {
    55.                 var array = new Uint8Array(reader.result);
    56.  
    57.                 var dataBytes = array.length * array.BYTES_PER_ELEMENT;
    58.                 var dataPtr = Module._malloc(dataBytes);
    59.                 var dataHeap = new Uint8Array(Module.HEAPU8.buffer, dataPtr, dataBytes);
    60.                 dataHeap.set(array);
    61.  
    62.                 var args = [dataPtr, dataBytes];
    63.                 console.log("calling native code");
    64.                 Runtime.dynCall('vii', MsgRcvd, args);
    65.             });
    66.             var blob = new Blob([e.data]);
    67.             reader.readAsArrayBuffer(blob);
    68.         }
    69.     };
    70.  
    71.     socket.socket.onclose = function (e) {
    72.         if (e.code != 1000)
    73.         {
    74.             if (e.reason != null && e.reason.length > 0)
    75.                 socket.error = e.reason;
    76.             else
    77.             {
    78.                 switch (e.code)
    79.                 {
    80.                     case 1001:
    81.                         socket.error = "Endpoint going away.";
    82.                         break;
    83.                     case 1002:
    84.                         socket.error = "Protocol error.";
    85.                         break;
    86.                     case 1003:
    87.                         socket.error = "Unsupported message.";
    88.                         break;
    89.                     case 1005:
    90.                         socket.error = "No status.";
    91.                         break;
    92.                     case 1006:
    93.                         socket.error = "Abnormal disconnection.";
    94.                         break;
    95.                     case 1009:
    96.                         socket.error = "Data frame too large.";
    97.                         break;
    98.                     default:
    99.                         socket.error = "Error "+e.code;
    100.                 }
    101.             }
    102.             Runtime.dynCall('v', ErrorCallback, 0);
    103.         }
    104.         else{
    105.             Runtime.dynCall('v', DisconnectedCallback, 0);
    106.         }
    107.     }
    108.     var instance = webSocketInstances.push(socket) - 1;
    109.     return instance;
    110. },
    111.  
    112. SocketState: function (socketInstance)
    113. {
    114.     var socket = webSocketInstances[socketInstance];
    115.     return socket.socket.readyState;
    116. },
    117.  
    118. SocketError: function (socketInstance, ptr, bufsize)
    119. {
    120.      var socket = webSocketInstances[socketInstance];
    121.      if (socket.error == null)
    122.          return 0;
    123.     var str = socket.error.slice(0, Math.max(0, bufsize - 1));
    124.     writeStringToMemory(str, ptr, false);
    125.     return 1;
    126. },
    127.  
    128. SocketSend: function (socketInstance, ptr, length)
    129. {
    130.     var socket = webSocketInstances[socketInstance];
    131.     socket.socket.send (HEAPU8.buffer.slice(ptr, ptr+length));
    132. },
    133.  
    134. SocketClose: function (socketInstance)
    135. {
    136.     var socket = webSocketInstances[socketInstance];
    137.     socket.socket.close();
    138. }
    139. };
    140.  
    141. autoAddDeps(LibraryWebSockets, '$webSocketInstances');
    142. mergeInto(LibraryManager.library, LibraryWebSockets);
    143.  
    The WebSockets part is modified from Unity's example, but I am trying to use callbacks to raise events instead of receiving data from the messages stack. The "Connected" and "Error" callbacks get thrown so I know that Runtime.dynCall is working, but I am never getting any data--the onmessage function never does its console.logs, the callback never says "Got data of" in Unity, so I know that the onmessage function is not firing at all and I can't figure out why exactly. Anyone have any ideas?

    Thanks.
     
  2. AlexHell

    AlexHell

    Joined:
    Oct 2, 2014
    Posts:
    167
    I have idea - remove all this stuff as it may un-compile and due to this the onmessage is not invoked
    I know that raw code work
    Code (CSharp):
    1. socket.socket.onmessage = function (e) {
    2.         // Todo: handle other data types?
    3.         if (e.data instanceof Blob)
    4.         {
    5.             var reader = new FileReader();
    6.             reader.addEventListener("loadend", function() {
    7.                 var array = new Uint8Array(reader.result);
    8.                 socket.messages.push(array);
    9.             });
    10.             reader.readAsArrayBuffer(e.data);
    11.         }
    12.         else if (e.data instanceof ArrayBuffer)
    13.         {
    14.             var array = new Uint8Array(e.data);
    15.             socket.messages.push(array);
    16.         }
    17.     };
    you can add your mallocs etc - step by step
     
  3. AlexHell

    AlexHell

    Joined:
    Oct 2, 2014
    Posts:
    167
    Did you found the solution?
    I have checked this
    Code (CSharp):
    1. ar dataPtr = Module._malloc(dataBytes);
    2. var dataHeap = new Uint8Array(Module.HEAPU8.buffer, dataPtr, dataBytes);
    The malloc allocated new memory,
    but then you write into Module.HEAPU8.buffer by dataPtr - it's incorrect

    if you write into Module.HEAPU8.buffer then it's not related to malloc and example of use heap buffer
    Code (JavaScript):
    1. // JS plugin
    2. function(key, sharedArray, sharedArrayLength)
    3. {
    4.   var resultArray = new Uint8Array(buffer, sharedArray, sharedArrayLength); // (buffer is heap)
    5. ...
    6.   resultArray.set(new Uint8Array(result.content));
    7. }
    if you allocated new memory by malloc for return C# string from JS, then you should use this
    Code (JavaScript):
    1. // JS plugin
    2. window.ConvertJsToHeapString = function(resultString)
    3. {
    4.    var bufferSize = lengthBytesUTF8(resultString) + 1; // (+1 null terminated)
    5.    var buffer = _malloc(bufferSize);
    6.    stringToUTF8(resultString, buffer, bufferSize);
    7.    return buffer;
    8. };
    9.  
    10. // then you call
    11. .. myFunc: function()
    12. {
    13.   var jsString = "abc";
    14.   return ConvertJsToHeapString (jsString);
    15. }
    16.  
    I don't test your total code with Runtime.dynCall , you can chain it yourself