/*
* Copyright (c) 2015 "JackWhite20"
*
* This file is part of Comix.
*
* Comix is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.jackwhite20.comix.handler;
import de.jackwhite20.comix.Comix;
import de.jackwhite20.comix.network.ComixClient;
import de.jackwhite20.comix.network.Protocol;
import de.jackwhite20.comix.network.ProtocolState;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import java.util.List;
import java.util.logging.Level;
/**
* Created by JackWhite20 on 18.07.2015.
*/
public class HandshakeHandler extends MessageToMessageDecoder<ByteBuf> {
private UpstreamHandler upstreamHandler;
private ProtocolState protocolMode = ProtocolState.HANDSHAKE;
private boolean downstreamInitialized = false;
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> out) throws Exception {
ByteBuf copy = byteBuf.copy();
Protocol.readVarInt(byteBuf);
int packetId = Protocol.readVarInt(byteBuf);
if(packetId == 0) {
if(protocolMode == ProtocolState.HANDSHAKE) {
Protocol.readVarInt(byteBuf);
Protocol.readString(byteBuf);
byteBuf.readUnsignedShort();
protocolMode = ProtocolState.valueOf((byte) Protocol.readVarInt(byteBuf));
}
if(protocolMode == ProtocolState.STATUS) {
ByteBuf responseBuffer = Unpooled.buffer();
String response = Comix.getInstance().getStatusResponseString();
response = response.replace("%online%", "" + Comix.getInstance().getClientsOnline()); // Replace online count
Protocol.writeVarInt(3 + response.length(), responseBuffer); // Size
Protocol.writeVarInt(0, responseBuffer); // Packet id
Protocol.writeString(response, responseBuffer); // Data as json string
channelHandlerContext.writeAndFlush(responseBuffer);
// Sending Pong instant because otherwise the pong will not receive properly!
ByteBuf pongBuffer = Unpooled.buffer();
Protocol.writeVarInt(9, pongBuffer);
Protocol.writeVarInt(1, pongBuffer);
pongBuffer.writeLong(0);
channelHandlerContext.writeAndFlush(pongBuffer);
channelHandlerContext.close();
}
if(protocolMode == ProtocolState.LOGIN) {
if(byteBuf.readableBytes() == 0) {
upstreamHandler.connectDownstream(copy);
downstreamInitialized = true;
out.add(copy.retain());
return;
}
String name = Protocol.readString(byteBuf);
//TODO: Improve
if(Comix.getInstance().getComixConfig().isMaintenance()) {
if(Comix.getInstance().isWhitelistEnabled()) {
if(!Comix.getInstance().isWhitelisted(name)) {
kick(channelHandlerContext, Comix.getInstance().getWhitelistKickMessage());
}
}else {
kick(channelHandlerContext, Comix.getInstance().getComixConfig().getMaintenanceKickMessage());
}
channelHandlerContext.close();
return;
}else if(Comix.getInstance().isWhitelistEnabled() && !Comix.getInstance().isWhitelisted(name)) {
kick(channelHandlerContext, Comix.getInstance().getWhitelistKickMessage());
channelHandlerContext.close();
return;
}
if(!downstreamInitialized)
upstreamHandler.connectDownstream(copy);
else
upstreamHandler.addInitialPacket(copy);
ComixClient comixClient = new ComixClient(name, upstreamHandler.getDownstreamHandler(), upstreamHandler);
Comix.getInstance().addClient(comixClient);
upstreamHandler.setClient(comixClient);
channelHandlerContext.channel().pipeline().remove(this);
Comix.getLogger().log(Level.INFO, "Handshake", "Player logged in: " + name);
out.add(copy.retain());
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
Channel ch = ctx.channel();
if (ch.isActive()) {
ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
}
private void kick(ChannelHandlerContext channelHandlerContext, String text) {
ByteBuf test = Unpooled.buffer();
Protocol.writeVarInt(2 + text.length(), test);
Protocol.writeVarInt(0, test);
Protocol.writeString(text, test);
channelHandlerContext.writeAndFlush(test);
}
public void setUpstreamHandler(UpstreamHandler upstreamHandler) {
this.upstreamHandler = upstreamHandler;
}
}