io.socket.client.Socket Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of socket.io-client Show documentation
Show all versions of socket.io-client Show documentation
Socket.IO Client Library for Java
The newest version!
package io.socket.client;
import io.socket.emitter.Emitter;
import io.socket.parser.Packet;
import io.socket.parser.Parser;
import io.socket.thread.EventThread;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* The socket class for Socket.IO Client.
*/
public class Socket extends Emitter {
private static final Logger logger = Logger.getLogger(Socket.class.getName());
/**
* Called on a connection.
*/
public static final String EVENT_CONNECT = "connect";
public static final String EVENT_CONNECTING = "connecting";
/**
* Called on a disconnection.
*/
public static final String EVENT_DISCONNECT = "disconnect";
/**
* Called on a connection error.
*
* Parameters:
*
* - (Exception) error data.
*
*/
public static final String EVENT_ERROR = "error";
public static final String EVENT_MESSAGE = "message";
public static final String EVENT_CONNECT_ERROR = Manager.EVENT_CONNECT_ERROR;
public static final String EVENT_CONNECT_TIMEOUT = Manager.EVENT_CONNECT_TIMEOUT;
public static final String EVENT_RECONNECT = Manager.EVENT_RECONNECT;
public static final String EVENT_RECONNECT_ERROR = Manager.EVENT_RECONNECT_ERROR;
public static final String EVENT_RECONNECT_FAILED = Manager.EVENT_RECONNECT_FAILED;
public static final String EVENT_RECONNECT_ATTEMPT = Manager.EVENT_RECONNECT_ATTEMPT;
public static final String EVENT_RECONNECTING = Manager.EVENT_RECONNECTING;
public static final String EVENT_PING = Manager.EVENT_PING;
public static final String EVENT_PONG = Manager.EVENT_PONG;
protected static Map events = new HashMap() {{
put(EVENT_CONNECT, 1);
put(EVENT_CONNECT_ERROR, 1);
put(EVENT_CONNECT_TIMEOUT, 1);
put(EVENT_CONNECTING, 1);
put(EVENT_DISCONNECT, 1);
put(EVENT_ERROR, 1);
put(EVENT_RECONNECT, 1);
put(EVENT_RECONNECT_ATTEMPT, 1);
put(EVENT_RECONNECT_FAILED, 1);
put(EVENT_RECONNECT_ERROR, 1);
put(EVENT_RECONNECTING, 1);
put(EVENT_PING, 1);
put(EVENT_PONG, 1);
}};
/*package*/ String id;
private volatile boolean connected;
private int ids;
private String nsp;
private Manager io;
private String query;
private Map acks = new HashMap();
private Queue subs;
private final Queue> receiveBuffer = new LinkedList>();
private final Queue> sendBuffer = new LinkedList>();
public Socket(Manager io, String nsp, Manager.Options opts) {
this.io = io;
this.nsp = nsp;
if (opts != null) {
this.query = opts.query;
}
}
private void subEvents() {
if (this.subs != null) return;
final Manager io = Socket.this.io;
Socket.this.subs = new LinkedList() {{
add(On.on(io, Manager.EVENT_OPEN, new Listener() {
@Override
public void call(Object... args) {
Socket.this.onopen();
}
}));
add(On.on(io, Manager.EVENT_PACKET, new Listener() {
@Override
public void call(Object... args) {
Socket.this.onpacket((Packet>) args[0]);
}
}));
add(On.on(io, Manager.EVENT_CLOSE, new Listener() {
@Override
public void call(Object... args) {
Socket.this.onclose(args.length > 0 ? (String) args[0] : null);
}
}));
}};
}
/**
* Connects the socket.
*/
public Socket open() {
EventThread.exec(new Runnable() {
@Override
public void run() {
if (Socket.this.connected) return;
Socket.this.subEvents();
Socket.this.io.open(); // ensure open
if (Manager.ReadyState.OPEN == Socket.this.io.readyState) Socket.this.onopen();
Socket.this.emit(EVENT_CONNECTING);
}
});
return this;
}
/**
* Connects the socket.
*/
public Socket connect() {
return this.open();
}
/**
* Send messages.
*
* @param args data to send.
* @return a reference to this object.
*/
public Socket send(final Object... args) {
EventThread.exec(new Runnable() {
@Override
public void run() {
Socket.this.emit(EVENT_MESSAGE, args);
}
});
return this;
}
/**
* Emits an event. When you pass {@link Ack} at the last argument, then the acknowledge is done.
*
* @param event an event name.
* @param args data to send.
* @return a reference to this object.
*/
@Override
public Emitter emit(final String event, final Object... args) {
EventThread.exec(new Runnable() {
@Override
public void run() {
if (events.containsKey(event)) {
Socket.super.emit(event, args);
return;
}
Ack ack;
Object[] _args;
int lastIndex = args.length - 1;
if (args.length > 0 && args[lastIndex] instanceof Ack) {
_args = new Object[lastIndex];
for (int i = 0; i < lastIndex; i++) {
_args[i] = args[i];
}
ack = (Ack) args[lastIndex];
} else {
_args = args;
ack = null;
}
emit(event, _args, ack);
}
});
return this;
}
/**
* Emits an event with an acknowledge.
*
* @param event an event name
* @param args data to send.
* @param ack the acknowledgement to be called
* @return a reference to this object.
*/
public Emitter emit(final String event, final Object[] args, final Ack ack) {
EventThread.exec(new Runnable() {
@Override
public void run() {
JSONArray jsonArgs = new JSONArray();
jsonArgs.put(event);
if (args != null) {
for (Object arg : args) {
jsonArgs.put(arg);
}
}
Packet packet = new Packet(Parser.EVENT, jsonArgs);
if (ack != null) {
logger.fine(String.format("emitting packet with ack id %d", ids));
Socket.this.acks.put(ids, ack);
packet.id = ids++;
}
if (Socket.this.connected) {
Socket.this.packet(packet);
} else {
if (ack instanceof AckWithTimeOut)
((AckWithTimeOut) ack).cancelTimer();
Socket.this.sendBuffer.add(packet);
}
}
});
return this;
}
private void packet(Packet packet) {
packet.nsp = this.nsp;
this.io.packet(packet);
}
private void onopen() {
logger.fine("transport is open - connecting");
if (!"/".equals(this.nsp)) {
if (this.query != null && !this.query.isEmpty()) {
Packet packet = new Packet(Parser.CONNECT);
packet.query = this.query;
this.packet(packet);
} else {
this.packet(new Packet(Parser.CONNECT));
}
}
}
private void onclose(String reason) {
if (logger.isLoggable(Level.FINE)) {
logger.fine(String.format("close (%s)", reason));
}
this.connected = false;
this.id = null;
this.emit(EVENT_DISCONNECT, reason);
}
private void onpacket(Packet> packet) {
if (!this.nsp.equals(packet.nsp)) return;
switch (packet.type) {
case Parser.CONNECT:
this.onconnect();
break;
case Parser.EVENT:
case Parser.BINARY_EVENT: {
@SuppressWarnings("unchecked")
Packet p = (Packet) packet;
this.onevent(p);
break;
}
case Parser.ACK:
case Parser.BINARY_ACK: {
@SuppressWarnings("unchecked")
Packet p = (Packet) packet;
this.onack(p);
break;
}
case Parser.DISCONNECT:
this.ondisconnect();
break;
case Parser.ERROR:
this.emit(EVENT_ERROR, packet.data);
break;
}
}
private void onevent(Packet packet) {
List