From f5dbb0916a130dbc3d2d5e14dfce0197a5df0e25 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Tue, 20 Oct 2020 01:32:16 +0200 Subject: [PATCH] working on autorouting and turnout code --- resources/css/style.css | 8 +++- resources/js/plan.js | 18 ++++--- .../de/srsoftware/web4rail/Application.java | 4 +- .../java/de/srsoftware/web4rail/Plan.java | 4 +- .../java/de/srsoftware/web4rail/Route.java | 3 +- .../de/srsoftware/web4rail/moving/Train.java | 48 +++++++++++++------ .../de/srsoftware/web4rail/tiles/Tile.java | 10 +++- .../de/srsoftware/web4rail/tiles/Turnout.java | 35 ++++++++++++-- .../srsoftware/web4rail/tiles/TurnoutL.java | 20 ++++---- .../srsoftware/web4rail/tiles/TurnoutR.java | 11 +++-- 10 files changed, 111 insertions(+), 50 deletions(-) diff --git a/resources/css/style.css b/resources/css/style.css index e2f1da8..560ce22 100644 --- a/resources/css/style.css +++ b/resources/css/style.css @@ -175,9 +175,9 @@ h2{ width: 15px; height: 15px; background: lime; - position: absolute; + position: fixed; top: 10px; - right: 10px; + left: 10px; display: none; } @@ -206,3 +206,7 @@ fieldset{ border: 1px solid black; border-radius: 5px; } +.error{ + background: red; +} + diff --git a/resources/js/plan.js b/resources/js/plan.js index 9bc77ba..ede0ab4 100644 --- a/resources/js/plan.js +++ b/resources/js/plan.js @@ -1,14 +1,14 @@ const ADD = 'add'; -const MOVE = 'move'; -const SQUARE = 30; const BODY = 'body'; +const CU = 'cu'; const DIV = 'DIV'; -const SVG = 'svg'; +const MOVE = 'move'; +const OPAC = 100; const PLAN = '#plan'; const POST = 'POST'; const PROPS = 'props'; -const CU = 'cu'; -const OPAC = 100; +const SQUARE = 30; +const SVG = 'svg'; var selected = null; var mode = null; var messageTimer = null; @@ -157,6 +157,7 @@ function request(data){ data : data, success: function(resp){ if (data.realm != 'car' && data.realm != 'loco') closeWindows(); + if (resp.startsWith(' badClients = null; for (Entry entry : clients.entrySet()) { OutputStreamWriter client = entry.getKey(); diff --git a/src/main/java/de/srsoftware/web4rail/Route.java b/src/main/java/de/srsoftware/web4rail/Route.java index 80e951e..1ac8e54 100644 --- a/src/main/java/de/srsoftware/web4rail/Route.java +++ b/src/main/java/de/srsoftware/web4rail/Route.java @@ -308,7 +308,8 @@ public class Route implements Constants{ for (Entry entry : turnouts.entrySet()) {// try to switch all turnouts of this route CompletableFuture reply = entry.getKey().state(entry.getValue()); // switching a turnout is an asynchronous process, so it returns a CompletableFuture here promise = promise == null ? reply : promise.thenCombine(reply, (a,b) -> a); - } + } + if (promise == null) promise = CompletableFuture.completedFuture(null); promise.exceptionally(ex -> { for (Tile tile : locked) try { tile.unlock(); diff --git a/src/main/java/de/srsoftware/web4rail/moving/Train.java b/src/main/java/de/srsoftware/web4rail/moving/Train.java index dbebadc..6a745d7 100644 --- a/src/main/java/de/srsoftware/web4rail/moving/Train.java +++ b/src/main/java/de/srsoftware/web4rail/moving/Train.java @@ -12,7 +12,6 @@ import java.util.HashSet; import java.util.Map.Entry; import java.util.Random; import java.util.Vector; -import java.util.concurrent.CompletableFuture; import org.json.JSONObject; import org.slf4j.Logger; @@ -22,6 +21,7 @@ import de.keawe.tools.translations.Translation; import de.srsoftware.tools.Tag; import de.srsoftware.web4rail.Application; import de.srsoftware.web4rail.Constants; +import de.srsoftware.web4rail.Plan; import de.srsoftware.web4rail.Plan.Direction; import de.srsoftware.web4rail.Route; import de.srsoftware.web4rail.Window; @@ -98,6 +98,8 @@ public class Train implements Constants { public int speed = 0; private Autopilot autopilot = null; + + private Plan plan; public Train(Locomotive loco) { this(loco,null); @@ -110,15 +112,15 @@ public class Train implements Constants { trains.put(id, this); } - public static Object action(HashMap params) throws IOException { + public static Object action(HashMap params, Plan plan) throws IOException { String action = params.get(ACTION); if (action == null) return t("No action passed to Train.action!"); if (!params.containsKey(Train.ID)) { switch (action) { case ACTION_PROPS: return manager(); - case ACTION_ADD: - return create(params); + case ACTION_ADD: + return create(params,plan); } return t("No train id passed!"); } @@ -140,10 +142,10 @@ public class Train implements Constants { return t("Unknown action: {}",params.get(ACTION)); } - private static Object create(HashMap params) { + private static Object create(HashMap params, Plan plan) { Locomotive loco = (Locomotive) Locomotive.get(params.get(Train.LOCO_ID)); if (loco == null) return t("unknown locomotive: {}",params.get(ID)); - Train train = new Train(loco); + Train train = new Train(loco).plan(plan); if (params.containsKey(NAME)) train.name(params.get(NAME)); return train; } @@ -215,7 +217,7 @@ public class Train implements Constants { return trains.values(); } - public static void loadAll(String filename) throws IOException { + public static void loadAll(String filename, Plan plan) throws IOException { BufferedReader file = new BufferedReader(new FileReader(filename)); String line = file.readLine(); while (line != null) { @@ -224,18 +226,19 @@ public class Train implements Constants { long id = json.getLong(ID); Train train = new Train(null,id); - train.load(json); + train.load(json).plan(plan); line = file.readLine(); } file.close(); } - private void load(JSONObject json) { + private Train load(JSONObject json) { pushPull = json.getBoolean(PUSH_PULL); if (json.has(NAME)) name = json.getString(NAME); for (Object id : json.getJSONArray(CARS)) add(Car.get((String)id)); for (Object id : json.getJSONArray(LOCOS)) add((Locomotive) Car.get((String)id)); + return this; } public static Object manager() { @@ -277,7 +280,12 @@ public class Train implements Constants { } return result; } - + + private Train plan(Plan plan) { + this.plan = plan; + return this; + } + public Tag props() { Window window = new Window("train-properties",t("Properties of {}",getClass().getSimpleName())); @@ -310,6 +318,9 @@ public class Train implements Constants { actions.addTo(list); } + if (route != null) { + new Tag("li").content(t("Current route: {}",route)).addTo(list); + } if (direction != null) new Tag("li").content(t("Direction: heading {}",direction)).addTo(list); @@ -332,8 +343,8 @@ public class Train implements Constants { this.speed = v; } - public CompletableFuture start() throws IOException { - if (block == null) return CompletableFuture.failedFuture(new RuntimeException(t("{} not in a block",this))); + public String start() throws IOException { + if (block == null) return t("{} not in a block",this); if (route != null) route.unlock().setSignals(Signal.STOP); HashSet routes = block.routes(); Vector availableRoutes = new Vector(); @@ -352,9 +363,10 @@ public class Train implements Constants { availableRoutes.add(rt); } Random rand = new Random(); - if (availableRoutes.isEmpty()) return CompletableFuture.failedFuture(new RuntimeException(t("No free routes from {}",block))); + if (availableRoutes.isEmpty()) return t("No free routes from {}",block); route = availableRoutes.get(rand.nextInt(availableRoutes.size())); - return route.lock(this).thenApply(reply -> { + + route.lock(this).thenApply(reply -> { try { route.setSignals(null); if (direction != route.startDirection) turn(); @@ -363,7 +375,13 @@ public class Train implements Constants { } catch (Exception e) { throw new RuntimeException(e); } - }); + }).thenAccept(message -> plan.stream(message)) + .exceptionally(ex -> { + plan.stream(ex.getMessage()); + throw new RuntimeException(ex); + }); + + return t("Trying to start {}",this); } private Object stop() { diff --git a/src/main/java/de/srsoftware/web4rail/tiles/Tile.java b/src/main/java/de/srsoftware/web4rail/tiles/Tile.java index 28f9a9e..6c179b8 100644 --- a/src/main/java/de/srsoftware/web4rail/tiles/Tile.java +++ b/src/main/java/de/srsoftware/web4rail/tiles/Tile.java @@ -274,7 +274,7 @@ public abstract class Tile implements Constants{ .id((x!=-1 && y!=-1)?(id()):(getClass().getSimpleName())) .clazz(classes()) .size(100,100) - .attr("name", getClass().getSimpleName()) + .attr("name", getClass().getSimpleName()) .attr("viewbox", "0 0 "+width+" "+height); if (x>-1) style="left: "+(30*x)+"px; top: "+(30*y)+"px;"; if (len()>1) style+=" width: "+(30*len())+"px;"; @@ -322,10 +322,16 @@ public abstract class Tile implements Constants{ .content("?") .addTo(svg); } - + String title = title(); + if (title!=null) new Tag("title").content(title()).addTo(svg); + return svg; } + public String title() { + return null; + } + @Override public String toString() { return t("{}({},{})",getClass().getSimpleName(),x,y) ; diff --git a/src/main/java/de/srsoftware/web4rail/tiles/Turnout.java b/src/main/java/de/srsoftware/web4rail/tiles/Turnout.java index 8c47050..968d90f 100644 --- a/src/main/java/de/srsoftware/web4rail/tiles/Turnout.java +++ b/src/main/java/de/srsoftware/web4rail/tiles/Turnout.java @@ -24,9 +24,10 @@ public abstract class Turnout extends Tile implements Device{ private Protocol protocol = Protocol.DCC128; protected int address = 0; - protected int portA = 0, portB = 0; + protected int portA = 0, portB = 1; protected int delay = 400; - protected boolean initialized; + protected boolean initialized = false; + protected boolean error = false; public enum State{ LEFT,STRAIGHT,RIGHT,UNDEF; @@ -36,11 +37,21 @@ public abstract class Turnout extends Tile implements Device{ @Override public Object click() throws IOException { - LOG.debug("Turnout.click()"); + LOG.debug(getClass().getSimpleName()+".click()"); init(); return super.click(); } + public void error(Reply reply) { + this.error = true; + try { + plan.stream(tag(null).toString()); + } catch (IOException e) { + LOG.error("Was not able to stream: ",e); + } + throw new RuntimeException(reply.message()); + } + protected void init() { if (!initialized) { plan.queue("INIT {} GA "+address+" "+proto()); @@ -52,7 +63,7 @@ public abstract class Turnout extends Tile implements Device{ public JSONObject json() { JSONObject json = super.json(); if (portA != 0) json.put(PORT_A, portA); - if (portB != 0) json.put(PORT_B, portB); + if (portB != 1) json.put(PORT_B, portB); if (address != 0) json.put(ADDRESS, address); json.put(PROTOCOL, protocol); return json; @@ -101,14 +112,28 @@ public abstract class Turnout extends Tile implements Device{ } public abstract CompletableFuture state(State newState) throws IOException; + + public void success() { + this.error = false; + try { + plan.stream(tag(null).toString()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } @Override public Tag tag(Map replacements) throws IOException { Tag tag = super.tag(replacements); - tag.clazz(tag.get("class")+(" "+state).toLowerCase()); + tag.clazz(tag.get("class")+(" "+state).toLowerCase()+(error?" error":"")); return tag; } + @Override + public String title() { + return getClass().getSimpleName()+t("(Address: {}, Ports {} and {})",address,portA,portB); + } + public void toggle() { state = State.STRAIGHT; } diff --git a/src/main/java/de/srsoftware/web4rail/tiles/TurnoutL.java b/src/main/java/de/srsoftware/web4rail/tiles/TurnoutL.java index 0e207f2..74f76f4 100644 --- a/src/main/java/de/srsoftware/web4rail/tiles/TurnoutL.java +++ b/src/main/java/de/srsoftware/web4rail/tiles/TurnoutL.java @@ -16,7 +16,6 @@ public class TurnoutL extends Turnout { @Override public Object click() throws IOException { - LOG.debug("TurnoutL.click()"); Object o = super.click(); if (route != null) { plan.stream(t("{} is locked by {}!",this,route)); @@ -45,13 +44,6 @@ public class TurnoutL extends Turnout { return form; } - @Override - public Tile update(HashMap params) throws IOException { - if (params.containsKey(STRAIGHT)) portA = Integer.parseInt(params.get(STRAIGHT)); - if (params.containsKey(LEFT)) portB = Integer.parseInt(params.get(LEFT)); - return super.update(params); - } - @Override public CompletableFuture state(State newState) throws IOException { init(); @@ -68,10 +60,18 @@ public class TurnoutL extends Turnout { throw new IllegalStateException(); } return result.thenApply(reply -> { - LOG.debug("{} received {}",TurnoutL.this,reply); - if (!reply.is(200)) throw new RuntimeException(reply.message()); + LOG.debug("{} received {}",getClass().getSimpleName(),reply); + if (!reply.is(200)) error(reply); state = newState; + success(); return reply; }); } + + @Override + public Tile update(HashMap params) throws IOException { + if (params.containsKey(STRAIGHT)) portA = Integer.parseInt(params.get(STRAIGHT)); + if (params.containsKey(LEFT)) portB = Integer.parseInt(params.get(LEFT)); + return super.update(params); + } } diff --git a/src/main/java/de/srsoftware/web4rail/tiles/TurnoutR.java b/src/main/java/de/srsoftware/web4rail/tiles/TurnoutR.java index 4b0d76f..599aaef 100644 --- a/src/main/java/de/srsoftware/web4rail/tiles/TurnoutR.java +++ b/src/main/java/de/srsoftware/web4rail/tiles/TurnoutR.java @@ -16,7 +16,6 @@ public class TurnoutR extends Turnout { @Override public Object click() throws IOException { - LOG.debug("Turnoutr.click()"); Object o = super.click(); if (route != null) { plan.stream(t("{} is locked by {}!",this,route)); @@ -34,8 +33,8 @@ public class TurnoutR extends Turnout { break; } } - new Input(STRAIGHT, portA).addTo(new Label(t("Straight port"))).addTo(fieldset); - new Input(RIGHT, portB).addTo(new Label(t("Right port"))).addTo(fieldset); + new Input(STRAIGHT, portA).numeric().addTo(new Label(t("Straight port"))).addTo(fieldset); + new Input(RIGHT, portB).numeric().addTo(new Label(t("Right port"))).addTo(fieldset); return form; } @@ -62,8 +61,10 @@ public class TurnoutR extends Turnout { throw new IllegalStateException(); } return result.thenApply(reply -> { - LOG.debug("{} received {}",reply); - if (reply.is(200)) state = newState; + LOG.debug("{} received {}",getClass().getSimpleName(),reply); + if (!reply.is(200)) error(reply); + state = newState; + success(); return reply; }); }