0

Over my websocket I expect a Binary message from the server to the client (the other way works). I want to cast that to an Array[Byte] to further process it it as protobuf-message

ws.onmessage = {
  (event: MessageEvent) =>
    val msg = event.data.toString
    dom.window.console.log(msg) 

    val x = event.data.asInstanceOf[ArrayBuffer]
    val df = new DataView(x)
    dom.window.console.log("result")
    dom.window.console.log(bin2User(df).toString)
}

private def bin2User(data: DataView): User = {
    val bytes = new Array[Byte](data.byteLength)

    for(index <- 0 to data.byteLength) {
      bytes(index) = data.getInt8(index)
    }

    User.parseFrom(bytes)
  }

now dom.window.console.log(msg) gives me

[object Blob]

Blob { size: 9, type: "" }

I would expect the x be of type ArrayBuffer because of the explicit cast, but alas, it's not, as I get

TypeError: DataView: expected ArrayBuffer, got Blob

How can I overcome this?

I tried with:

val fr = new FileReader
fr.readAsArrayBuffer(event.data.asInstanceOf[Blob])
val y = fr.result.asInstanceOf[ArrayBuffer]
dom.window.console.log(y)

but this prints null for y and also

TypeError: y is not an object

Community
  • 1
  • 1
  • 1
    Hmm. I haven't worked with `Blob`, so I'm not sure of the answer, but I think your experiment at the end should be on the right track. `asInstanceOf` can't work -- that only says to the compiler, "I know what type this value *already* is, so ignore what you know and believe me". It doesn't do conversions. From what I see elsewhere on SO, I would have expected the `FileReader` approach to work. You may want to put JavaScript / DOM tags on this question -- it probably isn't a Scala.js question per se... – Justin du Coeur Jan 29 '17 at 16:13
  • `FileReader` `.result` is returned asynchronously. Have you tried using `load` event handler of `FileReader` to check `.result`? Have you set `.binaryType` of `WebSocket` to `ArrayBuffer`? – guest271314 Feb 01 '17 at 04:16
  • Note that in Scala.js `asInstanceOf[T]` where `T` is a subtype of `js.Any` **does not do anything** (not even any checking). – gzm0 Feb 01 '17 at 08:51
  • 1
    I don't know anything about scala.js, but in general you want to set the `binaryType` property to `"arraybuffer"` to receive a ArrayBuffer instead of a Blob. – Matthias247 Feb 01 '17 at 09:04

2 Answers2

1

You were almost there: FileReader is asynchronous so you'll have to:

val fr = new FileReader
fr.onload = { _ =>
  val y = fr.result
  dom.window.console.log(y)
}

fr.readAsArrayBuffer(event.data.asInstanceOf[Blob])

This is essentially a translated example from this response.

You'll probably want to wrap this in a future API:

import scala.concurrent.Promise

def blob2ArrayBuffer(blob: Blob): Future[ArrayBuffer] = {
  val result = Promise[ArrayBuffer]()
  val fr = new FileReader
  fr.onload = { _ => result.success(fr.result) }
  fr.readAsArrayBuffer(blob)
  result.future
}
Community
  • 1
  • 1
gzm0
  • 14,752
  • 1
  • 36
  • 64
1

As some people already pointed out, setting ws.binaryType = "arraybuffer" is enough too.

Doing it like this:

 ws.onmessage =
      {
        ws.binaryType = "arraybuffer"

        (event: MessageEvent) => 

            val msg = event.data.asInstanceOf[ArrayBuffer]
            dom.window.console.log(msg)

results in

ArrayBuffer { byteLength: 9 }

  • You probably want to move the assignment to `ws.binaryType` above `ws.onmessage = `. – gzm0 Feb 02 '17 at 17:03
  • @gzm0, nope, did not intend to. It's only important it's before the event. I can send as blob or string and expect as arraybuffer that way. –  Feb 02 '17 at 18:13
  • Moving `ws.binaryType =` upwards does the exact same thing in terms of execution order (have a look at the generated JavaScript code if you don't believe it). However, it is much less confusing if the order in the code is the same as the execution order. – gzm0 Feb 03 '17 at 09:15
  • But I only want this to be interpreted as arraybuffer in case of `ws.onmessage` hence I put it in this block, because that's what blocks are for (maybe I get you wrong though) –  Feb 03 '17 at 13:41