diff --git a/src/main/java/com/corundumstudio/socketio/AuthorizeHandler.java b/src/main/java/com/corundumstudio/socketio/AuthorizeHandler.java index 0c34c33..7d76f23 100644 --- a/src/main/java/com/corundumstudio/socketio/AuthorizeHandler.java +++ b/src/main/java/com/corundumstudio/socketio/AuthorizeHandler.java @@ -29,6 +29,7 @@ import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; +import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; @@ -40,6 +41,7 @@ import com.corundumstudio.socketio.messages.AuthorizeMessage; import com.corundumstudio.socketio.parser.Packet; import com.corundumstudio.socketio.parser.PacketType; +@Sharable public class AuthorizeHandler extends SimpleChannelUpstreamHandler implements Disconnectable { private final Logger log = LoggerFactory.getLogger(getClass()); diff --git a/src/main/java/com/corundumstudio/socketio/PacketHandler.java b/src/main/java/com/corundumstudio/socketio/PacketHandler.java index 10af14d..9dc3e1e 100644 --- a/src/main/java/com/corundumstudio/socketio/PacketHandler.java +++ b/src/main/java/com/corundumstudio/socketio/PacketHandler.java @@ -51,20 +51,13 @@ public class PacketHandler extends SimpleChannelUpstreamHandler { private Packet decode(ChannelBuffer buffer) throws IOException { if (isCurrentDelimiter(buffer, buffer.readerIndex())) { - StringBuilder length = new StringBuilder(4); - for (int i = buffer.readerIndex() + Packet.DELIMITER_BYTES.length; i < buffer.readerIndex() + buffer.readableBytes(); i++) { - if (isCurrentDelimiter(buffer, i)) { - break; - } else { - length.append((char)buffer.getUnsignedByte(i)); - } - } - Integer len = Integer.valueOf(length.toString()); + buffer.readerIndex(buffer.readerIndex() + Packet.DELIMITER_BYTES.length); + + Integer len = parseLength(buffer); - int startIndex = buffer.readerIndex() + Packet.DELIMITER_BYTES.length + length.length() + Packet.DELIMITER_BYTES.length; - ChannelBuffer frame = buffer.slice(startIndex, len); + ChannelBuffer frame = buffer.slice(buffer.readerIndex(), len); Packet packet = decoder.decodePacket(frame); - buffer.readerIndex(startIndex + len); + buffer.readerIndex(buffer.readerIndex() + len); return packet; } else { Packet packet = decoder.decodePacket(buffer); @@ -73,6 +66,19 @@ public class PacketHandler extends SimpleChannelUpstreamHandler { } } + private Integer parseLength(ChannelBuffer buffer) { + byte[] digits = null; + for (int i = buffer.readerIndex(); i < buffer.readerIndex() + buffer.readableBytes(); i++) { + if (isCurrentDelimiter(buffer, i)) { + digits = new byte[i - buffer.readerIndex()]; + buffer.getBytes(buffer.readerIndex(), digits); + break; + } + } + buffer.readerIndex(buffer.readerIndex() + digits.length + Packet.DELIMITER_BYTES.length); + return decoder.parseInt(digits); + } + private boolean isCurrentDelimiter(ChannelBuffer buffer, int index) { for (int i = 0; i < Packet.DELIMITER_BYTES.length; i++) { if (buffer.getByte(index + i) != Packet.DELIMITER_BYTES[i]) { diff --git a/src/main/java/com/corundumstudio/socketio/SocketIOEncoder.java b/src/main/java/com/corundumstudio/socketio/SocketIOEncoder.java index 07b2cf3..603694f 100644 --- a/src/main/java/com/corundumstudio/socketio/SocketIOEncoder.java +++ b/src/main/java/com/corundumstudio/socketio/SocketIOEncoder.java @@ -36,6 +36,7 @@ import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpResponse; @@ -59,6 +60,7 @@ import com.corundumstudio.socketio.messages.XHRPostMessage; import com.corundumstudio.socketio.parser.Encoder; import com.corundumstudio.socketio.parser.Packet; +@Sharable public class SocketIOEncoder extends OneToOneEncoder implements MessageHandler { class XHRClientEntry { @@ -146,9 +148,6 @@ public class SocketIOEncoder extends OneToOneEncoder implements MessageHandler { break; } } - if (packets.isEmpty()) { - return; - } String message = encoder.encodePackets(packets); sendMessage(origin, sessionId, channel, message); diff --git a/src/main/java/com/corundumstudio/socketio/parser/Decoder.java b/src/main/java/com/corundumstudio/socketio/parser/Decoder.java index 628544f..b07f72f 100644 --- a/src/main/java/com/corundumstudio/socketio/parser/Decoder.java +++ b/src/main/java/com/corundumstudio/socketio/parser/Decoder.java @@ -70,17 +70,32 @@ public class Decoder { } */ + // fastest way to parse chars to int + public Integer parseInt(byte[] chars) { + int result = 0; + for (int i = 0; i < chars.length; i++) { + int digit = ((int)chars[i] & 0xF); + for (int j = 0; j < chars.length-1-i; j++) { + digit *= 10; + } + result += digit; + } + return result; + } + public Packet decodePacket(ChannelBuffer buffer) throws IOException { - byte typeId = Byte.valueOf(Character.valueOf((char)buffer.getUnsignedByte(0)).toString()); - if (typeId >= PacketType.VALUES.length - || buffer.getByte(1) != separator) { + if (buffer.readableBytes() < 3) { throw new DecoderException("Can't parse " + buffer.toString(CharsetUtil.UTF_8)); } - PacketType type = PacketType.valueOf(typeId); + PacketType type = getType(buffer); int readerIndex = 1; - StringBuilder messageId = new StringBuilder(4); + // 'null' to avoid unnecessary StringBuilder creation + StringBuilder messageId = null; for (readerIndex += 1; readerIndex < buffer.readableBytes(); readerIndex++) { + if (messageId == null) { + messageId = new StringBuilder(4); + } byte msg = buffer.getByte(readerIndex); if (msg == separator) { break; @@ -90,12 +105,16 @@ public class Decoder { } } Integer id = null; - if (messageId.length() > 0) { + if (messageId != null && messageId.length() > 0) { id = Integer.valueOf(messageId.toString()); } - StringBuilder endpointBuffer = new StringBuilder(); + // 'null' to avoid unnecessary StringBuilder creation + StringBuilder endpointBuffer = null; for (readerIndex += 1; readerIndex < buffer.readableBytes(); readerIndex++) { + if (endpointBuffer == null) { + endpointBuffer = new StringBuilder(); + } byte msg = buffer.getByte(readerIndex); if (msg == separator) { break; @@ -104,7 +123,7 @@ public class Decoder { } String endpoint = null; - if (endpointBuffer.length() > 0) { + if (endpointBuffer != null && endpointBuffer.length() > 0) { endpoint = endpointBuffer.toString(); } @@ -193,6 +212,15 @@ public class Decoder { return packet; } + private PacketType getType(ChannelBuffer buffer) { + int typeId = buffer.getByte(0) & 0xF; + if (typeId >= PacketType.VALUES.length + || buffer.getByte(1) != separator) { + throw new DecoderException("Can't parse " + buffer.toString(CharsetUtil.UTF_8)); + } + return PacketType.valueOf(typeId); + } + private String extract(Matcher matcher, int index) { if (index > matcher.groupCount()) { return null; diff --git a/src/main/java/com/corundumstudio/socketio/transport/WebSocketTransport.java b/src/main/java/com/corundumstudio/socketio/transport/WebSocketTransport.java index cf67231..99a394d 100644 --- a/src/main/java/com/corundumstudio/socketio/transport/WebSocketTransport.java +++ b/src/main/java/com/corundumstudio/socketio/transport/WebSocketTransport.java @@ -26,6 +26,7 @@ import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; +import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.QueryStringDecoder; @@ -42,6 +43,7 @@ import com.corundumstudio.socketio.Disconnectable; import com.corundumstudio.socketio.SocketIOClient; import com.corundumstudio.socketio.messages.PacketsMessage; +@Sharable public class WebSocketTransport extends SimpleChannelUpstreamHandler implements Disconnectable { private final Logger log = LoggerFactory.getLogger(getClass()); diff --git a/src/main/java/com/corundumstudio/socketio/transport/XHRPollingTransport.java b/src/main/java/com/corundumstudio/socketio/transport/XHRPollingTransport.java index b686085..f14c087 100644 --- a/src/main/java/com/corundumstudio/socketio/transport/XHRPollingTransport.java +++ b/src/main/java/com/corundumstudio/socketio/transport/XHRPollingTransport.java @@ -25,6 +25,7 @@ import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; +import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; @@ -45,6 +46,7 @@ import com.corundumstudio.socketio.parser.ErrorReason; import com.corundumstudio.socketio.parser.Packet; import com.corundumstudio.socketio.parser.PacketType; +@Sharable public class XHRPollingTransport extends SimpleChannelUpstreamHandler implements Disconnectable { private final Logger log = LoggerFactory.getLogger(getClass());