/* * BackendWorkerConnectionHandler.java * * Copyright (C) 2015 Pixelgaffer * * This work is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation; either version 2 of the License, or any later * version. * * This work 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 version 2 and version 3 of the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.pixelgaffer.turnierserver.backend.server; import static org.pixelgaffer.turnierserver.networking.bwprotocol.ProtocolLine.AICONNECTED; import static org.pixelgaffer.turnierserver.networking.bwprotocol.ProtocolLine.ANSWER; import static org.pixelgaffer.turnierserver.networking.bwprotocol.ProtocolLine.INFO; import static org.pixelgaffer.turnierserver.networking.bwprotocol.ProtocolLine.SANDBOX_MESSAGE; import static org.pixelgaffer.turnierserver.networking.messages.SandboxMessage.FINISHED_AI; import static org.pixelgaffer.turnierserver.networking.messages.SandboxMessage.TERMINATED_AI; import static org.pixelgaffer.turnierserver.networking.messages.WorkerCommand.KILLAI; import java.io.IOException; import org.pixelgaffer.turnierserver.Airbrake; import org.pixelgaffer.turnierserver.Parsers; import org.pixelgaffer.turnierserver.backend.AiWrapper; import org.pixelgaffer.turnierserver.backend.BackendMain; import org.pixelgaffer.turnierserver.backend.Games; import org.pixelgaffer.turnierserver.backend.Jobs; import org.pixelgaffer.turnierserver.backend.WorkerConnection; import org.pixelgaffer.turnierserver.backend.Workers; import org.pixelgaffer.turnierserver.backend.server.message.BackendFrontendCompileMessage; import org.pixelgaffer.turnierserver.networking.ConnectionHandler; import org.pixelgaffer.turnierserver.networking.bwprotocol.AiConnected; import org.pixelgaffer.turnierserver.networking.bwprotocol.ProtocolLine; import org.pixelgaffer.turnierserver.networking.bwprotocol.WorkerCommandAnswer; import org.pixelgaffer.turnierserver.networking.messages.MessageForward; import org.pixelgaffer.turnierserver.networking.messages.SandboxMessage; import org.pixelgaffer.turnierserver.networking.messages.WorkerCommand; import org.pixelgaffer.turnierserver.networking.messages.WorkerInfo; import org.pixelgaffer.turnierserver.networking.util.DataBuffer; import lombok.NonNull; import naga.NIOSocket; /** * Diese Klasse ist der ConnectionHandler für den BackendServer. */ public class BackendWorkerConnectionHandler extends ConnectionHandler { /** Der lokale Buffer mit den noch nicht gelesenen bytes. */ private DataBuffer buffer = new DataBuffer(); /** Die erstellte WorkerConnection. */ private WorkerConnection workerConnection; public BackendWorkerConnectionHandler (NIOSocket socket) { super(socket); } public synchronized void sendCommand (@NonNull WorkerCommand cmd) throws IOException { getClient().write(Parsers.getWorker().parse(cmd, true)); } public void sendMessage (MessageForward mf) throws IOException { workerConnection.sendMessage(mf); } @Override protected void disconnected () { BackendMain.getLogger().warning("Der Worker " + workerConnection + " hat sich disconnected."); if (workerConnection != null) { Workers.removeWorker(workerConnection); workerConnection.disconnectClient(); } } @Override public void packetReceived (NIOSocket socket, byte[] packet) { buffer.add(packet); byte line[]; while ((line = buffer.readLine()) != null) { if (workerConnection == null) { try { workerConnection = new WorkerConnection(this, socket.getIp(), Parsers.getWorker().parse(line, WorkerInfo.class)); Workers.registerWorker(workerConnection); } catch (Exception e) { BackendMain.getLogger().critical("Exception while creating WorkerConnection: " + e); } } else { try { ProtocolLine l = new ProtocolLine(line); if (l.getMode() == ANSWER) { WorkerCommandAnswer answer = (WorkerCommandAnswer)l.getObject(); if (answer.getWhat() == WorkerCommandAnswer.MESSAGE) { BackendFrontendCompileMessage msg = new BackendFrontendCompileMessage(answer.getMessage(), Jobs.findRequestId(answer.getUuid())); BackendFrontendConnectionHandler.getFrontend() .sendMessage(Parsers.getFrontend().parse(msg, false)); } else if ((answer.getWhat() == WorkerCommandAnswer.CRASH) || (answer.getWhat() == WorkerCommandAnswer.SUCCESS)) { Jobs.jobFinished(answer); } } else if (l.getMode() == INFO) { WorkerInfo info = (WorkerInfo)l.getObject(); workerConnection.update(info); } else if (l.getMode() == AICONNECTED) { AiConnected aicon = (AiConnected)l.getObject(); AiWrapper ai = Games.getAiWrapper(aicon.getUuid()); if (ai == null) { BackendMain.getLogger().critical("Unknown AI with UUID " + aicon.getUuid() + " connected"); sendCommand(new WorkerCommand(KILLAI, -1, -1, null, -1, aicon.getUuid(), -1)); } else ai.connected(); } else if (l.getMode() == SANDBOX_MESSAGE) { BackendMain.getLogger().info("SandboxMessage received: " + l.getObject()); if (l.getObject(SandboxMessage.class).getEvent() == TERMINATED_AI) Games.aiTerminated(l.getObject(SandboxMessage.class).getUuid()); else Games.aiDisconnected(l.getObject(SandboxMessage.class).getUuid()); if (l.getObject(SandboxMessage.class).getEvent() == FINISHED_AI) { AiWrapper ai = Games.getAiWrapper(l.getObject(SandboxMessage.class).getUuid()); ai.crashed(); } } else BackendMain.getLogger().critical("Unknown ProtocolLine Mode " + ((char)l.getMode())); } catch (Exception e) { BackendMain.getLogger().critical("Failed to parse answer from Worker: " + e); Airbrake.log(e).printStackTrace(); } } } } }