/** * emits an event from {@link SocketIO} to the {@link IOTransport}. * * @param socket the socket * @param event the event * @param ack acknowledge package which can be called from the server * @param args the arguments to be send */ public void emit(SocketIO socket, String event, IOAcknowledge ack, Object... args) { String jsonString = null; try { Map<String, Object> map = new HashMap<String, Object>(); map.put("name", event); map.put("args", args); jsonString = objectMapper.writeValueAsString(map); IOMessage message = new IOMessage(IOMessage.TYPE_EVENT, socket.getNamespace(), jsonString); synthesizeAck(message, ack); sendPlain(message.toString()); } catch (Exception e) { error( new SocketIOException( "Error while emitting an event. Make sure you only try to send arguments, which can be serialized into JSON.")); } }
/** Connect transport */ private void connectTransport() { if (getState() == STATE_INVALID) { return; } setState(STATE_CONNECTING); if (protocols.contains(WebSocketTransport.TRANSPORT_NAME)) { transport = WebSocketTransport.create(this.url.getProtocol() + "://" + this.url.getAuthority(), this); } else if (protocols.contains(XhrTransport.TRANSPORT_NAME)) { transport = XhrTransport.create(this.url.getProtocol() + "://" + this.url.getAuthority(), this); } else { error( new SocketIOException( "Server supports no available transports. You should reconfigure the server to support a available transport")); return; } transport.connect(); }
/** * {@link IOTransport} should call this function if it does not support framing. If it does, * transportMessage should be used * * @param text the text */ public void transportData(String text) { if (!text.startsWith(FRAME_DELIMITER)) { transportMessage(text); return; } Iterator<String> fragments = Arrays.asList(text.split(FRAME_DELIMITER)).listIterator(1); while (fragments.hasNext()) { int length = Integer.parseInt(fragments.next()); String string = fragments.next(); // Potential BUG: it is not defined if length is in bytes or // characters. Assuming characters. if (length != string.length()) { error(new SocketIOException("Garbage from server: " + text)); return; } transportMessage(string); } }
/** Handshake. */ private void handshake() { URL url; String response; URLConnection connection; try { setState(STATE_HANDSHAKE); url = new URL( this.url.getProtocol() + "://" + this.url.getAuthority() + SOCKET_IO_1 + (this.url.getQuery() == null ? "" : "?" + this.url.getQuery())); connection = url.openConnection(); if (connection instanceof HttpsURLConnection) { ((HttpsURLConnection) connection).setSSLSocketFactory(sslSocketFactory); } connection.setConnectTimeout(connectTimeout); connection.setReadTimeout(connectTimeout); /* Setting the request headers */ for (Entry<Object, Object> entry : headers.entrySet()) { connection.setRequestProperty((String) entry.getKey(), (String) entry.getValue()); } log.debug("> " + connection.toString()); InputStream stream = connection.getInputStream(); Scanner in = new Scanner(stream); response = in.nextLine(); log.debug("< " + response); String[] data = response.split(":"); sessionId = data[0]; heartbeatTimeout = Long.parseLong(data[1]) * 1000; closingTimeout = Long.parseLong(data[2]) * 1000; protocols = Arrays.asList(data[3].split(",")); } catch (Exception e) { error(new SocketIOException("Error while handshaking", e)); } }
/** * Transport message. {@link IOTransport} calls this, when a message has been received. * * @param text the text */ public void transportMessage(String text) { log.debug("< " + text); IOMessage message; try { message = new IOMessage(text); } catch (Exception e) { error(new SocketIOException("Garbage from server: " + text, e)); return; } resetTimeout(); switch (message.getType()) { case IOMessage.TYPE_DISCONNECT: try { findCallback(message).onDisconnect(); } catch (Exception e) { error(new SocketIOException("Exception was thrown in onDisconnect()", e)); } break; case IOMessage.TYPE_CONNECT: try { if (firstSocket != null && "".equals(message.getEndpoint())) { if (firstSocket.getNamespace().equals("")) { firstSocket.getCallback().onConnect(); } else { IOMessage connect = new IOMessage(IOMessage.TYPE_CONNECT, firstSocket.getNamespace(), ""); sendPlain(connect.toString()); } } else { findCallback(message).onConnect(); } firstSocket = null; } catch (Exception e) { error(new SocketIOException("Exception was thrown in onConnect()", e)); } break; case IOMessage.TYPE_HEARTBEAT: sendPlain("2::"); break; case IOMessage.TYPE_MESSAGE: try { findCallback(message).onMessage(message.getData(), remoteAcknowledge(message)); } catch (Exception e) { error( new SocketIOException( "Exception was thrown in onMessage(String).\n" + "Message was: " + message.toString(), e)); } break; case IOMessage.TYPE_JSON_MESSAGE: try { // test if JSON is valid by catching a parse Exception objectMapper.readValue(message.getData(), new TypeReference<Map<String, Object>>() {}); // JSONUtils.getJsonGenericMap(message.getData(), objectMapper); findCallback(message).onMessage(message.getData(), remoteAcknowledge(message)); } catch (JsonParseException e) { log.warn("Malformated JSON received: " + message.getData()); } catch (Exception e) { error( new SocketIOException( "Exception was thrown in onMessage(JSON).\n" + "Message was: " + message.toString(), e)); } break; case IOMessage.TYPE_EVENT: try { Map<String, Object> map = objectMapper.readValue( message.getData(), new TypeReference<Map<String, Object>>() {}); Object[] argsArray; if (map.containsKey("args")) { Object argsString = map.get("args"); List<Object> argObjects = objectMapper.readValue(argsString.toString(), new TypeReference<List<Object>>() {}); argsArray = new Object[argObjects.size()]; for (int i = 0; i < argObjects.size(); i++) { if (argObjects.get(i) != null) { argsArray[i] = argObjects.get(i); } } } else { argsArray = new Object[0]; } String eventName = map.get("name").toString(); try { findCallback(message).on(eventName, remoteAcknowledge(message), argsArray); } catch (Exception e) { error( new SocketIOException( "Exception was thrown in on(String, JSON[]).\n" + "Message was: " + message.toString(), e)); } } catch (JsonParseException e) { log.warn("Malformated JSON received: " + message.getData()); } catch (JsonMappingException e) { log.warn("Mapping JSON received: " + message.getData()); } catch (IOException e) { log.warn("IO Exception: " + message.getData()); } break; case IOMessage.TYPE_ACK: String[] data = message.getData().split("\\+", 2); if (data.length == 2) { try { int id = Integer.parseInt(data[0]); IOAcknowledge ack = acknowledge.get(id); if (ack == null) { log.warn("Received unknown ack packet"); } else { List<Object> argObjects = objectMapper.readValue(data[1].toString(), new TypeReference<List<Object>>() {}); Object[] argsArray = new Object[argObjects.size()]; for (int i = 0; i < argObjects.size(); i++) { if (argObjects.get(i) != null) { argsArray[i] = argObjects.get(i); } } ack.ack(argsArray); } } catch (NumberFormatException e) { log.warn( "Received malformated Acknowledge! This is potentially filling up the acknowledges!"); } catch (JsonParseException e) { log.warn("Malformated JSON received: " + message.getData()); } catch (JsonMappingException e) { log.warn("Mapping JSON received: " + message.getData()); } catch (IOException e) { log.warn("IO Exception: " + message.getData()); } } else if (data.length == 1) { sendPlain("6:::" + data[0]); } break; case IOMessage.TYPE_ERROR: try { findCallback(message).onError(new SocketIOException(message.getData())); } catch (SocketIOException e) { error(e); } if (message.getData().endsWith("+0")) { // We are advised to disconnect cleanup(); } break; case IOMessage.TYPE_NOOP: break; default: log.warn("Unkown type received" + message.getType()); break; } }