/**
* 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.io.IOException;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.scalecube.socketio.Session;
import io.scalecube.socketio.SocketIOListener;
import io.scalecube.socketio.packets.ConnectPacket;
import io.scalecube.socketio.packets.IPacket;
import io.scalecube.socketio.packets.Packet;
import io.scalecube.socketio.packets.PacketType;
import io.scalecube.socketio.session.ManagedSession;
import io.scalecube.socketio.session.SessionDisconnectHandler;
import io.scalecube.socketio.session.SessionStorage;
@ChannelHandler.Sharable
public class PacketDispatcherHandler extends ChannelInboundHandlerAdapter implements SessionDisconnectHandler {
private final Logger log = LoggerFactory.getLogger(getClass());
private final SessionStorage sessionStorage;
private final SocketIOListener listener;
public PacketDispatcherHandler(SessionStorage sessionStorage, SocketIOListener listener) {
this.sessionStorage = sessionStorage;
this.listener = listener;
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
if (log.isDebugEnabled())
log.debug("Channel active: {}", ctx.channel());
super.channelActive(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
if (log.isDebugEnabled())
log.debug("Channel inactive: {}", ctx.channel());
super.channelInactive(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (cause instanceof IOException) {
log.info("Exception caught at channel: {}, {}", ctx.channel(), cause.getMessage());
} else {
log.error("Exception caught at channel: {}, {}", ctx.channel(), cause);
}
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object message) throws Exception {
final Channel channel = ctx.channel();
if (message instanceof IPacket) {
final IPacket packet = (IPacket) message;
try {
if (log.isDebugEnabled())
log.debug("Dispatching packet: {} from channel: {}", packet, channel);
dispatchPacket(channel, packet);
} catch (Exception e) {
log.error("Failed to dispatch packet: {}", packet, e);
}
} else {
log.warn("Received unknown message: {} from channel {}", message, channel);
}
}
private void dispatchPacket(final Channel channel, final IPacket packet) throws Exception {
if (packet instanceof ConnectPacket) {
ConnectPacket connectPacket = (ConnectPacket) packet;
final ManagedSession session = sessionStorage.getSession(connectPacket, channel, this);
onConnectPacket(channel, session);
} else if (packet instanceof Packet) {
Packet message = (Packet) packet;
final String sessionId = packet.getSessionId();
final ManagedSession session = sessionStorage.getSessionIfExist(sessionId);
if (session != null) {
onPacket(channel, session, message);
} else {
if (message.getData() != null) {
message.getData().release();
}
}
} else {
throw new UnsupportedPacketTypeException(packet);
}
}
private void onConnectPacket(final Channel channel, final ManagedSession session) {
boolean initialConnect = session.connect(channel);
if (initialConnect && listener != null) {
listener.onConnect(session);
}
}
private void onPacket(final Channel channel, final ManagedSession session, final Packet packet) {
if (packet.getType() == PacketType.DISCONNECT) {
if (log.isDebugEnabled())
log.debug("Got {} packet, {} session will be disconnected", packet.getType().name(), session.getSessionId());
session.disconnect(channel);
} else {
session.acceptPacket(channel, packet);
if (listener != null && (packet.getType() == PacketType.MESSAGE || packet.getType() == PacketType.JSON)) {
listener.onMessage(session, packet.getData());
}
}
}
@Override
public void onSessionDisconnect(Session session) {
if (sessionStorage.containSession(session.getSessionId())) {
if (log.isDebugEnabled())
log.debug("Client with sessionId: {} disconnected", session.getSessionId());
sessionStorage.removeSession(session.getSessionId());
if (listener != null) {
listener.onDisconnect(session);
}
}
}
}