All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.zipwhip.signals.server.protocol.SocketIoProtocol Maven / Gradle / Ivy

/**
 * 
 */
package com.zipwhip.signals.server.protocol;

import java.util.regex.Pattern;

/**
 * @author jdinsel
 *
 */
public class SocketIoProtocol {

	private static final String HEARTBEAT_INFO = ":1680:1800:"; // 28minutes:30minutes
	private static final Pattern socketIoPattern = Pattern.compile(":");
	private static final int LIMIT = 4;
	public static final long NO_ID = -1;

	public static final char DISCONNECT = '0';
	public static final char CONNECT = '1';
	public static final char HEART_BEAT = '2';
	public static final char MESSAGE = '3';
	public static final char JSON_MESSAGE = '4';
	public static final char EVENT = '5';
	public static final char ACK = '6';
	public static final char ERROR = '7';
	public static final char NOOP = '8';

	private static final int CLIENT_ID_LENGTH = 5;

	public static final String NOOP_MESSAGE = "8::";
	private static final String supportedProtocols = "websocket,xhr-polling,rawsocket";

	/**
	 * Format a Socket.IO style message as a JSON Message or a standard Message depending upon the content.
	 * 
	 * @param message
	 * @return
	 */
	public static String encode(long messageId, String message) {
		if (message.charAt(0) == '{') {
			message = jsonMessageResponse(messageId, message);
		} else {
			message = messageResponse(messageId, message);
		}

		return message;
	}

	/**
	 * @param message
	 * @return
	 */
	public static boolean isDisconnectCommand(String message) {
		return SocketIoProtocol.DISCONNECT == message.charAt(0) && isSocketIoPrefix(message);
	}

	/**
	 * @param message
	 * @return
	 */
	public static boolean isConnectCommand(String message) {
		return SocketIoProtocol.CONNECT == message.charAt(0) && isSocketIoPrefix(message);
	}

	/**
	 * @param message
	 * @return
	 */
	public static boolean isHeartBeatCommand(String message) {
		return SocketIoProtocol.HEART_BEAT == message.charAt(0) && isSocketIoPrefix(message);
	}

	/**
	 * @param message
	 * @return
	 */
	public static boolean isMessageCommand(String message) {
		return SocketIoProtocol.MESSAGE == message.charAt(0) && isSocketIoPrefix(message);
	}

	/**
	 * @param message
	 * @return
	 */
	public static boolean isJsonMessageCommand(String message) {
		return SocketIoProtocol.JSON_MESSAGE == message.charAt(0) && isSocketIoPrefix(message);
	}

	/**
	 * @param message
	 * @return
	 */
	public static boolean isEventCommand(String message) {
		return SocketIoProtocol.EVENT == message.charAt(0) && isSocketIoPrefix(message);
	}

	/**
	 * @param message
	 * @return
	 */
	public static boolean isAckCommand(String message) {
		return SocketIoProtocol.ACK == message.charAt(0) && isSocketIoPrefix(message);
	}

	/**
	 * @param message
	 * @return
	 */
	public static boolean isErrorCommand(String message) {
		return SocketIoProtocol.ERROR == message.charAt(0) && isSocketIoPrefix(message);
	}

	/**
	 * @param message
	 * @return
	 */
	public static boolean isNoopCommand(String message) {
		return SocketIoProtocol.NOOP == message.charAt(0) && isSocketIoPrefix(message);
	}

	/**
	 * @param message
	 * @return
	 */
	public static long getClientId(String message) {
		String[] blocks = socketIoPattern.split(message, LIMIT);

		if (blocks.length >= 3) {
			String possibleId = blocks[2];
			if ((possibleId != null) && (possibleId.length() >= CLIENT_ID_LENGTH)) {
				return Long.parseLong(possibleId.trim());
			}
		}
		return NO_ID;

	}

	/**
	 * The Socket.IO specification requires that upon connection, a string is returned with the
	 * id:heartBeat:disconnect:supportedTransports such as 1234567890:30:10:websockets
	 * 
	 * @param clientId
	 * @return
	 */
	public static String connectResponse(Long clientId) {
		return clientId + HEARTBEAT_INFO + supportedProtocols;
	}

	public static String messageResponse(long messageId, String message) {
		return baseMessageResponse(MESSAGE, messageId, message, null);
	}

	public static String jsonMessageResponse(long messageId, String message) {
		return baseMessageResponse(JSON_MESSAGE, messageId, message, null);
	}

	public static String connectMessageResponse(String message) {
		return connectMessageResponse(message, null);
	}

	public static String connectMessageResponse(String message, String clientId) {
		return baseMessageResponse(CONNECT, 0l, message, clientId);
	}

	public static String heartBeatMessageResponse(long messageId, String message) {
		return baseMessageResponse(HEART_BEAT, messageId, message, null);
	}

	private static final String baseMessageResponse(char messageType, long messageId, String message, String clientId) {
		return messageType + ":" + messageId + ":" + (clientId == null ? "" : clientId) + ":" + message + "\n";
	}

    public static boolean isSocketIoPrefix(String message) {
        return message.length() >= 2 && message.charAt(1) == ':';
    }

	/**
	 * Object a message or a json message
	 * 
	 * @param message
	 * @return
	 */
	public static String extractCommand(String message) {

		String[] blocks = socketIoPattern.split(message, LIMIT);
		if (blocks.length >= 3) {
			return blocks[3];
		}
		return null;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy