diff --git a/src/main/java/de/tudresden/inf/st/mg/ImmersiveSortingController.java b/src/main/java/de/tudresden/inf/st/mg/ImmersiveSortingController.java index d5efac843d5e4ff0f9d33d444218a8f83b95079d..7aea0bf42d121c5797842a4d4de963913778d379 100644 --- a/src/main/java/de/tudresden/inf/st/mg/ImmersiveSortingController.java +++ b/src/main/java/de/tudresden/inf/st/mg/ImmersiveSortingController.java @@ -6,13 +6,11 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import de.tudresden.inf.st.mg.common.MotionGrammarConfig; import de.tudresden.inf.st.mg.common.MotionGrammarParser; import de.tudresden.inf.st.mg.common.TableDeserializer; +import de.tudresden.inf.st.mg.common.Webserver; import de.tudresden.inf.st.mg.jastadd.model.JastAddList; import de.tudresden.inf.st.mg.jastadd.model.RobotWorld; import de.tudresden.inf.st.mg.jastadd.model.Table; import de.tudresden.inf.st.mg.jastadd.model.World; -import io.javalin.Javalin; -import io.javalin.core.JavalinConfig; -import io.javalin.websocket.WsContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,25 +19,15 @@ import java.io.IOException; import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; -import java.time.Instant; import java.util.Comparator; -import java.util.Date; -import java.util.Map; import java.util.Random; -import java.util.concurrent.ConcurrentHashMap; public class ImmersiveSortingController { public static final Path TIDY_AST_DIAGRAM_DIR = Path.of("src", "gen", "resources", "diagrams", "parsing", "tidy"); private static final Logger logger = LoggerFactory.getLogger(ImmersiveSortingController.class); - private static final Map<WsContext, String> clients = new ConcurrentHashMap<>(); - private static ImmersiveSortingController INSTANCE; private final RobotWorld world; private ParseThread parse; - private Diagram ast; - private Diagram context; - - private boolean initialized = false; public ImmersiveSortingController(boolean simulate) { MotionGrammarConfig.astDiagramDir = TIDY_AST_DIAGRAM_DIR; @@ -64,9 +52,19 @@ public class ImmersiveSortingController { e.printStackTrace(); } - initializeWebserver(); + // initialize webserver + Webserver ws = Webserver.getInstance(); + + ws.setCallback("cell1", (String command) -> { + logger.info("got message " + command); + if ("parse".equals(command)) { + startParse(); + } else if ("reset".equals(command)) { + resetSelections(); + printContext("reset selection"); + } + }); - initialized = true; World.enableContextPrinting(true); world.printContext("initial"); @@ -107,20 +105,13 @@ public class ImmersiveSortingController { * on localhost:1883 */ public static void main(String[] args) { - ImmersiveSortingController controller = ImmersiveSortingController.getInstance(); + ImmersiveSortingController controller = new ImmersiveSortingController(false); try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) { } } - public static ImmersiveSortingController getInstance() { - if (INSTANCE == null) { - INSTANCE = new ImmersiveSortingController(false); - } - return INSTANCE; - } - public void startParse() { if (parse != null && parse.isAlive()) { parse.stopParsing(); @@ -141,79 +132,6 @@ public class ImmersiveSortingController { world.printContext(message); } - private void initializeWebserver() { - ast = new Diagram(new Date(), 0, "<no rule>", "", "ast"); - context = new Diagram(Date.from(Instant.now()), 0, "<no rule>", "", "context"); - - Javalin webserver = Javalin.create(JavalinConfig::enableCorsForAllOrigins).start(7070); - webserver.get("/", ctx -> ctx.result("the context is delivered at /context and the ast is delivered at /ast")); - - webserver.get("/ast/", ctx -> { - ctx.json(ast); - }); - - webserver.get("/context/", ctx -> { - ctx.json(context); - }); - - webserver.ws("ast-events", ws -> { - ws.onConnect(ctx -> { - System.err.println("somebody connected " + ctx.host()); - clients.put(ctx, ctx.host()); - }); - ws.onClose(ctx -> { - System.err.println("somebody disconnected"); - clients.remove(ctx); - }); - ws.onMessage(ctx -> { - if (initialized) { - logger.info("got message " + ctx.message()); - } else { - logger.error("ignoring message " + ctx.message() + ", because system is not initialized yet"); - return; - } - if ("parse".equals(ctx.message())) { - startParse(); - } else if ("reset".equals(ctx.message())) { - resetSelections(); - printContext("reset selection"); - } - }); - }); - } - - public void publish(Date timestamp, int step, String parseRule, Path diagramPath, String type) { - try { - if ("ast".equals(type)) { - ast = new Diagram(timestamp, step, parseRule, Files.readString(diagramPath), type); - clients.keySet().forEach(session -> session.send(ast)); - } else if ("context".equals(type)) { - context = new Diagram(timestamp, step, parseRule, Files.readString(diagramPath), type); - clients.keySet().forEach(session -> session.send(context)); - } - } catch (IOException e) { - System.err.println("Unable to read " + type + " diagram file " + diagramPath); - e.printStackTrace(); - } - } - - public static class Diagram { - public Date timestamp; - public int step; - public String parseRule; - public String diagram; - - public String type; - - public Diagram(Date timestamp, int step, String parseRule, String diagram, String type) { - this.timestamp = timestamp; - this.step = step; - this.parseRule = parseRule; - this.diagram = diagram; - this.type = type; - } - } - class ParseThread extends Thread { private RobotParser parser; diff --git a/src/main/java/de/tudresden/inf/st/mg/common/MotionGrammarParser.java b/src/main/java/de/tudresden/inf/st/mg/common/MotionGrammarParser.java index 0732e15e0df5aa79945dcd947e820898da6b767f..def2e40de27b8518fa40afc9be377ca7b3751a6f 100644 --- a/src/main/java/de/tudresden/inf/st/mg/common/MotionGrammarParser.java +++ b/src/main/java/de/tudresden/inf/st/mg/common/MotionGrammarParser.java @@ -3,7 +3,6 @@ package de.tudresden.inf.st.mg.common; import de.tudresden.inf.st.jastadd.dumpAst.ast.Dumper; import de.tudresden.inf.st.jastadd.dumpAst.ast.SkinParamBooleanSetting; import de.tudresden.inf.st.jastadd.dumpAst.ast.SkinParamStringSetting; -import de.tudresden.inf.st.mg.ImmersiveSortingController; import de.tudresden.inf.st.mg.jastadd.model.*; import java.io.IOException; @@ -34,7 +33,7 @@ public abstract class MotionGrammarParser<T extends MotionGrammarElement> { } try { TimeUnit.MILLISECONDS.sleep(100); - } catch(InterruptedException e) { + } catch (InterruptedException ignored) { } } @@ -84,7 +83,7 @@ public abstract class MotionGrammarParser<T extends MotionGrammarElement> { .skinParam(SkinParamBooleanSetting.Shadowing, false) .skinParam(SkinParamStringSetting.backgroundColor, "white") .dumpAsSVG(svgPath); - ImmersiveSortingController.getInstance().publish(new Date(), timeStep_, step, svgPath, "ast"); + Webserver.getInstance().publish(new Date(), timeStep_, step, svgPath, "ast"); timeStep_++; } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/java/de/tudresden/inf/st/mg/common/Webserver.java b/src/main/java/de/tudresden/inf/st/mg/common/Webserver.java new file mode 100644 index 0000000000000000000000000000000000000000..9fdc27b47da327fd6c7bd7b1d73461c6ca033410 --- /dev/null +++ b/src/main/java/de/tudresden/inf/st/mg/common/Webserver.java @@ -0,0 +1,110 @@ +package de.tudresden.inf.st.mg.common; + +import io.javalin.Javalin; +import io.javalin.core.JavalinConfig; +import io.javalin.websocket.WsContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; + +public class Webserver { + + private static final Logger logger = LoggerFactory.getLogger(Webserver.class); + private final Map<WsContext, String> clients = new ConcurrentHashMap<>(); + private static Webserver INSTANCE; + private Diagram ast; + private Diagram context; + + private final Map<String, Consumer<String>> callbacks = new ConcurrentHashMap<>(); + + private Webserver() { + ast = new Diagram(new Date(), 0, "<no rule>", "", "ast"); + context = new Diagram(Date.from(Instant.now()), 0, "<no rule>", "", "context"); + + Javalin webserver = Javalin.create(JavalinConfig::enableCorsForAllOrigins).start(7070); + webserver.get("/", ctx -> ctx.result("the context is delivered at /context and the ast is delivered at /ast")); + + webserver.get("/ast/", ctx -> { + ctx.json(ast); + }); + + webserver.get("/context/", ctx -> { + ctx.json(context); + }); + + webserver.ws("ast-events", ws -> { + ws.onConnect(ctx -> { + System.err.println("somebody connected " + ctx.host()); + clients.put(ctx, ctx.host()); + }); + ws.onClose(ctx -> { + System.err.println("somebody disconnected"); + clients.remove(ctx); + }); + ws.onMessage(ctx -> { + String[] splitString = ctx.message().split("\\s"); + if (splitString.length == 2) { + if (callbacks.containsKey(splitString[0])) { + callbacks.get(splitString[0]).accept(splitString[1]); + } + } else { + logger.error("Unable to execute command, because it does not fit the command syntax: " + ctx.message()); + } + }); + }); + + } + + public static Webserver getInstance() { + if (INSTANCE == null) { + INSTANCE = new Webserver(); + } + return INSTANCE; + } + + public void setCallback(String client, Consumer<String> callback) { + callbacks.put(client, callback); + } + + public void publish(Date timestamp, int step, String parseRule, Path diagramPath, String type) { + try { + if ("ast".equals(type)) { + ast = new Diagram(timestamp, step, parseRule, Files.readString(diagramPath), type); + clients.keySet().forEach(session -> session.send(ast)); + } else if ("context".equals(type)) { + context = new Diagram(timestamp, step, parseRule, Files.readString(diagramPath), type); + clients.keySet().forEach(session -> session.send(context)); + } + } catch (IOException e) { + System.err.println("Unable to read " + type + " diagram file " + diagramPath); + e.printStackTrace(); + } + } + + + public static class Diagram { + public Date timestamp; + public int step; + public String parseRule; + public String diagram; + + public String type; + + public Diagram(Date timestamp, int step, String parseRule, String diagram, String type) { + this.timestamp = timestamp; + this.step = step; + this.parseRule = parseRule; + this.diagram = diagram; + this.type = type; + } + } + +}