io.scalecube.socketio.pipeline.PacketEncoderHandler.java Source code

Java tutorial

Introduction

Here is the source code for io.scalecube.socketio.pipeline.PacketEncoderHandler.java

Source

/**
 * Copyright 2012 Ronen Hamias, Anton Kharenko
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package io.scalecube.socketio.pipeline;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCounted;
import io.scalecube.socketio.TransportType;
import io.scalecube.socketio.packets.IPacket;
import io.scalecube.socketio.packets.Packet;
import io.scalecube.socketio.packets.PacketsFrame;
import io.scalecube.socketio.serialization.PacketEncoder;
import io.scalecube.socketio.serialization.PacketFramer;

/**
 * <p>
 * This class encodes Socket.IO messages they're sent. The structure of a
 * message is as follows:
 * </p>
 *
 * <p>
 * {@code [message type] ':' [message id ('+')] ':' [message endpoint] (':' [message data])}
 * </p>
 *
 * <p>
 * The message type is a single digit integer. The message id is an incremental
 * integer, required for ACKs (can be ommitted). If the message id is followed
 * by a +, the ACK is not handled by socket.io, but by the user instead.
 * Socket.IO has built-in support for multiple channels of communication (which
 * we call "multiple sockets"). Each socket is identified by an endpoint (can be
 * omitted).
 * </p>
 *
 * @author Ronen Hamias, Anton Kharenko
 *
 */
@ChannelHandler.Sharable
public class PacketEncoderHandler extends MessageToMessageEncoder<Object> {

    private final static String JSONP_TEMPLATE = "io.j[%s]('%s');";

    private final Logger log = LoggerFactory.getLogger(getClass());

    @Override
    protected void encode(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception {
        if (msg instanceof IPacket) {
            IPacket packet = (IPacket) msg;

            if (log.isDebugEnabled())
                log.debug("Sending packet: {} to channel: {}", msg, ctx.channel());
            ByteBuf encodedPacket = encodePacket(packet);
            if (log.isDebugEnabled())
                log.debug("Encoded packet: {}", encodedPacket);

            TransportType transportType = packet.getTransportType();
            if (transportType == TransportType.WEBSOCKET || transportType == TransportType.FLASHSOCKET) {
                out.add(new TextWebSocketFrame(encodedPacket));
            } else if (transportType == TransportType.XHR_POLLING) {
                out.add(PipelineUtils.createHttpResponse(packet.getOrigin(), encodedPacket, false));
            } else if (transportType == TransportType.JSONP_POLLING) {
                String jsonpIndexParam = (packet.getJsonpIndexParam() != null) ? packet.getJsonpIndexParam() : "0";
                String encodedStringPacket = encodedPacket.toString(CharsetUtil.UTF_8);
                encodedPacket.release();
                String encodedJsonpPacket = String.format(JSONP_TEMPLATE, jsonpIndexParam, encodedStringPacket);
                HttpResponse httpResponse = PipelineUtils.createHttpResponse(packet.getOrigin(),
                        PipelineUtils.copiedBuffer(ctx.alloc(), encodedJsonpPacket), true);
                httpResponse.headers().add("X-XSS-Protection", "0");
                out.add(httpResponse);
            } else {
                throw new UnsupportedTransportTypeException(transportType);
            }
        } else {
            if (msg instanceof ReferenceCounted) {
                ((ReferenceCounted) msg).retain();
            }
            out.add(msg);
        }
    }

    private ByteBuf encodePacket(final IPacket msg) throws Exception {
        if (msg instanceof PacketsFrame) {
            return PacketFramer.encodePacketsFrame((PacketsFrame) msg);
        } else if (msg instanceof Packet) {
            return PacketEncoder.encodePacket((Packet) msg);
        } else {
            throw new UnsupportedPacketTypeException(msg);
        }
    }

}