package net.johnewart.gearman.server.net;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import net.johnewart.gearman.common.packets.Packet;
import net.johnewart.gearman.common.packets.request.CanDo;
import net.johnewart.gearman.common.packets.request.CanDoTimeout;
import net.johnewart.gearman.common.packets.request.CantDo;
import net.johnewart.gearman.common.packets.request.EchoRequest;
import net.johnewart.gearman.common.packets.request.GetStatus;
import net.johnewart.gearman.common.packets.request.OptionRequest;
import net.johnewart.gearman.common.packets.request.SubmitJob;
import net.johnewart.gearman.common.packets.response.WorkResponse;
import net.johnewart.gearman.common.packets.response.WorkStatus;
import net.johnewart.gearman.engine.queue.JobQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
public class PacketHandler extends SimpleChannelInboundHandler<Object> {
private static final Logger LOG = LoggerFactory.getLogger(PacketHandler.class);
private final NetworkManager networkManager;
public PacketHandler(NetworkManager networkManager)
{
LOG.debug("Creating new handler!");
this.networkManager = networkManager;
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
}
@Override
public void channelRead0(ChannelHandlerContext ctx, Object request) throws Exception {
LOG.debug(" ---> " + request.toString());
if (request instanceof Packet) {
handlePacket((Packet)request, ctx.channel());
} else if (request instanceof String) {
handleTextCommand((String)request, ctx.channel());
} else {
LOG.error("Received un-handled message: " + request);
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
LOG.debug("Client closed channel: " + ctx.channel().toString());
networkManager.channelDisconnected(ctx.channel());
}
private void handleTextCommand(String message, Channel channel)
{
switch(message.toLowerCase()) {
case "status":
String header = "FUNCTION\tTOTAL\tRUNNING\tAVAILABLE_WORKERS\n";
Map<String, JobQueue> jobQueues = networkManager.getJobManager().getJobQueues();
channel.writeAndFlush(header);
for(String jobQueueName : jobQueues.keySet())
{
JobQueue queue = jobQueues.get(jobQueueName);
channel.writeAndFlush(String.format("%s\t%s\t%s\t%s\n", jobQueueName, queue.size(), 0, 0));
}
channel.writeAndFlush(".\n");
break;
case "workers":
break;
case "maxqueue":
break;
case "shutdown":
break;
case "version":
break;
default:
LOG.debug("Unhandled text command: " + message);
}
}
private void handlePacket(Packet packet, Channel channel)
{
switch(packet.getType())
{
case CAN_DO:
networkManager.registerAbility(((CanDo)packet).getFunctionName(), channel);
return;
case CAN_DO_TIMEOUT:
// TODO: Support timeout
networkManager.registerAbility(((CanDoTimeout)packet).getFunctionName(), channel);
return;
case CANT_DO:
networkManager.unregisterAbility(((CantDo)packet).getFunctionName(), channel);
return;
case GRAB_JOB:
networkManager.nextJobForWorker(channel, false);
return;
case GRAB_JOB_UNIQ:
networkManager.nextJobForWorker(channel, true);
return;
case GRAB_JOB_ALL:
// TODO: Consider support for partitioning and reducing here
networkManager.nextJobForWorker(channel, true);
return;
case SUBMIT_JOB:
case SUBMIT_JOB_BG:
case SUBMIT_JOB_HIGH:
case SUBMIT_JOB_HIGH_BG:
case SUBMIT_JOB_LOW:
case SUBMIT_JOB_LOW_BG:
case SUBMIT_JOB_EPOCH:
networkManager.createJob((SubmitJob)packet, channel);
break;
case WORK_COMPLETE:
case WORK_WARNING:
case WORK_EXCEPTION:
case WORK_DATA:
case WORK_FAIL:
networkManager.workResponse((WorkResponse) packet, channel);
return;
case WORK_STATUS:
networkManager.updateJobStatus((WorkStatus)packet);
return;
case GET_STATUS:
networkManager.checkJobStatus((GetStatus)packet, channel);
return;
case SET_CLIENT_ID:
return;
case PRE_SLEEP:
networkManager.sleepingWorker(channel);
return;
// Packets Not Yet Implemented
case ECHO_REQ:
networkManager.handleEchoRequest((EchoRequest)packet, channel);
return;
case OPTION_REQ:
networkManager.handleOptionRequest((OptionRequest)packet, channel);
return;
case RESET_ABILITIES:
networkManager.resetWorkerAbilities(channel);
case ALL_YOURS:
case SUBMIT_JOB_SCHED:
//client.sendPacket(StaticPackets.ERROR_BAD_COMMAND, null);
return;
// Unknown Command
default:
//client.sendPacket(StaticPackets.ERROR_BAD_COMMAND, null);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
{
// Close the connection when an exception is raised.
LOG.warn("Unexpected exception from downstream.", cause);
ctx.channel().close();
}
}