/* * Copyright (c) 2011 PonySDK * Owners: * Luciano Broussal <luciano.broussal AT gmail.com> * Mathieu Barbier <mathieu.barbier AT gmail.com> * Nicolas Ciaravola <nicolas.ciaravola.pro AT gmail.com> * * WebSite: * http://code.google.com/p/pony-sdk/ * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.ponysdk.core.terminal.socket; import java.util.logging.Level; import java.util.logging.Logger; import com.google.gwt.core.client.Scheduler; import com.ponysdk.core.model.ClientToServerModel; import com.ponysdk.core.terminal.UIBuilder; import com.ponysdk.core.terminal.model.ReaderBuffer; import com.ponysdk.core.terminal.request.WebSocketRequestBuilder; import elemental.client.Browser; import elemental.events.CloseEvent; import elemental.events.MessageEvent; import elemental.html.ArrayBuffer; import elemental.html.WebSocket; import elemental.html.Window; public class WebSocketClient implements MessageSender { private static final Logger log = Logger.getLogger(WebSocketClient.class.getName()); private final WebSocket webSocket; private final UIBuilder uiBuilder; private final Window window; private final ReaderBuffer readerBuffer; private boolean initialized; public WebSocketClient(final String url, final UIBuilder uiBuilder, final WebSocketDataType webSocketDataType) { this.uiBuilder = uiBuilder; createSetElementsMethodOnUint8Array(); readerBuffer = new ReaderBuffer(); window = Browser.getWindow(); webSocket = window.newWebSocket(url); webSocket.setBinaryType(webSocketDataType.getName()); final MessageReader messageReader; if (WebSocketDataType.ARRAYBUFFER.equals(webSocketDataType)) messageReader = new ArrayBufferReader(this); else if (WebSocketDataType.BLOB.equals(webSocketDataType)) messageReader = new BlobReader(this); else throw new IllegalArgumentException("Wrong reader type : " + webSocketDataType); webSocket.setOnopen(event -> { if (log.isLoggable(Level.INFO)) log.info("WebSoket connected"); Scheduler.get().scheduleFixedDelay(() -> { if (log.isLoggable(Level.FINE)) log.log(Level.FINE, "Heart beat sent"); send(ClientToServerModel.HEARTBEAT.toStringValue()); return true; }, 1000); }); webSocket.setOnclose(event -> { if (event instanceof CloseEvent) { final CloseEvent closeEvent = (CloseEvent) event; final int statusCode = closeEvent.getCode(); if (log.isLoggable(Level.INFO)) log.info("WebSoket disconnected : " + statusCode); } else { log.severe("WebSoket disconnected : " + event); } }); webSocket.setOnerror(event -> { log.severe("WebSoket error : " + event); }); webSocket.setOnmessage(event -> messageReader.read((MessageEvent) event)); } // WORKAROUND : No setElements on Uint8Array but Elemental need it, create a passthrough private final native void createSetElementsMethodOnUint8Array() /*-{ Uint8Array.prototype.setElements = function(array, offset) { this.set(array, offset) }; }-*/; @Override public void read(final ArrayBuffer arrayBuffer) { try { if (!initialized) { uiBuilder.init(new WebSocketRequestBuilder(WebSocketClient.this)); initialized = true; } readerBuffer.init(window.newUint8Array(arrayBuffer, 0, arrayBuffer.getByteLength())); uiBuilder.updateMainTerminal(readerBuffer); } catch (final Exception e) { log.log(Level.SEVERE, "Error while processing the " + readerBuffer, e); } } public void send(final String message) { webSocket.send(message); } public void close() { webSocket.close(); } public enum WebSocketDataType { ARRAYBUFFER("arraybuffer"), BLOB("blob"); private String name; WebSocketDataType(final String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return getName(); } } }