/* * WorkerConnection.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; import static org.pixelgaffer.turnierserver.networking.messages.WorkerCommand.COMPILE; import static org.pixelgaffer.turnierserver.networking.messages.WorkerCommand.KILLAI; import static org.pixelgaffer.turnierserver.networking.messages.WorkerCommand.STARTAI; import static org.pixelgaffer.turnierserver.networking.messages.WorkerCommand.TERMAI; import java.io.IOException; import java.util.List; import java.util.UUID; import org.pixelgaffer.turnierserver.backend.server.BackendWorkerConnectionHandler; import org.pixelgaffer.turnierserver.backend.workerclient.WorkerClient; import org.pixelgaffer.turnierserver.networking.messages.MessageForward; import org.pixelgaffer.turnierserver.networking.messages.WorkerCommand; import org.pixelgaffer.turnierserver.networking.messages.WorkerInfo; import org.pixelgaffer.turnierserver.networking.messages.WorkerInfo.SandboxInfo; import it.sauronsoftware.ftp4j.FTPAbortedException; import it.sauronsoftware.ftp4j.FTPDataTransferException; import it.sauronsoftware.ftp4j.FTPException; import it.sauronsoftware.ftp4j.FTPIllegalReplyException; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NonNull; import lombok.Setter; import lombok.ToString; /** * Diese Klasse speichert Informationen über einen verbundenen Worker. */ @ToString(exclude = { "connection", "client" }) @EqualsAndHashCode(of = { "id" }) public class WorkerConnection { // id des Workers private static long nid = 0; private long id = nid++; private List<SandboxInfo> sandboxes; @Getter private boolean tournament; /** Gibt an, ob gerade ein Kompilierungsauftrag läuft. */ @Getter @Setter private boolean compiling; /** Die Connection vom Backend zum Worker. */ private BackendWorkerConnectionHandler connection; /** Die Connection vom Worker zum Backend. */ private WorkerClient client; public WorkerConnection (@NonNull BackendWorkerConnectionHandler con, String addr, WorkerInfo info) throws IOException { connection = con; sandboxes = info.getSandboxes(); tournament = info.isTournament(); client = new WorkerClient(addr, info); } /** * Disconnected alle Verbindungen zum Worker. */ public void disconnect () { disconnectClient(); disconnectConnection(); } /** * Disconnected den Client zum Worker. */ public void disconnectClient () { client.disconnect(); } /** * Disconnected die Verbindung vom Worker zum BackendWorkerServer. */ public void disconnectConnection () { connection.disconnect(); } /** * Gibt an, ob der Worker gerade eine KI starten kann oder ob alle Sandboxen * komplett ausgelastet sind. */ public synchronized boolean canStartAi (String lang) { for (SandboxInfo info : sandboxes) if ((lang == null || info.getLangs().contains(lang)) && !info.isBusy()) return true; return false; } /** * Gibt die Anzahl der nicht ausgelasteten Sandboxen zurück. */ public synchronized int getStartableSandboxes () { int count = 0; for (SandboxInfo info : sandboxes) if (!info.isBusy()) count++; return count; } /** * Schickt einen Kompilieren-Befehl an den Worker, ai enthält * ${ai-id}v${ai-version}. */ public WorkerCommand compile (String ai, String lang, int game) throws IOException, NumberFormatException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException { String s[] = ai.split("v"); if (s.length != 2) throw new IllegalArgumentException(ai); return compile(Integer.parseInt(s[0]), Integer.parseInt(s[1]), lang, game); } /** * Schickt einen Kompilieren-Befehl an den Worker. */ public synchronized WorkerCommand compile (int aiId, int version, String lang, int game) throws IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException { if (isCompiling()) BackendMain.getLogger().warning("Gebe Kompilierungsauftrag an beschägtigten Worker weiter"); setCompiling(true); WorkerCommand cmd = new WorkerCommand(COMPILE, aiId, version, lang, game, UUID.randomUUID(), -1); connection.sendCommand(cmd); return cmd; } /** * Schickt einen StarteKI-Befehl an den Worker insofern dieser nicht * komplett beschäftigt ist. */ public synchronized boolean addJob (AiWrapper ai, int game) throws IOException { if (!canStartAi(ai.getLang())) return false; connection.sendCommand(new WorkerCommand(STARTAI, ai.getAiId(), ai.getVersion(), ai.getLang(), game, ai.getUuid(), ai.getGame().getLogic().aiTimeout())); return true; } /** * Schickt einen TerminiereKI-Befehl an den Worker. */ public void terminateJob (AiWrapper ai) throws IOException { connection.sendCommand(new WorkerCommand(TERMAI, ai.getAiId(), ai.getVersion(), ai.getLang(), -1, ai.getUuid(), -1)); } /** * Schickt einen TerminiereKI-Befehl an den Worker. */ public void killJob (AiWrapper ai) throws IOException { connection.sendCommand(new WorkerCommand(KILLAI, ai.getAiId(), ai.getVersion(), ai.getLang(), -1, ai.getUuid(), -1)); } /** * Schickt den MessageForward an den Worker weiter. */ public void sendMessage (MessageForward mf) throws IOException { client.sendMessage(mf); } /** * Aktualisiert die Daten dieses Workers. */ public synchronized void update (WorkerInfo info) { BackendMain.getLogger().info("Der Worker " + id + " hat sich geupdated: " + info); sandboxes = info.getSandboxes(); tournament = info.isTournament(); // Workers notifien Workers.workerIsAvailable(); } }