package net.md_5.bungee.netty;
import com.google.common.base.Preconditions;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.timeout.ReadTimeoutException;
import java.io.IOException;
import java.util.logging.Level;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.connection.CancelSendSignal;
import net.md_5.bungee.connection.InitialHandler;
import net.md_5.bungee.connection.PingHandler;
import net.md_5.bungee.protocol.BadPacketException;
import net.md_5.bungee.protocol.OverflowPacketException;
import net.md_5.bungee.protocol.PacketWrapper;
/**
* This class is a primitive wrapper for {@link PacketHandler} instances tied to
* channels to maintain simple states, and only call the required, adapted
* methods when the channel is connected.
*/
public class HandlerBoss extends ChannelInboundHandlerAdapter
{
private ChannelWrapper channel;
private PacketHandler handler;
public void setHandler(PacketHandler handler)
{
Preconditions.checkArgument( handler != null, "handler" );
this.handler = handler;
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception
{
if ( handler != null )
{
channel = new ChannelWrapper( ctx );
handler.connected( channel );
if ( !( handler instanceof InitialHandler || handler instanceof PingHandler ) )
{
ProxyServer.getInstance().getLogger().log( Level.INFO, "{0} has connected", handler );
}
}
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception
{
if ( handler != null )
{
channel.markClosed();
handler.disconnected( channel );
if ( !( handler instanceof InitialHandler || handler instanceof PingHandler ) )
{
ProxyServer.getInstance().getLogger().log( Level.INFO, "{0} has disconnected", handler );
}
}
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
{
if ( handler != null )
{
PacketWrapper packet = (PacketWrapper) msg;
boolean sendPacket = handler.shouldHandle( packet );
try
{
if ( sendPacket && packet.packet != null )
{
try
{
packet.packet.handle( handler );
} catch ( CancelSendSignal ex )
{
sendPacket = false;
}
}
if ( sendPacket )
{
handler.handle( packet );
}
} finally
{
packet.trySingleRelease();
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
{
if ( ctx.channel().isActive() )
{
if ( cause instanceof ReadTimeoutException )
{
ProxyServer.getInstance().getLogger().log( Level.WARNING, "{0} - read timed out", handler );
} else if ( cause instanceof DecoderException && cause.getCause() instanceof BadPacketException )
{
ProxyServer.getInstance().getLogger().log( Level.WARNING, "{0} - bad packet ID, are mods in use!? {1}", new Object[]
{
handler, cause.getCause().getMessage()
} );
} else if ( cause instanceof DecoderException && cause.getCause() instanceof OverflowPacketException )
{
ProxyServer.getInstance().getLogger().log( Level.WARNING, "{0} - overflow in packet detected! {1}", new Object[]
{
handler, cause.getCause().getMessage()
} );
} else if ( cause instanceof IOException || ( cause instanceof IllegalStateException && handler instanceof InitialHandler ) )
{
ProxyServer.getInstance().getLogger().log( Level.WARNING, "{0} - {1}: {2}", new Object[]
{
handler, cause.getClass().getSimpleName(), cause.getMessage()
} );
} else
{
ProxyServer.getInstance().getLogger().log( Level.SEVERE, handler + " - encountered exception", cause );
}
if ( handler != null )
{
try
{
handler.exception( cause );
} catch ( Exception ex )
{
ProxyServer.getInstance().getLogger().log( Level.SEVERE, handler + " - exception processing exception", ex );
}
}
ctx.close();
}
}
}