3

I want to send binary data from my stompClient to the spring controller. this is my JS

var socket = new SockJS('/test/binary');
        var stompClient = Stomp.over(socket);

        socket.binaryType = "arraybuffer";
        var appModel = new ApplicationModel(stompClient);
        ko.applyBindings(appModel);

        appModel.connect();
        appModel.pushNotification("Notifications.");


 var ctx =   canvas.get()[0].getContext('2d');
 ctx.drawImage(img, 0, 0, 320, 240);
 var data  = canvas.get()[0].toDataURL('image/jpeg', 1.0);
 newblob = dataURItoBlob(data);


 stompClient.send("/app/vid", {},  newblob);

function dataURItoBlob(dataURI) {
    // convert base64/URLEncoded data component to raw binary data held in a string
    var byteString;
    if (dataURI.split(',')[0].indexOf('base64') >= 0)
        byteString = atob(dataURI.split(',')[1]);
        else
        byteString = unescape(dataURI.split(',')[1]);

    // separate out the mime component
    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

    // write the bytes of the string to a typed array
    var ia = new Uint8Array(byteString.length);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }

   return new Blob([ia], {type:mimeString});

I have tried sending Blob, Uint8Array the message is sent but on the server side I can not use it. My method in the controller is:

@MessageMapping("/vid")
public void getVid(Message<byte[]> message, Principal principal) throws IOException {
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
bOut.write(message.getPayload());
bOut.flush();
byte[]  imageInByte = bOut.toByteArray();
bOut.close();

InputStream in = new ByteArrayInputStream(imageInByte);
BufferedImage bImageFromConvert = ImageIO.read(in);

ImageIO.write(bImageFromConvert, "jpeg", new File(
        "E:/new-darksouls.jpg"));

template.convertAndSend("/topic/binarydemo2",   message);

I have used ByteArrayMessageConverter,StringMessageConverter,MappingJackson2MessageConverter and a Base64JavaObjectMessageConverter that I wrote:

public class Base64JavaObjectMessageConverter extends AbstractMessageConverter {

public Base64JavaObjectMessageConverter() {
    super(MimeTypeUtils.APPLICATION_OCTET_STREAM);
}

@Override
protected boolean supports(Class<?> clazz) {
    return true;
}


@Override
public Object convertFromInternal(Message<?> message, Class<?> targetClass) {
    byte[] messageBytes =Base64Utils.decode( (byte[])message.getPayload() );
    return SerializationUtils.deserialize( messageBytes  );
}

@Override
public Object convertToInternal(Object payload, MessageHeaders headers) {
    byte[] messageBytes = SerializationUtils.serialize( payload );
    return Base64Utils.encode( messageBytes);
}

}

I only am able to send the byte[] as string removing the 'base64' etc from it:

stompClient.send("/app/vid", {},   data.split(',')[1]);

in the controller :

@MessageMapping("/vid")
public void getVid(String message, Principal principal) throws IOException {


    byte[] bytearray = Base64.decode(message);
    BufferedImage imag=ImageIO.read(new ByteArrayInputStream(bytearray));

    ImageIO.write(imag, "jpg", new File("E:/new-darksouls.jpg"));

But this is not what I wish to achieve. I suppose that this will take a tall on performance.

I am using Spring 4.2.0.RC1 WebSockets,StompJS I read on different posts that it is possible to send from back end to client and client to back end but I was not able to reproduce it. I would be very thankful if I can get a concrete example how to structure and send the Uint8Array or blob on the client and how to deal with it on the server side.

Thank you for your time and help

Ivan Jacobs
  • 178
  • 1
  • 9
  • Can't manage.I connect using `var socket = new Stomp.client('ws://server:port/spring-websocket-portfolio/portfolio'); var ws = Stomp.client(url); ws.binaryType = "arraybuffer"; `If I creat a Uint8Array and send it I recieve a string with the type of object I have sent in the Controller. Websocket config server side `@Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/portfolio").withSockJS(); } ` – Ivan Jacobs Jun 19 '15 at 13:51

1 Answers1

0

SockJS does not support sending binary data. You can send binary messages with use STOMP over a plain WebSocket.

On the server side see StompSubProtocolHandler which checks if incoming messages are binary or text and hence can handle either. From there it doesn't matter much, i.e. from a STOMP perspective the body is a byte array and the content-type/content-length headers determine what the body contains and how it should be intepreted. On the sending side StompSubProtocolHandler can also send either binary or text and at the moment it uses binary if the content-type is application/octet-stream and as long as SockJS is not being used.

So in short over WebSocket it should work but not when using SockJS as the transport.

Rossen Stoyanchev
  • 4,910
  • 23
  • 26
  • BTW it's worth commenting here on the SockJS ticket for binary message support ... https://github.com/sockjs/sockjs-protocol/issues/74. – Rossen Stoyanchev Jun 17 '15 at 16:31
  • It's quit tricky to mix WebSocket and sockjs in the same application. I will give it a try and to see what it will give. – Ivan Jacobs Jun 17 '15 at 16:38
  • It shouldn't be difficult. If you want both you can configure a STOMP/SockJS endpoint on the server side (say at URL "/foo"). Then you can get a straight websocket via "/foo/websocket". This is built into the SockJS protocol so you can access a raw websocket on a SockJS endpoint say from another, non-browser client. – Rossen Stoyanchev Jun 17 '15 at 17:03
  • I did try with `var socket = new Stomp.client('ws://server:port/spring-websocket-portfolio/portfolio'); `and Removed the `.withSockJS();` from the endpoint but messages did not arrive. So it should be :Server `registry.addEndpoint("/portfolio").withSockJS(); client: var socket = new Stomp.client('ws://server:port/spring-websocket-portfolio/portfolio/websocket');` – Ivan Jacobs Jun 17 '15 at 17:21
  • Can't manage to send a binary. I connect using `var socket = new Stomp.client('ws://server:port/spring-websocket-portfolio/portfolio'); websocket config server side @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/portfolio").withSockJS(); } ` – Ivan Jacobs Jun 19 '15 at 13:41