/*
* Copyright (C) 2015 Actor LLC. <https://actor.im>
*/
package im.actor.runtime.js.websocket;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.typedarrays.shared.ArrayBuffer;
import com.google.gwt.typedarrays.shared.TypedArrays;
import com.google.gwt.typedarrays.shared.Uint8Array;
import im.actor.runtime.Log;
import im.actor.runtime.js.utils.Conversion;
import im.actor.runtime.mtproto.AsyncConnection;
import im.actor.runtime.mtproto.AsyncConnectionInterface;
import im.actor.runtime.mtproto.ConnectionEndpoint;
public class WebSocketConnection extends AsyncConnection {
private static int connectionId = 0;
private final String TAG = "WebSocketConnection#" + (connectionId++);
private JavaScriptObject jsWebSocket;
private boolean isClosed;
public WebSocketConnection(ConnectionEndpoint endpoint, AsyncConnectionInterface connection) {
super(endpoint, connection);
}
@Override
public void doConnect() {
// Log.d(TAG, "doConnect");
isClosed = true;
String url;
if (getEndpoint().getType() == ConnectionEndpoint.TYPE_WS) {
url = "ws://" + getEndpoint().getHost() + ":" + getEndpoint().getPort() + "/";
} else if (getEndpoint().getType() == ConnectionEndpoint.TYPE_WS_TLS) {
url = "wss://" + getEndpoint().getHost() + ":" + getEndpoint().getPort() + "/";
} else {
throw new RuntimeException();
}
this.jsWebSocket = createJSWebSocket(url, this);
}
@Override
public void doSend(byte[] data) {
// Log.d(TAG, "doSend");
if (isClosed) {
return;
}
Uint8Array push = TypedArrays.createUint8Array(data.length);
for (int i = 0; i < data.length; i++) {
push.set(i, data[i]);
}
send(push);
}
@Override
public void doClose() {
// Log.d(TAG, "doClose");
isClosed = true;
close();
}
private void onRawMessage(ArrayBuffer message) {
// Log.d(TAG, "onRawMessage");
if (isClosed) {
return;
}
onReceived(Conversion.convertBytes(message));
}
private void onRawConnected() {
// Log.d(TAG, "onRawConnected");
isClosed = false;
onConnected();
}
private void onRawClosed() {
// Log.d(TAG, "onRawClosed");
isClosed = true;
onClosed();
}
// Native interfaces
public native void send(Uint8Array message) /*-{
if (message == null)
return;
this.@im.actor.runtime.js.websocket.WebSocketConnection::jsWebSocket.send(message);
}-*/;
public native void close() /*-{
this.@im.actor.runtime.js.websocket.WebSocketConnection::jsWebSocket.close();
}-*/;
public native int getBufferedAmount() /*-{
return this.@im.actor.runtime.js.websocket.WebSocketConnection::jsWebSocket.bufferedAmount;
}-*/;
public native int getReadyState() /*-{
return this.@im.actor.runtime.js.websocket.WebSocketConnection::jsWebSocket.readyState;
}-*/;
public native String getURL() /*-{
return this.@im.actor.runtime.js.websocket.WebSocketConnection::jsWebSocket.url;
}-*/;
/**
* Creates the JavaScript WebSocket component and set's all callback handlers.
*
* @param url
*/
private native JavaScriptObject createJSWebSocket(final String url, final WebSocketConnection webSocket) /*-{
var jsWebSocket = new WebSocket(url);
jsWebSocket.binaryType = "arraybuffer"
jsWebSocket.onopen = function () {
webSocket.@im.actor.runtime.js.websocket.WebSocketConnection::onRawConnected()();
}
jsWebSocket.onclose = function () {
webSocket.@im.actor.runtime.js.websocket.WebSocketConnection::onRawClosed()();
}
jsWebSocket.onerror = function () {
webSocket.@im.actor.runtime.js.websocket.WebSocketConnection::onRawClosed()();
}
jsWebSocket.onmessage = function (socketResponse) {
if (socketResponse.data) {
webSocket.@im.actor.runtime.js.websocket.WebSocketConnection::onRawMessage(*)(socketResponse.data);
}
}
return jsWebSocket;
}-*/;
}