From 829ccd1178ba69e5d034bf40e1558d164c2503ec Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 20 Jan 2024 05:25:57 -0800 Subject: [PATCH 001/131] model for aiml xml --- .../myrobotlab/programab/models/Event.java | 65 +++++++++++++++++++ .../org/myrobotlab/programab/models/Mrl.java | 14 ++++ .../org/myrobotlab/programab/models/Oob.java | 14 ++++ .../myrobotlab/programab/models/Sraix.java | 10 +++ .../myrobotlab/programab/models/Template.java | 51 +++++++++++++++ 5 files changed, 154 insertions(+) create mode 100644 src/main/java/org/myrobotlab/programab/models/Event.java create mode 100644 src/main/java/org/myrobotlab/programab/models/Mrl.java create mode 100644 src/main/java/org/myrobotlab/programab/models/Oob.java create mode 100644 src/main/java/org/myrobotlab/programab/models/Sraix.java create mode 100644 src/main/java/org/myrobotlab/programab/models/Template.java diff --git a/src/main/java/org/myrobotlab/programab/models/Event.java b/src/main/java/org/myrobotlab/programab/models/Event.java new file mode 100644 index 0000000000..93e85c4086 --- /dev/null +++ b/src/main/java/org/myrobotlab/programab/models/Event.java @@ -0,0 +1,65 @@ +package org.myrobotlab.programab.models; + +/** + * Pojo for state change of one of ProgramAB's state info + * @author GroG + * + */ +public class Event { + /** + * the botName in this state change - typically + * current session botName + */ + public String botname; + /** + * unique identifier for the session user & bot + */ + public String id; + + /** + * name of the predicate changed + */ + public String name; + + /** + * service this topic change came from + */ + public String src; + + /** + * new topic or state name in this transition + */ + public String topic; + + /** + * timestamp + */ + public long ts = System.currentTimeMillis(); + + /** + * the user name in this state change - usually + * current session userName + */ + public String user; + + /** + * new value + */ + public String value; + + public Event() { + } + + public Event(String src, String userName, String botName, String topic) { + this.src = src; + this.user = userName; + this.botname = botName; + this.topic = topic; + } + + + @Override + public String toString() { + return String.format("%s %s=%s", id, name, value); + } +} diff --git a/src/main/java/org/myrobotlab/programab/models/Mrl.java b/src/main/java/org/myrobotlab/programab/models/Mrl.java new file mode 100644 index 0000000000..04c1bf79bb --- /dev/null +++ b/src/main/java/org/myrobotlab/programab/models/Mrl.java @@ -0,0 +1,14 @@ +package org.myrobotlab.programab.models; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; + +public class Mrl { + public String service; + public String method; + @JacksonXmlElementWrapper(useWrapping = false) + @JsonProperty("param") + public List params; +} \ No newline at end of file diff --git a/src/main/java/org/myrobotlab/programab/models/Oob.java b/src/main/java/org/myrobotlab/programab/models/Oob.java new file mode 100644 index 0000000000..833bab5a0f --- /dev/null +++ b/src/main/java/org/myrobotlab/programab/models/Oob.java @@ -0,0 +1,14 @@ +package org.myrobotlab.programab.models; + +import java.util.List; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; + +public class Oob { + + public String mrljson; + + @JacksonXmlElementWrapper(useWrapping = false) + public List mrl; +} + diff --git a/src/main/java/org/myrobotlab/programab/models/Sraix.java b/src/main/java/org/myrobotlab/programab/models/Sraix.java new file mode 100644 index 0000000000..99b0639cb6 --- /dev/null +++ b/src/main/java/org/myrobotlab/programab/models/Sraix.java @@ -0,0 +1,10 @@ +package org.myrobotlab.programab.models; + +// FIXME add attributes and internal tags +public class Sraix { + + public String search; + + public Oob oob; + +} diff --git a/src/main/java/org/myrobotlab/programab/models/Template.java b/src/main/java/org/myrobotlab/programab/models/Template.java new file mode 100644 index 0000000000..91f8e5de51 --- /dev/null +++ b/src/main/java/org/myrobotlab/programab/models/Template.java @@ -0,0 +1,51 @@ +package org.myrobotlab.programab.models; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText; + +//@JacksonXmlRootElement(localName = "template") +//@JsonIgnoreProperties(ignoreUnknown = true) +@JsonIgnoreProperties(ignoreUnknown = true) +public class Template { + // @JacksonXmlElementWrapper(useWrapping = false) + + @JacksonXmlProperty(localName = "template") + + @JacksonXmlText + public String text; + + +public Oob oob; + +// @JsonProperty("ignorable") +// public List oob; +// +// public List getOob() { +// return oob; +// } +// +// public void setOob(List oob) { +// this.oob = oob; +// } + + public static void main(String[] args) { + + try { + + // String xml = ""; + // String xml = ""; + String xml = ""; + + XmlMapper xmlMapper = new XmlMapper(); + Template template = xmlMapper.readValue(xml, Template.class); + + System.out.println(template); + + } catch(Exception e) { + e.printStackTrace(); + } + } + +} From 67bd304087adcb0f3e6fc2f88a86bcc2f31311f5 Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 20 Jan 2024 07:48:16 -0800 Subject: [PATCH 002/131] InMoov gets a heart --- .../java/org/myrobotlab/service/InMoov2.java | 622 +++++++++++++----- .../service/config/InMoov2Config.java | 2 +- 2 files changed, 441 insertions(+), 183 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index 339aeaf107..462258a2ac 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -4,15 +4,23 @@ import java.io.FilenameFilter; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.Set; +import java.util.TreeMap; import java.util.TreeSet; +import java.util.concurrent.locks.ReentrantLock; import org.apache.commons.io.FilenameUtils; import org.myrobotlab.framework.Message; +import org.myrobotlab.framework.Peer; import org.myrobotlab.framework.Plan; import org.myrobotlab.framework.Platform; import org.myrobotlab.framework.Registration; @@ -41,14 +49,73 @@ import org.myrobotlab.service.interfaces.ServiceLifeCycleListener; import org.myrobotlab.service.interfaces.ServoControl; import org.myrobotlab.service.interfaces.Simulator; +import org.myrobotlab.service.interfaces.SpeechListener; import org.myrobotlab.service.interfaces.SpeechRecognizer; import org.myrobotlab.service.interfaces.SpeechSynthesis; import org.myrobotlab.service.interfaces.TextListener; import org.myrobotlab.service.interfaces.TextPublisher; import org.slf4j.Logger; -public class InMoov2 extends Service implements ServiceLifeCycleListener, TextListener, TextPublisher, - JoystickListener, LocaleProvider, IKJointAngleListener { +public class InMoov2 extends Service implements ServiceLifeCycleListener, SpeechListener, TextListener, TextPublisher, JoystickListener, LocaleProvider, IKJointAngleListener { + + public class Heartbeat { + public long count = 0; + public long ts = System.currentTimeMillis(); + public String state; + public List errors; + double batteryLevel = 100; + public boolean isPirOn = false; + + public Heartbeat(InMoov2 inmoov) { + this.state = inmoov.state; + this.errors = inmoov.errors; + this.count = inmoov.heartbeatCount; + this.isPirOn = inmoov.isPirOn; + } + } + + public class Heart implements Runnable { + private final ReentrantLock lock = new ReentrantLock(); + private Thread thread; + + @Override + public void run() { + if (lock.tryLock()) { + try { + while (!Thread.currentThread().isInterrupted()) { + invoke("publishHeartbeat"); + Thread.sleep(config.heartbeatInterval); + } + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + } finally { + lock.unlock(); + log.info("heart stopping"); + thread = null; + } + } + } + + public void start() { + if (thread == null) { + log.info("starting heart"); + thread = new Thread(this, String.format("%s-heart", getName())); + thread.start(); + config.heartbeat = true; + } else { + log.info("heart already started"); + } + } + + public void stop() { + if (thread != null) { + thread.interrupt(); + config.heartbeat = false; + } else { + log.info("heart already stopped"); + } + } + } public final static Logger log = LoggerFactory.getLogger(InMoov2.class); @@ -58,6 +125,7 @@ public class InMoov2 extends Service implements ServiceLifeCycleL static String speechRecognizer = "WebkitSpeechRecognition"; + /** * This method will load a python file into the python interpreter. * @@ -68,6 +136,7 @@ public class InMoov2 extends Service implements ServiceLifeCycleL @Deprecated /* use execScript - this doesn't handle resources correctly */ public static boolean loadFile(String file) { File f = new File(file); + // FIXME cannot be casting to Python ! Py4j would break Python p = (Python) Runtime.getService("python"); log.info("Loading Python file {}", f.getAbsolutePath()); if (p == null) { @@ -97,17 +166,19 @@ public static boolean loadFile(String file) { return true; } + /** + * number of times waited in boot state + */ + protected int bootCount = 0; + protected transient ProgramAB chatBot; protected List configList; /** - * Configuration from runtime has started. This is when runtime starts - * processing a configuration set for the first time since inmoov was started + * map of events or states to sounds */ - protected boolean configStarted = false; - - String currentConfigurationName = "default"; + protected Map customSoundMap = new TreeMap<>(); protected transient SpeechRecognizer ear; @@ -126,14 +197,31 @@ public static boolean loadFile(String file) { protected Set gestures = new TreeSet(); + /** + * Prevents actions or events from happening when InMoov2 is first booted + */ + private boolean hasBooted = false; + + private transient final Heart heart = new Heart(); + + protected long heartbeatCount = 0; + + protected boolean heartBeating = false; + protected transient HtmlFilter htmlFilter; protected transient ImageDisplay imageDisplay; + protected boolean isPirOn = false; + + protected boolean isSpeaking = false; + protected String lastGestureExecuted; protected Long lastPirActivityTime; + protected String lastState = null; + /** * supported locales */ @@ -149,10 +237,22 @@ public static boolean loadFile(String file) { protected transient Python python; + /** + * initial state - updated on any state change + */ + String state = "boot"; + + protected long stateLastIdleTime = System.currentTimeMillis(); + + protected long stateLastRandomTime = System.currentTimeMillis(); + protected String voiceSelected; + protected Double batteryLevel = 100.0; + public InMoov2(String n, String id) { super(n, id); + locales = Locale.getLocaleMap("en-US", "fr-FR", "es-ES", "de-DE", "nl-NL", "ru-RU", "hi-IN", "it-IT", "fi-FI", "pt-PT", "tr-TR"); } // should be removed in favor of general listeners @@ -166,29 +266,12 @@ public InMoov2Config apply(InMoov2Config c) { super.apply(c); try { - locales = Locale.getLocaleMap("en-US", "fr-FR", "es-ES", "de-DE", "nl-NL", "ru-RU", "hi-IN", "it-IT", "fi-FI", - "pt-PT", "tr-TR"); - if (c.locale != null) { setLocale(c.locale); } else { setLocale(getSupportedLocale(Runtime.getInstance().getLocale().toString())); } - loadAppsScripts(); - - loadInitScripts(); - - if (c.loadGestures) { - loadGestures(); - } - - if (c.heartbeat) { - startHeartbeat(); - } else { - stopHeartbeat(); - } - } catch (Exception e) { error(e); } @@ -215,6 +298,141 @@ public void attachTextPublisher(TextPublisher service) { subscribe(service.getName(), "publishText"); } + /** + * At boot all services specified through configuration have started, or if no + * configuration has started minimally the InMoov2 service has started. During + * the processing of config and starting other services data will have + * accumulated, and at boot, some of data may now be inspected and processed + * in a synchronous single threaded way. With reporting after startup, vs + * during, other peer services are not needed (e.g. audioPlayer is no longer + * needed to be started "before" InMoov2 because when boot is called + * everything that is wanted has been started. + * + * This method gets called multiple times by the heart beat, it walks through + * required processing and effectively waits and tries again if not finished. + * While in "boot", nothing else should be allowed to process until this + * process is completed. + */ + synchronized public void boot() { + + Runtime runtime = Runtime.getInstance(); + + try { + + if (hasBooted) { + log.warn("will not boot again"); + return; + } + + bootCount++; + log.info("boot count {}", bootCount); + + // config has not finished processing yet.. + if (runtime.isProcessingConfig()) { + log.warn("runtime still processing config set {}, waiting ....", runtime.getConfigName()); + return; + } + + // check all required services are completely started - or + // wait/return until they are + + // there is not much point in running InMoov2 without its + // core dependencies - those dependencies are ProgramAB, + // FiniteStatemachine and Py4j/Python - so boot will not + // finish unless these services have loaded + + // Although this exposes type, it does use startPeer + // which allows the potential of the user switching types of processors + // if the processor + + // TODO - make Py4j without zombies and more robust + /** + * Py4j is not ready for primetime yet + *
+       
+      Py4j py4j = (Py4j) startPeer("py4j");
+      if (!py4j.isReady()) {
+        log.warn("{} not ready....", getPeerName("py4j"));
+        return;
+      }
+      String code = FileIO.toString(getResourceDir() + fs + "InMoov2.py");
+      py4j.exec(code);
+
+      
+ */ + + // TODO - MAKE BOOT REPORT !!!! deliver it on a heartbeat + runtime.invoke("publishConfigList"); + // FIXME - reduce the number of these + if (config.loadAppsScripts) { + loadAppsScripts(); + } + + if (config.loadInitScripts) { + loadInitScripts(); + } + + if (config.loadGestures) { + loadGestures(); + } + + if (config.startupSound) { + String startupsound = FileIO.gluePaths(getResourceDir(), "/system/sounds/startupsound.mp3"); + invoke("publishPlayAudioFile", startupsound); + } + + List services = Runtime.getServices(); + for (ServiceInterface si : services) { + if ("Servo".equals(si.getSimpleName())) { + send(si.getFullName(), "setAutoDisable", true); + } + } + hasBooted = true; + } catch (Exception e) { + hasBooted = false; + error(e); + } + + /** + * TODO reporting on errors found in boot process TODO make a report on all + * peers that have started, of the config processed if there was a config + * set + */ + if (config.reportOnBoot) { + systemEvent("CONFIG STARTED %s", runtime.getConfigName()); + + // TODO spin through all services in the order they were started + // send all system events + Collection local = Runtime.getLocalServices().values(); + List ordered = new ArrayList<>(local); + ordered.removeIf(Objects::isNull); + Collections.sort(ordered); + + Map peers = getPeers(); + Set peerNames = new HashSet<>(); + for (String peerKey : peers.keySet()) { + Peer peer = peers.get(peerKey); + if (peer.name == null) { + peerNames.add(String.format("%s.%s", getName(), peerKey)); + } else { + peerNames.add(peer.name); + } + } + + for (ServiceInterface si : ordered) { + if (peerNames.contains(si.getName())) { + systemEvent("STARTED %s", getPeerKey(si.getName()).replace(".", " ")); + } + } + + // reporting on all services and config started + systemEvent("CONFIG LOADED %s", runtime.getConfigName()); + } + + // say finished booting + fire("wake"); + } + public void beginCheckingOnInactivity() { beginCheckingOnInactivity(maxInactivityTimeSeconds); } @@ -584,6 +802,14 @@ public InMoov2Hand getRightHand() { return (InMoov2Hand) getPeer("rightHand"); } + public String getState() { + FiniteStateMachine fsm = (FiniteStateMachine) getPeer("fsm"); + if (fsm == null) { + return null; + } + return fsm.getCurrent(); + } + /** * matches on language only not variant expands language match to full InMoov2 * bot locale @@ -870,6 +1096,11 @@ public void onCreated(String fullname) { log.info("{} created", fullname); } + @Override + public void onEndSpeaking(String utterance) { + isSpeaking = false; + } + public void onFinishedConfig(String configName) { log.info("onFinishedConfig"); // invoke("publishEvent", "configFinished"); @@ -885,6 +1116,10 @@ public void onGestureStatus(Status status) { unsubscribe("python", "publishStatus", this.getName(), "onGestureStatus"); } + /** + * Central hub of input motion control. Potentially, all input from joysticks, + * quest2 controllers and headset, or any IK service could be sent here + */ @Override public void onJointAngles(Map angleMap) { log.debug("onJointAngles {}", angleMap); @@ -951,7 +1186,7 @@ public OpenCVData onOpenCVData(OpenCVData data) { * @param volume */ public void onPeak(double volume) { - if (config.neoPixelFlashWhenSpeaking && !configStarted) { + if (config.neoPixelFlashWhenSpeaking && !"boot".equals(getState())) { if (volume > 0.5) { invoke("publishSpeakingFlash", "speaking"); } @@ -1031,121 +1266,10 @@ public void onStartConfig(String configName) { */ @Override public void onStarted(String name) { - InMoov2Config c = (InMoov2Config) config; - - log.info("onStarted {}", name); try { - Runtime runtime = Runtime.getInstance(); log.info("onStarted {}", name); - - // BAD IDEA - better to ask for a system report or an error report - // if (runtime.isProcessingConfig()) { - // invoke("publishEvent", "CONFIG STARTED"); - // } - - String peerKey = getPeerKey(name); - if (peerKey == null) { - // service not a peer - return; - } - - if (runtime.isProcessingConfig() && !configStarted) { - invoke("publishEvent", "CONFIG STARTED " + runtime.getConfigName()); - configStarted = true; - } - - invoke("publishEvent", "STARTED " + peerKey); - - switch (peerKey) { - case "audioPlayer": - break; - case "chatBot": - ProgramAB chatBot = (ProgramAB) Runtime.getService(name); - chatBot.attachTextListener(getPeerName("htmlFilter")); - startPeer("htmlFilter"); - break; - case "controller3": - break; - case "controller4": - break; - case "ear": - AbstractSpeechRecognizer ear = (AbstractSpeechRecognizer) Runtime.getService(name); - ear.attachTextListener(getPeerName("chatBot")); - break; - case "eyeTracking": - break; - case "fsm": - break; - case "gpt3": - break; - case "head": - addListener("publishMoveHead", name); - break; - case "headTracking": - break; - case "htmlFilter": - TextPublisher htmlFilter = (TextPublisher) Runtime.getService(name); - htmlFilter.attachTextListener(getPeerName("mouth")); - break; - case "imageDisplay": - break; - case "leap": - break; - case "left": - break; - case "leftArm": - addListener("publishMoveLeftArm", name, "onMoveArm"); - break; - case "leftHand": - addListener("publishMoveLeftHand", name, "onMoveHand"); - break; - case "mouth": - mouth = (AbstractSpeechSynthesis) Runtime.getService(name); - mouth.attachSpeechListener(getPeerName("ear")); - break; - case "mouthControl": - break; - case "neoPixel": - break; - case "opencv": - subscribeTo(name, "publishOpenCVData"); - break; - case "openni": - break; - case "openWeatherMap": - break; - case "pid": - break; - case "pir": - break; - case "random": - break; - case "right": - break; - case "rightArm": - addListener("publishMoveRightArm", name, "onMoveArm"); - break; - case "rightHand": - addListener("publishMoveRightHand", name, "onMoveHand"); - break; - case "servoMixer": - break; - case "simulator": - break; - case "torso": - addListener("publishMoveTorso", name); - break; - case "ultrasonicRight": - break; - case "ultrasonicLeft": - break; - default: - log.warn("unknown peer %s not hanled in onStarted", peerKey); - break; - } - - // type processing for Servo + // new servo ServiceInterface si = Runtime.getService(name); if ("Servo".equals(si.getSimpleName())) { log.info("sending setAutoDisable true to {}", name); @@ -1158,8 +1282,52 @@ public void onStarted(String name) { } } + // FIXME - rebroadcast these + @Override + public void onStartSpeaking(String utterance) { + isSpeaking = true; + } + + /** + * The integration between the FiniteStateMachine (fsm) and the InMoov2 + * service and potentially other services (Python, ProgramAB) happens here. + * + * After boot all state changes get published here. + * + * Some InMoov2 service methods will be called here for "default + * implemenation" of states. If a user doesn't want to have that default + * implementation, they can change it by changing the definition of the state + * machine, and have a new state which will call a Python inmoov2 library + * callback. Overriding, appending, or completely transforming the behavior is + * all easily accomplished by managing the fsm and python inmoov2 library + * callbacks. + * + * Python inmoov2 callbacks ProgramAB topic switching + * + * Depending on config: + * + * + * @param stateChange + * @return + */ + public FiniteStateMachine.StateChange onStateChange(FiniteStateMachine.StateChange stateChange) { + try { + log.info("onStateChange {}", stateChange); + + lastState = state; + state = stateChange.state; + + processMessage("onStateChange", stateChange); + + } catch (Exception e) { + error(e); + } + return stateChange; + } + @Override public void onStopped(String name) { + log.info("service {} has stopped"); // using release peer for peer releasing // FIXME - auto remove subscriptions of peers? } @@ -1262,9 +1430,102 @@ public String publishFlash(String flashName) { return flashName; } - public String publishHeartbeat() { - invoke("publishFlash", "heartbeat"); - return getName(); + /** + * A heartbeat that continues to check status, and fire events to the FSM. + * Checks battery, flashes leds and processes all the configured checks in + * onHeartbeat at a regular interval + */ + public Heartbeat publishHeartbeat() { + log.debug("publishHeartbeat"); + heartbeatCount++; + Heartbeat heartbeat = new Heartbeat(this); + try { + + if ("boot".equals(state)) { + // continue booting - we don't put heartbeats in user/python space + // until java-land is done booting + log.info("boot hasn't completed, will not process heartbeat"); + boot(); + return heartbeat; + } + + Long lastActivityTime = getLastActivityTime(); + + // FIXME lastActivityTime != 0 is bogus - the value should be null if + // never set + if (config.stateIdleInterval != null && lastActivityTime != null && lastActivityTime != 0 + && lastActivityTime + (config.stateIdleInterval * 1000) < System.currentTimeMillis()) { + stateLastIdleTime = lastActivityTime; + } + + if (System.currentTimeMillis() > stateLastIdleTime + (config.stateIdleInterval * 1000)) { + fsm.fire("idle"); + stateLastIdleTime = System.currentTimeMillis(); + } + + // interval event firing + if (config.stateRandomInterval != null && System.currentTimeMillis() > stateLastRandomTime + (config.stateRandomInterval * 1000)) { + // fsm.fire("random"); + stateLastRandomTime = System.currentTimeMillis(); + } + + } catch (Exception e) { + error(e); + } + + // if (config.pirOnFlash && isPeerStarted("pir") && isPirOn) { + //// flash("pir"); + // } + + if (config.batteryInSystem) { + double batteryLevel = Runtime.getBatteryLevel(); + invoke("publishBatteryLevel", batteryLevel); + // FIXME - thresholding should always have old value or state + // so we don't pump endless errors + if (batteryLevel < 5) { + error("battery level < 5 percent"); + // systemEvent(BATTERY ERROR) + } else if (batteryLevel < 10) { + warn("battery level < 10 percent"); + // systemEvent(BATTERY WARN) + } + } + + // flash error until errors are cleared + if (config.flashOnErrors) { + if (errors.size() > 0) { + // invoke("publishFlash", "error"); + } else { + // invoke("publishFlash", "heartbeat"); + } + } + + // FIXME - add errors to heartbeat + processMessage("onHeartbeat", heartbeat); + return heartbeat; + } + + public void processMessage(String method) { + processMessage(method, null); + } + + /** + * Will publish processing messages to the processor(s) currently subscribed. + * + * @param method + * @param data + */ + public void processMessage(String method, Object data) { + // User processing should not occur until after boot has completed + if (!state.equals("boot")) { + // FIXME - this needs to be in config + // FIXME - change peer name to "processor" + String processor = getPeerName("py4j"); + Message msg = Message.createMessage(getName(), processor, method, data); + // FIXME - is this too much abstraction .. to publish as well as + // configurable send ? + invoke("publishProcessMessage", msg); + } } /** @@ -1393,6 +1654,7 @@ public void releasePeer(String peerKey) { public void releaseService() { try { disable(); + heart.stop(); super.releaseService(); } catch (Exception e) { error(e); @@ -1791,7 +2053,7 @@ public void startedGesture(String nameOfGesture) { } public void startHeartbeat() { - addTask(1000, "publishHeartbeat"); + heart.start(); } // TODO - general objective "might" be to reduce peers down to something @@ -1852,57 +2114,42 @@ public ServiceInterface startPeer(String peer) { @Override public void startService() { super.startService(); - + // FIXME - hardcoded peer no choice of type + fsm = (FiniteStateMachine) startPeer("fsm"); + + // a python processor is + // necessary for InMoov2 to properly + // function but this is not the place to start it + // it should be a peer definition too, it can be "python" + // it doesn't need to be i01.python to be a peer + // also should determine type Py4j or Python + // Runtime.start("python"); + + // just for comparing config with current "default" + // debugging only Runtime runtime = Runtime.getInstance(); + // if you hardcode subscriptions here - they should + // be controlled/branched by config + // get service start and release life cycle events runtime.attachServiceLifeCycleListener(getName()); - List services = Runtime.getServices(); - for (ServiceInterface si : services) { - if ("Servo".equals(si.getSimpleName())) { - send(si.getFullName(), "setAutoDisable", true); - } - } - + // FIXME all subscriptions should be in InMoov2Config // get events of new services and shutdown + // we can't add listener's in config, perhaps there should be + // "subscriptions" in config too ? subscribe("runtime", "shutdown"); - // power up loopback subscription - addListener(getName(), "powerUp"); - subscribe("runtime", "publishConfigList"); - if (runtime.isProcessingConfig()) { - invoke("publishEvent", "configStarted"); - } - subscribe("runtime", "publishConfigStarted"); - subscribe("runtime", "publishConfigFinished"); - // chatbot getresponse attached to publishEvent - addListener("publishEvent", getPeerName("chatBot"), "getResponse"); + runtime.invoke("publishConfigList"); - try { - // copy config if it doesn't already exist - String resourceBotDir = FileIO.gluePaths(getResourceDir(), "config"); - List files = FileIO.getFileList(resourceBotDir); - for (File f : files) { - String botDir = "data/config/" + f.getName(); - File bDir = new File(botDir); - if (bDir.exists() || !f.isDirectory()) { - log.info("skipping data/config/{}", botDir); - } else { - log.info("will copy new data/config/{}", botDir); - try { - FileIO.copy(f.getAbsolutePath(), botDir); - } catch (Exception e) { - error(e); - } - } - } - } catch (Exception e) { - error(e); + if (config.heartbeat) { + startHeartbeat(); + } else { + stopHeartbeat(); } - runtime.invoke("publishConfigList"); } public void startServos() { @@ -1930,12 +2177,13 @@ public void stop() { } public void stopGesture() { + // FIXME cannot be casting to Python Python p = (Python) Runtime.getService("python"); p.stop(); } public void stopHeartbeat() { - purgeTask("publishHeartbeat"); + heart.stop(); } public void stopNeopixelAnimation() { @@ -1962,7 +2210,17 @@ public void systemCheck() { Platform platform = Runtime.getPlatform(); setPredicate("system version", platform.getVersion()); // ERROR buffer !!! - invoke("publishEvent", "systemCheckFinished"); + systemEvent("SYSTEMCHECKFINISHED"); // wtf is this? + } + + public String systemEvent(String eventMsg) { + invoke("publishSystemEvent", eventMsg); + return eventMsg; + } + + public String systemEvent(String format, Object... ags) { + String eventMsg = String.format(format, ags); + return systemEvent(eventMsg); } // FIXME - if this is really desired it will drive local references for all diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index 564fe516e4..3c9571e435 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -55,7 +55,7 @@ public class InMoov2Config extends ServiceConfig { * fire events to the FSM. Checks battery level and sends a heartbeat flash on * publishHeartbeat and onHeartbeat at a regular interval */ - public boolean heartbeat = false; + public boolean heartbeat = true; /** * flashes the neopixel every time a health check is preformed. green == good From 754bed4f764ac802d8643ea841184573e4be0105 Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 20 Jan 2024 13:38:40 -0800 Subject: [PATCH 003/131] jython worky with InMoov2.py --- .../java/org/myrobotlab/service/InMoov2.java | 104 ++++++++++++++---- .../service/config/InMoov2Config.java | 8 +- 2 files changed, 90 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index 462258a2ac..cba05f550f 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -58,7 +58,7 @@ public class InMoov2 extends Service implements ServiceLifeCycleListener, SpeechListener, TextListener, TextPublisher, JoystickListener, LocaleProvider, IKJointAngleListener { - public class Heartbeat { + public static class Heartbeat { public long count = 0; public long ts = System.currentTimeMillis(); public String state; @@ -360,6 +360,10 @@ synchronized public void boot() { */ + + // load the InMoov2.py and publish it for Python/Jython or Py4j to consume + String script = getResourceAsString("InMoov2.py"); + invoke("publishPython", script); // TODO - MAKE BOOT REPORT !!!! deliver it on a heartbeat runtime.invoke("publishConfigList"); @@ -730,30 +734,32 @@ public InMoov2Head getHead() { * @return the timestamp of the last activity time. */ public Long getLastActivityTime() { - try { - - Long lastActivityTime = 0L; - - Long head = (Long) sendToPeerBlocking("head", "getLastActivityTime", getName()); - Long leftArm = (Long) sendToPeerBlocking("leftArm", "getLastActivityTime", getName()); - Long rightArm = (Long) sendToPeerBlocking("rightArm", "getLastActivityTime", getName()); - Long leftHand = (Long) sendToPeerBlocking("leftHand", "getLastActivityTime", getName()); - Long rightHand = (Long) sendToPeerBlocking("rightHand", "getLastActivityTime", getName()); - Long torso = (Long) sendToPeerBlocking("torso", "getLastActivityTime", getName()); - - lastActivityTime = Math.max(head, leftArm); + Long head = (InMoov2Head) getPeer("head") != null ? ((InMoov2Head) getPeer("head")).getLastActivityTime() : null; + Long leftArm = (InMoov2Arm) getPeer("leftArm") != null ? ((InMoov2Arm) getPeer("leftArm")).getLastActivityTime() : null; + Long rightArm = (InMoov2Arm) getPeer("rightArm") != null ? ((InMoov2Arm) getPeer("rightArm")).getLastActivityTime() : null; + Long leftHand = (InMoov2Hand) getPeer("leftHand") != null ? ((InMoov2Hand) getPeer("leftHand")).getLastActivityTime() : null; + Long rightHand = (InMoov2Hand) getPeer("rightHand") != null ? ((InMoov2Hand) getPeer("rightHand")).getLastActivityTime() : null; + Long torso = (InMoov2Torso) getPeer("torso") != null ? ((InMoov2Torso) getPeer("torso")).getLastActivityTime() : null; + + Long lastActivityTime = null; + + if (head != null || leftArm != null || rightArm != null || leftHand != null || rightHand != null || torso != null) { + lastActivityTime = 0L; + if (head != null) + lastActivityTime = Math.max(lastActivityTime, head); + if (leftArm != null) + lastActivityTime = Math.max(lastActivityTime, leftArm); + if (rightArm != null) lastActivityTime = Math.max(lastActivityTime, rightArm); + if (leftHand != null) lastActivityTime = Math.max(lastActivityTime, leftHand); + if (rightHand != null) lastActivityTime = Math.max(lastActivityTime, rightHand); + if (torso != null) lastActivityTime = Math.max(lastActivityTime, torso); - - return lastActivityTime; - - } catch (Exception e) { - error(e); - return null; } + return lastActivityTime; } public InMoov2Arm getLeftArm() { @@ -1520,7 +1526,9 @@ public void processMessage(String method, Object data) { if (!state.equals("boot")) { // FIXME - this needs to be in config // FIXME - change peer name to "processor" - String processor = getPeerName("py4j"); + // String processor = getPeerName("py4j"); + String processor = "python"; + Message msg = Message.createMessage(getName(), processor, method, data); // FIXME - is this too much abstraction .. to publish as well as // configurable send ? @@ -1634,6 +1642,62 @@ public HashMap publishMoveTorso(Double topStom, Double midStom, return map; } + public String publishPlayAudioFile(String filename) { + return filename; + } + + /** + * Processing publishing point, where everything InMoov2 wants to be processed + * is turned into a message and published. + * + * @param msg + * @return + */ + public Message publishProcessMessage(Message msg) { + return msg; + } + + /** + * Possible pub/sub way to interface with python - no blocking though + * + * @param code + * @return + */ + public String publishPython(String code) { + return code; + } + + + /** + * publishes a name for NeoPixel.onFlash to consume, in a seperate channel to + * potentially be used by "speaking only" leds + * + * @param name + * @return + */ + public String publishSpeakingFlash(String name) { + return name; + } + + /** + * stop animation event + */ + public void publishStopAnimation() { + } + + /** + * event publisher for the fsm - although other services potentially can + * consume and filter this event channel + * + * @param event + * @return + */ + public String publishSystemEvent(String event) { + // well, it turned out underscore was a goofy selection, as underscore in + // aiml is wildcard ... duh + return String.format("SYSTEM_EVENT %s", event); + } + /** * all published text from InMoov2 - including ProgramAB */ diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index 3c9571e435..014cfcf0e9 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -188,7 +188,7 @@ public Plan getDefault(Plan plan, String name) { addDefaultPeerConfig(plan, name, "openWeatherMap", "OpenWeatherMap", false); addDefaultPeerConfig(plan, name, "pid", "Pid", false); addDefaultPeerConfig(plan, name, "pir", "Pir", false); - addDefaultPeerConfig(plan, name, "py4j", "Py4j", true); + addDefaultPeerConfig(plan, name, "py4j", "Py4j", false); addDefaultPeerConfig(plan, name, "random", "Random", false); addDefaultPeerConfig(plan, name, "right", "Arduino", false); addDefaultPeerConfig(plan, name, "rightArm", "InMoov2Arm", false); @@ -519,7 +519,11 @@ public Plan getDefault(Plan plan, String name) { listeners.add(new Listener("publishPlayAudioFile", getPeerName("audioPlayer"))); listeners.add(new Listener("publishPlayAnimation", getPeerName("neoPixel"))); listeners.add(new Listener("publishStopAnimation", getPeerName("neoPixel"))); - listeners.add(new Listener("publishProcessMessage", getPeerName("py4j"), "onPythonMessage")); + // listeners.add(new Listener("publishProcessMessage", getPeerName("python"), "onPythonMessage")); + listeners.add(new Listener("publishProcessMessage", "python", "onPythonMessage")); + listeners.add(new Listener("publishPython", "python")); + + // InMoov2 --to--> InMoov2 listeners.add(new Listener("publishMoveHead", name)); From ed459dafbc7da4867a86e7867e99f3c97c6b3487 Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 20 Jan 2024 20:56:11 -0800 Subject: [PATCH 004/131] reset --- .../org/myrobotlab/service/RandomTest.java | 55 ++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/src/test/java/org/myrobotlab/service/RandomTest.java b/src/test/java/org/myrobotlab/service/RandomTest.java index 9c3739f510..1e42ab9e3a 100644 --- a/src/test/java/org/myrobotlab/service/RandomTest.java +++ b/src/test/java/org/myrobotlab/service/RandomTest.java @@ -17,24 +17,23 @@ public class RandomTest extends AbstractServiceTest { * rarely happens - seems not useful and silly */ public Service createService() throws Exception { - return (Service) Runtime.start("randomTest", "Random"); + return (Service) Runtime.start("random", "Random"); } - + @Before /* before each test */ public void setUp() throws IOException { // remove all services - also resets config name to DEFAULT effectively Runtime.releaseAll(true, true); - // clean our config directory - // Runtime.removeConfig("RandomTest"); + // clean our config directory + Runtime.removeConfig("RandomTest"); // set our config Runtime.setConfig("RandomTest"); } - @Override public void testService() throws Exception { Clock clock = (Clock) Runtime.start("clock", "Clock"); - Random random = (Random) Runtime.start("randomTest", "Random"); + Random random = (Random) Runtime.start("random", "Random"); clock.stopClock(); clock.setInterval(1000); @@ -43,65 +42,71 @@ public void testService() throws Exception { random.addRandom(0, 200, "clock", "setInterval", 5000, 10000); random.enable(); - sleep(1000); + sleep(500); assertTrue("should have method", random.getKeySet().contains("clock.setInterval")); - - assertTrue(String.format("random method 1 should be %d => 5000 values", clock.getInterval()), 5000 <= clock.getInterval()); - assertTrue(String.format("random method 1 should be %d <= 10000 values",clock.getInterval()) , clock.getInterval() <= 10000); - + + assertTrue(String.format("random method 1 should be %d => 5000 values", clock.getInterval()), + 5000 <= clock.getInterval()); + assertTrue(String.format("random method 1 should be %d <= 10000 values", clock.getInterval()), + clock.getInterval() <= 10000); + random.remove("clock.setInterval"); - + assertTrue("should not have method", !random.getKeySet().contains("clock.setInterval")); random.addRandom(0, 200, "clock", "setInterval", 5000, 10000); random.addRandom(0, 200, "clock", "startClock"); - + sleep(500); assertTrue("clock should be started 1", clock.isClockRunning()); - + // disable all of a services random events random.disable("clock.startClock"); clock.stopClock(); sleep(250); assertTrue("clock should not be started 1", !clock.isClockRunning()); - + // enable all of a service's random events random.enable("clock.startClock"); sleep(250); assertTrue("clock should be started 2", clock.isClockRunning()); - + // disable one method - leave other enabled random.disable("clock.startClock"); clock.stopClock(); clock.setInterval(999999); sleep(200); assertTrue("clock should not be started 3", !clock.isClockRunning()); - assertTrue(String.format("random method 2 should be %d => 5000 values", clock.getInterval()), 5000 <= clock.getInterval()); - assertTrue(String.format("random method 2 should be %d <= 10000 values",clock.getInterval()) , clock.getInterval() <= 10000); + assertTrue(String.format("random method 2 should be %d => 5000 values", clock.getInterval()), + 5000 <= clock.getInterval()); + assertTrue(String.format("random method 2 should be %d <= 10000 values", clock.getInterval()), + clock.getInterval() <= 10000); // disable all random.disable(); sleep(200); clock.setInterval(999999); - assertTrue("clock should not be started 4", !clock.isClockRunning()); - assertEquals(999999, (long)clock.getInterval()); + assertTrue("clock should not be started 4", !clock.isClockRunning()); + assertEquals(999999, (long) clock.getInterval()); // re-enable all that were previously enabled but not explicitly disabled ones random.enable(); sleep(1000); assertTrue("clock should not be started 5", !clock.isClockRunning()); - assertTrue(String.format("random method 3 should be %d => 5000 values", clock.getInterval()), 5000 <= clock.getInterval()); - assertTrue(String.format("random method 3 should be %d <= 10000 values",clock.getInterval()) , clock.getInterval() <= 10000); + assertTrue(String.format("random method 3 should be %d => 5000 values", clock.getInterval()), + 5000 <= clock.getInterval()); + assertTrue(String.format("random method 3 should be %d <= 10000 values", clock.getInterval()), + clock.getInterval() <= 10000); clock.stopClock(); random.purge(); - + Map events = random.getRandomEvents(); assertTrue(events.size() == 0); - + random.addRandom("named task", 200, 500, "clock", "setInterval", 100, 1000, 10); - + clock.releaseService(); random.releaseService(); From e0d1687d9aa144fc3bbab7c68f1e3ad649edf67c Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 21 Jan 2024 06:47:48 -0800 Subject: [PATCH 005/131] ordered and formatted --- .../java/org/myrobotlab/service/InMoov2.java | 567 +++++++++--------- .../service/config/InMoov2Config.java | 8 +- 2 files changed, 272 insertions(+), 303 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index cba05f550f..caa06027f3 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -12,7 +12,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; @@ -36,7 +35,6 @@ import org.myrobotlab.programab.PredicateEvent; import org.myrobotlab.programab.Response; import org.myrobotlab.service.Log.LogEntry; -import org.myrobotlab.service.abstracts.AbstractSpeechRecognizer; import org.myrobotlab.service.abstracts.AbstractSpeechSynthesis; import org.myrobotlab.service.config.InMoov2Config; import org.myrobotlab.service.config.OpenCVConfig; @@ -56,23 +54,8 @@ import org.myrobotlab.service.interfaces.TextPublisher; import org.slf4j.Logger; -public class InMoov2 extends Service implements ServiceLifeCycleListener, SpeechListener, TextListener, TextPublisher, JoystickListener, LocaleProvider, IKJointAngleListener { - - public static class Heartbeat { - public long count = 0; - public long ts = System.currentTimeMillis(); - public String state; - public List errors; - double batteryLevel = 100; - public boolean isPirOn = false; - - public Heartbeat(InMoov2 inmoov) { - this.state = inmoov.state; - this.errors = inmoov.errors; - this.count = inmoov.heartbeatCount; - this.isPirOn = inmoov.isPirOn; - } - } +public class InMoov2 extends Service + implements ServiceLifeCycleListener, SpeechListener, TextListener, TextPublisher, JoystickListener, LocaleProvider, IKJointAngleListener { public class Heart implements Runnable { private final ReentrantLock lock = new ReentrantLock(); @@ -117,6 +100,22 @@ public void stop() { } } + public static class Heartbeat { + double batteryLevel = 100; + public long count = 0; + public List errors; + public boolean isPirOn = false; + public String state; + public long ts = System.currentTimeMillis(); + + public Heartbeat(InMoov2 inmoov) { + this.state = inmoov.state; + this.errors = inmoov.errors; + this.count = inmoov.heartbeatCount; + this.isPirOn = inmoov.isPirOn; + } + } + public final static Logger log = LoggerFactory.getLogger(InMoov2.class); public static LinkedHashMap lpVars = new LinkedHashMap(); @@ -125,12 +124,11 @@ public void stop() { static String speechRecognizer = "WebkitSpeechRecognition"; - /** * This method will load a python file into the python interpreter. * * @param file - * file to load + * file to load * @return success/failure */ @Deprecated /* use execScript - this doesn't handle resources correctly */ @@ -166,6 +164,102 @@ public static boolean loadFile(String file) { return true; } + public static void main(String[] args) { + try { + + LoggingFactory.init(Level.ERROR); + // Platform.setVirtual(true); + // Runtime.start("s01", "Servo"); + // Runtime.start("intro", "Intro"); + + Runtime.startConfig("dev"); + + WebGui webgui = (WebGui) Runtime.create("webgui", "WebGui"); + // webgui.setSsl(true); + webgui.autoStartBrowser(false); + // webgui.setPort(8888); + webgui.startService(); + InMoov2 i01 = (InMoov2) Runtime.start("i01", "InMoov2"); + + boolean done = true; + if (done) { + return; + } + + OpenCVConfig ocvConfig = i01.getPeerConfig("opencv", new StaticType<>() { + }); + ocvConfig.flip = true; + i01.setPeerConfigValue("opencv", "flip", true); + // i01.savePeerConfig("", null); + + // Runtime.startConfig("default"); + + // Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", + // "WebGui", + // "intro", "Intro", "python", "Python" }); + + Runtime.start("python", "Python"); + // Runtime.start("ros", "Ros"); + Runtime.start("intro", "Intro"); + // InMoov2 i01 = (InMoov2) Runtime.start("i01", "InMoov2"); + // i01.startPeer("simulator"); + // Runtime.startConfig("i01-05"); + // Runtime.startConfig("pir-01"); + + // Polly polly = (Polly)Runtime.start("i01.mouth", "Polly"); + // i01 = (InMoov2) Runtime.start("i01", "InMoov2"); + + // polly.speakBlocking("Hi, to be or not to be that is the question, + // wheather to take arms against a see of trouble, and by aposing them end + // them, to sleep, to die"); + // i01.startPeer("mouth"); + // i01.speakBlocking("Hi, to be or not to be that is the question, + // wheather to take arms against a see of trouble, and by aposing them end + // them, to sleep, to die"); + + Runtime.start("python", "Python"); + + // i01.startSimulator(); + Plan plan = Runtime.load("webgui", "WebGui"); + // WebGuiConfig webgui = (WebGuiConfig) plan.get("webgui"); + // webgui.autoStartBrowser = false; + Runtime.startConfig("webgui"); + Runtime.start("webgui", "WebGui"); + + Random random = (Random) Runtime.start("random", "Random"); + + random.addRandom(3000, 8000, "i01", "setLeftArmSpeed", 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0); + random.addRandom(3000, 8000, "i01", "setRightArmSpeed", 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0); + + random.addRandom(3000, 8000, "i01", "moveLeftArm", 0.0, 5.0, 85.0, 95.0, 25.0, 30.0, 10.0, 15.0); + random.addRandom(3000, 8000, "i01", "moveRightArm", 0.0, 5.0, 85.0, 95.0, 25.0, 30.0, 10.0, 15.0); + + random.addRandom(3000, 8000, "i01", "setLeftHandSpeed", 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0); + random.addRandom(3000, 8000, "i01", "setRightHandSpeed", 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0); + + random.addRandom(3000, 8000, "i01", "moveRightHand", 10.0, 160.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, 130.0, 175.0); + random.addRandom(3000, 8000, "i01", "moveLeftHand", 10.0, 160.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, 5.0, 40.0); + + random.addRandom(200, 1000, "i01", "setHeadSpeed", 8.0, 20.0, 8.0, 20.0, 8.0, 20.0); + random.addRandom(200, 1000, "i01", "moveHead", 70.0, 110.0, 65.0, 115.0, 70.0, 110.0); + + random.addRandom(200, 1000, "i01", "setTorsoSpeed", 2.0, 5.0, 2.0, 5.0, 2.0, 5.0); + random.addRandom(200, 1000, "i01", "moveTorso", 85.0, 95.0, 88.0, 93.0, 70.0, 110.0); + + random.save(); + + // i01.startChatBot(); + // + // i01.startAll("COM3", "COM4"); + Runtime.start("python", "Python"); + + } catch (Exception e) { + log.error("main threw", e); + } + } + + protected Double batteryLevel = 100.0; + /** * number of times waited in boot state */ @@ -248,8 +342,6 @@ public static boolean loadFile(String file) { protected String voiceSelected; - protected Double batteryLevel = 100.0; - public InMoov2(String n, String id) { super(n, id); locales = Locale.getLocaleMap("en-US", "fr-FR", "es-ES", "de-DE", "nl-NL", "ru-RU", "hi-IN", "it-IT", "fi-FI", "pt-PT", "tr-TR"); @@ -298,6 +390,18 @@ public void attachTextPublisher(TextPublisher service) { subscribe(service.getName(), "publishText"); } + public void beginCheckingOnInactivity() { + beginCheckingOnInactivity(maxInactivityTimeSeconds); + } + + public void beginCheckingOnInactivity(int maxInactivityTimeSeconds) { + this.maxInactivityTimeSeconds = maxInactivityTimeSeconds; + // speakBlocking("power down after %s seconds inactivity is on", + // this.maxInactivityTimeSeconds); + log.info("power down after %s seconds inactivity is on", this.maxInactivityTimeSeconds); + addTask("checkInactivity", 5 * 1000, 0, "checkInactivity"); + } + /** * At boot all services specified through configuration have started, or if no * configuration has started minimally the InMoov2 service has started. During @@ -348,19 +452,20 @@ synchronized public void boot() { // TODO - make Py4j without zombies and more robust /** * Py4j is not ready for primetime yet + * *
-       
-      Py4j py4j = (Py4j) startPeer("py4j");
-      if (!py4j.isReady()) {
-        log.warn("{} not ready....", getPeerName("py4j"));
-        return;
-      }
-      String code = FileIO.toString(getResourceDir() + fs + "InMoov2.py");
-      py4j.exec(code);
+       * 
+       * Py4j py4j = (Py4j) startPeer("py4j");
+       * if (!py4j.isReady()) {
+       *   log.warn("{} not ready....", getPeerName("py4j"));
+       *   return;
+       * }
+       * String code = FileIO.toString(getResourceDir() + fs + "InMoov2.py");
+       * py4j.exec(code);
+       * 
+       * 
+ */ - - */ - // load the InMoov2.py and publish it for Python/Jython or Py4j to consume String script = getResourceAsString("InMoov2.py"); invoke("publishPython", script); @@ -437,18 +542,6 @@ synchronized public void boot() { fire("wake"); } - public void beginCheckingOnInactivity() { - beginCheckingOnInactivity(maxInactivityTimeSeconds); - } - - public void beginCheckingOnInactivity(int maxInactivityTimeSeconds) { - this.maxInactivityTimeSeconds = maxInactivityTimeSeconds; - // speakBlocking("power down after %s seconds inactivity is on", - // this.maxInactivityTimeSeconds); - log.info("power down after %s seconds inactivity is on", this.maxInactivityTimeSeconds); - addTask("checkInactivity", 5 * 1000, 0, "checkInactivity"); - } - public void cameraOff() { if (opencv != null) { opencv.stopCapture(); @@ -629,7 +722,7 @@ public boolean exec(String pythonCode) { * This method will try to launch a python command with error handling * * @param gesture - * the gesture + * the gesture * @return gesture result */ public String execGesture(String gesture) { @@ -657,7 +750,7 @@ public String execGesture(String gesture) { * a filesystem file :P * * @param someScriptName - * execute a resource script + * execute a resource script * @return success or failure */ public boolean execScript(String someScriptName) { @@ -750,16 +843,16 @@ public Long getLastActivityTime() { if (leftArm != null) lastActivityTime = Math.max(lastActivityTime, leftArm); if (rightArm != null) - lastActivityTime = Math.max(lastActivityTime, rightArm); + lastActivityTime = Math.max(lastActivityTime, rightArm); if (leftHand != null) - lastActivityTime = Math.max(lastActivityTime, leftHand); + lastActivityTime = Math.max(lastActivityTime, leftHand); if (rightHand != null) - lastActivityTime = Math.max(lastActivityTime, rightHand); + lastActivityTime = Math.max(lastActivityTime, rightHand); if (torso != null) - lastActivityTime = Math.max(lastActivityTime, torso); + lastActivityTime = Math.max(lastActivityTime, torso); } - return lastActivityTime; + return lastActivityTime; } public InMoov2Arm getLeftArm() { @@ -859,15 +952,6 @@ public void halfSpeed() { sendToPeer("torso", "setSpeed", 20.0, 20.0, 20.0); } - /** - * execute python scripts in the init directory on startup of the service - * - * @throws IOException - */ - public void loadInitScripts() throws IOException { - loadScripts(getResourceDir() + fs + "init"); - } - public boolean isCameraOn() { if (opencv != null) { if (opencv.isCapturing()) { @@ -901,7 +985,7 @@ public void loadGestures() { * file should contain 1 method definition that is the same as the filename. * * @param directory - * - the directory that contains the gesture python files. + * - the directory that contains the gesture python files. * @return true/false */ public boolean loadGestures(String directory) { @@ -941,6 +1025,15 @@ public boolean loadGestures(String directory) { return true; } + /** + * execute python scripts in the init directory on startup of the service + * + * @throws IOException + */ + public void loadInitScripts() throws IOException { + loadScripts(getResourceDir() + fs + "init"); + } + /** * Generalized directory python script loading method * @@ -991,8 +1084,7 @@ public void moveHand(String which, Double thumb, Double index, Double majeure, D moveHand(which, thumb, index, majeure, ringFinger, pinky, null); } - public void moveHand(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, - Double wrist) { + public void moveHand(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { invoke("publishMoveHand", which, thumb, index, majeure, ringFinger, pinky, wrist); } @@ -1044,10 +1136,8 @@ public void moveLeftHand(Double thumb, Double index, Double majeure, Double ring moveHand("left", thumb, index, majeure, ringFinger, pinky, wrist); } - public void moveLeftHand(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, - Integer wrist) { - moveHand("left", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, - (double) wrist); + public void moveLeftHand(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, Integer wrist) { + moveHand("left", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, (double) wrist); } public void moveRightArm(Double bicep, Double rotate, Double shoulder, Double omoplate) { @@ -1058,10 +1148,8 @@ public void moveRightHand(Double thumb, Double index, Double majeure, Double rin moveHand("right", thumb, index, majeure, ringFinger, pinky, wrist); } - public void moveRightHand(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, - Integer wrist) { - moveHand("right", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, - (double) wrist); + public void moveRightHand(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, Integer wrist) { + moveHand("right", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, (double) wrist); } public void moveTorso(Double topStom, Double midStom, Double lowStom) { @@ -1090,7 +1178,7 @@ public PredicateEvent onChangePredicate(PredicateEvent event) { * comes in from runtime which owns the config list * * @param configList - * list of configs + * list of configs */ public void onConfigList(List configList) { this.configList = configList; @@ -1146,23 +1234,6 @@ public void onJoystickInput(JoystickData input) throws Exception { invoke("publishEvent", "joystick"); } - public String onNewState(String state) { - log.error("onNewState {}", state); - - // put configurable filter here ! - - // state substitutions ? - // let python subscribe directly to fsm.publishNewState - - // if - invoke(state); - // depending on configuration .... - // call python ? - // fire fsm events ? - // do defaults ? - return state; - } - /** * Centralized logging system will have all logging from all services, * including lower level logs that do not propegate as statuses @@ -1180,6 +1251,22 @@ public void onLogEvents(List log) { } } + public String onNewState(String state) { + log.error("onNewState {}", state); + + // put configurable filter here ! + + // state substitutions ? + // let python subscribe directly to fsm.publishNewState + + // if + invoke(state); + // depending on configuration .... + // call python ? + // fire fsm events ? + // do defaults ? + return state; + } public OpenCVData onOpenCVData(OpenCVData data) { // FIXME - publish event with or without data ? String file reference @@ -1380,6 +1467,31 @@ public void powerUp() { python.execMethod("power_up"); } + public void processMessage(String method) { + processMessage(method, null); + } + + /** + * Will publish processing messages to the processor(s) currently subscribed. + * + * @param method + * @param data + */ + public void processMessage(String method, Object data) { + // User processing should not occur until after boot has completed + if (!state.equals("boot")) { + // FIXME - this needs to be in config + // FIXME - change peer name to "processor" + // String processor = getPeerName("py4j"); + String processor = "python"; + + Message msg = Message.createMessage(getName(), processor, method, data); + // FIXME - is this too much abstraction .. to publish as well as + // configurable send ? + invoke("publishProcessMessage", msg); + } + } + /** * easy utility to publishMessage * @@ -1392,12 +1504,6 @@ public void publish(String name, String method, Object... data) { invoke("publishMessage", msg); } - public String publishConfigStarted(String configName) { - info("config %s started", configName); - invoke("publishEvent", "CONFIG STARTED " + configName); - return configName; - } - public String publishConfigFinished(String configName) { info("config %s finished", configName); invoke("publishEvent", "CONFIG LOADED " + configName); @@ -1415,6 +1521,12 @@ public List publishConfigList() { return configList; } + public String publishConfigStarted(String configName) { + info("config %s started", configName); + invoke("publishEvent", "CONFIG STARTED " + configName); + return configName; + } + /** * event publisher for the fsm - although other services potentially can * consume and filter this event channel @@ -1511,31 +1623,6 @@ public Heartbeat publishHeartbeat() { return heartbeat; } - public void processMessage(String method) { - processMessage(method, null); - } - - /** - * Will publish processing messages to the processor(s) currently subscribed. - * - * @param method - * @param data - */ - public void processMessage(String method, Object data) { - // User processing should not occur until after boot has completed - if (!state.equals("boot")) { - // FIXME - this needs to be in config - // FIXME - change peer name to "processor" - // String processor = getPeerName("py4j"); - String processor = "python"; - - Message msg = Message.createMessage(getName(), processor, method, data); - // FIXME - is this too much abstraction .. to publish as well as - // configurable send ? - invoke("publishProcessMessage", msg); - } - } - /** * A more extensible interface point than publishEvent FIXME - create * interface for this @@ -1547,8 +1634,7 @@ public Message publishMessage(Message msg) { return msg; } - public HashMap publishMoveArm(String which, Double bicep, Double rotate, Double shoulder, - Double omoplate) { + public HashMap publishMoveArm(String which, Double bicep, Double rotate, Double shoulder, Double omoplate) { HashMap map = new HashMap<>(); map.put("bicep", bicep); map.put("rotate", rotate); @@ -1562,8 +1648,7 @@ public HashMap publishMoveArm(String which, Double bicep, Double return map; } - public HashMap publishMoveHand(String which, Double thumb, Double index, Double majeure, - Double ringFinger, Double pinky, Double wrist) { + public HashMap publishMoveHand(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { HashMap map = new HashMap<>(); map.put("which", which); map.put("thumb", thumb); @@ -1580,8 +1665,7 @@ public HashMap publishMoveHand(String which, Double thumb, Doubl return map; } - public HashMap publishMoveHead(Double neck, Double rothead, Double eyeX, Double eyeY, Double jaw, - Double rollNeck) { + public HashMap publishMoveHead(Double neck, Double rothead, Double eyeX, Double eyeY, Double jaw, Double rollNeck) { HashMap map = new HashMap<>(); map.put("neck", neck); map.put("rothead", rothead); @@ -1601,8 +1685,7 @@ public HashMap publishMoveLeftArm(Double bicep, Double rotate, D return map; } - public HashMap publishMoveLeftHand(Double thumb, Double index, Double majeure, Double ringFinger, - Double pinky, Double wrist) { + public HashMap publishMoveLeftHand(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { HashMap map = new HashMap<>(); map.put("thumb", thumb); map.put("index", index); @@ -1622,8 +1705,7 @@ public HashMap publishMoveRightArm(Double bicep, Double rotate, return map; } - public HashMap publishMoveRightHand(Double thumb, Double index, Double majeure, Double ringFinger, - Double pinky, Double wrist) { + public HashMap publishMoveRightHand(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { HashMap map = new HashMap<>(); map.put("thumb", thumb); map.put("index", index); @@ -1667,7 +1749,6 @@ public String publishPython(String code) { return code; } - /** * publishes a name for NeoPixel.onFlash to consume, in a seperate channel to * potentially be used by "speaking only" leds @@ -1769,8 +1850,7 @@ public void setHandSpeed(String which, Double thumb, Double index, Double majeur setHandSpeed(which, thumb, index, majeure, ringFinger, pinky, null); } - public void setHandSpeed(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, - Double wrist) { + public void setHandSpeed(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { InMoov2Hand hand = getHand(which); if (hand == null) { warn("%s hand not started", which); @@ -1780,14 +1860,12 @@ public void setHandSpeed(String which, Double thumb, Double index, Double majeur } @Deprecated - public void setHandVelocity(String which, Double thumb, Double index, Double majeure, Double ringFinger, - Double pinky) { + public void setHandVelocity(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky) { setHandSpeed(which, thumb, index, majeure, ringFinger, pinky, null); } @Deprecated - public void setHandVelocity(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, - Double wrist) { + public void setHandVelocity(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { setHandSpeed(which, thumb, index, majeure, ringFinger, pinky, wrist); } @@ -1803,8 +1881,7 @@ public void setHeadSpeed(Double rothead, Double neck, Double eyeXSpeed, Double e setHeadSpeed(rothead, neck, eyeXSpeed, eyeYSpeed, jawSpeed, null); } - public void setHeadSpeed(Double rothead, Double neck, Double eyeXSpeed, Double eyeYSpeed, Double jawSpeed, - Double rollNeckSpeed) { + public void setHeadSpeed(Double rothead, Double neck, Double eyeXSpeed, Double eyeYSpeed, Double jawSpeed, Double rollNeckSpeed) { sendToPeer("head", "setSpeed", rothead, neck, eyeXSpeed, eyeYSpeed, jawSpeed, rollNeckSpeed); } @@ -1828,8 +1905,7 @@ public void setHeadVelocity(Double rothead, Double neck, Double eyeXSpeed, Doubl } @Deprecated - public void setHeadVelocity(Double rothead, Double neck, Double eyeXSpeed, Double eyeYSpeed, Double jawSpeed, - Double rollNeckSpeed) { + public void setHeadVelocity(Double rothead, Double neck, Double eyeXSpeed, Double eyeYSpeed, Double jawSpeed, Double rollNeckSpeed) { setHeadSpeed(rothead, neck, eyeXSpeed, eyeYSpeed, jawSpeed, rollNeckSpeed); } @@ -1841,15 +1917,12 @@ public void setLeftArmSpeed(Integer bicep, Integer rotate, Integer shoulder, Int setArmSpeed("left", (double) bicep, (double) rotate, (double) shoulder, (double) omoplate); } - public void setLeftHandSpeed(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, - Double wrist) { + public void setLeftHandSpeed(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { setHandSpeed("left", thumb, index, majeure, ringFinger, pinky, wrist); } - public void setLeftHandSpeed(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, - Integer wrist) { - setHandSpeed("left", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, - (double) wrist); + public void setLeftHandSpeed(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, Integer wrist) { + setHandSpeed("left", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, (double) wrist); } @Override @@ -1918,15 +1991,49 @@ public void setRightArmSpeed(Integer bicep, Integer rotate, Integer shoulder, In setArmSpeed("right", (double) bicep, (double) rotate, (double) shoulder, (double) omoplate); } - public void setRightHandSpeed(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, - Double wrist) { + public void setRightHandSpeed(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { setHandSpeed("right", thumb, index, majeure, ringFinger, pinky, wrist); } - public void setRightHandSpeed(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, - Integer wrist) { - setHandSpeed("right", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, - (double) wrist); + public void setRightHandSpeed(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, Integer wrist) { + setHandSpeed("right", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, (double) wrist); + } + + public boolean setSpeechType(String speechType) { + + if (speechType == null) { + error("cannot change speech type to null"); + return false; + } + + if (!speechType.contains(".")) { + speechType = "org.myrobotlab.service." + speechType; + } + + Runtime runtime = Runtime.getInstance(); + String peerName = getName() + ".mouth"; + Plan plan = runtime.getDefault(peerName, speechType); + try { + SpeechSynthesisConfig mouth = (SpeechSynthesisConfig) plan.get(peerName); + mouth.speechRecognizers = new String[] { getName() + ".ear" }; + + savePeerConfig("mouth", plan.get(peerName)); + + if (isPeerStarted("mouth")) { + // restart + releasePeer("mouth"); + startPeer("mouth"); + } + + } catch (Exception e) { + error("could not create config for %s", speechType); + return false; + } + + return true; + + // updatePeerType("mouth" /* getPeerName("mouth") */, speechType); + // return speechType; } public void setTorsoSpeed(Double topStom, Double midStom, Double lowStom) { @@ -1937,6 +2044,11 @@ public void setTorsoSpeed(Integer topStom, Integer midStom, Integer lowStom) { setTorsoSpeed((double) topStom, (double) midStom, (double) lowStom); } + // ----------------------------------------------------------------------------- + // These are methods added that were in InMoov1 that we no longer had in + // InMoov2. + // From original InMoov1 so we don't loose the + @Deprecated /* use setTorsoSpeed */ public void setTorsoVelocity(Double topStom, Double midStom, Double lowStom) { setTorsoSpeed(topStom, midStom, lowStom); @@ -1950,11 +2062,6 @@ public void setVoice(String name) { } } - // ----------------------------------------------------------------------------- - // These are methods added that were in InMoov1 that we no longer had in - // InMoov2. - // From original InMoov1 so we don't loose the - public void sleeping() { log.error("sleeping"); } @@ -2057,8 +2164,7 @@ public ProgramAB startChatBot() { chatBot.setPredicate("null", ""); // load last user session if (!chatBot.getPredicate("name").isEmpty()) { - if (chatBot.getPredicate("lastUsername").isEmpty() || chatBot.getPredicate("lastUsername").equals("unknown") - || chatBot.getPredicate("lastUsername").equals("default")) { + if (chatBot.getPredicate("lastUsername").isEmpty() || chatBot.getPredicate("lastUsername").equals("unknown") || chatBot.getPredicate("lastUsername").equals("default")) { chatBot.setPredicate("lastUsername", chatBot.getPredicate("name")); } } @@ -2074,8 +2180,7 @@ public ProgramAB startChatBot() { // !chatBot.getPredicate("default", "lastUsername").equals("unknown")) { // chatBot.startSession(chatBot.getPredicate("lastUsername")); // } - if (chatBot.getPredicate("default", "firstinit").isEmpty() - || chatBot.getPredicate("default", "firstinit").equals("unknown") + if (chatBot.getPredicate("default", "firstinit").isEmpty() || chatBot.getPredicate("default", "firstinit").equals("unknown") || chatBot.getPredicate("default", "firstinit").equals("started")) { chatBot.startSession(chatBot.getPredicate("default", "lastUsername")); invoke("publishEvent", "FIRST INIT"); @@ -2299,138 +2404,4 @@ public void waitTargetPos() { sendToPeer("torso", "waitTargetPos"); } - public boolean setSpeechType(String speechType) { - - if (speechType == null) { - error("cannot change speech type to null"); - return false; - } - - if (!speechType.contains(".")) { - speechType = "org.myrobotlab.service." + speechType; - } - - Runtime runtime = Runtime.getInstance(); - String peerName = getName() + ".mouth"; - Plan plan = runtime.getDefault(peerName, speechType); - try { - SpeechSynthesisConfig mouth = (SpeechSynthesisConfig) plan.get(peerName); - mouth.speechRecognizers = new String[] { getName() + ".ear" }; - - savePeerConfig("mouth", plan.get(peerName)); - - if (isPeerStarted("mouth")) { - // restart - releasePeer("mouth"); - startPeer("mouth"); - } - - } catch (Exception e) { - error("could not create config for %s", speechType); - return false; - } - - return true; - - // updatePeerType("mouth" /* getPeerName("mouth") */, speechType); - // return speechType; - } - - public static void main(String[] args) { - try { - - LoggingFactory.init(Level.ERROR); - // Platform.setVirtual(true); - // Runtime.start("s01", "Servo"); - // Runtime.start("intro", "Intro"); - - Runtime.startConfig("dev"); - - WebGui webgui = (WebGui) Runtime.create("webgui", "WebGui"); - // webgui.setSsl(true); - webgui.autoStartBrowser(false); - // webgui.setPort(8888); - webgui.startService(); - InMoov2 i01 = (InMoov2) Runtime.start("i01", "InMoov2"); - - boolean done = true; - if (done) { - return; - } - - OpenCVConfig ocvConfig = i01.getPeerConfig("opencv", new StaticType<>() { - }); - ocvConfig.flip = true; - i01.setPeerConfigValue("opencv", "flip", true); - // i01.savePeerConfig("", null); - - // Runtime.startConfig("default"); - - // Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", "WebGui", - // "intro", "Intro", "python", "Python" }); - - Runtime.start("python", "Python"); - // Runtime.start("ros", "Ros"); - Runtime.start("intro", "Intro"); - // InMoov2 i01 = (InMoov2) Runtime.start("i01", "InMoov2"); - // i01.startPeer("simulator"); - // Runtime.startConfig("i01-05"); - // Runtime.startConfig("pir-01"); - - // Polly polly = (Polly)Runtime.start("i01.mouth", "Polly"); - // i01 = (InMoov2) Runtime.start("i01", "InMoov2"); - - // polly.speakBlocking("Hi, to be or not to be that is the question, - // wheather to take arms against a see of trouble, and by aposing them end - // them, to sleep, to die"); - // i01.startPeer("mouth"); - // i01.speakBlocking("Hi, to be or not to be that is the question, - // wheather to take arms against a see of trouble, and by aposing them end - // them, to sleep, to die"); - - Runtime.start("python", "Python"); - - // i01.startSimulator(); - Plan plan = Runtime.load("webgui", "WebGui"); - // WebGuiConfig webgui = (WebGuiConfig) plan.get("webgui"); - // webgui.autoStartBrowser = false; - Runtime.startConfig("webgui"); - Runtime.start("webgui", "WebGui"); - - Random random = (Random) Runtime.start("random", "Random"); - - random.addRandom(3000, 8000, "i01", "setLeftArmSpeed", 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0); - random.addRandom(3000, 8000, "i01", "setRightArmSpeed", 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0); - - random.addRandom(3000, 8000, "i01", "moveLeftArm", 0.0, 5.0, 85.0, 95.0, 25.0, 30.0, 10.0, 15.0); - random.addRandom(3000, 8000, "i01", "moveRightArm", 0.0, 5.0, 85.0, 95.0, 25.0, 30.0, 10.0, 15.0); - - random.addRandom(3000, 8000, "i01", "setLeftHandSpeed", 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, - 8.0, 25.0); - random.addRandom(3000, 8000, "i01", "setRightHandSpeed", 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, - 8.0, 25.0); - - random.addRandom(3000, 8000, "i01", "moveRightHand", 10.0, 160.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, - 130.0, 175.0); - random.addRandom(3000, 8000, "i01", "moveLeftHand", 10.0, 160.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, - 5.0, 40.0); - - random.addRandom(200, 1000, "i01", "setHeadSpeed", 8.0, 20.0, 8.0, 20.0, 8.0, 20.0); - random.addRandom(200, 1000, "i01", "moveHead", 70.0, 110.0, 65.0, 115.0, 70.0, 110.0); - - random.addRandom(200, 1000, "i01", "setTorsoSpeed", 2.0, 5.0, 2.0, 5.0, 2.0, 5.0); - random.addRandom(200, 1000, "i01", "moveTorso", 85.0, 95.0, 88.0, 93.0, 70.0, 110.0); - - random.save(); - - // i01.startChatBot(); - // - // i01.startAll("COM3", "COM4"); - Runtime.start("python", "Python"); - - } catch (Exception e) { - log.error("main threw", e); - } - } - } diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index 014cfcf0e9..c599a5a1ad 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -519,11 +519,10 @@ public Plan getDefault(Plan plan, String name) { listeners.add(new Listener("publishPlayAudioFile", getPeerName("audioPlayer"))); listeners.add(new Listener("publishPlayAnimation", getPeerName("neoPixel"))); listeners.add(new Listener("publishStopAnimation", getPeerName("neoPixel"))); - // listeners.add(new Listener("publishProcessMessage", getPeerName("python"), "onPythonMessage")); + // listeners.add(new Listener("publishProcessMessage", + // getPeerName("python"), "onPythonMessage")); listeners.add(new Listener("publishProcessMessage", "python", "onPythonMessage")); listeners.add(new Listener("publishPython", "python")); - - // InMoov2 --to--> InMoov2 listeners.add(new Listener("publishMoveHead", name)); @@ -536,12 +535,11 @@ public Plan getDefault(Plan plan, String name) { // service --to--> InMoov2 AudioFileConfig mouth_audioFile = (AudioFileConfig) plan.get(getPeerName("mouth.audioFile")); mouth_audioFile.listeners.add(new Listener("publishPeak", name)); - + OakDConfig oakd = (OakDConfig) plan.get(getPeerName("oakd")); oakd.listeners.add(new Listener("publishClassification", name)); oakd.getPeer("py4j").name = getPeerName("py4j"); - webxr.listeners.add(new Listener("publishJointAngles", name)); // mouth_audioFile.listeners.add(new Listener("publishAudioEnd", name)); From 683808410395130c743fc102628b34999b6c7803 Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 21 Jan 2024 06:58:19 -0800 Subject: [PATCH 006/131] recovering from bad merge --- .../java/org/myrobotlab/service/InMoov2.java | 122 ++++++------------ 1 file changed, 41 insertions(+), 81 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index 568edece8d..caa06027f3 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -55,8 +55,7 @@ import org.slf4j.Logger; public class InMoov2 extends Service - implements ServiceLifeCycleListener, SpeechListener, TextListener, TextPublisher, JoystickListener, LocaleProvider, - IKJointAngleListener { + implements ServiceLifeCycleListener, SpeechListener, TextListener, TextPublisher, JoystickListener, LocaleProvider, IKJointAngleListener { public class Heart implements Runnable { private final ReentrantLock lock = new ReentrantLock(); @@ -129,7 +128,7 @@ public Heartbeat(InMoov2 inmoov) { * This method will load a python file into the python interpreter. * * @param file - * file to load + * file to load * @return success/failure */ @Deprecated /* use execScript - this doesn't handle resources correctly */ @@ -235,15 +234,11 @@ public static void main(String[] args) { random.addRandom(3000, 8000, "i01", "moveLeftArm", 0.0, 5.0, 85.0, 95.0, 25.0, 30.0, 10.0, 15.0); random.addRandom(3000, 8000, "i01", "moveRightArm", 0.0, 5.0, 85.0, 95.0, 25.0, 30.0, 10.0, 15.0); - random.addRandom(3000, 8000, "i01", "setLeftHandSpeed", 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, - 8.0, 25.0); - random.addRandom(3000, 8000, "i01", "setRightHandSpeed", 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, - 8.0, 25.0); + random.addRandom(3000, 8000, "i01", "setLeftHandSpeed", 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0); + random.addRandom(3000, 8000, "i01", "setRightHandSpeed", 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0); - random.addRandom(3000, 8000, "i01", "moveRightHand", 10.0, 160.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, - 130.0, 175.0); - random.addRandom(3000, 8000, "i01", "moveLeftHand", 10.0, 160.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, - 5.0, 40.0); + random.addRandom(3000, 8000, "i01", "moveRightHand", 10.0, 160.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, 130.0, 175.0); + random.addRandom(3000, 8000, "i01", "moveLeftHand", 10.0, 160.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, 5.0, 40.0); random.addRandom(200, 1000, "i01", "setHeadSpeed", 8.0, 20.0, 8.0, 20.0, 8.0, 20.0); random.addRandom(200, 1000, "i01", "moveHead", 70.0, 110.0, 65.0, 115.0, 70.0, 110.0); @@ -263,8 +258,6 @@ public static void main(String[] args) { } } - <<<<<<>>>>>>60e56597d 29d 490d 553855 aff73d5930130c063d protected transient ProgramAB chatBot; protected List configList; @@ -352,8 +344,7 @@ public static void main(String[] args) { public InMoov2(String n, String id) { super(n, id); - locales = Locale.getLocaleMap("en-US", "fr-FR", "es-ES", "de-DE", "nl-NL", "ru-RU", "hi-IN", "it-IT", "fi-FI", - "pt-PT", "tr-TR"); + locales = Locale.getLocaleMap("en-US", "fr-FR", "es-ES", "de-DE", "nl-NL", "ru-RU", "hi-IN", "it-IT", "fi-FI", "pt-PT", "tr-TR"); } // should be removed in favor of general listeners @@ -731,7 +722,7 @@ public boolean exec(String pythonCode) { * This method will try to launch a python command with error handling * * @param gesture - * the gesture + * the gesture * @return gesture result */ public String execGesture(String gesture) { @@ -759,7 +750,7 @@ public String execGesture(String gesture) { * a filesystem file :P * * @param someScriptName - * execute a resource script + * execute a resource script * @return success or failure */ public boolean execScript(String someScriptName) { @@ -837,18 +828,11 @@ public InMoov2Head getHead() { */ public Long getLastActivityTime() { Long head = (InMoov2Head) getPeer("head") != null ? ((InMoov2Head) getPeer("head")).getLastActivityTime() : null; - Long leftArm = (InMoov2Arm) getPeer("leftArm") != null ? ((InMoov2Arm) getPeer("leftArm")).getLastActivityTime() - : null; - Long rightArm = (InMoov2Arm) getPeer("rightArm") != null ? ((InMoov2Arm) getPeer("rightArm")).getLastActivityTime() - : null; - Long leftHand = (InMoov2Hand) getPeer("leftHand") != null - ? ((InMoov2Hand) getPeer("leftHand")).getLastActivityTime() - : null; - Long rightHand = (InMoov2Hand) getPeer("rightHand") != null - ? ((InMoov2Hand) getPeer("rightHand")).getLastActivityTime() - : null; - Long torso = (InMoov2Torso) getPeer("torso") != null ? ((InMoov2Torso) getPeer("torso")).getLastActivityTime() - : null; + Long leftArm = (InMoov2Arm) getPeer("leftArm") != null ? ((InMoov2Arm) getPeer("leftArm")).getLastActivityTime() : null; + Long rightArm = (InMoov2Arm) getPeer("rightArm") != null ? ((InMoov2Arm) getPeer("rightArm")).getLastActivityTime() : null; + Long leftHand = (InMoov2Hand) getPeer("leftHand") != null ? ((InMoov2Hand) getPeer("leftHand")).getLastActivityTime() : null; + Long rightHand = (InMoov2Hand) getPeer("rightHand") != null ? ((InMoov2Hand) getPeer("rightHand")).getLastActivityTime() : null; + Long torso = (InMoov2Torso) getPeer("torso") != null ? ((InMoov2Torso) getPeer("torso")).getLastActivityTime() : null; Long lastActivityTime = null; @@ -1001,7 +985,7 @@ public void loadGestures() { * file should contain 1 method definition that is the same as the filename. * * @param directory - * - the directory that contains the gesture python files. + * - the directory that contains the gesture python files. * @return true/false */ public boolean loadGestures(String directory) { @@ -1100,8 +1084,7 @@ public void moveHand(String which, Double thumb, Double index, Double majeure, D moveHand(which, thumb, index, majeure, ringFinger, pinky, null); } - public void moveHand(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, - Double wrist) { + public void moveHand(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { invoke("publishMoveHand", which, thumb, index, majeure, ringFinger, pinky, wrist); } @@ -1153,10 +1136,8 @@ public void moveLeftHand(Double thumb, Double index, Double majeure, Double ring moveHand("left", thumb, index, majeure, ringFinger, pinky, wrist); } - public void moveLeftHand(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, - Integer wrist) { - moveHand("left", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, - (double) wrist); + public void moveLeftHand(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, Integer wrist) { + moveHand("left", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, (double) wrist); } public void moveRightArm(Double bicep, Double rotate, Double shoulder, Double omoplate) { @@ -1167,10 +1148,8 @@ public void moveRightHand(Double thumb, Double index, Double majeure, Double rin moveHand("right", thumb, index, majeure, ringFinger, pinky, wrist); } - public void moveRightHand(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, - Integer wrist) { - moveHand("right", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, - (double) wrist); + public void moveRightHand(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, Integer wrist) { + moveHand("right", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, (double) wrist); } public void moveTorso(Double topStom, Double midStom, Double lowStom) { @@ -1199,7 +1178,7 @@ public PredicateEvent onChangePredicate(PredicateEvent event) { * comes in from runtime which owns the config list * * @param configList - * list of configs + * list of configs */ public void onConfigList(List configList) { this.configList = configList; @@ -1260,7 +1239,7 @@ public void onJoystickInput(JoystickData input) throws Exception { * including lower level logs that do not propegate as statuses * * @param log - * - flushed log from Log service + * - flushed log from Log service */ public void onLogEvents(List log) { // scan for warn or errors @@ -1603,8 +1582,7 @@ public Heartbeat publishHeartbeat() { } // interval event firing - if (config.stateRandomInterval != null - && System.currentTimeMillis() > stateLastRandomTime + (config.stateRandomInterval * 1000)) { + if (config.stateRandomInterval != null && System.currentTimeMillis() > stateLastRandomTime + (config.stateRandomInterval * 1000)) { // fsm.fire("random"); stateLastRandomTime = System.currentTimeMillis(); } @@ -1656,8 +1634,7 @@ public Message publishMessage(Message msg) { return msg; } - public HashMap publishMoveArm(String which, Double bicep, Double rotate, Double shoulder, - Double omoplate) { + public HashMap publishMoveArm(String which, Double bicep, Double rotate, Double shoulder, Double omoplate) { HashMap map = new HashMap<>(); map.put("bicep", bicep); map.put("rotate", rotate); @@ -1671,8 +1648,7 @@ public HashMap publishMoveArm(String which, Double bicep, Double return map; } - public HashMap publishMoveHand(String which, Double thumb, Double index, Double majeure, - Double ringFinger, Double pinky, Double wrist) { + public HashMap publishMoveHand(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { HashMap map = new HashMap<>(); map.put("which", which); map.put("thumb", thumb); @@ -1689,8 +1665,7 @@ public HashMap publishMoveHand(String which, Double thumb, Doubl return map; } - public HashMap publishMoveHead(Double neck, Double rothead, Double eyeX, Double eyeY, Double jaw, - Double rollNeck) { + public HashMap publishMoveHead(Double neck, Double rothead, Double eyeX, Double eyeY, Double jaw, Double rollNeck) { HashMap map = new HashMap<>(); map.put("neck", neck); map.put("rothead", rothead); @@ -1710,8 +1685,7 @@ public HashMap publishMoveLeftArm(Double bicep, Double rotate, D return map; } - public HashMap publishMoveLeftHand(Double thumb, Double index, Double majeure, Double ringFinger, - Double pinky, Double wrist) { + public HashMap publishMoveLeftHand(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { HashMap map = new HashMap<>(); map.put("thumb", thumb); map.put("index", index); @@ -1731,8 +1705,7 @@ public HashMap publishMoveRightArm(Double bicep, Double rotate, return map; } - public HashMap publishMoveRightHand(Double thumb, Double index, Double majeure, Double ringFinger, - Double pinky, Double wrist) { + public HashMap publishMoveRightHand(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { HashMap map = new HashMap<>(); map.put("thumb", thumb); map.put("index", index); @@ -1877,8 +1850,7 @@ public void setHandSpeed(String which, Double thumb, Double index, Double majeur setHandSpeed(which, thumb, index, majeure, ringFinger, pinky, null); } - public void setHandSpeed(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, - Double wrist) { + public void setHandSpeed(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { InMoov2Hand hand = getHand(which); if (hand == null) { warn("%s hand not started", which); @@ -1888,14 +1860,12 @@ public void setHandSpeed(String which, Double thumb, Double index, Double majeur } @Deprecated - public void setHandVelocity(String which, Double thumb, Double index, Double majeure, Double ringFinger, - Double pinky) { + public void setHandVelocity(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky) { setHandSpeed(which, thumb, index, majeure, ringFinger, pinky, null); } @Deprecated - public void setHandVelocity(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, - Double wrist) { + public void setHandVelocity(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { setHandSpeed(which, thumb, index, majeure, ringFinger, pinky, wrist); } @@ -1911,8 +1881,7 @@ public void setHeadSpeed(Double rothead, Double neck, Double eyeXSpeed, Double e setHeadSpeed(rothead, neck, eyeXSpeed, eyeYSpeed, jawSpeed, null); } - public void setHeadSpeed(Double rothead, Double neck, Double eyeXSpeed, Double eyeYSpeed, Double jawSpeed, - Double rollNeckSpeed) { + public void setHeadSpeed(Double rothead, Double neck, Double eyeXSpeed, Double eyeYSpeed, Double jawSpeed, Double rollNeckSpeed) { sendToPeer("head", "setSpeed", rothead, neck, eyeXSpeed, eyeYSpeed, jawSpeed, rollNeckSpeed); } @@ -1936,8 +1905,7 @@ public void setHeadVelocity(Double rothead, Double neck, Double eyeXSpeed, Doubl } @Deprecated - public void setHeadVelocity(Double rothead, Double neck, Double eyeXSpeed, Double eyeYSpeed, Double jawSpeed, - Double rollNeckSpeed) { + public void setHeadVelocity(Double rothead, Double neck, Double eyeXSpeed, Double eyeYSpeed, Double jawSpeed, Double rollNeckSpeed) { setHeadSpeed(rothead, neck, eyeXSpeed, eyeYSpeed, jawSpeed, rollNeckSpeed); } @@ -1949,15 +1917,12 @@ public void setLeftArmSpeed(Integer bicep, Integer rotate, Integer shoulder, Int setArmSpeed("left", (double) bicep, (double) rotate, (double) shoulder, (double) omoplate); } - public void setLeftHandSpeed(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, - Double wrist) { + public void setLeftHandSpeed(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { setHandSpeed("left", thumb, index, majeure, ringFinger, pinky, wrist); } - public void setLeftHandSpeed(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, - Integer wrist) { - setHandSpeed("left", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, - (double) wrist); + public void setLeftHandSpeed(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, Integer wrist) { + setHandSpeed("left", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, (double) wrist); } @Override @@ -2026,15 +1991,12 @@ public void setRightArmSpeed(Integer bicep, Integer rotate, Integer shoulder, In setArmSpeed("right", (double) bicep, (double) rotate, (double) shoulder, (double) omoplate); } - public void setRightHandSpeed(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, - Double wrist) { + public void setRightHandSpeed(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { setHandSpeed("right", thumb, index, majeure, ringFinger, pinky, wrist); } - public void setRightHandSpeed(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, - Integer wrist) { - setHandSpeed("right", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, - (double) wrist); + public void setRightHandSpeed(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, Integer wrist) { + setHandSpeed("right", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, (double) wrist); } public boolean setSpeechType(String speechType) { @@ -2202,8 +2164,7 @@ public ProgramAB startChatBot() { chatBot.setPredicate("null", ""); // load last user session if (!chatBot.getPredicate("name").isEmpty()) { - if (chatBot.getPredicate("lastUsername").isEmpty() || chatBot.getPredicate("lastUsername").equals("unknown") - || chatBot.getPredicate("lastUsername").equals("default")) { + if (chatBot.getPredicate("lastUsername").isEmpty() || chatBot.getPredicate("lastUsername").equals("unknown") || chatBot.getPredicate("lastUsername").equals("default")) { chatBot.setPredicate("lastUsername", chatBot.getPredicate("name")); } } @@ -2219,8 +2180,7 @@ public ProgramAB startChatBot() { // !chatBot.getPredicate("default", "lastUsername").equals("unknown")) { // chatBot.startSession(chatBot.getPredicate("lastUsername")); // } - if (chatBot.getPredicate("default", "firstinit").isEmpty() - || chatBot.getPredicate("default", "firstinit").equals("unknown") + if (chatBot.getPredicate("default", "firstinit").isEmpty() || chatBot.getPredicate("default", "firstinit").equals("unknown") || chatBot.getPredicate("default", "firstinit").equals("started")) { chatBot.startSession(chatBot.getPredicate("default", "lastUsername")); invoke("publishEvent", "FIRST INIT"); From b5794f5f33c46b96be1f2797fd95a13045219f8a Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 21 Jan 2024 07:01:45 -0800 Subject: [PATCH 007/131] reset randomtest --- .../org/myrobotlab/service/RandomTest.java | 55 +++++++++---------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/src/test/java/org/myrobotlab/service/RandomTest.java b/src/test/java/org/myrobotlab/service/RandomTest.java index 1e42ab9e3a..9c3739f510 100644 --- a/src/test/java/org/myrobotlab/service/RandomTest.java +++ b/src/test/java/org/myrobotlab/service/RandomTest.java @@ -17,23 +17,24 @@ public class RandomTest extends AbstractServiceTest { * rarely happens - seems not useful and silly */ public Service createService() throws Exception { - return (Service) Runtime.start("random", "Random"); + return (Service) Runtime.start("randomTest", "Random"); } - + @Before /* before each test */ public void setUp() throws IOException { // remove all services - also resets config name to DEFAULT effectively Runtime.releaseAll(true, true); - // clean our config directory - Runtime.removeConfig("RandomTest"); + // clean our config directory + // Runtime.removeConfig("RandomTest"); // set our config Runtime.setConfig("RandomTest"); } + @Override public void testService() throws Exception { Clock clock = (Clock) Runtime.start("clock", "Clock"); - Random random = (Random) Runtime.start("random", "Random"); + Random random = (Random) Runtime.start("randomTest", "Random"); clock.stopClock(); clock.setInterval(1000); @@ -42,71 +43,65 @@ public void testService() throws Exception { random.addRandom(0, 200, "clock", "setInterval", 5000, 10000); random.enable(); - sleep(500); + sleep(1000); assertTrue("should have method", random.getKeySet().contains("clock.setInterval")); - - assertTrue(String.format("random method 1 should be %d => 5000 values", clock.getInterval()), - 5000 <= clock.getInterval()); - assertTrue(String.format("random method 1 should be %d <= 10000 values", clock.getInterval()), - clock.getInterval() <= 10000); - + + assertTrue(String.format("random method 1 should be %d => 5000 values", clock.getInterval()), 5000 <= clock.getInterval()); + assertTrue(String.format("random method 1 should be %d <= 10000 values",clock.getInterval()) , clock.getInterval() <= 10000); + random.remove("clock.setInterval"); - + assertTrue("should not have method", !random.getKeySet().contains("clock.setInterval")); random.addRandom(0, 200, "clock", "setInterval", 5000, 10000); random.addRandom(0, 200, "clock", "startClock"); - + sleep(500); assertTrue("clock should be started 1", clock.isClockRunning()); - + // disable all of a services random events random.disable("clock.startClock"); clock.stopClock(); sleep(250); assertTrue("clock should not be started 1", !clock.isClockRunning()); - + // enable all of a service's random events random.enable("clock.startClock"); sleep(250); assertTrue("clock should be started 2", clock.isClockRunning()); - + // disable one method - leave other enabled random.disable("clock.startClock"); clock.stopClock(); clock.setInterval(999999); sleep(200); assertTrue("clock should not be started 3", !clock.isClockRunning()); - assertTrue(String.format("random method 2 should be %d => 5000 values", clock.getInterval()), - 5000 <= clock.getInterval()); - assertTrue(String.format("random method 2 should be %d <= 10000 values", clock.getInterval()), - clock.getInterval() <= 10000); + assertTrue(String.format("random method 2 should be %d => 5000 values", clock.getInterval()), 5000 <= clock.getInterval()); + assertTrue(String.format("random method 2 should be %d <= 10000 values",clock.getInterval()) , clock.getInterval() <= 10000); // disable all random.disable(); sleep(200); clock.setInterval(999999); - assertTrue("clock should not be started 4", !clock.isClockRunning()); - assertEquals(999999, (long) clock.getInterval()); + assertTrue("clock should not be started 4", !clock.isClockRunning()); + assertEquals(999999, (long)clock.getInterval()); // re-enable all that were previously enabled but not explicitly disabled ones random.enable(); sleep(1000); assertTrue("clock should not be started 5", !clock.isClockRunning()); - assertTrue(String.format("random method 3 should be %d => 5000 values", clock.getInterval()), - 5000 <= clock.getInterval()); - assertTrue(String.format("random method 3 should be %d <= 10000 values", clock.getInterval()), - clock.getInterval() <= 10000); + assertTrue(String.format("random method 3 should be %d => 5000 values", clock.getInterval()), 5000 <= clock.getInterval()); + assertTrue(String.format("random method 3 should be %d <= 10000 values",clock.getInterval()) , clock.getInterval() <= 10000); clock.stopClock(); random.purge(); - + Map events = random.getRandomEvents(); assertTrue(events.size() == 0); - + random.addRandom("named task", 200, 500, "clock", "setInterval", 100, 1000, 10); - + clock.releaseService(); random.releaseService(); From 37a379590f162c92a62358c35c5605aaf75d98c7 Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 21 Jan 2024 08:13:15 -0800 Subject: [PATCH 008/131] finite state history --- .../service/views/FiniteStateMachineGui.html | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/resources/resource/WebGui/app/service/views/FiniteStateMachineGui.html b/src/main/resources/resource/WebGui/app/service/views/FiniteStateMachineGui.html index 067ee7624c..b61f5af303 100644 --- a/src/main/resources/resource/WebGui/app/service/views/FiniteStateMachineGui.html +++ b/src/main/resources/resource/WebGui/app/service/views/FiniteStateMachineGui.html @@ -54,5 +54,22 @@

Last Event {{event}} Current State: {{current}}

+ + + + + + + + + + + + + + + +
TimestampStateEvent
{{ item.ts }}{{ item.state }}{{ item.event }}
+ From a7c1b662f74b9cbd73101ee3faff739cc6f80ff9 Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 21 Jan 2024 13:56:02 -0800 Subject: [PATCH 009/131] fixed fire fsm event --- .../java/org/myrobotlab/service/InMoov2.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index caa06027f3..719025ce8c 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -778,9 +778,15 @@ public void finishedGesture(String nameOfGesture) { } } - // FIXME - this isn't the callback for fsm - why is it needed here ? + /** + * Fire an event to the FSM, potentially this can cause a state change + * + * @param event + */ public void fire(String event) { - invoke("publishEvent", event); + // Should this be sent to chatbot too ? + // invoke("publishEvent", event); + fsm.fire(event); } public void fullSpeed() { @@ -2283,16 +2289,13 @@ public ServiceInterface startPeer(String peer) { @Override public void startService() { super.startService(); - // FIXME - hardcoded peer no choice of type + + // This is required the core of InMoov is + // a FSM ProgramAB and some form of Python/Jython fsm = (FiniteStateMachine) startPeer("fsm"); - // a python processor is - // necessary for InMoov2 to properly - // function but this is not the place to start it - // it should be a peer definition too, it can be "python" - // it doesn't need to be i01.python to be a peer - // also should determine type Py4j or Python - // Runtime.start("python"); + // A python process is required - should be defined as a peer + // of Type Python or Py4j // just for comparing config with current "default" // debugging only From b90bd80573f4266edb384bf282505bed424eb0f9 Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 21 Jan 2024 14:19:19 -0800 Subject: [PATCH 010/131] requested updates --- .../org/myrobotlab/programab/models/Oob.java | 12 +++-- .../myrobotlab/programab/models/Sraix.java | 16 +++++- .../myrobotlab/programab/models/Template.java | 45 ++++++---------- .../myrobotlab/programab/TemplateTest.java | 52 +++++++++++++++++++ 4 files changed, 91 insertions(+), 34 deletions(-) create mode 100644 src/test/java/org/myrobotlab/programab/TemplateTest.java diff --git a/src/main/java/org/myrobotlab/programab/models/Oob.java b/src/main/java/org/myrobotlab/programab/models/Oob.java index 833bab5a0f..5e0d99c4cf 100644 --- a/src/main/java/org/myrobotlab/programab/models/Oob.java +++ b/src/main/java/org/myrobotlab/programab/models/Oob.java @@ -4,11 +4,17 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +/** + * AIML 2.0 Oob Out Of Band xml defined with mrl - legacy and mrljson - json + * typed message + * + * @author GroG + * + */ public class Oob { - + public String mrljson; - + @JacksonXmlElementWrapper(useWrapping = false) public List mrl; } - diff --git a/src/main/java/org/myrobotlab/programab/models/Sraix.java b/src/main/java/org/myrobotlab/programab/models/Sraix.java index 99b0639cb6..1b130ad805 100644 --- a/src/main/java/org/myrobotlab/programab/models/Sraix.java +++ b/src/main/java/org/myrobotlab/programab/models/Sraix.java @@ -1,10 +1,22 @@ package org.myrobotlab.programab.models; -// FIXME add attributes and internal tags +/** + * Basic Sraix model, AIML 2.0 has more elements but these seemed like the most + * relevant and ar actually used. + * + * @author GroG + * + */ public class Sraix { + /** + * Search text when a query is sent to a remote system + */ public String search; + /** + * Oob is Out Of Band text which can be handled by internal processing + */ public Oob oob; - + } diff --git a/src/main/java/org/myrobotlab/programab/models/Template.java b/src/main/java/org/myrobotlab/programab/models/Template.java index 91f8e5de51..d657973005 100644 --- a/src/main/java/org/myrobotlab/programab/models/Template.java +++ b/src/main/java/org/myrobotlab/programab/models/Template.java @@ -5,47 +5,34 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText; -//@JacksonXmlRootElement(localName = "template") -//@JsonIgnoreProperties(ignoreUnknown = true) +/** + * General aiml template used for future parsing + * + * @author GroG + */ @JsonIgnoreProperties(ignoreUnknown = true) public class Template { - // @JacksonXmlElementWrapper(useWrapping = false) - + @JacksonXmlProperty(localName = "template") - @JacksonXmlText - public String text; - - -public Oob oob; - -// @JsonProperty("ignorable") -// public List oob; -// -// public List getOob() { -// return oob; -// } -// -// public void setOob(List oob) { -// this.oob = oob; -// } - + public String text; + + public Oob oob; + public static void main(String[] args) { try { - - // String xml = ""; - // String xml = ""; + String xml = ""; - + XmlMapper xmlMapper = new XmlMapper(); Template template = xmlMapper.readValue(xml, Template.class); - + System.out.println(template); - - } catch(Exception e) { + + } catch (Exception e) { e.printStackTrace(); } - } + } } diff --git a/src/test/java/org/myrobotlab/programab/TemplateTest.java b/src/test/java/org/myrobotlab/programab/TemplateTest.java new file mode 100644 index 0000000000..8d2beb245d --- /dev/null +++ b/src/test/java/org/myrobotlab/programab/TemplateTest.java @@ -0,0 +1,52 @@ +package org.myrobotlab.programab; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import org.junit.Test; +import org.myrobotlab.logging.LoggerFactory; +import org.myrobotlab.programab.models.Mrl; +import org.myrobotlab.programab.models.Template; +import org.slf4j.Logger; + +import com.fasterxml.jackson.dataformat.xml.XmlMapper; + +public class TemplateTest { + + public final static Logger log = LoggerFactory.getLogger(TemplateTest.class); + + @Test + public void testXmlParsing() { + try { + + String xml = ""; + + XmlMapper xmlMapper = new XmlMapper(); + Template template = xmlMapper.readValue(xml, Template.class); + + assertNotNull(template); + assertEquals("XXXX", template.text); + + // Verify Oob parsing + assertNotNull(template.oob); + assertEquals(2, template.oob.mrl.size()); + + // Verify the first Mrl + Mrl mrl1 = template.oob.mrl.get(0); + assertEquals("blah1", mrl1.service); + assertEquals("method1", mrl1.method); + assertEquals(3, mrl1.params.size()); + + // Verify the second Mrl + Mrl mrl2 = template.oob.mrl.get(1); + assertEquals("blah2", mrl2.service); + assertEquals("method2", mrl2.method); + assertNull(mrl2.params); + + } catch (Exception e) { + fail("Exception occurred: " + e.getMessage()); + } + } +} From 8d4fdb992b9bc75e81993e48fb87f73f8644fa65 Mon Sep 17 00:00:00 2001 From: grog Date: Tue, 23 Jan 2024 22:34:44 -0800 Subject: [PATCH 011/131] init scripts turned off --- src/main/java/org/myrobotlab/service/Python.java | 2 +- .../java/org/myrobotlab/service/config/InMoov2Config.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/Python.java b/src/main/java/org/myrobotlab/service/Python.java index c17a905f23..44f38f4bac 100644 --- a/src/main/java/org/myrobotlab/service/Python.java +++ b/src/main/java/org/myrobotlab/service/Python.java @@ -677,7 +677,7 @@ public void onStarted(String serviceName) { @Override public void onReleased(String serviceName) { - String registerScript = String.format("%s = None\n", CodecUtils.getSafeReferenceName(serviceName)); + String registerScript = String.format("%s = None\n", CodecUtils.getSafeReferenceName(CodecUtils.getShortName(serviceName))); exec(registerScript, false); } diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index 1a4cbf51fe..0a4937210a 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -68,17 +68,17 @@ public class InMoov2Config extends ServiceConfig { */ public long heartbeatInterval = 3000; - public boolean loadAppsScripts = true; + public boolean loadAppsScripts = false; /** * loads all python gesture files in the gesture directory */ - public boolean loadGestures = true; + public boolean loadGestures = false; /** * executes all scripts in the init directory on startup */ - public boolean loadInitScripts = true; + public boolean loadInitScripts = false; /** * default to null - allow the OS to set it, unless explicilty set @@ -546,7 +546,7 @@ public Plan getDefault(Plan plan, String name) { // mouth_audioFile.listeners.add(new Listener("publishAudioStart", name)); // Needs upcoming pr - // fsm.listeners.add(new Listener("publishStateChange", name)); + fsm.listeners.add(new Listener("publishStateChange", name)); return plan; } From 9aacb0b81e6401e0ebfc0444f8994d76cd19a800 Mon Sep 17 00:00:00 2001 From: grog Date: Fri, 26 Jan 2024 08:35:09 -0800 Subject: [PATCH 012/131] publishStateChange vs onStateChange --- .../org/myrobotlab/service/HtmlFilter.java | 28 ++++----- .../java/org/myrobotlab/service/InMoov2.java | 27 ++++---- .../org/myrobotlab/service/ProgramAB.java | 62 +++++++++++++------ .../service/config/InMoov2Config.java | 5 +- .../app/service/js/FiniteStateMachineGui.js | 1 + 5 files changed, 72 insertions(+), 51 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/HtmlFilter.java b/src/main/java/org/myrobotlab/service/HtmlFilter.java index ff0a4b4fb1..66134acd34 100644 --- a/src/main/java/org/myrobotlab/service/HtmlFilter.java +++ b/src/main/java/org/myrobotlab/service/HtmlFilter.java @@ -36,8 +36,7 @@ public HtmlFilter(String n, String id) { // helper function to add html tags public String addHtml(String text) { - HtmlFilterConfig c = (HtmlFilterConfig) config; - return c.preHtmlTag + text + c.postHtmlTag; + return config.preHtmlTag + text + config.postHtmlTag; } public void addTextListener(TextListener service) { @@ -45,18 +44,15 @@ public void addTextListener(TextListener service) { } public String getPostHtmlTag() { - HtmlFilterConfig c = (HtmlFilterConfig) config; - return c.postHtmlTag; + return config.postHtmlTag; } public String getPreHtmlTag() { - HtmlFilterConfig c = (HtmlFilterConfig) config; - return c.preHtmlTag; + return config.preHtmlTag; } public boolean isStripHtml() { - HtmlFilterConfig c = (HtmlFilterConfig) config; - return c.stripHtml; + return config.stripHtml; } @Override @@ -67,20 +63,20 @@ public void onText(String text) { @Override public String processText(String text) { - HtmlFilterConfig c = (HtmlFilterConfig) config; + invoke("publishRawText", text); String processedText = text; - if (c.stripHtml) { + if (config.stripHtml) { // clean text processedText = stripHtml(text); } else { processedText = addHtml(text); } - if (c.stripUrls) { + if (config.stripUrls) { processedText = stripUrls(processedText); } @@ -104,8 +100,8 @@ public String publishText(String text) { * - a string to append to the text */ public void setPostHtmlTag(String postHtmlTag) { - HtmlFilterConfig c = (HtmlFilterConfig) config; - c.postHtmlTag = postHtmlTag; + + config.postHtmlTag = postHtmlTag; } /** @@ -115,8 +111,7 @@ public void setPostHtmlTag(String postHtmlTag) { * - a string to prepend to the text. */ public void setPreHtmlTag(String preHtmlTag) { - HtmlFilterConfig c = (HtmlFilterConfig) config; - c.preHtmlTag = preHtmlTag; + config.preHtmlTag = preHtmlTag; } /** @@ -127,8 +122,7 @@ public void setPreHtmlTag(String preHtmlTag) { * - if true, all content between <and > will be removed. */ public void setStripHtml(boolean stripHtml) { - HtmlFilterConfig c = (HtmlFilterConfig) config; - c.stripHtml = stripHtml; + config.stripHtml = stripHtml; } // helper function to strip html tags. diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index 719025ce8c..ab6bb08b94 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -34,6 +34,7 @@ import org.myrobotlab.opencv.OpenCVData; import org.myrobotlab.programab.PredicateEvent; import org.myrobotlab.programab.Response; +import org.myrobotlab.service.FiniteStateMachine.StateChange; import org.myrobotlab.service.Log.LogEntry; import org.myrobotlab.service.abstracts.AbstractSpeechSynthesis; import org.myrobotlab.service.config.InMoov2Config; @@ -1388,6 +1389,8 @@ public void onStartSpeaking(String utterance) { } /** + * publishStateChange + * * The integration between the FiniteStateMachine (fsm) and the InMoov2 * service and potentially other services (Python, ProgramAB) happens here. * @@ -1405,22 +1408,19 @@ public void onStartSpeaking(String utterance) { * * Depending on config: * - * * @param stateChange * @return */ - public FiniteStateMachine.StateChange onStateChange(FiniteStateMachine.StateChange stateChange) { - try { - log.info("onStateChange {}", stateChange); - - lastState = state; - state = stateChange.state; + public StateChange publishStateChange(StateChange stateChange) { + log.info("publishStateChange {}", stateChange); + + log.info("onStateChange {}", stateChange); - processMessage("onStateChange", stateChange); + lastState = state; + state = stateChange.state; - } catch (Exception e) { - error(e); - } + processMessage("onStateChange", stateChange); + return stateChange; } @@ -1583,7 +1583,8 @@ public Heartbeat publishHeartbeat() { } if (System.currentTimeMillis() > stateLastIdleTime + (config.stateIdleInterval * 1000)) { - fsm.fire("idle"); + // idle event to be handled with the processor + processMessage("onIdle"); stateLastIdleTime = System.currentTimeMillis(); } @@ -1628,7 +1629,7 @@ public Heartbeat publishHeartbeat() { processMessage("onHeartbeat", heartbeat); return heartbeat; } - + /** * A more extensible interface point than publishEvent FIXME - create * interface for this diff --git a/src/main/java/org/myrobotlab/service/ProgramAB.java b/src/main/java/org/myrobotlab/service/ProgramAB.java index 332d546df9..804115b67e 100644 --- a/src/main/java/org/myrobotlab/service/ProgramAB.java +++ b/src/main/java/org/myrobotlab/service/ProgramAB.java @@ -97,7 +97,7 @@ public class ProgramAB extends Service boolean peerSearch = true; transient SimpleLogPublisher logPublisher = null; - + final transient private OobProcessor oobProcessor; /** @@ -762,7 +762,7 @@ public void addCategory(String pattern, String template, String that) { public void addCategory(String pattern, String template) { addCategory(pattern, template, "*"); } - + /** * Verifies and adds a new path to the search directories for bots * @@ -1103,7 +1103,7 @@ public ProgramABConfig apply(ProgramABConfig c) { addBotPath(botPath); } } - + if (c.botDir == null) { c.botDir = getResourceDir(); } @@ -1116,19 +1116,40 @@ public ProgramABConfig apply(ProgramABConfig c) { if (c.currentUserName != null) { setCurrentUserName(c.currentUserName); } - + if (c.currentBotName != null) { setCurrentBotName(c.currentBotName); - } - + } + if (c.startTopic != null) { - setTopic(c.startTopic); + setTopic(c.startTopic); } - return c; } + /** + * Set the current locale for this service. In ProgramAB's case if a bot + * matches the local then set the bot + * + */ + @Override + public void setLocale(String code) { + if (code == null) { + error("locale cannot be null"); + return; + } + locale = new Locale(code); + log.info("{} new locale is {}", getName(), code); + + for (String bot : bots.keySet()) { + if (code.equals(bot)) { + setCurrentBotName(bot); + } + } + broadcastState(); + } + public static void main(String args[]) { try { LoggingFactory.init("INFO"); @@ -1306,7 +1327,7 @@ public void sleep() { @Override public void onUtterance(Utterance utterance) throws Exception { - + log.info("Utterance Received " + utterance); boolean talkToBots = false; @@ -1371,17 +1392,18 @@ public void onUtterance(Utterance utterance) throws Exception { } } } - + /** * This receiver can take a config published by another service and sync * predicates from it + * * @param cfg */ public void onConfig(ServiceConfig cfg) { - Yaml yaml = new Yaml(); + Yaml yaml = new Yaml(); String yml = yaml.dumpAsMap(cfg); Map cfgMap = yaml.load(yml); - + for (Map.Entry entry : cfgMap.entrySet()) { if (entry.getValue() == null) { setPredicate("cfg_" + entry.getKey(), null); @@ -1389,7 +1411,7 @@ public void onConfig(ServiceConfig cfg) { setPredicate("cfg_" + entry.getKey(), entry.getValue().toString()); } } - + invoke("getPredicates"); } @@ -1402,19 +1424,19 @@ public TopicChange publishTopic(TopicChange topicChange) { return topicChange; } - public String getTopic() { + public String getTopic() { return getPredicate(getCurrentUserName(), "topic"); } - - public String getTopic(String username) { + + public String getTopic(String username) { return getPredicate(username, "topic"); } - - public void setTopic(String username, String topic) { + + public void setTopic(String username, String topic) { setPredicate(username, "topic", topic); } - - public void setTopic(String topic) { + + public void setTopic(String topic) { setPredicate(getCurrentUserName(), "topic", topic); } diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index 0a4937210a..1ec4694f0e 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -522,6 +522,7 @@ public Plan getDefault(Plan plan, String name) { // listeners.add(new Listener("publishProcessMessage", // getPeerName("python"), "onPythonMessage")); listeners.add(new Listener("publishProcessMessage", "python", "onPythonMessage")); + listeners.add(new Listener("publishPython", "python")); // InMoov2 --to--> InMoov2 @@ -535,6 +536,8 @@ public Plan getDefault(Plan plan, String name) { // service --to--> InMoov2 AudioFileConfig mouth_audioFile = (AudioFileConfig) plan.get(getPeerName("mouth.audioFile")); mouth_audioFile.listeners.add(new Listener("publishPeak", name)); + + htmlFilter.listeners.add(new Listener("publishText", name)); OakDConfig oakd = (OakDConfig) plan.get(getPeerName("oakd")); oakd.listeners.add(new Listener("publishClassification", name)); @@ -546,7 +549,7 @@ public Plan getDefault(Plan plan, String name) { // mouth_audioFile.listeners.add(new Listener("publishAudioStart", name)); // Needs upcoming pr - fsm.listeners.add(new Listener("publishStateChange", name)); + fsm.listeners.add(new Listener("publishStateChange", name, "publishStateChange")); return plan; } diff --git a/src/main/resources/resource/WebGui/app/service/js/FiniteStateMachineGui.js b/src/main/resources/resource/WebGui/app/service/js/FiniteStateMachineGui.js index 42c559c999..d08f8f2fc8 100644 --- a/src/main/resources/resource/WebGui/app/service/js/FiniteStateMachineGui.js +++ b/src/main/resources/resource/WebGui/app/service/js/FiniteStateMachineGui.js @@ -51,6 +51,7 @@ angular.module('mrlapp.service.FiniteStateMachineGui', []).controller('FiniteSta break case 'onStateChange': $scope.current = data.current + $scope.service.history.push(data) $scope.$apply() break default: From 4c9e5e0fd976f4d349bdd1b7d5f3338e20a79532 Mon Sep 17 00:00:00 2001 From: grog Date: Fri, 26 Jan 2024 15:04:48 -0800 Subject: [PATCH 013/131] execScript() --- .../java/org/myrobotlab/service/InMoov2.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index ab6bb08b94..146b72e68d 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -468,8 +468,7 @@ synchronized public void boot() { */ // load the InMoov2.py and publish it for Python/Jython or Py4j to consume - String script = getResourceAsString("InMoov2.py"); - invoke("publishPython", script); + execScript(); // TODO - MAKE BOOT REPORT !!!! deliver it on a heartbeat runtime.invoke("publishConfigList"); @@ -740,6 +739,14 @@ public String execGesture(String gesture) { } return python.evalAndWait(gesture); } + + /** + * Reload the InMoov2.py script + */ + public void execScript() { + execScript("InMoov2.py"); + } + /** * FIXME - I think there was lots of confusion of executing resources or just @@ -754,15 +761,9 @@ public String execGesture(String gesture) { * execute a resource script * @return success or failure */ - public boolean execScript(String someScriptName) { - try { - Python p = (Python) Runtime.start("python", "Python"); + public void execScript(String someScriptName) { String script = getResourceAsString(someScriptName); - return p.exec(script, true); - } catch (Exception e) { - error("unable to execute script %s", someScriptName); - return false; - } + invoke("publishPython", script); } public void finishedGesture() { @@ -1801,6 +1802,7 @@ public void releasePeer(String peerKey) { invoke("publishEvent", "STOPPED " + peerKey); } } + @Override public void releaseService() { From 5bbdfe0e997a73b89ecb448e90820149da64baee Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 28 Jan 2024 09:54:22 -0800 Subject: [PATCH 014/131] config utils --- .../org/myrobotlab/config/ConfigUtils.java | 71 +++++++++++++++++++ .../org/myrobotlab/framework/Service.java | 16 ++--- src/main/java/org/myrobotlab/io/FileIO.java | 36 +++------- .../java/org/myrobotlab/service/InMoov2.java | 14 +++- .../java/org/myrobotlab/service/Runtime.java | 14 +++- .../service/config/InMoov2Config.java | 2 - .../java/org/myrobotlab/io/FileIOTest.java | 5 -- 7 files changed, 113 insertions(+), 45 deletions(-) create mode 100644 src/main/java/org/myrobotlab/config/ConfigUtils.java diff --git a/src/main/java/org/myrobotlab/config/ConfigUtils.java b/src/main/java/org/myrobotlab/config/ConfigUtils.java new file mode 100644 index 0000000000..35c8a776a8 --- /dev/null +++ b/src/main/java/org/myrobotlab/config/ConfigUtils.java @@ -0,0 +1,71 @@ +package org.myrobotlab.config; + +import java.io.File; +import java.io.IOException; + +import org.myrobotlab.codec.CodecUtils; +import org.myrobotlab.framework.StartYml; +import org.myrobotlab.io.FileIO; +import org.myrobotlab.service.Runtime; +import org.myrobotlab.service.config.RuntimeConfig; + +public class ConfigUtils { + + /** + * This gets the current resource root without starting a Runtime instance if + * not already started. The resource root depends on config, if Runtime is + * running the logic and current config name is already available. If Runtime + * is not running, we need to go through a series of steps to deterime where + * the resource root is configured. + * + * @return + */ + public static String getResourceRoot() { + + String resource = "resource"; + + // check if runtime is running + if (!Runtime.isAvailable()) { + // check for start.yml + + File checkStartYml = new File("start.yml"); + StartYml startYml = new StartYml(); + if (checkStartYml.exists()) { + String yml; + try { + yml = FileIO.toString("start.yml"); + startYml = CodecUtils.fromYaml(yml, StartYml.class); + + // see if autostart is on with a config + if (startYml.enable) { + // use that config to find runtime.yml + + File runtimeYml = new File(Runtime.ROOT_CONFIG_DIR + File.separator + startYml.config + File.separator + "runtime.yml"); + if (runtimeYml.exists()) { + // parse that file look for resource: entry in file + RuntimeConfig config = (RuntimeConfig) CodecUtils.readServiceConfig(runtimeYml.getAbsolutePath()); + resource = config.resource; + } + + } else { + // start.yml enable = false / so we'll use default config + File runtimeYml = new File(Runtime.ROOT_CONFIG_DIR + File.separator + "default" + File.separator + "runtime.yml"); + if (runtimeYml.exists()) { + // parse that file look for resource: entry in file + RuntimeConfig config = (RuntimeConfig) CodecUtils.readServiceConfig(runtimeYml.getAbsolutePath()); + resource = config.resource; + } + } + + } catch (IOException e) { + // problem getting or parsing + // going to assume default "resource" + } + } // no startYml + return resource; + } else { + // Runtime is available - ask it + return Runtime.getInstance().getConfig().resource; + } + } +} diff --git a/src/main/java/org/myrobotlab/framework/Service.java b/src/main/java/org/myrobotlab/framework/Service.java index 8f0d4ad2bf..95e23a5616 100644 --- a/src/main/java/org/myrobotlab/framework/Service.java +++ b/src/main/java/org/myrobotlab/framework/Service.java @@ -57,6 +57,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import org.myrobotlab.codec.CodecUtils; +import org.myrobotlab.config.ConfigUtils; import org.myrobotlab.framework.interfaces.Attachable; import org.myrobotlab.framework.interfaces.Broadcaster; import org.myrobotlab.framework.interfaces.ConfigurableService; @@ -474,22 +475,15 @@ static public String getResourceDir(Class clazz, String additionalPath) { * then it needs an instance of Runtime which is not available. * */ - @Deprecated /* this should not be static - remove it */ static public String getResourceDir(String serviceType, String additionalPath) { // setting resource directory - String resourceDir = null; + String resource = ConfigUtils.getResourceRoot() + fs + serviceType; - // stupid solution to get past static problem - if (!"Runtime".equals(serviceType)) { - resourceDir = Runtime.getInstance().getConfig().resource + fs + serviceType; - } else { - resourceDir = "resource"; - } if (additionalPath != null) { - resourceDir = FileIO.gluePaths(resourceDir, additionalPath); + resource = FileIO.gluePaths(resource, additionalPath); } - return resourceDir; + return resource; } /** @@ -516,7 +510,7 @@ public String getResourcePath(String additionalPath) { */ static public String getResourceRoot() { - return Runtime.getInstance().getConfig().resource; + return ConfigUtils.getResourceRoot();//Runtime.getInstance().getConfig().resource; } /** diff --git a/src/main/java/org/myrobotlab/io/FileIO.java b/src/main/java/org/myrobotlab/io/FileIO.java index 2cdad66af2..8b3fe189c4 100644 --- a/src/main/java/org/myrobotlab/io/FileIO.java +++ b/src/main/java/org/myrobotlab/io/FileIO.java @@ -58,8 +58,8 @@ import java.util.zip.ZipException; import org.apache.commons.io.Charsets; +import org.myrobotlab.config.ConfigUtils; import org.myrobotlab.framework.Platform; -import org.myrobotlab.framework.Service; import org.myrobotlab.logging.Level; import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.logging.Logging; @@ -854,8 +854,6 @@ public static void main(String[] args) throws ZipException, IOException { f = new File(uri); log.info("{} exists {}", uri, f.exists()); - log.info("isJar : {}", isJar()); - } catch (Exception e) { Logging.logError(e); } @@ -870,33 +868,22 @@ public static void main(String[] args) throws ZipException, IOException { * Python/examples/someFile.py * @return byte array */ - @Deprecated /* user Service.getResource(src) */ static public final byte[] resourceToByteArray(String src) { - // this path assumes in a jar ? - // String filename = "/resource/" + src; - log.info("looking for Resource {}", src); + log.info("looking for resource {}", src); InputStream isr = null; - if (isJar()) { - // this path assumes in a jar ? ensure it's forward slashes - String filename = "/resource/" + src.replace("\\", "/"); - isr = FileIO.class.getResourceAsStream(filename); - } else { - String localFilename = Service.getResourceRoot() + File.separator + src; - try { - isr = new FileInputStream(localFilename); - } catch (Exception e) { - Logging.logError(e); - log.error("File not found. {}", localFilename, e); - return null; - } + String resource = ConfigUtils.getResourceRoot(); + String localFilename = resource + File.separator + src; + try { + isr = new FileInputStream(localFilename); + } catch (Exception e) { + Logging.logError(e); + log.error("file not found. {}", localFilename, e); + return null; } + byte[] data = null; try { - if (isr == null) { - log.error("can not find resource [{}]", src); - return null; - } data = toByteArray(isr); } finally { try { @@ -918,7 +905,6 @@ static public final byte[] resourceToByteArray(String src) { * Python/examples/someFile.py * @return string */ - @Deprecated /* use Service.getResourceAsString(src) */ static public final String resourceToString(String src) { byte[] bytes = resourceToByteArray(src); if (bytes == null) { diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index 146b72e68d..0248333656 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -890,13 +890,18 @@ public Object getPredicate(String key) { return null; } + /** + * getResponse from ProgramAB + * @param text + * @return + */ public Response getResponse(String text) { ProgramAB chatBot = (ProgramAB) getPeer("chatBot"); if (chatBot != null) { Response response = chatBot.getResponse(text); return response; } else { - log.info("chatbot not ready"); + log.warn("chatbot not ready"); } return null; } @@ -2044,6 +2049,13 @@ public boolean setSpeechType(String speechType) { // updatePeerType("mouth" /* getPeerName("mouth") */, speechType); // return speechType; } + + public void setTopic(String topic) { + ProgramAB chatBot = (ProgramAB)getPeer("chatBot"); + if (chatBot != null) { + chatBot.setTopic(topic); + } + } public void setTorsoSpeed(Double topStom, Double midStom, Double lowStom) { sendToPeer("torso", "setSpeed", topStom, midStom, lowStom); diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 2b4b40e59f..a989e7046a 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -229,7 +229,7 @@ public class Runtime extends Service implements MessageListener, /** * default parent path of configPath static ! */ - final static protected String ROOT_CONFIG_DIR = DATA_DIR + fs + "config"; + public final static String ROOT_CONFIG_DIR = DATA_DIR + fs + "config"; /** * number of services created by this runtime @@ -926,6 +926,10 @@ public static Runtime getInstance() { Runtime.startConfig(options.config); } else if (startYml != null && startYml.config != null && startYml.enable) { Runtime.startConfig(startYml.config); + } else { + RuntimeConfig rtConfig = runtime.readServiceConfig(runtime.getConfigName(), "runtime", new StaticType<>() { + }); + runtime.apply(rtConfig); } } catch (Exception e) { log.info("runtime will not be loading config"); @@ -5408,4 +5412,12 @@ public static void removeConfig(String configName) { } } + /** + * Method used to determine is runtime is running without starting it + * @return true if available + */ + static public boolean isAvailable() { + return runtime != null && runtime.isRunning(); + } + } diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index 1ec4694f0e..13eefd7b56 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -266,8 +266,6 @@ public Plan getDefault(Plan plan, String name) { } } - chatBot.currentUserName = "human"; - chatBot.listeners.add(new Listener("publishText", name + ".htmlFilter", "onText")); Gpt3Config gpt3 = (Gpt3Config) plan.get(getPeerName("gpt3")); diff --git a/src/test/java/org/myrobotlab/io/FileIOTest.java b/src/test/java/org/myrobotlab/io/FileIOTest.java index a8700219a8..c554835175 100644 --- a/src/test/java/org/myrobotlab/io/FileIOTest.java +++ b/src/test/java/org/myrobotlab/io/FileIOTest.java @@ -134,11 +134,6 @@ public void testGluePaths() { assertEquals("/abc/def/", ret); } - @Test - public void testIsJar() { - assertFalse(FileIO.isJar()); - } - @Test public void testGetFileListString() throws IOException { String dir = FileIO.gluePaths(tempDir, "testGetFileListString"); From 565f9ddf6288e59c1b742ba5f58cb8030f408eea Mon Sep 17 00:00:00 2001 From: grog Date: Tue, 30 Jan 2024 05:18:11 -0800 Subject: [PATCH 015/131] set chatBot reference on startService added setup to fsm --- .../java/org/myrobotlab/service/InMoov2.java | 95 ++++++++++--------- .../service/config/InMoov2Config.java | 8 +- 2 files changed, 55 insertions(+), 48 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index 0248333656..3db43b416e 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -739,7 +739,7 @@ public String execGesture(String gesture) { } return python.evalAndWait(gesture); } - + /** * Reload the InMoov2.py script */ @@ -747,7 +747,6 @@ public void execScript() { execScript("InMoov2.py"); } - /** * FIXME - I think there was lots of confusion of executing resources or just * a file on the file system ... "execScript" I would expect to be just a file @@ -762,8 +761,8 @@ public void execScript() { * @return success or failure */ public void execScript(String someScriptName) { - String script = getResourceAsString(someScriptName); - invoke("publishPython", script); + String script = getResourceAsString(someScriptName); + invoke("publishPython", script); } public void finishedGesture() { @@ -880,30 +879,23 @@ public OpenCV getOpenCV() { return opencv; } - public Object getPredicate(String key) { - ProgramAB chatBot = (ProgramAB) getPeer("chatBot"); - if (chatBot != null) { - return chatBot.getPredicate(key); - } else { - error("no chatBot available"); - } - return null; + public String getPredicate(String key) { + return getPredicate(chatBot.getConfig().currentUserName, key); + } + + public String getPredicate(String user, String key) { + return chatBot.getPredicate(user, key); } /** * getResponse from ProgramAB + * * @param text * @return */ public Response getResponse(String text) { - ProgramAB chatBot = (ProgramAB) getPeer("chatBot"); - if (chatBot != null) { - Response response = chatBot.getResponse(text); - return response; - } else { - log.warn("chatbot not ready"); - } - return null; + Response response = chatBot.getResponse(text); + return response; } public InMoov2Arm getRightArm() { @@ -965,6 +957,22 @@ public void halfSpeed() { sendToPeer("torso", "setSpeed", 20.0, 20.0, 20.0); } + /** + * If there have been any errors + * + * @return + */ + public boolean hasErrors() { + return errors.size() > 0; + } + + /** + * clear all errors + */ + public void clearErrors() { + errors.clear(); + } + public boolean isCameraOn() { if (opencv != null) { if (opencv.isCapturing()) { @@ -1306,12 +1314,9 @@ public void onPeak(double volume) { public void onPirOn() { // FIXME flash on config.flashOnBoot invoke("publishFlash", "pir"); - ProgramAB chatBot = (ProgramAB) getPeer("chatBot"); - if (chatBot != null) { - String botState = chatBot.getPredicate("botState"); - if ("sleeping".equals(botState)) { - invoke("publishEvent", "WAKE"); - } + String botState = chatBot.getPredicate("botState"); + if ("sleeping".equals(botState)) { + invoke("publishEvent", "WAKE"); } } @@ -1419,14 +1424,14 @@ public void onStartSpeaking(String utterance) { */ public StateChange publishStateChange(StateChange stateChange) { log.info("publishStateChange {}", stateChange); - + log.info("onStateChange {}", stateChange); lastState = state; state = stateChange.state; processMessage("onStateChange", stateChange); - + return stateChange; } @@ -1561,6 +1566,9 @@ public String publishFlash(String flashName) { } /** + * FIXME - get rid of all functionality here - should all be controlled by + * behaviors + * * A heartbeat that continues to check status, and fire events to the FSM. * Checks battery, flashes leds and processes all the configured checks in * onHeartbeat at a regular interval @@ -1635,7 +1643,7 @@ public Heartbeat publishHeartbeat() { processMessage("onHeartbeat", heartbeat); return heartbeat; } - + /** * A more extensible interface point than publishEvent FIXME - create * interface for this @@ -1807,7 +1815,6 @@ public void releasePeer(String peerKey) { invoke("publishEvent", "STOPPED " + peerKey); } } - @Override public void releaseService() { @@ -1984,15 +1991,10 @@ public boolean setPirPlaySounds(boolean b) { } public Object setPredicate(String key, Object data) { - ProgramAB chatBot = (ProgramAB) getPeer("chatBot"); - if (chatBot != null) { - if (data == null) { - chatBot.setPredicate(key, null); // "unknown" "null" other sillyness ? - } else { - chatBot.setPredicate(key, data.toString()); - } + if (data == null) { + chatBot.setPredicate(key, null); // "unknown" "null" other sillyness ? } else { - error("no chatBot available"); + chatBot.setPredicate(key, data.toString()); } return data; } @@ -2049,12 +2051,9 @@ public boolean setSpeechType(String speechType) { // updatePeerType("mouth" /* getPeerName("mouth") */, speechType); // return speechType; } - + public void setTopic(String topic) { - ProgramAB chatBot = (ProgramAB)getPeer("chatBot"); - if (chatBot != null) { - chatBot.setTopic(topic); - } + chatBot.setTopic(topic); } public void setTorsoSpeed(Double topStom, Double midStom, Double lowStom) { @@ -2159,7 +2158,6 @@ public void startBrain() { public ProgramAB startChatBot() { try { - chatBot = (ProgramAB) startPeer("chatBot"); if (locale != null) { chatBot.setCurrentBotName(locale.getTag()); @@ -2309,6 +2307,15 @@ public void startService() { // a FSM ProgramAB and some form of Python/Jython fsm = (FiniteStateMachine) startPeer("fsm"); + // Chatbot is a required part of InMoov2 + chatBot = (ProgramAB) startPeer("chatBot"); + try { + chatBot.startSession(); + chatBot.setPredicate("robot", getName()); + } catch (IOException e) { + error(e); + } + // A python process is required - should be defined as a peer // of Type Python or Py4j diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index 13eefd7b56..e567016cdc 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -362,16 +362,16 @@ public Plan getDefault(Plan plan, String name) { // exists ? fsm.current = "boot"; fsm.transitions.add(new Transition("boot", "wake", "wake")); - fsm.transitions.add(new Transition("wake", "idle", "idle")); - fsm.transitions.add(new Transition("first_init", "idle", "idle")); + // fsm.transitions.add(new Transition("wake", "idle", "idle")); wake, setup, nor sleep should be affected by idle + fsm.transitions.add(new Transition("setup", "setup_done", "idle")); fsm.transitions.add(new Transition("idle", "random", "random")); fsm.transitions.add(new Transition("random", "idle", "idle")); fsm.transitions.add(new Transition("idle", "sleep", "sleep")); fsm.transitions.add(new Transition("sleep", "wake", "wake")); fsm.transitions.add(new Transition("sleep", "power_down", "power_down")); fsm.transitions.add(new Transition("idle", "power_down", "power_down")); - fsm.transitions.add(new Transition("wake", "first_init", "first_init")); - fsm.transitions.add(new Transition("idle", "first_init", "first_init")); + fsm.transitions.add(new Transition("wake", "setup", "setup")); + fsm.transitions.add(new Transition("idle", "setup", "setup")); // power_down to shutdown // fsm.transitions.add(new Transition("systemCheck", "systemCheckFinished", // "awake")); From d2510bc16a2b4e995e4258a39c4d4a7a7217695b Mon Sep 17 00:00:00 2001 From: grog Date: Thu, 1 Feb 2024 08:28:33 -0800 Subject: [PATCH 016/131] working processor action in servomixer --- .../org/myrobotlab/kinematics/Action.java | 7 + .../java/org/myrobotlab/service/Py4j.java | 7 +- .../java/org/myrobotlab/service/Python.java | 3 +- .../org/myrobotlab/service/ServoMixer.java | 681 +++++++++--------- .../service/config/ServoMixerConfig.java | 5 + .../service/interfaces/Processor.java | 18 + .../WebGui/app/service/js/ServoMixerGui.js | 8 + .../app/service/views/ServoMixerGui.html | 8 +- 8 files changed, 392 insertions(+), 345 deletions(-) create mode 100644 src/main/java/org/myrobotlab/service/interfaces/Processor.java diff --git a/src/main/java/org/myrobotlab/kinematics/Action.java b/src/main/java/org/myrobotlab/kinematics/Action.java index afb159ffcb..6eb4108fda 100644 --- a/src/main/java/org/myrobotlab/kinematics/Action.java +++ b/src/main/java/org/myrobotlab/kinematics/Action.java @@ -57,4 +57,11 @@ public static Action createGestureToAction(String gestureName) { action.value = gestureName; return action; } + + public static Action createProcessingAction(String methodName) { + Action action = new Action(); + action.type = "process"; + action.value = methodName; + return action; + } } diff --git a/src/main/java/org/myrobotlab/service/Py4j.java b/src/main/java/org/myrobotlab/service/Py4j.java index 16b335f455..d5530fc50d 100644 --- a/src/main/java/org/myrobotlab/service/Py4j.java +++ b/src/main/java/org/myrobotlab/service/Py4j.java @@ -25,6 +25,7 @@ import org.myrobotlab.service.data.Script; import org.myrobotlab.service.interfaces.Executor; import org.myrobotlab.service.interfaces.Gateway; +import org.myrobotlab.service.interfaces.Processor; import org.slf4j.Logger; import py4j.GatewayServer; @@ -54,7 +55,7 @@ * * @author GroG */ -public class Py4j extends Service implements GatewayServerListener, Gateway { +public class Py4j extends Service implements GatewayServerListener, Gateway, Processor { /** * POJO class to tie all the data elements of a external python process @@ -235,17 +236,19 @@ public void connectionStopped(Py4JServerConnection gatewayConnection) { * * @param code The Python code to execute in the interpreter. */ - public void exec(String code) { + public boolean exec(String code) { log.info(String.format("exec %s", code)); try { if (handler != null) { handler.exec(code); + return true; } else { error("handler is null"); } } catch (Exception e) { error(e); } + return false; } private String getClientKey(Py4JServerConnection gatewayConnection) { diff --git a/src/main/java/org/myrobotlab/service/Python.java b/src/main/java/org/myrobotlab/service/Python.java index 90502146f2..77fd9fd529 100644 --- a/src/main/java/org/myrobotlab/service/Python.java +++ b/src/main/java/org/myrobotlab/service/Python.java @@ -25,6 +25,7 @@ import org.myrobotlab.logging.LoggingFactory; import org.myrobotlab.service.config.PythonConfig; import org.myrobotlab.service.data.Script; +import org.myrobotlab.service.interfaces.Processor; import org.myrobotlab.service.interfaces.ServiceLifeCycleListener; import org.myrobotlab.service.meta.abstracts.MetaData; import org.python.core.Py; @@ -49,7 +50,7 @@ * @author GroG * */ -public class Python extends Service implements ServiceLifeCycleListener, MessageListener { +public class Python extends Service implements ServiceLifeCycleListener, MessageListener, Processor { /** * this thread handles all callbacks to Python process all input and sets msg diff --git a/src/main/java/org/myrobotlab/service/ServoMixer.java b/src/main/java/org/myrobotlab/service/ServoMixer.java index 644557185b..5e20888104 100755 --- a/src/main/java/org/myrobotlab/service/ServoMixer.java +++ b/src/main/java/org/myrobotlab/service/ServoMixer.java @@ -15,7 +15,6 @@ import java.util.concurrent.Executors; import org.myrobotlab.codec.CodecUtils; -import org.myrobotlab.framework.Message; import org.myrobotlab.framework.Registration; import org.myrobotlab.framework.Service; import org.myrobotlab.framework.interfaces.Attachable; @@ -28,6 +27,7 @@ import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.logging.LoggingFactory; import org.myrobotlab.service.config.ServoMixerConfig; +import org.myrobotlab.service.interfaces.Processor; import org.myrobotlab.service.interfaces.SelectListener; import org.myrobotlab.service.interfaces.ServiceLifeCycleListener; import org.myrobotlab.service.interfaces.ServoControl; @@ -44,31 +44,6 @@ */ public class ServoMixer extends Service implements ServiceLifeCycleListener, SelectListener { - public class PlayingGesture { - public String name; - public Gesture gesture; - public int startIndex = 0; - - public PlayingGesture(String name, Gesture gesture) { - this(name, gesture, 0); - } - - public PlayingGesture(String name, Gesture gesture, int index) { - this.name = name; - this.gesture = gesture; - this.startIndex = index; - } - - public String toString() { - int actionCnt = 0; - if (gesture != null && gesture.actions != null) { - actionCnt = gesture.actions.size(); - } - return String.format("name:%s actionCnt:%d index:%d", name, actionCnt, startIndex); - } - - } - /** * The Player plays a requested gesture, which is a sequence of Poses. Poses * can be positions, delays, or speech. It publishes when it starts a gesture @@ -78,10 +53,10 @@ public String toString() { * */ public class Player implements Runnable { - protected String playingGesture = null; - protected boolean running = false; transient private ExecutorService executor; + protected String playingGesture = null; transient Deque playStack = new ArrayDeque<>(); + protected boolean running = false; // FIXME - add optional start index to start playing at a midpoint private void play() { @@ -188,8 +163,17 @@ public void processAction(PlayingGesture current, int i) { case "speak": speak((Map) action.value); break; - case "msg": - invoke("publishProcessMessage", (Message) action.value); + case "process": + + if (config.processor != null) { + Processor processor = (Processor) Runtime.getService(config.processor); + String code = (String) action.value; + if (!processor.exec(code)) { + error("could not execute %s", code); + } + } else { + error("no processor"); + } break; default: { error("do not know how to handle gesture part of type %s", action.type); @@ -232,16 +216,102 @@ public void stop() { } } + public class PlayingGesture { + public Gesture gesture; + public String name; + public int startIndex = 0; + + public PlayingGesture(String name, Gesture gesture) { + this(name, gesture, 0); + } + + public PlayingGesture(String name, Gesture gesture, int index) { + this.name = name; + this.gesture = gesture; + this.startIndex = index; + } + + public String toString() { + int actionCnt = 0; + if (gesture != null && gesture.actions != null) { + actionCnt = gesture.actions.size(); + } + return String.format("name:%s actionCnt:%d index:%d", name, actionCnt, startIndex); + } + + } + public final static Logger log = LoggerFactory.getLogger(InMoov2.class); private static final long serialVersionUID = 1L; + public static void main(String[] args) throws Exception { + + try { + Runtime.main(new String[] { "--id", "admin" }); + LoggingFactory.init("INFO"); + + Runtime.start("i01.head.rothead", "Servo"); + Runtime.start("i01.head.neck", "Servo"); + WebGui webgui = (WebGui) Runtime.create("webgui", "WebGui"); + webgui.autoStartBrowser(false); + webgui.startService(); + Python python = (Python) Runtime.start("python", "Python"); + ServoMixer mixer = (ServoMixer) Runtime.start("mixer", "ServoMixer"); + // mixer.playGesture(""); + + boolean done = true; + if (done) { + return; + } + + mixer.addNewGestureFile("test"); + Gesture gesture = mixer.getGesture("test"); + String gestureName = "aaa"; + String servoName = "i01.head.rothead"; + Double position = 90.0; + Double speed = null; + + Map> moves = new TreeMap<>(); + + Map poseMove1 = new TreeMap<>(); + poseMove1.put("position", 90.0); + + Map poseMove2 = new TreeMap<>(); + poseMove2.put("position", 90); + poseMove2.put("speed", 35.0); + + moves.put("i01.head.rothead", poseMove1); + moves.put("i01.head.neck", poseMove2); + + mixer.openGesture(gestureName); + mixer.addMoveToAction(moves); // autofill delay from keyframe ? + mixer.saveGesture(); + + mixer.addNewGestureFile("test2"); + + // mixer.save(gestureName); + mixer.addGestureToAction("test"); + + mixer.saveGesture(); + + // mixer.setPose("test", ) + } catch (Exception e) { + log.error("main threw", e); + } + } + + // TODO selected servos + /** * Set of servo names kept in sync with current registry */ protected Set allServos = new TreeSet<>(); - // TODO selected servos + /** + * gesture name of the currentGesture + */ + protected String currentEditGestureName = null; /** * current gesture being edited @@ -253,13 +323,67 @@ public void stop() { */ final protected transient Player player = new Player(); + public ServoMixer(String n, String id) { + super(n, id); + } + + public void addAction(Action action, Integer index) { + if (currentGesture == null) { + error("current gesture not set"); + return; + } + if (index != null) { + if (currentGesture.actions.size() == 0) { + currentGesture.actions.add(action); + } else { + currentGesture.actions.add(index, action); + } + } else { + currentGesture.actions.add(action); + } + } + + public void addGestureToAction(String gestureName) { + addGestureToAction(gestureName, null); + }; + + public void addGestureToAction(String gestureName, Integer index) { + addAction(Action.createGestureToAction(gestureName), index); + } + + public void addMoveToAction(List servos) { + addMoveToAction(servos, null); + } + /** - * gesture name of the currentGesture + * list of servos to add to an action - they're current speed and input + * positions will be added at index + * + * @param servos + * @param index */ - protected String currentEditGestureName = null; + public void addMoveToAction(List servos, Integer index) { + Map> moves = new TreeMap<>(); + for (String servoName : servos) { + ServoControl sc = (ServoControl) Runtime.getService(servoName); + Map posAndSpeed = new TreeMap<>(); + if (sc == null) { + error("%s not a valid service name", servoName); + continue; + } + posAndSpeed.put("position", sc.getCurrentInputPos()); + posAndSpeed.put("speed", sc.getSpeed()); + moves.put(servoName, posAndSpeed); + } + addAction(Action.createMoveToAction(moves), index); + } - public ServoMixer(String n, String id) { - super(n, id); + public void addMoveToAction(Map> moves) { + addMoveToAction(moves, null); + } + + public void addMoveToAction(Map> moves, Integer index) { + addAction(Action.createMoveToAction(moves), index); } /** @@ -294,10 +418,28 @@ public String addNewGestureFile(String name) { return filename; } - public void saveGesture(String name) { - // FIXME - warn if overwrite - // FIXME - don't warn if opened - saveGesture(name, currentGesture); + public void addProcessingAction(String methodName) { + addProcessingAction(methodName, null); + } + + public void addProcessingAction(String methodName, Integer index) { + addAction(Action.createProcessingAction(methodName), index); + } + + public void addSleepAction(double sleep) { + addSleepAction(sleep, null); + } + + public void addSleepAction(double sleep, Integer index) { + addAction(Action.createSleepAction(sleep), index); + } + + public void addSpeakAction(Map speechCommand) { + addSpeakAction(speechCommand, null); + } + + public void addSpeakAction(Map speechCommand, Integer index) { + addAction(Action.createSpeakAction(speechCommand), index); } /** @@ -308,24 +450,14 @@ public void attach(Attachable attachable) { if (attachable instanceof Servo) { attachServo((Servo) attachable); } - }; + } /** * attach(String) should always have the implementation */ @Override public void attach(String name) { - allServos.add(name); - // refresh subscribers - invoke("getServos"); - } - - /** - * detach(String) should always have the implementation - */ - @Override - public void detach(String name) { - allServos.remove(name); + allServos.add(name); // refresh subscribers invoke("getServos"); } @@ -341,6 +473,20 @@ public void attachServo(Servo servo) { attach(servo.getName()); } + /** + * detach(String) should always have the implementation + */ + @Override + public void detach(String name) { + allServos.remove(name); + // refresh subscribers + invoke("getServos"); + } + + public Gesture getGesture() { + return currentGesture; + } + public Gesture getGesture(String name) { Gesture gesture = null; @@ -404,9 +550,10 @@ public List getGestureFiles() { public String getPosesDirectory() { return config.posesDir; } - + /** * get a refreshed ordered list of servos + * * @return */ public Set getServos() { @@ -431,34 +578,61 @@ public List listAllServos() { return servos; } - public void step(int index) { - step(currentEditGestureName, index); - } - - public void step(String gestureName, int index) { - - if (gestureName == null) { - error("gesture name cannot be null"); + public void moveActionDown(int index) { + if (currentGesture == null) { + error("cannot move: gesture not set"); return; } - if (!gestureName.equals(currentEditGestureName)) { - // load gesture - getGesture(gestureName); + List list = currentGesture.actions; + + if (index >= 0 && index < list.size() - 1) { + Action action = list.remove(index); + list.add(index + 1, action); + } else { + error("index out of range or at the end of the list."); } + invoke("getGesture"); + } + public void moveActionUp(int index) { if (currentGesture == null) { - error("gesture cannot be nulle"); + error("cannot move gesture not set"); return; } - player.processAction(new PlayingGesture(gestureName, currentGesture), index); - // step to next action - index++; - if (index < currentGesture.actions.size()) { - Action action = currentGesture.actions.get(index); - invoke("publishPlayingAction", action); - invoke("publishPlayingActionIndex", index); + List list = currentGesture.actions; + + if (index > 0 && index < list.size()) { + Action action = list.remove(index); + list.add(index - 1, action); + } else { + error("index out of range or at the beginning of the list."); + } + invoke("getGesture"); + } + + private void moveTo(String servoName, Map move) { + ServoControl servo = (ServoControl) Runtime.getService(servoName); + if (servo == null) { + warn("servo (%s) cannot move to pose because it does not exist", servoName); + return; + } + + Object speed = move.get("speed"); + if (speed != null) { + if (speed instanceof Integer) { + servo.setSpeed((Integer) speed); + } else if (speed instanceof Double) { + servo.setSpeed((Double) speed); + } + } + + Object position = move.get("position"); + if (position instanceof Integer) { + servo.moveTo((Integer) position); + } else if (position instanceof Double) { + servo.moveTo((Double) position); } } @@ -534,6 +708,24 @@ public void onStarted(String name) { public void onStopped(String name) { } + public Gesture openGesture(String name) { + if (currentGesture != null) { + warn("replacing current gesture"); + // prompt user return null etc. + } + + Gesture gesture = getGesture(name); + if (gesture == null) { + // gesture not found make new + gesture = new Gesture(); + } + + currentEditGestureName = name; + currentGesture = gesture; + + return currentGesture; + } + public void playGesture(String name) { // Gesture gesture = (Gesture) broadcast("getGesture", name); invoke("getGesture", name); @@ -585,17 +777,6 @@ public String publishPlayingPose(String name) { return name; } - /** - * Processing publishing point, where everything InMoov2 wants to be processed - * is turned into a message and published. - * - * @param msg - * @return - */ - public Message publishProcessMessage(Message msg) { - return msg; - } - public String publishStopPose(String name) { return name; } @@ -611,6 +792,23 @@ public String publishText(String text) { return text; } + public void removeActionFromGesture(int index) { + try { + + Gesture gesture = getGesture(); + if (gesture == null) { + error("gesture not set"); + return; + } + if (gesture.actions.size() != 0 && index < gesture.actions.size()) { + gesture.actions.remove(index); + } + + } catch (Exception e) { + error(e); + } + } + public void removeGesture(String name) { try { @@ -632,57 +830,6 @@ public void removeGesture(String name) { } } - public void moveActionUp(int index) { - if (currentGesture == null) { - error("cannot move gesture not set"); - return; - } - - List list = currentGesture.actions; - - if (index > 0 && index < list.size()) { - Action action = list.remove(index); - list.add(index - 1, action); - } else { - error("index out of range or at the beginning of the list."); - } - invoke("getGesture"); - } - - public void moveActionDown(int index) { - if (currentGesture == null) { - error("cannot move: gesture not set"); - return; - } - - List list = currentGesture.actions; - - if (index >= 0 && index < list.size() - 1) { - Action action = list.remove(index); - list.add(index + 1, action); - } else { - error("index out of range or at the end of the list."); - } - invoke("getGesture"); - } - - public void removeActionFromGesture(int index) { - try { - - Gesture gesture = getGesture(); - if (gesture == null) { - error("gesture not set"); - return; - } - if (gesture.actions.size() != 0 && index < gesture.actions.size()) { - gesture.actions.remove(index); - } - - } catch (Exception e) { - error(e); - } - } - public void rest() { for (String servo : allServos) { Servo s = (Servo) Runtime.getService(servo); @@ -690,6 +837,17 @@ public void rest() { } } + public void saveGesture() { + // FIXME check if exists - ask overwrite + saveGesture(currentEditGestureName, currentGesture); + } + + public void saveGesture(String name) { + // FIXME - warn if overwrite + // FIXME - don't warn if opened + saveGesture(name, currentGesture); + } + /** * Takes name of a file and a json encoded string of a gesture, saves it to * file and sets the "current" gesture to the data @@ -767,6 +925,32 @@ public void setPosesDirectory(String posesDirectory) { broadcastState(); } + private void speak(Map speechPart) { + if (config.mouth == null) { + warn("mouth configuration not set"); + return; + } + SpeechSynthesis mouth = (SpeechSynthesis) Runtime.getService(config.mouth); + if (mouth == null) { + error("%s speech synthesis service missing", config.mouth); + return; + } + try { + // makes it harder to block + // FIXME if blocking send(mouthName, "speak") + // TODO - show multiple SpeechSynthesis select like Servos + Boolean blocking = (Boolean) speechPart.get("blocking"); + // if (blocking != null && blocking) { + mouth.speakBlocking((String) speechPart.get("text")); // default blocking + // } else { + // mouth.speak((String) speechPart.get("text")); + // } + } catch (Exception e) { + error(e); + } + + } + @Override public void startService() { try { @@ -790,225 +974,48 @@ public void startService() { } } - /** - * stop the current running gesture - */ - public void stop() { - player.stop(); - } - - @Override - public void stopService() { - super.stopService(); - player.stop(); - } - - public static void main(String[] args) throws Exception { - - try { - Runtime.main(new String[] { "--id", "admin" }); - LoggingFactory.init("INFO"); - - Runtime.start("i01.head.rothead", "Servo"); - Runtime.start("i01.head.neck", "Servo"); - WebGui webgui = (WebGui) Runtime.create("webgui", "WebGui"); - webgui.autoStartBrowser(false); - webgui.startService(); - Python python = (Python) Runtime.start("python", "Python"); - ServoMixer mixer = (ServoMixer) Runtime.start("mixer", "ServoMixer"); - // mixer.playGesture(""); - - boolean done = true; - if (done) { - return; - } - - mixer.addNewGestureFile("test"); - Gesture gesture = mixer.getGesture("test"); - String gestureName = "aaa"; - String servoName = "i01.head.rothead"; - Double position = 90.0; - Double speed = null; - - Map> moves = new TreeMap<>(); - - Map poseMove1 = new TreeMap<>(); - poseMove1.put("position", 90.0); - - Map poseMove2 = new TreeMap<>(); - poseMove2.put("position", 90); - poseMove2.put("speed", 35.0); - - moves.put("i01.head.rothead", poseMove1); - moves.put("i01.head.neck", poseMove2); - - mixer.openGesture(gestureName); - mixer.addMoveToAction(moves); // autofill delay from keyframe ? - mixer.saveGesture(); - - mixer.addNewGestureFile("test2"); - - // mixer.save(gestureName); - mixer.addGestureToAction("test"); - - mixer.saveGesture(); - - // mixer.setPose("test", ) - } catch (Exception e) { - log.error("main threw", e); - } - } - - public void addGestureToAction(String gestureName) { - addGestureToAction(gestureName, null); - } - - public void addGestureToAction(String gestureName, Integer index) { - addAction(Action.createGestureToAction(gestureName), index); - } - - public void saveGesture() { - // FIXME check if exists - ask overwrite - saveGesture(currentEditGestureName, currentGesture); + public void step(int index) { + step(currentEditGestureName, index); } - public Gesture openGesture(String name) { - if (currentGesture != null) { - warn("replacing current gesture"); - // prompt user return null etc. - } + public void step(String gestureName, int index) { - Gesture gesture = getGesture(name); - if (gesture == null) { - // gesture not found make new - gesture = new Gesture(); + if (gestureName == null) { + error("gesture name cannot be null"); + return; } - currentEditGestureName = name; - currentGesture = gesture; - - return currentGesture; - } - - public void addSpeakAction(Map speechCommand) { - addSpeakAction(speechCommand, null); - } - - public void addSpeakAction(Map speechCommand, Integer index) { - addAction(Action.createSpeakAction(speechCommand), index); - } - - public void addMoveToAction(List servos) { - addMoveToAction(servos, null); - } - - /** - * list of servos to add to an action - they're current speed and input - * positions will be added at index - * - * @param servos - * @param index - */ - public void addMoveToAction(List servos, Integer index) { - Map> moves = new TreeMap<>(); - for (String servoName : servos) { - ServoControl sc = (ServoControl) Runtime.getService(servoName); - Map posAndSpeed = new TreeMap<>(); - if (sc == null) { - error("%s not a valid service name", servoName); - continue; - } - posAndSpeed.put("position", sc.getCurrentInputPos()); - posAndSpeed.put("speed", sc.getSpeed()); - moves.put(servoName, posAndSpeed); + if (!gestureName.equals(currentEditGestureName)) { + // load gesture + getGesture(gestureName); } - addAction(Action.createMoveToAction(moves), index); - } - - public void addMoveToAction(Map> moves) { - addMoveToAction(moves, null); - } - - public void addMoveToAction(Map> moves, Integer index) { - addAction(Action.createMoveToAction(moves), index); - } - public void addAction(Action action, Integer index) { if (currentGesture == null) { - error("current gesture not set"); - return; - } - if (index != null) { - if (currentGesture.actions.size() == 0) { - currentGesture.actions.add(action); - } else { - currentGesture.actions.add(index, action); - } - } else { - currentGesture.actions.add(action); - } - } - - public void addSleepAction(double sleep) { - addSleepAction(sleep, null); - } - - public void addSleepAction(double sleep, Integer index) { - addAction(Action.createSleepAction(sleep), index); - } - - public Gesture getGesture() { - return currentGesture; - } - - private void moveTo(String servoName, Map move) { - ServoControl servo = (ServoControl) Runtime.getService(servoName); - if (servo == null) { - warn("servo (%s) cannot move to pose because it does not exist", servoName); + error("gesture cannot be nulle"); return; } - Object speed = move.get("speed"); - if (speed != null) { - if (speed instanceof Integer) { - servo.setSpeed((Integer) speed); - } else if (speed instanceof Double) { - servo.setSpeed((Double) speed); - } - } - - Object position = move.get("position"); - if (position instanceof Integer) { - servo.moveTo((Integer) position); - } else if (position instanceof Double) { - servo.moveTo((Double) position); + player.processAction(new PlayingGesture(gestureName, currentGesture), index); + // step to next action + index++; + if (index < currentGesture.actions.size()) { + Action action = currentGesture.actions.get(index); + invoke("publishPlayingAction", action); + invoke("publishPlayingActionIndex", index); } } - private void speak(Map speechPart) { - if (config.mouth == null) { - warn("mouth configuration not set"); - return; - } - SpeechSynthesis mouth = (SpeechSynthesis) Runtime.getService(config.mouth); - if (mouth == null) { - error("%s speech synthesis service missing", config.mouth); - return; - } - try { - // makes it harder to block - // FIXME if blocking send(mouthName, "speak") - // TODO - show multiple SpeechSynthesis select like Servos - Boolean blocking = (Boolean) speechPart.get("blocking"); - // if (blocking != null && blocking) { - mouth.speakBlocking((String) speechPart.get("text")); // default blocking - // } else { - // mouth.speak((String) speechPart.get("text")); - // } - } catch (Exception e) { - error(e); - } + /** + * stop the current running gesture + */ + public void stop() { + player.stop(); + } + @Override + public void stopService() { + super.stopService(); + player.stop(); } } diff --git a/src/main/java/org/myrobotlab/service/config/ServoMixerConfig.java b/src/main/java/org/myrobotlab/service/config/ServoMixerConfig.java index b62c1200a5..813b32ae8a 100644 --- a/src/main/java/org/myrobotlab/service/config/ServoMixerConfig.java +++ b/src/main/java/org/myrobotlab/service/config/ServoMixerConfig.java @@ -22,5 +22,10 @@ public class ServoMixerConfig extends ServiceConfig { * speech service name */ public String mouth; + + /** + * name of the default processor + */ + public String processor = "python"; } diff --git a/src/main/java/org/myrobotlab/service/interfaces/Processor.java b/src/main/java/org/myrobotlab/service/interfaces/Processor.java new file mode 100644 index 0000000000..8a32c2622a --- /dev/null +++ b/src/main/java/org/myrobotlab/service/interfaces/Processor.java @@ -0,0 +1,18 @@ +package org.myrobotlab.service.interfaces; + +public interface Processor { + + /** + * + * FIXME - this should be refactored to return an Object + * but I don't want to break anything for now + * FIXME - if there is an error this should throw and return + * and object or null if successful + * + * A processor can exec code + * @param code + * @return success or not + */ + public boolean exec(String code); + +} diff --git a/src/main/resources/resource/WebGui/app/service/js/ServoMixerGui.js b/src/main/resources/resource/WebGui/app/service/js/ServoMixerGui.js index 85dc0cbcf3..6c231adacb 100644 --- a/src/main/resources/resource/WebGui/app/service/js/ServoMixerGui.js +++ b/src/main/resources/resource/WebGui/app/service/js/ServoMixerGui.js @@ -241,6 +241,14 @@ angular.module("mrlapp.service.ServoMixerGui", []).controller("ServoMixerGuiCtrl msg.send("getGesture") } + $scope.addPython = function(methodName){ + let index = parseInt($scope.state.gestureIndex) + 1 + $scope.state.gestureIndex = index + "" + msg.send("addProcessingAction", methodName, index) + msg.send("getGesture") + + } + $scope.playGesture = function (gesture) { if (gesture) { msg.send("playGesture", gesture) diff --git a/src/main/resources/resource/WebGui/app/service/views/ServoMixerGui.html b/src/main/resources/resource/WebGui/app/service/views/ServoMixerGui.html index 4e7b48072a..4e38b899b4 100644 --- a/src/main/resources/resource/WebGui/app/service/views/ServoMixerGui.html +++ b/src/main/resources/resource/WebGui/app/service/views/ServoMixerGui.html @@ -78,16 +78,14 @@

{{state.selectedGestureFile}} {{state.playingPose.name}} {{state.gestureInde - From 3398f8a7744e001476da68385ea38e1309ff355a Mon Sep 17 00:00:00 2001 From: grog Date: Fri, 2 Feb 2024 06:18:31 -0800 Subject: [PATCH 017/131] fix runtime.resource for tests --- .../java/org/myrobotlab/service/Runtime.java | 3 +-- .../java/org/myrobotlab/test/AbstractTest.java | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 54f9462425..66cf15b322 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -2786,10 +2786,9 @@ public Runtime(String n, String id) { if (deps.size() == 0) { metaData.installed = true; } else { - warn("{} not installed", metaData.getSimpleName()); + log.info("{} not installed", metaData.getSimpleName()); } } - } } diff --git a/src/test/java/org/myrobotlab/test/AbstractTest.java b/src/test/java/org/myrobotlab/test/AbstractTest.java index c4fc33b83d..00cc6a202d 100644 --- a/src/test/java/org/myrobotlab/test/AbstractTest.java +++ b/src/test/java/org/myrobotlab/test/AbstractTest.java @@ -1,5 +1,7 @@ package org.myrobotlab.test; +import java.io.File; +import java.io.FileOutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; @@ -13,10 +15,12 @@ import org.junit.BeforeClass; import org.junit.Rule; import org.junit.rules.TestName; +import org.myrobotlab.codec.CodecUtils; import org.myrobotlab.framework.Platform; import org.myrobotlab.framework.interfaces.Attachable; import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.service.Runtime; +import org.myrobotlab.service.config.RuntimeConfig; import org.slf4j.Logger; public class AbstractTest { @@ -83,6 +87,20 @@ public static void main(String[] args) { @BeforeClass public static void setUpAbstractTest() throws Exception { + + // setup runtime resource = src/main/resources/resource + File runtimeYml = new File("data/conf/default/runtime.yml"); + if (!runtimeYml.exists()) { + RuntimeConfig rc = new RuntimeConfig(); + rc.resource = "src/main/resources/resource"; + String yml = CodecUtils.toYaml(rc); + + FileOutputStream fos = null; + fos = new FileOutputStream(runtimeYml); + fos.write(yml.getBytes()); + fos.close(); + + } Platform.setVirtual(true); From 557cd80986e66b871c19c47263ecedae18e7ae4d Mon Sep 17 00:00:00 2001 From: grog Date: Fri, 2 Feb 2024 06:22:13 -0800 Subject: [PATCH 018/131] again --- src/test/java/org/myrobotlab/test/AbstractTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/org/myrobotlab/test/AbstractTest.java b/src/test/java/org/myrobotlab/test/AbstractTest.java index 00cc6a202d..3b3351c674 100644 --- a/src/test/java/org/myrobotlab/test/AbstractTest.java +++ b/src/test/java/org/myrobotlab/test/AbstractTest.java @@ -91,6 +91,7 @@ public static void setUpAbstractTest() throws Exception { // setup runtime resource = src/main/resources/resource File runtimeYml = new File("data/conf/default/runtime.yml"); if (!runtimeYml.exists()) { + runtimeYml.getParentFile().mkdirs(); RuntimeConfig rc = new RuntimeConfig(); rc.resource = "src/main/resources/resource"; String yml = CodecUtils.toYaml(rc); From 0a3c81cf50dea1eb50576e4d5d2d585bd85005b4 Mon Sep 17 00:00:00 2001 From: grog Date: Fri, 2 Feb 2024 06:26:55 -0800 Subject: [PATCH 019/131] again --- src/test/java/org/myrobotlab/test/AbstractTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/myrobotlab/test/AbstractTest.java b/src/test/java/org/myrobotlab/test/AbstractTest.java index 3b3351c674..3ea2b7f589 100644 --- a/src/test/java/org/myrobotlab/test/AbstractTest.java +++ b/src/test/java/org/myrobotlab/test/AbstractTest.java @@ -90,7 +90,7 @@ public static void setUpAbstractTest() throws Exception { // setup runtime resource = src/main/resources/resource File runtimeYml = new File("data/conf/default/runtime.yml"); - if (!runtimeYml.exists()) { +// if (!runtimeYml.exists()) { runtimeYml.getParentFile().mkdirs(); RuntimeConfig rc = new RuntimeConfig(); rc.resource = "src/main/resources/resource"; @@ -101,7 +101,7 @@ public static void setUpAbstractTest() throws Exception { fos.write(yml.getBytes()); fos.close(); - } +// } Platform.setVirtual(true); From ce82eb5d6087b6b92391e3beea6eb05b147cd986 Mon Sep 17 00:00:00 2001 From: grog Date: Fri, 2 Feb 2024 06:30:31 -0800 Subject: [PATCH 020/131] corrected wrong path --- src/test/java/org/myrobotlab/test/AbstractTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/myrobotlab/test/AbstractTest.java b/src/test/java/org/myrobotlab/test/AbstractTest.java index 3ea2b7f589..6b7ec2b432 100644 --- a/src/test/java/org/myrobotlab/test/AbstractTest.java +++ b/src/test/java/org/myrobotlab/test/AbstractTest.java @@ -89,7 +89,7 @@ public static void main(String[] args) { public static void setUpAbstractTest() throws Exception { // setup runtime resource = src/main/resources/resource - File runtimeYml = new File("data/conf/default/runtime.yml"); + File runtimeYml = new File("data/config/default/runtime.yml"); // if (!runtimeYml.exists()) { runtimeYml.getParentFile().mkdirs(); RuntimeConfig rc = new RuntimeConfig(); From 0483fb827c3da507f8fa355fe32fa0887eca4de9 Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 4 Feb 2024 07:13:12 -0800 Subject: [PATCH 021/131] Subscription fixes in config - removal of hardcoded subscriptions --- .../org/myrobotlab/config/ConfigUtils.java | 71 ++++++++++++++++ .../java/org/myrobotlab/service/InMoov2.java | 83 ------------------- .../org/myrobotlab/service/InMoov2Arm.java | 2 +- .../org/myrobotlab/service/InMoov2Hand.java | 2 +- .../org/myrobotlab/service/InMoov2Head.java | 2 +- .../org/myrobotlab/service/InMoov2Torso.java | 2 +- .../service/config/InMoov2Config.java | 12 +-- 7 files changed, 81 insertions(+), 93 deletions(-) create mode 100644 src/main/java/org/myrobotlab/config/ConfigUtils.java diff --git a/src/main/java/org/myrobotlab/config/ConfigUtils.java b/src/main/java/org/myrobotlab/config/ConfigUtils.java new file mode 100644 index 0000000000..35c8a776a8 --- /dev/null +++ b/src/main/java/org/myrobotlab/config/ConfigUtils.java @@ -0,0 +1,71 @@ +package org.myrobotlab.config; + +import java.io.File; +import java.io.IOException; + +import org.myrobotlab.codec.CodecUtils; +import org.myrobotlab.framework.StartYml; +import org.myrobotlab.io.FileIO; +import org.myrobotlab.service.Runtime; +import org.myrobotlab.service.config.RuntimeConfig; + +public class ConfigUtils { + + /** + * This gets the current resource root without starting a Runtime instance if + * not already started. The resource root depends on config, if Runtime is + * running the logic and current config name is already available. If Runtime + * is not running, we need to go through a series of steps to deterime where + * the resource root is configured. + * + * @return + */ + public static String getResourceRoot() { + + String resource = "resource"; + + // check if runtime is running + if (!Runtime.isAvailable()) { + // check for start.yml + + File checkStartYml = new File("start.yml"); + StartYml startYml = new StartYml(); + if (checkStartYml.exists()) { + String yml; + try { + yml = FileIO.toString("start.yml"); + startYml = CodecUtils.fromYaml(yml, StartYml.class); + + // see if autostart is on with a config + if (startYml.enable) { + // use that config to find runtime.yml + + File runtimeYml = new File(Runtime.ROOT_CONFIG_DIR + File.separator + startYml.config + File.separator + "runtime.yml"); + if (runtimeYml.exists()) { + // parse that file look for resource: entry in file + RuntimeConfig config = (RuntimeConfig) CodecUtils.readServiceConfig(runtimeYml.getAbsolutePath()); + resource = config.resource; + } + + } else { + // start.yml enable = false / so we'll use default config + File runtimeYml = new File(Runtime.ROOT_CONFIG_DIR + File.separator + "default" + File.separator + "runtime.yml"); + if (runtimeYml.exists()) { + // parse that file look for resource: entry in file + RuntimeConfig config = (RuntimeConfig) CodecUtils.readServiceConfig(runtimeYml.getAbsolutePath()); + resource = config.resource; + } + } + + } catch (IOException e) { + // problem getting or parsing + // going to assume default "resource" + } + } // no startYml + return resource; + } else { + // Runtime is available - ask it + return Runtime.getInstance().getConfig().resource; + } + } +} diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index d9b93659cd..53d2019ba7 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -1123,7 +1123,6 @@ public void onStartConfig(String configName) { */ @Override public void onStarted(String name) { - InMoov2Config c = (InMoov2Config) config; log.info("onStarted {}", name); try { @@ -1157,81 +1156,21 @@ public void onStarted(String name) { chatBot.attachTextListener(getPeerName("htmlFilter")); startPeer("htmlFilter"); break; - case "controller3": - break; - case "controller4": - break; case "ear": AbstractSpeechRecognizer ear = (AbstractSpeechRecognizer) Runtime.getService(name); ear.attachTextListener(getPeerName("chatBot")); break; - case "eyeTracking": - break; - case "fsm": - break; - case "gpt3": - break; - case "head": - addListener("publishMoveHead", name); - break; - case "headTracking": - break; case "htmlFilter": TextPublisher htmlFilter = (TextPublisher) Runtime.getService(name); htmlFilter.attachTextListener(getPeerName("mouth")); break; - case "imageDisplay": - break; - case "leap": - break; - case "left": - break; - case "leftArm": - addListener("publishMoveLeftArm", name, "onMoveArm"); - break; - case "leftHand": - addListener("publishMoveLeftHand", name, "onMoveHand"); - break; case "mouth": mouth = (AbstractSpeechSynthesis) Runtime.getService(name); mouth.attachSpeechListener(getPeerName("ear")); break; - case "mouthControl": - break; - case "neoPixel": - break; case "opencv": subscribeTo(name, "publishOpenCVData"); break; - case "openni": - break; - case "openWeatherMap": - break; - case "pid": - break; - case "pir": - break; - case "random": - break; - case "right": - break; - case "rightArm": - addListener("publishMoveRightArm", name, "onMoveArm"); - break; - case "rightHand": - addListener("publishMoveRightHand", name, "onMoveHand"); - break; - case "servoMixer": - break; - case "simulator": - break; - case "torso": - addListener("publishMoveTorso", name); - break; - case "ultrasonicRight": - break; - case "ultrasonicLeft": - break; default: log.warn("unknown peer %s not hanled in onStarted", peerKey); break; @@ -1991,28 +1930,6 @@ public void startService() { // chatbot getresponse attached to publishEvent addListener("publishEvent", getPeerName("chatBot"), "getResponse"); - try { - // copy config if it doesn't already exist - String resourceBotDir = FileIO.gluePaths(getResourceDir(), "config"); - List files = FileIO.getFileList(resourceBotDir); - for (File f : files) { - String botDir = "data/config/" + f.getName(); - File bDir = new File(botDir); - if (bDir.exists() || !f.isDirectory()) { - log.info("skipping data/config/{}", botDir); - } else { - log.info("will copy new data/config/{}", botDir); - try { - FileIO.copy(f.getAbsolutePath(), botDir); - } catch (Exception e) { - error(e); - } - } - } - } catch (Exception e) { - error(e); - } - runtime.invoke("publishConfigList"); } diff --git a/src/main/java/org/myrobotlab/service/InMoov2Arm.java b/src/main/java/org/myrobotlab/service/InMoov2Arm.java index d190af46e8..3b74a3bf20 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2Arm.java +++ b/src/main/java/org/myrobotlab/service/InMoov2Arm.java @@ -89,7 +89,7 @@ public static DHRobotArm getDHRobotArm(String name, String side) { return arm; } - @Deprecated /* use onMove */ + @Deprecated /* use onMove(map) */ public void onMoveArm(HashMap map) { onMove(map); } diff --git a/src/main/java/org/myrobotlab/service/InMoov2Hand.java b/src/main/java/org/myrobotlab/service/InMoov2Hand.java index 876bfcf5ca..b30c2bd792 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2Hand.java +++ b/src/main/java/org/myrobotlab/service/InMoov2Hand.java @@ -490,7 +490,7 @@ public LeapData onLeapData(LeapData data) { return data; } - @Deprecated /* use onMove */ + @Deprecated /* use onMove(map) */ public void onMoveHand(HashMap map) { onMove(map); } diff --git a/src/main/java/org/myrobotlab/service/InMoov2Head.java b/src/main/java/org/myrobotlab/service/InMoov2Head.java index f77ef9c823..f3f5edf366 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2Head.java +++ b/src/main/java/org/myrobotlab/service/InMoov2Head.java @@ -221,7 +221,7 @@ public void lookAt(Double x, Double y, Double z) { log.info("object distance is {},rothead servo {},neck servo {} ", distance, rotation, colatitude); } - @Deprecated /* use onMoov */ + @Deprecated /* use onMove(map) */ public void onMoveHead(HashMap map) { onMove(map); } diff --git a/src/main/java/org/myrobotlab/service/InMoov2Torso.java b/src/main/java/org/myrobotlab/service/InMoov2Torso.java index f3953699c5..75fa410ca2 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2Torso.java +++ b/src/main/java/org/myrobotlab/service/InMoov2Torso.java @@ -94,7 +94,7 @@ public void disable() { lowStom.disable(); } - @Deprecated /* use onMove */ + @Deprecated /* use onMove(map) */ public void onMoveTorso(HashMap map) { onMove(map); } diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index 55630c9f1b..c0d624d3e6 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -522,12 +522,12 @@ public Plan getDefault(Plan plan, String name) { listeners.add(new Listener("publishProcessMessage", getPeerName("py4j"), "onPythonMessage")); // InMoov2 --to--> InMoov2 - listeners.add(new Listener("publishMoveHead", name)); - listeners.add(new Listener("publishMoveRightArm", name)); - listeners.add(new Listener("publishMoveLeftArm", name)); - listeners.add(new Listener("publishMoveRightHand", name)); - listeners.add(new Listener("publishMoveLeftHand", name)); - listeners.add(new Listener("publishMoveTorso", name)); + listeners.add(new Listener("publishMoveHead", getPeerName("head"), "onMove")); + listeners.add(new Listener("publishMoveRightArm", getPeerName("rightArm"), "onMove")); + listeners.add(new Listener("publishMoveLeftArm", getPeerName("leftArm"), "onMove")); + listeners.add(new Listener("publishMoveRightHand", getPeerName("rightHand"), "onMove")); + listeners.add(new Listener("publishMoveLeftHand", getPeerName("leftHand"), "onMove")); + listeners.add(new Listener("publishMoveTorso", getPeerName("torso"), "onMove")); // service --to--> InMoov2 AudioFileConfig mouth_audioFile = (AudioFileConfig) plan.get(getPeerName("mouth.audioFile")); From 135f12aa671f3ede45619cb406c58d7e67f9381f Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 4 Feb 2024 07:20:18 -0800 Subject: [PATCH 022/131] small runtime updates --- src/main/java/org/myrobotlab/service/Runtime.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 3a66750f54..e5da31305f 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -229,7 +229,7 @@ public class Runtime extends Service implements MessageListener, /** * default parent path of configPath static ! */ - final static protected String ROOT_CONFIG_DIR = DATA_DIR + fs + "config"; + public final static String ROOT_CONFIG_DIR = DATA_DIR + fs + "config"; /** * number of services created by this runtime @@ -5408,4 +5408,12 @@ public static void removeConfig(String configName) { } } + /** + * Method used to determine is runtime is running without starting it + * @return true if available + */ + static public boolean isAvailable() { + return runtime != null && runtime.isRunning(); + } + } From 13323366c5ef4e1304545fab57945c1af83951e5 Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 4 Feb 2024 07:23:58 -0800 Subject: [PATCH 023/131] added test --- src/test/java/org/myrobotlab/service/RuntimeTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/java/org/myrobotlab/service/RuntimeTest.java b/src/test/java/org/myrobotlab/service/RuntimeTest.java index 50c6c03268..2a5db617ad 100644 --- a/src/test/java/org/myrobotlab/service/RuntimeTest.java +++ b/src/test/java/org/myrobotlab/service/RuntimeTest.java @@ -1,6 +1,7 @@ package org.myrobotlab.service; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.Date; @@ -103,6 +104,15 @@ public void testRuntimeLocale() { assertEquals("fr-FR", l.toString()); } + + @Test + public void testRuntimeIsAvailable() { + Runtime runtime = Runtime.getInstance(); + assertTrue(Runtime.isAvailable()); + Runtime.releaseAll(true, true); + assertFalse(Runtime.isAvailable()); + } + @Test public void testGetDescribeMessage() { From 2ea567e0e60b21b3ad343fdc2ee2464e73b408f1 Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 4 Feb 2024 07:47:06 -0800 Subject: [PATCH 024/131] trying to make idempotent test --- src/test/java/org/myrobotlab/service/RuntimeTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/myrobotlab/service/RuntimeTest.java b/src/test/java/org/myrobotlab/service/RuntimeTest.java index 2a5db617ad..a20a13db38 100644 --- a/src/test/java/org/myrobotlab/service/RuntimeTest.java +++ b/src/test/java/org/myrobotlab/service/RuntimeTest.java @@ -107,10 +107,12 @@ public void testRuntimeLocale() { @Test public void testRuntimeIsAvailable() { - Runtime runtime = Runtime.getInstance(); + Runtime.getInstance(); assertTrue(Runtime.isAvailable()); Runtime.releaseAll(true, true); assertFalse(Runtime.isAvailable()); + Runtime.getInstance(); + assertTrue(Runtime.isAvailable()); } From 6a0507172abfe51c686c1399ad2626c33b45f408 Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 4 Feb 2024 08:32:27 -0800 Subject: [PATCH 025/131] npe check --- src/main/java/org/myrobotlab/service/Runtime.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 66cf15b322..9def8ddf30 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -2023,7 +2023,9 @@ synchronized public static void unregister(String inName) { // and config RuntimeConfig c = (RuntimeConfig) Runtime.getInstance().config; - c.remove(CodecUtils.getShortName(name)); + if (c != null) { + c.remove(CodecUtils.getShortName(name)); + } log.info("released {}", name); } From dcdab9bdc4d2e793a148982a21fb4ae8afd9fc41 Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 4 Feb 2024 10:57:01 -0800 Subject: [PATCH 026/131] finally ! fixed randomTest issue --- src/test/java/org/myrobotlab/service/RandomTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/myrobotlab/service/RandomTest.java b/src/test/java/org/myrobotlab/service/RandomTest.java index 9c3739f510..7c8add5923 100644 --- a/src/test/java/org/myrobotlab/service/RandomTest.java +++ b/src/test/java/org/myrobotlab/service/RandomTest.java @@ -74,7 +74,7 @@ public void testService() throws Exception { // disable one method - leave other enabled random.disable("clock.startClock"); clock.stopClock(); - clock.setInterval(999999); + clock.setInterval(9999); sleep(200); assertTrue("clock should not be started 3", !clock.isClockRunning()); assertTrue(String.format("random method 2 should be %d => 5000 values", clock.getInterval()), 5000 <= clock.getInterval()); @@ -83,9 +83,9 @@ public void testService() throws Exception { // disable all random.disable(); sleep(200); - clock.setInterval(999999); + clock.setInterval(9999); assertTrue("clock should not be started 4", !clock.isClockRunning()); - assertEquals(999999, (long)clock.getInterval()); + assertEquals(9999, (long)clock.getInterval()); // re-enable all that were previously enabled but not explicitly disabled ones random.enable(); From 2e8fdb566d14bb4804a36662ca1fa21ee15d6d8a Mon Sep 17 00:00:00 2001 From: grog Date: Mon, 5 Feb 2024 11:14:52 -0800 Subject: [PATCH 027/131] javadoc updates to runtime config --- .../java/org/myrobotlab/service/Runtime.java | 1 - .../service/config/RuntimeConfig.java | 25 +++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 3f5641ba90..8e96ec71b5 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -938,7 +938,6 @@ public static Runtime getInstance() { } catch (Exception e) { log.error("runtime will not be loading config", e); } - } // synchronized lock } diff --git a/src/main/java/org/myrobotlab/service/config/RuntimeConfig.java b/src/main/java/org/myrobotlab/service/config/RuntimeConfig.java index 3e989aaea3..6296f4d536 100644 --- a/src/main/java/org/myrobotlab/service/config/RuntimeConfig.java +++ b/src/main/java/org/myrobotlab/service/config/RuntimeConfig.java @@ -17,12 +17,30 @@ public class RuntimeConfig extends ServiceConfig { * virtual hardware if enabled all services created will enable virtualization if applicable */ public Boolean virtual = false; + + /** + * Determines if stdin can be used for commands + */ public boolean enableCli = true; + + /** + * Log level debug, info, warning, error + */ public String logLevel = "info"; + + /** + * Locale setting for the instance, initial default will be set by the default jvm/os + * through java.util.Locale.getDefault() + */ public String locale; - // NEED THIS PRIVATE BUT CANNOT BE - public List registry = new ArrayList<>(); + + /** + * Although this should be a set of unique services, it cannot be a LinkedHashSet + * because SnakeYml's interpretation would be a map with null values. Instead + * its a protected member with accessors that prevent duplicates. + */ + protected List registry = new ArrayList<>(); /** * Root of resource location @@ -30,6 +48,9 @@ public class RuntimeConfig extends ServiceConfig { public String resource = "resource"; + /** + * Constructor sets the default locale if not already set. + */ public RuntimeConfig() { if (locale == null) { locale = Locale.getDefault().getTag(); From 0c4ba80581c9d8bbc0c535c674023a10b9a75507 Mon Sep 17 00:00:00 2001 From: grog Date: Mon, 5 Feb 2024 11:36:37 -0800 Subject: [PATCH 028/131] guard against no runtime.xml --- src/main/java/org/myrobotlab/service/Runtime.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 8e96ec71b5..61f66cd4ef 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -910,7 +910,6 @@ public static Runtime getInstance() { Runtime.setAllVirtual(Platform.isVirtual()); // setting the singleton security - Security.getInstance(); runtime.getRepo().addStatusPublisher(runtime); FileIO.extractResources(); // protected services we don't want to remove when releasing a config @@ -929,7 +928,9 @@ public static Runtime getInstance() { } else { RuntimeConfig rtConfig = runtime.readServiceConfig(runtime.getConfigName(), "runtime", new StaticType<>() { }); - runtime.apply(rtConfig); + if (rtConfig != null) { + runtime.apply(rtConfig); + } } } catch (Exception e) { log.info("runtime will not be loading config"); From beafe7208cd84d8b0c0bcb26a8ed857fd8241a9b Mon Sep 17 00:00:00 2001 From: grog Date: Mon, 5 Feb 2024 11:59:15 -0800 Subject: [PATCH 029/131] removed dependency test --- Jenkinsfile | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 8e7ccc45f2..63a28dcadb 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -64,18 +64,18 @@ pipeline { } // stage build - stage('dependencies') { - when { - expression { params.verify == 'true' } - } - steps { - script { - sh ''' - mvn test -Dtest=org.myrobotlab.framework.DependencyTest -q - ''' - } - } - } // stage dependencies + // stage('dependencies') { + // when { + // expression { params.verify == 'true' } + // } + // steps { + // script { + // sh ''' + // mvn test -Dtest=org.myrobotlab.framework.DependencyTest -q + // ''' + // } + // } + // } // stage dependencies // --fail-fast // -DargLine="-Xmx1024m" From dbe67cf25dfd86b0a2970bdf567795fd46756a07 Mon Sep 17 00:00:00 2001 From: grog Date: Mon, 5 Feb 2024 12:15:48 -0800 Subject: [PATCH 030/131] fixing unit tests --- src/main/java/org/myrobotlab/service/Runtime.java | 10 +++++++++- src/test/java/org/myrobotlab/framework/ConfigTest.java | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 61f66cd4ef..4976d8c349 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -583,6 +583,8 @@ public final static void createAndStartServices(List services) { @Override public boolean setVirtual(boolean b) { boolean changed = config.virtual != b; + config.virtual = b; + isVirtual = b; setAllVirtual(b); if (changed) { broadcastState(); @@ -909,7 +911,6 @@ public static Runtime getInstance() { // platform virtual is higher priority than service virtual Runtime.setAllVirtual(Platform.isVirtual()); - // setting the singleton security runtime.getRepo().addStatusPublisher(runtime); FileIO.extractResources(); // protected services we don't want to remove when releasing a config @@ -932,6 +933,13 @@ public static Runtime getInstance() { runtime.apply(rtConfig); } } + + + // FIXME - should simply set default RuntimeConfig services and include security + // setting the singleton security + Security.getInstance(); + + } catch (Exception e) { log.info("runtime will not be loading config"); } diff --git a/src/test/java/org/myrobotlab/framework/ConfigTest.java b/src/test/java/org/myrobotlab/framework/ConfigTest.java index 4f8f1a9567..95b3da920b 100644 --- a/src/test/java/org/myrobotlab/framework/ConfigTest.java +++ b/src/test/java/org/myrobotlab/framework/ConfigTest.java @@ -109,7 +109,7 @@ public void testStartNoConfig() throws Exception { // starting an empty config automatically needs a runtime, and runtime // by default starts the singleton security service names = Runtime.getServiceNames(); - assertEquals("complete teardown should be 2 after trying to start a config runtime and security", 2, names.length); + assertEquals("complete teardown should be 2 after trying to start a config runtime and security", 1, names.length); } From 62aa00728e57660ae19e73ea806d78098f3f5d1b Mon Sep 17 00:00:00 2001 From: grog Date: Tue, 6 Feb 2024 06:35:08 -0800 Subject: [PATCH 031/131] config update --- .../org/myrobotlab/service/config/OpenWeatherMapConfig.java | 2 +- .../myrobotlab/service/config/YahooFinanceStockQuoteConfig.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/config/OpenWeatherMapConfig.java b/src/main/java/org/myrobotlab/service/config/OpenWeatherMapConfig.java index 37cdd82a0b..9a6a51baab 100644 --- a/src/main/java/org/myrobotlab/service/config/OpenWeatherMapConfig.java +++ b/src/main/java/org/myrobotlab/service/config/OpenWeatherMapConfig.java @@ -3,7 +3,7 @@ import org.myrobotlab.framework.Peer; import org.myrobotlab.framework.Plan; -public class OpenWeatherMapConfig extends ServiceConfig { +public class OpenWeatherMapConfig extends HttpClientConfig { public String currentUnits; public String currentTown; diff --git a/src/main/java/org/myrobotlab/service/config/YahooFinanceStockQuoteConfig.java b/src/main/java/org/myrobotlab/service/config/YahooFinanceStockQuoteConfig.java index d351154c44..32ae5984d8 100644 --- a/src/main/java/org/myrobotlab/service/config/YahooFinanceStockQuoteConfig.java +++ b/src/main/java/org/myrobotlab/service/config/YahooFinanceStockQuoteConfig.java @@ -1,5 +1,5 @@ package org.myrobotlab.service.config; -public class YahooFinanceStockQuoteConfig extends ServiceConfig { +public class YahooFinanceStockQuoteConfig extends HttpClientConfig { } From 139d01f7372467a404a361f57cdd22668923845b Mon Sep 17 00:00:00 2001 From: grog Date: Tue, 6 Feb 2024 06:35:39 -0800 Subject: [PATCH 032/131] http client config --- src/main/java/org/myrobotlab/service/HttpClient.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/HttpClient.java b/src/main/java/org/myrobotlab/service/HttpClient.java index c7caaa2982..bb43043861 100644 --- a/src/main/java/org/myrobotlab/service/HttpClient.java +++ b/src/main/java/org/myrobotlab/service/HttpClient.java @@ -54,7 +54,7 @@ import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.logging.LoggingFactory; import org.myrobotlab.net.InstallCert; -import org.myrobotlab.service.config.ServiceConfig; +import org.myrobotlab.service.config.HttpClientConfig; import org.myrobotlab.service.data.HttpData; import org.myrobotlab.service.interfaces.HttpDataListener; import org.myrobotlab.service.interfaces.HttpResponseListener; @@ -74,7 +74,7 @@ * - Proxies proxies proxies ! - * https://memorynotfound.com/configure-http-proxy-settings-java/ */ -public class HttpClient extends Service implements TextPublisher { +public class HttpClient extends Service implements TextPublisher { public final static Logger log = LoggerFactory.getLogger(HttpClient.class); From 743226653f5f5f34773837953a9f39b510366bc7 Mon Sep 17 00:00:00 2001 From: grog Date: Fri, 9 Feb 2024 10:26:48 -0800 Subject: [PATCH 033/131] synchronized --- README.md | 36 + .../java/org/myrobotlab/codec/CodecUtils.java | 4 +- .../org/myrobotlab/config/ConfigUtils.java | 142 +- .../org/myrobotlab/framework/CmdOptions.java | 62 +- .../org/myrobotlab/framework/Platform.java | 51 +- .../org/myrobotlab/framework/Service.java | 6 +- .../org/myrobotlab/framework/StartYml.java | 4 - .../framework/repo/MavenWrapper.java | 6 +- .../java/org/myrobotlab/process/Launcher.java | 43 +- .../java/org/myrobotlab/service/Hd44780.java | 2 +- .../java/org/myrobotlab/service/InMoov2.java | 42 - .../org/myrobotlab/service/JMonkeyEngine.java | 2 +- .../org/myrobotlab/service/MotorDualPwm.java | 2 +- .../java/org/myrobotlab/service/Mqtt.java | 2 +- .../java/org/myrobotlab/service/Runtime.java | 1513 ++++++++--------- .../java/org/myrobotlab/service/Serial.java | 2 +- .../java/org/myrobotlab/service/WebGui.java | 46 +- .../service/config/RuntimeConfig.java | 26 +- .../service/interfaces/Gateway.java | 2 +- .../myrobotlab/service/meta/JoystickMeta.java | 6 +- .../myrobotlab/vertx/WebSocketHandler.java | 2 +- .../org/myrobotlab/codec/CodecUtilsTest.java | 19 - .../myrobotlab/config/ConfigUtilsTest.java | 43 + .../myrobotlab/framework/CmdOptionsTest.java | 32 +- .../org/myrobotlab/framework/ConfigTest.java | 132 +- .../org/myrobotlab/framework/ServiceTest.java | 46 - .../org/myrobotlab/service/RuntimeTest.java | 13 - .../org/myrobotlab/service/SerialTest.java | 2 +- .../org/myrobotlab/test/AbstractTest.java | 8 +- 29 files changed, 1079 insertions(+), 1217 deletions(-) create mode 100644 src/test/java/org/myrobotlab/config/ConfigUtilsTest.java delete mode 100644 src/test/java/org/myrobotlab/framework/ServiceTest.java diff --git a/README.md b/README.md index 69e1433cbf..f22e3b94f8 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,42 @@ type: Runtime virtual: false ``` +# Starting Flowchart +```mermaid +flowchart LR + CommandLine[CommandLine] + Runtime.main([Runtime.main]) + install{install} + shutdown([shutdown]) + checkForStartYml{start.yml + exists?} + startYmlEnabled{start.yml + enabled?} + + CommandLine --> Runtime.main + Runtime.main --> checkForStartYml + checkForStartYml --> |yes| loadStartYml[load start.yml] + checkForStartYml --> |no| createDefaultStartYml[create default start.yml] + createDefaultStartYml --> loadStartYml + loadStartYml --> startYmlEnabled + startYmlEnabled --> |yes| Runtime.startConfig[config = start.yml config] + startYmlEnabled --> |no| default[config = default] + Runtime.startConfig --> loadRuntimeConfig[load runtime config] + default --> loadRuntimeConfig + loadRuntimeConfig --> startRuntime[start runtime] + startRuntime --> applyRuntimeConfig[apply runtime config + does not process registry] + applyRuntimeConfig --> install{install?} + + install -->|yes| loadServiceData[loadServiceData] + install -->|no| Runtime.startConf[get runtime.startConfig config] + + loadServiceData --> findUninstalledDependencies[find uninstallled dependencies] + findUninstalledDependencies -->installDependencies[install dependencies] + installDependencies --> shutdown +``` + + # Network Distributed Architecture ## Websockets - Default Response for New Connection diff --git a/src/main/java/org/myrobotlab/codec/CodecUtils.java b/src/main/java/org/myrobotlab/codec/CodecUtils.java index 372caa474b..09d2086c9e 100644 --- a/src/main/java/org/myrobotlab/codec/CodecUtils.java +++ b/src/main/java/org/myrobotlab/codec/CodecUtils.java @@ -495,7 +495,7 @@ public static String getFullName(String name) { } if (getId(name) == null) { - return name + '@' + Platform.getLocalInstance().getId(); + return name + '@' + Runtime.getInstance().getId(); } else { return name; } @@ -1466,7 +1466,7 @@ public static boolean isLocal(String name) { if (!name.contains("@")) { return true; } - return name.substring(name.indexOf("@") + 1).equals(Platform.getLocalInstance().getId()); + return name.substring(name.indexOf("@") + 1).equals(Runtime.getInstance().getId()); } /** diff --git a/src/main/java/org/myrobotlab/config/ConfigUtils.java b/src/main/java/org/myrobotlab/config/ConfigUtils.java index 35c8a776a8..19c256a8cf 100644 --- a/src/main/java/org/myrobotlab/config/ConfigUtils.java +++ b/src/main/java/org/myrobotlab/config/ConfigUtils.java @@ -4,13 +4,26 @@ import java.io.IOException; import org.myrobotlab.codec.CodecUtils; +import org.myrobotlab.framework.CmdOptions; import org.myrobotlab.framework.StartYml; import org.myrobotlab.io.FileIO; +import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.service.Runtime; import org.myrobotlab.service.config.RuntimeConfig; +import org.slf4j.Logger; +/** + * Class to process basic configuration functions and processing. + * + * @author GroG + * + */ public class ConfigUtils { + public final static Logger log = LoggerFactory.getLogger(Runtime.class); + + private static RuntimeConfig config; + /** * This gets the current resource root without starting a Runtime instance if * not already started. The resource root depends on config, if Runtime is @@ -21,51 +34,100 @@ public class ConfigUtils { * @return */ public static String getResourceRoot() { + if (config == null) { + loadRuntimeConfig(null); + } + return config.resource; + + } + + /** + * Loads a runtime config based on the configName. config = + * data/config/{configName}/runtime.yml If one does exits, it is returned, if + * one does not exist a default one is created and saved. + * + * @param configName + * @return + */ + static public RuntimeConfig loadRuntimeConfig(CmdOptions options) { + + if (config != null) { + return config; + } - String resource = "resource"; + StartYml startYml = loadStartYml(); + String configName = null; - // check if runtime is running - if (!Runtime.isAvailable()) { - // check for start.yml + if (startYml.enable) { + configName = startYml.config; + } + + // start with default + config = new RuntimeConfig(); + try { - File checkStartYml = new File("start.yml"); - StartYml startYml = new StartYml(); - if (checkStartYml.exists()) { - String yml; + File runtimeYml = new File(Runtime.ROOT_CONFIG_DIR + File.separator + configName + File.separator + "runtime.yml"); + if (runtimeYml.exists()) { + // parse that file look for resource: entry in file + config = (RuntimeConfig) CodecUtils.readServiceConfig(runtimeYml.getAbsolutePath()); + } else { + FileIO.toFile(runtimeYml, CodecUtils.toYaml(config).getBytes()); + } + + } catch (IOException e) { + log.error("loadRuntimeConfig threw", e); + } + + if (options != null && options.id != null) { + config.id = options.id; + } + + return config; + } + + public static StartYml loadStartYml() { + StartYml startYml = new StartYml(); + String defaultStartFile = CodecUtils.toYaml(startYml); + File checkStartYml = new File("start.yml"); + if (!checkStartYml.exists()) { + // save default start.yml + startYml = new StartYml(); + try { + FileIO.toFile("start.yml", defaultStartFile); + } catch (IOException e) { + log.error("could not save start.yml"); + } + } else { + // load start.yml + try { + String yml = FileIO.toString("start.yml"); + startYml = CodecUtils.fromYaml(yml, StartYml.class); + } catch (Exception e) { + log.error("could not load start.yml replacing with new start.yml", e); + startYml = new StartYml(); try { - yml = FileIO.toString("start.yml"); - startYml = CodecUtils.fromYaml(yml, StartYml.class); - - // see if autostart is on with a config - if (startYml.enable) { - // use that config to find runtime.yml - - File runtimeYml = new File(Runtime.ROOT_CONFIG_DIR + File.separator + startYml.config + File.separator + "runtime.yml"); - if (runtimeYml.exists()) { - // parse that file look for resource: entry in file - RuntimeConfig config = (RuntimeConfig) CodecUtils.readServiceConfig(runtimeYml.getAbsolutePath()); - resource = config.resource; - } - - } else { - // start.yml enable = false / so we'll use default config - File runtimeYml = new File(Runtime.ROOT_CONFIG_DIR + File.separator + "default" + File.separator + "runtime.yml"); - if (runtimeYml.exists()) { - // parse that file look for resource: entry in file - RuntimeConfig config = (RuntimeConfig) CodecUtils.readServiceConfig(runtimeYml.getAbsolutePath()); - resource = config.resource; - } - } - - } catch (IOException e) { - // problem getting or parsing - // going to assume default "resource" + FileIO.toFile("start.yml", defaultStartFile); + } catch (IOException ex) { + log.error("could not save start.yml", ex); } - } // no startYml - return resource; - } else { - // Runtime is available - ask it - return Runtime.getInstance().getConfig().resource; + } } + log.info("start.yml exists {} {}", checkStartYml.exists(), CodecUtils.toJson(startYml)); + return startYml; } + + public static String getId() { + if (config == null) { + loadRuntimeConfig(null); + } + return config.id; + } + + /** + * If Runtime.releaseAll is called the statics here should be reset + */ + public static void reset() { + config = null; + } + } diff --git a/src/main/java/org/myrobotlab/framework/CmdOptions.java b/src/main/java/org/myrobotlab/framework/CmdOptions.java index f0eb00c0e7..2c357e8db6 100644 --- a/src/main/java/org/myrobotlab/framework/CmdOptions.java +++ b/src/main/java/org/myrobotlab/framework/CmdOptions.java @@ -26,9 +26,7 @@ * */ @Command(name = "java -jar myrobotlab.jar ") -public class CmdOptions { - - public final String DEFAULT_CONNECT = "http://localhost:8888"; +public class CmdOptions { static boolean contains(List l, String flag) { for (String f : l) { @@ -39,51 +37,28 @@ static boolean contains(List l, String flag) { return false; } - // launcher ?? - @Option(names = { "-a", "--auto-update" }, description = "auto updating - this feature allows mrl instances to be automatically updated when a new version is available") - public boolean autoUpdate = false; - // launcher @Option(names = { "-c", - "--config" }, fallbackValue="default", description = "Specify a configuration set to start. The config set is a directory which has all the necessary configuration files. It loads runtime.yml first, and subsequent service configuration files will then load. \n example: --config data/config/my-config-dir") + "--config" }, fallbackValue = "default", description = "Specify a configuration set to start. The config set is a directory which has all the necessary configuration files. It loads runtime.yml first, and subsequent service configuration files will then load. \n example: --config data/config/my-config-dir") public String config = null; - @Option(names = { - "--connect" }, arity = "0..*", /* - * defaultValue = DEFAULT_CONNECT, - */ fallbackValue = DEFAULT_CONNECT, description = "connects this mrl instance to another mrl instance - default is " + DEFAULT_CONNECT) - public String connect = null; - @Option(names = { "-h", "-?", "--help" }, description = "shows help") public boolean help = false; - - @Option(names = { "-r", "--config-root" }, description = "sets configuration root, the root for which all config directories are in") - public String configRoot = null; - - - @Option(names = { "--id" }, description = "process identifier to be mdns or network overlay name for this instance - one is created at random if not assigned") + @Option(names = { + "--id" }, description = "process identifier to be mdns or network overlay name for this instance - one is created at random if not assigned") public String id; @Option(names = { "-i", "--install" }, arity = "0..*", description = "installs all dependencies for all services, --install {serviceType} installs dependencies for a specific service, if no type is specified then all services are installed") public String install[]; - @Option(names = { "-I", - "--invoke" }, arity = "0..*", description = "invokes a method on a service --invoke {serviceName} {method} {param0} {param1} ... : --invoke python execFile myFile.py") - public String invoke[]; - - // for launcher @Option(names = { "-j", "--jvm" }, arity = "0..*", description = "jvm parameters for the instance of mrl") public String jvm; - @Option(names = { "-l", "--log-level" }, description = "log level - helpful for troubleshooting [debug info warn error]") + @Option(names = { "-l", + "--log-level" }, description = "log level - helpful for troubleshooting [debug info warn error]") public String logLevel = "info"; - @Option(names = { "--log-file" }, description = "log file name [myrobotlab.log]") - public String logFile = "myrobotlab.log"; - - // FIXME - highlight or italics for examples !! - // launcher @Option(names = { "-m", "--memory" }, description = "adjust memory can e.g. -m 2g \n -m 128m") public String memory = null; @@ -91,9 +66,6 @@ static boolean contains(List l, String flag) { "--services" }, arity = "0..*", description = "services requested on startup, the services must be {name} {Type} paired, e.g. gui SwingGui webgui WebGui servo Servo ...") public List services = new ArrayList<>(); - @Option(names = { "-V", "--virtual" }, description = "sets global environment as virtual - all services which support virtual hardware will create virtual hardware") - public boolean virtual = false; - public CmdOptions() { } @@ -133,34 +105,18 @@ public static String toString(String[] cmdLine) { * * @return the list of output command * @throws IOException - * boom + * boom * */ public List getOutputCmd() throws IOException { List cmd = new ArrayList<>(); - if (autoUpdate) { - cmd.add("-a"); - } - if (config != null) { cmd.add("--config"); cmd.add(config); } - if (connect != null) { - cmd.add("-c"); - cmd.add(connect); - } - - if (invoke != null) { - cmd.add("-I"); - for (int i = 0; i < invoke.length; ++i) { - cmd.add(invoke[i]); - } - } - if (help) { cmd.add("-h"); } @@ -206,10 +162,6 @@ public List getOutputCmd() throws IOException { cmd.add(s); } - if (virtual) { - cmd.add("-v"); - } - return cmd; } diff --git a/src/main/java/org/myrobotlab/framework/Platform.java b/src/main/java/org/myrobotlab/framework/Platform.java index 1b1ed4f2d5..5742bf365e 100644 --- a/src/main/java/org/myrobotlab/framework/Platform.java +++ b/src/main/java/org/myrobotlab/framework/Platform.java @@ -13,6 +13,7 @@ import java.util.TreeMap; import java.util.zip.ZipFile; +import org.myrobotlab.config.ConfigUtils; // Do not pull in deps to this class ! import org.myrobotlab.io.FileIO; import org.myrobotlab.logging.Level; @@ -64,13 +65,7 @@ public class Platform implements Serializable { String vmName; String vmVersion; String mrlVersion; - boolean isVirtual = false; - /** - * Static identifier to identify the "instance" of myrobotlab - similar to - * network ip of a device and used in a similar way - */ - String id; String branch; String pid; @@ -95,7 +90,7 @@ public class Platform implements Serializable { * All data should be accessed through public functions on the local instance. * If the local instance is desired. If its from a serialized instance, the * "getters" will be retrieving appropriate info for that serialized instance. - * + * * @return - return the local instance of the current platform */ public static Platform getLocalInstance() { @@ -121,7 +116,8 @@ public static Platform getLocalInstance() { // === ARCH === String arch = System.getProperty("os.arch").toLowerCase(); - if ("i386".equals(arch) || "i486".equals(arch) || "i586".equals(arch) || "i686".equals(arch) || "amd64".equals(arch) || arch.startsWith("x86")) { + if ("i386".equals(arch) || "i486".equals(arch) || "i586".equals(arch) || "i686".equals(arch) + || "amd64".equals(arch) || arch.startsWith("x86")) { platform.arch = "x86"; // don't care at the moment } @@ -159,7 +155,8 @@ public static Platform getLocalInstance() { // tries very hard to hide this from running programs String procArch = System.getenv("PROCESSOR_ARCHITECTURE"); String procArchWow64 = System.getenv("PROCESSOR_ARCHITEW6432"); - platform.osBitness = (procArch != null && procArch.endsWith("64") || procArchWow64 != null && procArchWow64.endsWith("64")) ? 64 : 32; + platform.osBitness = (procArch != null && procArch.endsWith("64") + || procArchWow64 != null && procArchWow64.endsWith("64")) ? 64 : 32; switch (arch) { case "x86": case "i386": @@ -460,19 +457,6 @@ public String toString() { return String.format("%s.%d.%s", arch, jvmBitness, os); } - /** - * @return The instance identifier of the current running myrobotlab. Used for - * connecting multiple myrobotlabs together - * - */ - public String getId() { - // null ids are not allowed - if (id == null) { - id = NameGenerator.getName(); - } - return id; - } - /** * @return The Computer's hostname */ @@ -480,15 +464,6 @@ public String getHostname() { return hostname; } - /** - * @param newId - * Set your own instance identifier - * - */ - public void setId(String newId) { - id = newId; - } - /** * @return the time when this instance was started * @@ -497,20 +472,6 @@ public Date getStartTime() { return startTime; } - /** - * @return true if running in virtual mode - * - */ - public static boolean isVirtual() { - Platform p = getLocalInstance(); - return p.isVirtual; - } - - public static void setVirtual(boolean b) { - Platform p = getLocalInstance(); - p.isVirtual = b; - } - public static void main(String[] args) { try { LoggingFactory.init(Level.DEBUG); diff --git a/src/main/java/org/myrobotlab/framework/Service.java b/src/main/java/org/myrobotlab/framework/Service.java index 95e23a5616..0449c05e16 100644 --- a/src/main/java/org/myrobotlab/framework/Service.java +++ b/src/main/java/org/myrobotlab/framework/Service.java @@ -619,7 +619,7 @@ public Service(String reservedKey, String inId) { // necessary for serialized transport\ if (inId == null) { - id = Platform.getLocalInstance().getId(); + id = ConfigUtils.getId(); log.debug("creating local service for id {}", id); } else { id = inId; @@ -670,7 +670,7 @@ public Service(String reservedKey, String inId) { // register this service if local - if we are a foreign service, we probably // are being created in a // registration already - if (id.equals(Platform.getLocalInstance().getId())) { + if (id.equals(ConfigUtils.getId())) { Registration registration = new Registration(this); Runtime.register(registration); } @@ -1504,7 +1504,7 @@ public ServiceConfig getFilteredConfig() { // The StringUtils.removeEnd() call is a no-op when the ID is not our // local ID, // so doesn't conflict with remote routes - Listener newConfigListener = new Listener(listener.topicMethod, StringUtil.removeEnd(listener.callbackName, '@' + Platform.getLocalInstance().getId()), + Listener newConfigListener = new Listener(listener.topicMethod, StringUtil.removeEnd(listener.callbackName, '@' + Runtime.getInstance().getId()), listener.callbackMethod); newListeners.add(newConfigListener); } diff --git a/src/main/java/org/myrobotlab/framework/StartYml.java b/src/main/java/org/myrobotlab/framework/StartYml.java index c8bfb25a44..b1806d203c 100644 --- a/src/main/java/org/myrobotlab/framework/StartYml.java +++ b/src/main/java/org/myrobotlab/framework/StartYml.java @@ -9,10 +9,6 @@ * */ public class StartYml { - /** - * instance id of myrobotlab, default will be dynamically generated - */ - public String id; /** * configuration set to start under /data/config/{configName} diff --git a/src/main/java/org/myrobotlab/framework/repo/MavenWrapper.java b/src/main/java/org/myrobotlab/framework/repo/MavenWrapper.java index 8374f92cdf..62c0027cbd 100644 --- a/src/main/java/org/myrobotlab/framework/repo/MavenWrapper.java +++ b/src/main/java/org/myrobotlab/framework/repo/MavenWrapper.java @@ -1,5 +1,5 @@ package org.myrobotlab.framework.repo; - +import org.myrobotlab.service.Runtime; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -281,6 +281,8 @@ public static void main(String[] args) { LoggingFactory.init(Level.INFO); + Runtime.getInstance(); + File libraries = new File(ServiceData.LIBRARIES); libraries.mkdir(); File cache = new File(ServiceData.LIBRARIES + File.separator + "serviceData.json"); @@ -309,7 +311,7 @@ public static void main(String[] args) { // repo.installTo(dir); // repo.install(); // repo.installEach(); <-- TODO - test - + Runtime.shutdown(); log.info("done"); } catch (Exception e) { diff --git a/src/main/java/org/myrobotlab/process/Launcher.java b/src/main/java/org/myrobotlab/process/Launcher.java index 3e819f3c59..7954fd7d5d 100644 --- a/src/main/java/org/myrobotlab/process/Launcher.java +++ b/src/main/java/org/myrobotlab/process/Launcher.java @@ -2,9 +2,6 @@ import java.io.File; import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -241,41 +238,15 @@ public static void main(String[] args) { return; } - boolean instanceAlreadyRunning = false; - - try { - URI uri = new URI(options.connect); - Socket socket = new Socket(); - socket.connect(new InetSocketAddress(uri.getHost(), uri.getPort()), 1000); - socket.close(); - instanceAlreadyRunning = true; - } catch (Exception e) { - log.info("could not connect to {}", options.connect); + log.info("spawning new instance"); + ProcessBuilder builder = createBuilder(options); + process = builder.start(); + if (process.isAlive()) { + log.info("process is alive"); + } else { + log.error("process died"); } - if (instanceAlreadyRunning && options.connect.equals(options.DEFAULT_CONNECT)) { - log.error("zombie instance already running at {}", options.DEFAULT_CONNECT); - return; - } - - if (!instanceAlreadyRunning || !options.connect.equals(options.DEFAULT_CONNECT)) { - log.info("spawning new instance"); - ProcessBuilder builder = createBuilder(options); - process = builder.start(); - if (process.isAlive()) { - log.info("process is alive"); - } else { - log.error("process died"); - } - } - - /* - * // FIXME - use wsclient for remote access if (options.client != null) { - * // FIXME - delay & auto connect Client.main(new String[] { "-c", - * options.client }); } else { // terminating - "if" runtime exists - if - * not no biggy Runtime.shutdown(); } - */ - } catch (Exception e) { log.error("main threw", e); } diff --git a/src/main/java/org/myrobotlab/service/Hd44780.java b/src/main/java/org/myrobotlab/service/Hd44780.java index 9294fee992..72a4039585 100644 --- a/src/main/java/org/myrobotlab/service/Hd44780.java +++ b/src/main/java/org/myrobotlab/service/Hd44780.java @@ -687,7 +687,7 @@ public void preShutdown() { public static void main(String[] args) { try { LoggingFactory.init(Level.INFO); - Platform.setVirtual(false); + Runtime.getInstance().setVirtual(false); Runtime.start("webgui", "WebGui"); Pcf8574 pcf = (Pcf8574) Runtime.start("pcf8574t", "Pcf8574"); diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index 0c4486c40c..e6ad6326ab 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -2178,7 +2178,6 @@ public void startAll() throws Exception { @Deprecated /* use startPeers */ public void startAll(String leftPort, String rightPort) throws Exception { - startMouth(); startChatBot(); // startHeadTracking(); @@ -2289,47 +2288,6 @@ public void startHeartbeat() { heart.start(); } - // TODO - general objective "might" be to reduce peers down to something - // that does not need a reference - where type can be switched before creation - // and the only thing needed is pubs/subs that are not handled in abstracts - @Deprecated /* use startPeer */ - public SpeechSynthesis startMouth() { - - // FIXME - set type ??? - maybe a good product of InMoov - // if "new" type cannot necessarily grab yml file - // setMouthType - - // FIXME - bad to have a reference, should only need the "name" of the - // service !!! - mouth = (SpeechSynthesis) startPeer("mouth"); - - // voices = mouth.getVoices(); - // Voice voice = mouth.getVoice(); - // if (voice != null) { - // voiceSelected = voice.getName(); - // } - - if (mute) { - mouth.setMute(true); - } - - mouth.attachSpeechRecognizer(ear); - // mouth.attach(htmlFilter); // same as chatBot not needed - - // this.attach((Attachable) mouth); - // if (ear != null) .... - - broadcastState(); - - speakBlocking(get("STARTINGMOUTH")); - if (Platform.isVirtual()) { - speakBlocking(get("STARTINGVIRTUALHARD")); - } - speakBlocking(get("WHATISTHISLANGUAGE")); - - return mouth; - } - @Deprecated /* use startPeer */ public OpenCV startOpenCV() { speakBlocking(get("STARTINGOPENCV")); diff --git a/src/main/java/org/myrobotlab/service/JMonkeyEngine.java b/src/main/java/org/myrobotlab/service/JMonkeyEngine.java index 2d19048c84..af2d354f43 100644 --- a/src/main/java/org/myrobotlab/service/JMonkeyEngine.java +++ b/src/main/java/org/myrobotlab/service/JMonkeyEngine.java @@ -2489,7 +2489,7 @@ public static void main(String[] args) { i01.startPeer("simulator"); } - Platform.setVirtual(true); + Runtime.getInstance().setVirtual(true); // Runtime.main(new String[] { "--interactive", "--id", "admin" }); JMonkeyEngine jme = (JMonkeyEngine) Runtime.start("simulator", "JMonkeyEngine"); diff --git a/src/main/java/org/myrobotlab/service/MotorDualPwm.java b/src/main/java/org/myrobotlab/service/MotorDualPwm.java index e1746ca071..3187e52ee0 100644 --- a/src/main/java/org/myrobotlab/service/MotorDualPwm.java +++ b/src/main/java/org/myrobotlab/service/MotorDualPwm.java @@ -96,7 +96,7 @@ public static void main(String[] args) { LoggingFactory.init(Level.INFO); String arduinoPort = "COM5"; - Platform.setVirtual(true); + Runtime.getInstance().setVirtual(true); Runtime.startConfig("dev"); Runtime.start("webgui", "WebGui"); MotorDualPwm motor = (MotorDualPwm) Runtime.start("motor", "MotorDualPwm"); diff --git a/src/main/java/org/myrobotlab/service/Mqtt.java b/src/main/java/org/myrobotlab/service/Mqtt.java index 8466016039..b8e27bcc38 100644 --- a/src/main/java/org/myrobotlab/service/Mqtt.java +++ b/src/main/java/org/myrobotlab/service/Mqtt.java @@ -570,7 +570,7 @@ public void messageArrived(String topic, MqttMessage message) throws MqttExcepti // 4. describe new instance for me // FIXME why isn't this using Gateway.getDescribeMessage()? Message describe = Message.createMessage(String.format("%s@%s", getName(), getId()), "runtime@" + remoteId, "describe", - new Object[] { Gateway.FILL_UUID_MAGIC_VAL, new DescribeQuery(Platform.getLocalInstance().getId(), uuid) }); + new Object[] { Gateway.FILL_UUID_MAGIC_VAL, new DescribeQuery(Runtime.getInstance().getId(), uuid) }); describe.sendingMethod = "onConnect"; sendRemote(describe); diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 4976d8c349..36fe72a3f8 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -47,6 +47,7 @@ import org.myrobotlab.codec.CodecUtils; import org.myrobotlab.codec.CodecUtils.ApiDescription; import org.myrobotlab.codec.ForeignProcessUtils; +import org.myrobotlab.config.ConfigUtils; import org.myrobotlab.framework.CmdOptions; import org.myrobotlab.framework.DescribeQuery; import org.myrobotlab.framework.DescribeResults; @@ -129,7 +130,7 @@ * */ public class Runtime extends Service implements MessageListener, ServiceLifeCyclePublisher, RemoteMessageHandler, ConnectionManager, Gateway, LocaleProvider { - + final static private long serialVersionUID = 1L; // FIXME - AVOID STATIC FIELDS !!! use .getInstance() to get the singleton @@ -167,6 +168,8 @@ public class Runtime extends Service implements MessageListener, protected final Map> typeToInterface = new HashMap<>(); + private static final Object processLock = new Object(); + /** * FILTERED_INTERFACES are the set of low level interfaces which we are * interested in filtering out if we want to maintain a data structure which @@ -188,7 +191,13 @@ public class Runtime extends Service implements MessageListener, * name. It cannot be null, it cannot have "/" or "\" in the name - it has to * be a valid file name for the OS. It's defaulted to "default". Changed often */ - protected String configName = "default"; + protected static String configName = "default"; + + /** + * The runtime config which Runtime was started with. This is the config which + * will be applied to Runtime when its created on startup. + */ + // protected static RuntimeConfig startConfig = null; /** * State variable reporting if runtime is currently starting services from @@ -378,30 +387,32 @@ static public ServiceInterface create(String name) { * - Can be null if a service file exists for named service * @return the service */ - static public synchronized ServiceInterface create(String name, String type) { + static public ServiceInterface create(String name, String type) { - try { - ServiceInterface si = Runtime.getService(name); - if (si != null) { - return si; - } + synchronized (processLock) { - // FIXME remove configName from loadService - Plan plan = Runtime.load(name, type); - Runtime.check(name, type); - // at this point - the plan should be loaded, now its time to create the - // children peers - // and parent service - createServicesFromPlan(plan, null, name); - si = Runtime.getService(name); - if (si == null) { - Runtime.getInstance().error("coult not create %s of type %s", name, type); + try { + ServiceInterface si = Runtime.getService(name); + if (si != null) { + return si; + } + + Plan plan = Runtime.load(name, type); + Runtime.check(name, type); + // at this point - the plan should be loaded, now its time to create the + // children peers + // and parent service + createServicesFromPlan(plan, null, name); + si = Runtime.getService(name); + if (si == null) { + Runtime.getInstance().error("coult not create %s of type %s", name, type); + } + return si; + } catch (Exception e) { + runtime.error(e); } - return si; - } catch (Exception e) { - runtime.error(e); + return null; } - return null; } /** @@ -414,43 +425,46 @@ static public synchronized ServiceInterface create(String name, String type) { * @param name * @return */ - synchronized private static Map createServicesFromPlan(Plan plan, Map createdServices, String name) { - - if (createdServices == null) { - createdServices = new LinkedHashMap<>(); - } + private static Map createServicesFromPlan(Plan plan, Map createdServices, String name) { - // Plan's config - RuntimeConfig plansRtConfig = (RuntimeConfig) plan.get("runtime"); - // current Runtime config - RuntimeConfig currentConfig = Runtime.getInstance().config; + synchronized (processLock) { - for (String service : plansRtConfig.getRegistry()) { - // FIXME - determine if you want to return a complete merge of activated - // or just "recent" - if (Runtime.getService(service) != null) { - continue; + if (createdServices == null) { + createdServices = new LinkedHashMap<>(); } - ServiceConfig sc = plan.get(service); - if (sc == null) { - runtime.error("could not get %s from plan", service); - continue; - } - ServiceInterface si = createService(service, sc.type, null); - // process the base listeners/subscription of ServiceConfig - si.addConfigListeners(sc); - if (si instanceof ConfigurableService) { - try { - ((ConfigurableService) si).apply(sc); - } catch (Exception e) { - Runtime.getInstance().error("could not apply config of type %s to service %s, using default config", sc.type, si.getName(), sc.type); + + // Plan's config + RuntimeConfig plansRtConfig = (RuntimeConfig) plan.get("runtime"); + // current Runtime config + RuntimeConfig currentConfig = Runtime.getInstance().config; + + for (String service : plansRtConfig.getRegistry()) { + // FIXME - determine if you want to return a complete merge of activated + // or just "recent" + if (Runtime.getService(service) != null) { + continue; + } + ServiceConfig sc = plan.get(service); + if (sc == null) { + runtime.error("could not get %s from plan", service); + continue; + } + ServiceInterface si = createService(service, sc.type, null); + // process the base listeners/subscription of ServiceConfig + si.addConfigListeners(sc); + if (si instanceof ConfigurableService) { + try { + ((ConfigurableService) si).apply(sc); + } catch (Exception e) { + Runtime.getInstance().error("could not apply config of type %s to service %s, using default config", sc.type, si.getName(), sc.type); + } } + createdServices.put(service, si); + currentConfig.add(service); } - createdServices.put(service, si); - currentConfig.add(service); - } - return createdServices; + return createdServices; + } } public String getServiceExample(String serviceType) { @@ -601,7 +615,6 @@ public boolean setVirtual(boolean b) { * @return b */ static public boolean setAllVirtual(boolean b) { - Platform.setVirtual(b); for (ServiceInterface si : getServices()) { if (!si.isRuntime()) { si.setVirtual(b); @@ -624,7 +637,6 @@ static public boolean setAllVirtual(boolean b) { */ public void setAutoStart(boolean autoStart) throws IOException { log.debug("setAutoStart {}", autoStart); - startYml.id = getId(); startYml.enable = autoStart; startYml.config = configName; FileIO.toFile("start.yml", CodecUtils.toYaml(startYml)); @@ -659,126 +671,128 @@ public void setAutoStart(boolean autoStart) throws IOException { * '/', or a service with the same name exists but has a different * type, will return null instead. */ - static private synchronized ServiceInterface createService(String name, String type, String inId) { - log.info("Runtime.createService {}", name); + static private ServiceInterface createService(String name, String type, String inId) { + synchronized (processLock) { + log.info("Runtime.createService {}", name); - if (name == null) { - runtime.error("service name cannot be null"); + if (name == null) { + runtime.error("service name cannot be null"); - return null; - } + return null; + } - if (name.contains("@") || name.contains("/")) { - runtime.error("service name cannot contain '@' or '/': {}", name); + if (name.contains("@") || name.contains("/")) { + runtime.error("service name cannot contain '@' or '/': {}", name); - return null; - } + return null; + } - String fullName; - if (inId == null || inId.equals("")) - fullName = getFullName(name); - else - fullName = String.format("%s@%s", name, inId); + String fullName; + if (inId == null || inId.equals("")) + fullName = getFullName(name); + else + fullName = String.format("%s@%s", name, inId); - if (type == null) { - ServiceConfig sc; - try { - sc = CodecUtils.readServiceConfig(runtime.getConfigName() + fs + name + ".yml"); - } catch (IOException e) { - runtime.error("could not find type for service %s", name); - return null; + if (type == null) { + ServiceConfig sc; + try { + sc = CodecUtils.readServiceConfig(runtime.getConfigName() + fs + name + ".yml"); + } catch (IOException e) { + runtime.error("could not find type for service %s", name); + return null; + } + if (sc != null) { + log.info("found type for {} in plan", name); + type = sc.type; + } else { + runtime.error("createService type not specified and could not get type for {} from plan", name); + return null; + } } - if (sc != null) { - log.info("found type for {} in plan", name); - type = sc.type; - } else { - runtime.error("createService type not specified and could not get type for {} from plan", name); + + if (type == null) { + runtime.error("cannot create service {} no type in plan or yml file", name); return null; } - } - if (type == null) { - runtime.error("cannot create service {} no type in plan or yml file", name); - return null; - } + String fullTypeName = CodecUtils.makeFullTypeName(type); + + ServiceInterface si = Runtime.getService(fullName); + if (si != null) { + if (!si.getTypeKey().equals(fullTypeName)) { + runtime.error("Service with name {} already exists but is of type {} while requested type is ", name, si.getTypeKey(), type); + return null; + } + return si; + } - String fullTypeName = CodecUtils.makeFullTypeName(type); + // DO NOT LOAD HERE !!! - doing so would violate the service life cycle ! + // only try to resolve type by the plan - if not then error out - ServiceInterface si = Runtime.getService(fullName); - if (si != null) { - if (!si.getTypeKey().equals(fullTypeName)) { - runtime.error("Service with name {} already exists but is of type {} while requested type is ", name, si.getTypeKey(), type); + String id = (inId == null) ? Runtime.getInstance().getId() : inId; + if (name.length() == 0 || fullTypeName == null || fullTypeName.length() == 0) { + log.error("{} not a type or {} not defined ", fullTypeName, name); return null; } - return si; - } - - // DO NOT LOAD HERE !!! - doing so would violate the service life cycle ! - // only try to resolve type by the plan - if not then error out - String id = (inId == null) ? Platform.getLocalInstance().getId() : inId; - if (name.length() == 0 || fullTypeName == null || fullTypeName.length() == 0) { - log.error("{} not a type or {} not defined ", fullTypeName, name); - return null; - } + // TODO - test new create of existing service + ServiceInterface sw = Runtime.getService(String.format("%s@%s", name, id)); + if (sw != null) { + log.info("service {} already exists", name); + return sw; + } - // TODO - test new create of existing service - ServiceInterface sw = Runtime.getService(String.format("%s@%s", name, id)); - if (sw != null) { - log.info("service {} already exists", name); - return sw; - } + try { - try { + if (log.isDebugEnabled()) { + // TODO - determine if there have been new classes added from + // ivy --> Boot Classloader --> Ext ClassLoader --> System + // ClassLoader + // http://blog.jamesdbloom.com/JVMInternals.html + log.debug("ABOUT TO LOAD CLASS"); + log.debug("loader for this class " + Runtime.class.getClassLoader().getClass().getCanonicalName()); + log.debug("parent " + Runtime.class.getClassLoader().getParent().getClass().getCanonicalName()); + log.debug("system class loader " + ClassLoader.getSystemClassLoader()); + log.debug("parent should be null" + ClassLoader.getSystemClassLoader().getParent().getClass().getCanonicalName()); + log.debug("thread context " + Thread.currentThread().getContextClassLoader().getClass().getCanonicalName()); + log.debug("thread context parent " + Thread.currentThread().getContextClassLoader().getParent().getClass().getCanonicalName()); + } - if (log.isDebugEnabled()) { - // TODO - determine if there have been new classes added from - // ivy --> Boot Classloader --> Ext ClassLoader --> System - // ClassLoader - // http://blog.jamesdbloom.com/JVMInternals.html - log.debug("ABOUT TO LOAD CLASS"); - log.debug("loader for this class " + Runtime.class.getClassLoader().getClass().getCanonicalName()); - log.debug("parent " + Runtime.class.getClassLoader().getParent().getClass().getCanonicalName()); - log.debug("system class loader " + ClassLoader.getSystemClassLoader()); - log.debug("parent should be null" + ClassLoader.getSystemClassLoader().getParent().getClass().getCanonicalName()); - log.debug("thread context " + Thread.currentThread().getContextClassLoader().getClass().getCanonicalName()); - log.debug("thread context parent " + Thread.currentThread().getContextClassLoader().getParent().getClass().getCanonicalName()); - } + // FIXME - error if deps are missing - prompt license + // require restart ! + // FIXME - this should happen after inspecting the "loaded" "plan" not + // during the create/start/apply ! + + // create an instance + Object newService = Instantiator.getThrowableNewInstance(null, fullTypeName, name, id); + log.debug("returning {}", fullTypeName); + si = (ServiceInterface) newService; + + // si.setId(id); + if (Runtime.getInstance().getId().equals(id)) { + si.setVirtual(Runtime.getInstance().isVirtual()); + Runtime.getInstance().creationCount++; + si.setOrder(Runtime.getInstance().creationCount); + } - // FIXME - error if deps are missing - prompt license - // require restart ! - // FIXME - this should happen after inspecting the "loaded" "plan" not - // during the create/start/apply ! - - // create an instance - Object newService = Instantiator.getThrowableNewInstance(null, fullTypeName, name, id); - log.debug("returning {}", fullTypeName); - si = (ServiceInterface) newService; - - // si.setId(id); - if (Platform.getLocalInstance().getId().equals(id)) { - si.setVirtual(Platform.isVirtual()); - Runtime.getInstance().creationCount++; - si.setOrder(Runtime.getInstance().creationCount); - } + if (runtime != null) { - if (runtime != null) { + runtime.invoke("created", getFullName(name)); - runtime.invoke("created", getFullName(name)); + // add all the service life cycle subscriptions + // runtime.addListener("registered", name); + // runtime.addListener("created", name); + // runtime.addListener("started", name); + // runtime.addListener("stopped", name); + // runtime.addListener("released", name); + } - // add all the service life cycle subscriptions - // runtime.addListener("registered", name); - // runtime.addListener("created", name); - // runtime.addListener("started", name); - // runtime.addListener("stopped", name); - // runtime.addListener("released", name); + return (Service) newService; + } catch (Exception e) { + log.error("createService failed for {}@{} of type {}", name, id, fullTypeName, e); } - - return (Service) newService; - } catch (Exception e) { - log.error("createService failed for {}@{} of type {}", name, id, fullTypeName, e); + return null; } - return null; } static public Map>> getNotifyEntries() { @@ -885,67 +899,47 @@ public static final long getFreeMemory() { public static Runtime getInstance() { if (runtime == null) { synchronized (INSTANCE_LOCK) { - if (runtime == null) { + try { - // all though this is appropriate it cannot be done - // because you need runtime to correctly load/start/etc the plan - // so it needs to be bootstrapped - // load("runtime", "Runtime"); + RuntimeConfig c = null; + if (runtime == null) { + c = ConfigUtils.loadRuntimeConfig(options); - // just create Runtime - runtime = (Runtime) createService(RUNTIME_NAME, "Runtime", Platform.getLocalInstance().getId()); - } - try { - // a bit backwards - it loads after it been created - // but its necessary because you need an runtime instance before you - // load - - File cfgRoot = new File(ROOT_CONFIG_DIR); - cfgRoot.mkdirs(); - if (startYml.enable) { - Runtime.load("runtime", "Runtime"); - } - runtime.config.add("runtime"); + runtime = (Runtime) createService(RUNTIME_NAME, "Runtime", c.id); + runtime.startService(); + // klunky + Runtime.register(new Registration(runtime)); - runtime.startService(); - // platform virtual is higher priority than service virtual - Runtime.setAllVirtual(Platform.isVirtual()); + // assign, do not apply otherwise there will be + // a chicken-egg problem + runtime.config = c; + } runtime.getRepo().addStatusPublisher(runtime); + runtime.startService(); + // extract resources "if a jar" FileIO.extractResources(); - // protected services we don't want to remove when releasing a config - runtime.startingServices.add("runtime"); - runtime.startingServices.add("security"); - runtime.startingServices.add("webgui"); - runtime.startingServices.add("python"); - runtime.startInteractiveMode(); - try { - if (options.config != null) { - Runtime.startConfig(options.config); - } else if (startYml != null && startYml.config != null && startYml.enable) { - Runtime.startConfig(startYml.config); - } else { - RuntimeConfig rtConfig = runtime.readServiceConfig(runtime.getConfigName(), "runtime", new StaticType<>() { - }); - if (rtConfig != null) { - runtime.apply(rtConfig); - } - } - + if (Runtime.options.install != null) { + // minimal processed runtime - return it + return runtime; + } - // FIXME - should simply set default RuntimeConfig services and include security - // setting the singleton security - Security.getInstance(); + runtime.apply(c); - - } catch (Exception e) { - log.info("runtime will not be loading config"); + if (options.services != null) { + log.info("command line override for services created"); + createAndStartServices(options.services); + } else { + log.info("processing config.registry"); + if (startYml.enable) { + Runtime.startConfig(startYml.config); + } } } catch (Exception e) { - log.error("runtime will not be loading config", e); + log.error("runtime getInstance threw", e); } } // synchronized lock } @@ -1111,7 +1105,7 @@ public static Map getLocalServices() { Map local = new HashMap<>(); for (String serviceName : registry.keySet()) { // FIXME @ should be a requirement of "all" entries for consistency - if (!serviceName.contains("@") || serviceName.endsWith(String.format("@%s", Platform.getLocalInstance().getId()))) { + if (!serviceName.contains("@") || serviceName.endsWith(String.format("@%s", Runtime.getInstance().getId()))) { local.put(serviceName, registry.get(serviceName)); } } @@ -1161,8 +1155,10 @@ public static Map getMethodMap(String inName) { * * @return list of registrations */ - synchronized public List getServiceList() { - return registry.values().stream().map(si -> new Registration(si.getId(), si.getName(), si.getTypeKey())).collect(Collectors.toList()); + public List getServiceList() { + synchronized (processLock) { + return registry.values().stream().map(si -> new Registration(si.getId(), si.getName(), si.getTypeKey())).collect(Collectors.toList()); + } } // FIXME - scary function - returns private data @@ -1208,10 +1204,16 @@ public static S getService(String inName, StaticTyp * */ static public String[] getServiceNames() { - Set ret = registry.keySet(); + Set ret = registry.keySet(); String[] services = new String[ret.size()]; - - String localId = Platform.getLocalInstance().getId(); + if (ret.size() == 0) { + return services; + } + + // if there are more than 0 services we need runtime + // to filter to make sure they are "local" + // and this requires a runtime service + String localId = Runtime.getInstance().getId(); int cnt = 0; for (String fullname : ret) { if (fullname.endsWith(String.format("@%s", localId))) { @@ -1356,22 +1358,24 @@ public ServiceTypeNameResults getServiceTypeNamesFromInterface(String interfaze) * no longer used or needed - change events are pushed no longer * pulled <-- Over complicated solution */ - public static synchronized List getServicesFromInterface(Class interfaze) { - List ret = new ArrayList(); - - for (String service : getServiceNames()) { - Class clazz = getService(service).getClass(); - while (clazz != null) { - for (Class inter : clazz.getInterfaces()) { - if (inter.getName().equals(interfaze.getName())) { - ret.add(getService(service)); - continue; + public static List getServicesFromInterface(Class interfaze) { + synchronized (processLock) { + List ret = new ArrayList(); + + for (String service : getServiceNames()) { + Class clazz = getService(service).getClass(); + while (clazz != null) { + for (Class inter : clazz.getInterfaces()) { + if (inter.getName().equals(interfaze.getName())) { + ret.add(getService(service)); + continue; + } } + clazz = clazz.getSuperclass(); } - clazz = clazz.getSuperclass(); } + return ret; } - return ret; } /** @@ -1551,35 +1555,36 @@ static public void install(String serviceType) { * if this should block until done. * */ - synchronized static public void install(String serviceType, Boolean blocking) { - Runtime r = getInstance(); + static public void install(String serviceType, Boolean blocking) { + synchronized (processLock) { + Runtime r = getInstance(); - if (blocking == null) { - blocking = false; - } + if (blocking == null) { + blocking = false; + } - installerThread = new Thread() { - @Override - public void run() { - try { - if (serviceType == null) { - r.getRepo().install(); - } else { - r.getRepo().install(serviceType); + installerThread = new Thread() { + @Override + public void run() { + try { + if (serviceType == null) { + r.getRepo().install(); + } else { + r.getRepo().install(serviceType); + } + } catch (Exception e) { + r.error("dependencies failed - install error", e); + throw new RuntimeException(String.format("dependencies failed - install error %s", e.getMessage())); } - } catch (Exception e) { - r.error("dependencies failed - install error", e); - throw new RuntimeException(String.format("dependencies failed - install error %s", e.getMessage())); } - } - }; + }; - if (blocking) { - installerThread.run(); - } else { - installerThread.start(); + if (blocking) { + installerThread.run(); + } else { + installerThread.start(); + } } - } /** @@ -1620,7 +1625,7 @@ static public void invokeCommands(String[] invoke) { */ public static boolean isLocal(String serviceName) { ServiceInterface sw = getService(serviceName); - return Objects.equals(sw.getId(), Platform.getLocalInstance().getId()); + return Objects.equals(sw.getId(), Runtime.getInstance().getId()); } /* @@ -1717,10 +1722,12 @@ public void onState(ServiceInterface updatedService) { registry.put(String.format("%s@%s", updatedService.getName(), updatedService.getId()), updatedService); } - public static synchronized Registration register(String id, String name, String typeKey, ArrayList interfaces) { - Registration proxy = new Registration(id, name, typeKey, interfaces); - register(proxy); - return proxy; + public static Registration register(String id, String name, String typeKey, ArrayList interfaces) { + synchronized (processLock) { + Registration proxy = new Registration(id, name, typeKey, interfaces); + register(proxy); + return proxy; + } } /** @@ -1744,167 +1751,174 @@ public static synchronized Registration register(String id, String name, String * @return registration * */ - public static synchronized Registration register(Registration registration) { + public static Registration register(Registration registration) { + synchronized (processLock) { + try { - try { + // TODO - have rules on what registrations to accept - dependent on + // security, desire, re-broadcasting configuration etc. - // TODO - have rules on what registrations to accept - dependent on - // security, desire, re-broadcasting configuration etc. + String fullname = String.format("%s@%s", registration.getName(), registration.getId()); + if (registry.containsKey(fullname)) { + log.info("{} already registered", fullname); + return registration; + } - String fullname = String.format("%s@%s", registration.getName(), registration.getId()); - if (registry.containsKey(fullname)) { - log.info("{} already registered", fullname); - return registration; - } + // if (!ForeignProcessUtils.isValidTypeKey(registration.getTypeKey())) { + // log.error("Invalid type key being registered: " + + // registration.getTypeKey()); + // return null; + // } - // if (!ForeignProcessUtils.isValidTypeKey(registration.getTypeKey())) { - // log.error("Invalid type key being registered: " + - // registration.getTypeKey()); - // return null; - // } + log.info("{}@{} registering at {} of type {}", registration.getName(), registration.getId(), ConfigUtils.getId(), registration.getTypeKey()); - log.info("{}@{} registering at {} of type {}", registration.getName(), registration.getId(), Platform.getLocalInstance().getId(), registration.getTypeKey()); + if (!registration.isLocal(ConfigUtils.getId())) { - if (!registration.isLocal(Platform.getLocalInstance().getId())) { + // Check if we're registering a java service + if (ForeignProcessUtils.isValidJavaClassName(registration.getTypeKey())) { - // Check if we're registering a java service - if (ForeignProcessUtils.isValidJavaClassName(registration.getTypeKey())) { + String fullTypeName; + if (registration.getTypeKey().contains(".")) { + fullTypeName = registration.getTypeKey(); + } else { + fullTypeName = String.format("org.myrobotlab.service.%s", registration.getTypeKey()); + } - String fullTypeName; - if (registration.getTypeKey().contains(".")) { - fullTypeName = registration.getTypeKey(); + try { + // de-serialize, class exists + registration.service = Runtime.createService(registration.getName(), fullTypeName, registration.getId()); + if (registration.getState() != null) { + copyShallowFrom(registration.service, CodecUtils.fromJson(registration.getState(), Class.forName(fullTypeName))); + } + } catch (ClassNotFoundException classNotFoundException) { + log.error(String.format("Unknown service class for %s@%s: %s", registration.getName(), registration.getId(), registration.getTypeKey()), classNotFoundException); + return null; + } } else { - fullTypeName = String.format("org.myrobotlab.service.%s", registration.getTypeKey()); - } - - try { - // de-serialize, class exists - registration.service = Runtime.createService(registration.getName(), fullTypeName, registration.getId()); - if (registration.getState() != null) { - copyShallowFrom(registration.service, CodecUtils.fromJson(registration.getState(), Class.forName(fullTypeName))); + // We're registering a foreign process service. We don't need to + // check + // ForeignProcessUtils.isForeignTypeKey() because the type key is + // valid + // but is not a java class name + + // Class does not exist, check if registration has empty interfaces + // Interfaces should always include ServiceInterface if coming from + // remote client + if (registration.interfaces == null || registration.interfaces.isEmpty()) { + log.error("Unknown service type being registered, registration does not contain any " + "interfaces for proxy generation: " + registration.getTypeKey()); + return null; } - } catch (ClassNotFoundException classNotFoundException) { - log.error(String.format("Unknown service class for %s@%s: %s", registration.getName(), registration.getId(), registration.getTypeKey()), classNotFoundException); - return null; - } - } else { - // We're registering a foreign process service. We don't need to check - // ForeignProcessUtils.isForeignTypeKey() because the type key is - // valid - // but is not a java class name - - // Class does not exist, check if registration has empty interfaces - // Interfaces should always include ServiceInterface if coming from - // remote client - if (registration.interfaces == null || registration.interfaces.isEmpty()) { - log.error("Unknown service type being registered, registration does not contain any " + "interfaces for proxy generation: " + registration.getTypeKey()); - return null; - } - // FIXME - probably some more clear definition about the requirements - // of remote - // service registration - // In general, there should be very few requirements if any, besides - // providing a - // name, and the proxy - // interface should be responsible for creating a minimal - // interpretation - // (ServiceInterface) for the remote - // service - - // Class[] interfaces = registration.interfaces.stream().map(i -> { - // try { - // return Class.forName(i); - // } catch (ClassNotFoundException e) { - // throw new RuntimeException("Unable to load interface " + i + " - // defined in remote registration " + registration, e); - // } - // }).toArray(Class[]::new); - - // registration.service = (ServiceInterface) - // Proxy.newProxyInstance(Runtime.class.getClassLoader(), interfaces, - // new ProxyServiceInvocationHandler(registration.getName(), - // registration.getId())); - try { - registration.service = ProxyFactory.createProxyService(registration); - log.info("Created proxy: " + registration.service); - } catch (Exception e) { - // at the moment preventing throw - Runtime.getInstance().error(e); + // FIXME - probably some more clear definition about the + // requirements + // of remote + // service registration + // In general, there should be very few requirements if any, besides + // providing a + // name, and the proxy + // interface should be responsible for creating a minimal + // interpretation + // (ServiceInterface) for the remote + // service + + // Class[] interfaces = registration.interfaces.stream().map(i -> + // { + // try { + // return Class.forName(i); + // } catch (ClassNotFoundException e) { + // throw new RuntimeException("Unable to load interface " + i + " + // defined in remote registration " + registration, e); + // } + // }).toArray(Class[]::new); + + // registration.service = (ServiceInterface) + // Proxy.newProxyInstance(Runtime.class.getClassLoader(), + // interfaces, + // new ProxyServiceInvocationHandler(registration.getName(), + // registration.getId())); + try { + registration.service = ProxyFactory.createProxyService(registration); + log.info("Created proxy: " + registration.service); + } catch (Exception e) { + // at the moment preventing throw + Runtime.getInstance().error(e); + } } } - } - - registry.put(fullname, registration.service); - - if (runtime != null) { - - String type = registration.getTypeKey(); - - // If type does not exist in typeToNames, make it an empty hash set and - // return it - Set names = runtime.typeToNames.computeIfAbsent(type, k -> new HashSet<>()); - names.add(fullname); - // FIXME - most of this could be static as it represents meta data of - // class and interfaces + registry.put(fullname, registration.service); + + if (runtime != null) { + + String type = registration.getTypeKey(); + + // If type does not exist in typeToNames, make it an empty hash set + // and + // return it + Set names = runtime.typeToNames.computeIfAbsent(type, k -> new HashSet<>()); + names.add(fullname); + + // FIXME - most of this could be static as it represents meta data of + // class and interfaces + + // FIXME - was false - setting now to true .. because + // 1 edge case - "can something fulfill my need of an interface - is + // not + // currently + // switching to true + boolean updatedServiceLists = false; + + // maintaining interface type relations + // see if this service type is new + // PROCESS INDEXES ! - FIXME - will need this in unregister + // ALL CLASS/TYPE PROCESSING only needs to happen once per type + if (!runtime.serviceTypes.contains(type)) { + // CHECK IF "CAN FULFILL" + // add the interfaces of the new service type + Set interfaces = ClassUtil.getInterfaces(registration.service.getClass(), FILTERED_INTERFACES); + for (String interfaze : interfaces) { + Set types = runtime.interfaceToType.get(interfaze); + if (types == null) { + types = new HashSet<>(); + } + types.add(registration.getTypeKey()); + runtime.interfaceToType.put(interfaze, types); + } - // FIXME - was false - setting now to true .. because - // 1 edge case - "can something fulfill my need of an interface - is not - // currently - // switching to true - boolean updatedServiceLists = false; + runtime.typeToInterface.put(type, interfaces); + runtime.serviceTypes.add(registration.getTypeKey()); + updatedServiceLists = true; + } - // maintaining interface type relations - // see if this service type is new - // PROCESS INDEXES ! - FIXME - will need this in unregister - // ALL CLASS/TYPE PROCESSING only needs to happen once per type - if (!runtime.serviceTypes.contains(type)) { - // CHECK IF "CAN FULFILL" - // add the interfaces of the new service type - Set interfaces = ClassUtil.getInterfaces(registration.service.getClass(), FILTERED_INTERFACES); - for (String interfaze : interfaces) { - Set types = runtime.interfaceToType.get(interfaze); - if (types == null) { - types = new HashSet<>(); + // check to see if any of our interfaces can fulfill requested ones + Set myInterfaces = runtime.typeToInterface.get(type); + for (String inter : myInterfaces) { + if (runtime.interfaceToNames.containsKey(inter)) { + runtime.interfaceToNames.get(inter).add(fullname); + updatedServiceLists = true; } - types.add(registration.getTypeKey()); - runtime.interfaceToType.put(interfaze, types); } - runtime.typeToInterface.put(type, interfaces); - runtime.serviceTypes.add(registration.getTypeKey()); - updatedServiceLists = true; - } - - // check to see if any of our interfaces can fulfill requested ones - Set myInterfaces = runtime.typeToInterface.get(type); - for (String inter : myInterfaces) { - if (runtime.interfaceToNames.containsKey(inter)) { - runtime.interfaceToNames.get(inter).add(fullname); - updatedServiceLists = true; + if (updatedServiceLists) { + runtime.invoke("publishInterfaceToNames"); } - } - if (updatedServiceLists) { - runtime.invoke("publishInterfaceToNames"); + // TODO - determine rules on re-broadcasting based on configuration + runtime.invoke("registered", registration); } - // TODO - determine rules on re-broadcasting based on configuration - runtime.invoke("registered", registration); - } + // TODO - remove ? already get state from registration + if (!registration.isLocal(ConfigUtils.getId())) { + runtime.subscribe(registration.getFullName(), "publishState"); + } - // TODO - remove ? already get state from registration - if (!registration.isLocal(Platform.getLocalInstance().getId())) { - runtime.subscribe(registration.getFullName(), "publishState"); + } catch (Exception e) { + log.error("registration threw for {}@{}", registration.getName(), registration.getId(), e); + return null; } - } catch (Exception e) { - log.error("registration threw for {}@{}", registration.getName(), registration.getId(), e); - return null; + return registration; } - - return registration; } /** @@ -1918,58 +1932,60 @@ public static synchronized Registration register(Registration registration) { * @return true/false * */ - public synchronized static boolean releaseService(String inName) { - if (inName == null) { - log.debug("release (null)"); - return false; - } + public static boolean releaseService(String inName) { + synchronized (processLock) { + if (inName == null) { + log.debug("release (null)"); + return false; + } - String name = getFullName(inName); + String name = getFullName(inName); - String id = CodecUtils.getId(name); - if (!id.equals(Platform.getLocalInstance().getId())) { - log.warn("will only release local services - %s is remote", name); - return false; - } + String id = CodecUtils.getId(name); + if (!id.equals(Runtime.getInstance().getId())) { + log.warn("will only release local services - %s is remote", name); + return false; + } - log.info("releasing service {}", name); + log.info("releasing service {}", name); - if (!registry.containsKey(name)) { - log.info("{} not registered", name); - return false; - } + if (!registry.containsKey(name)) { + log.info("{} not registered", name); + return false; + } - // get reference from registry - ServiceInterface si = registry.get(name); - if (si == null) { - log.warn("cannot release {} - not in registry"); - return false; - } + // get reference from registry + ServiceInterface si = registry.get(name); + if (si == null) { + log.warn("cannot release {} - not in registry"); + return false; + } - // FIXME - TODO invoke and or blocking on preRelease - Future + // FIXME - TODO invoke and or blocking on preRelease - Future - // send msg to service to self terminate - if (si.isLocal()) { - si.purgeTasks(); - si.stopService(); - } else { - if (runtime != null) { - runtime.send(name, "releaseService"); + // send msg to service to self terminate + if (si.isLocal()) { + si.purgeTasks(); + si.stopService(); + } else { + if (runtime != null) { + runtime.send(name, "releaseService"); + } } - } - // recursive peer release - Map peers = si.getPeers(); - if (peers != null) { - for (Peer peer : peers.values()) { - release(peer.name); + // recursive peer release + Map peers = si.getPeers(); + if (peers != null) { + for (Peer peer : peers.values()) { + release(peer.name); + } } - } - // FOR remote this isn't correct - it should wait for - // a message from the other runtime to say that its released - unregister(name); - return true; + // FOR remote this isn't correct - it should wait for + // a message from the other runtime to say that its released + unregister(name); + return true; + } } /** @@ -1979,63 +1995,65 @@ public synchronized static boolean releaseService(String inName) { * @param inName * Name of the service to unregister */ - synchronized public static void unregister(String inName) { - String name = getFullName(inName); - log.info("unregister {}", name); + public static void unregister(String inName) { + synchronized (processLock) { + String name = getFullName(inName); + log.info("unregister {}", name); - // get reference from registry - ServiceInterface sw = registry.get(name); - if (sw == null) { - log.debug("{} already unregistered", name); - return; - } + // get reference from registry + ServiceInterface sw = registry.get(name); + if (sw == null) { + log.debug("{} already unregistered", name); + return; + } - // you have to send released before removing from registry - if (runtime != null) { - runtime.invoke("released", inName); // <- DO NOT CHANGE THIS IS CORRECT - // !! - // it should be FULLNAME ! - // runtime.broadcast("released", inName); - String type = sw.getTypeKey(); - - boolean updatedServiceLists = false; - - // check to see if any of our interfaces can fullfill requested ones - Set myInterfaces = runtime.typeToInterface.get(type); - if (myInterfaces != null) { - for (String inter : myInterfaces) { - if (runtime.interfaceToNames.containsKey(inter)) { - runtime.interfaceToNames.get(inter).remove(name); - updatedServiceLists = true; + // you have to send released before removing from registry + if (runtime != null) { + runtime.invoke("released", inName); // <- DO NOT CHANGE THIS IS CORRECT + // !! + // it should be FULLNAME ! + // runtime.broadcast("released", inName); + String type = sw.getTypeKey(); + + boolean updatedServiceLists = false; + + // check to see if any of our interfaces can fullfill requested ones + Set myInterfaces = runtime.typeToInterface.get(type); + if (myInterfaces != null) { + for (String inter : myInterfaces) { + if (runtime.interfaceToNames.containsKey(inter)) { + runtime.interfaceToNames.get(inter).remove(name); + updatedServiceLists = true; + } } } - } - if (updatedServiceLists) { - runtime.invoke("publishInterfaceToNames"); + if (updatedServiceLists) { + runtime.invoke("publishInterfaceToNames"); + } + } - } + // FIXME - release autostarted peers ? - // FIXME - release autostarted peers ? + // last step - remove from registry by making new registry + // thread safe way + Map removedService = new TreeMap<>(); + for (String key : registry.keySet()) { + if (!name.equals(key)) { + removedService.put(key, registry.get(key)); + } + } + registry = removedService; - // last step - remove from registry by making new registry - // thread safe way - Map removedService = new TreeMap<>(); - for (String key : registry.keySet()) { - if (!name.equals(key)) { - removedService.put(key, registry.get(key)); + // and config + RuntimeConfig c = (RuntimeConfig) Runtime.getInstance().config; + if (c != null) { + c.remove(CodecUtils.getShortName(name)); } - } - registry = removedService; - // and config - RuntimeConfig c = (RuntimeConfig) Runtime.getInstance().config; - if (c != null) { - c.remove(CodecUtils.getShortName(name)); + log.info("released {}", name); } - - log.info("released {}", name); } /** @@ -2106,12 +2124,14 @@ public static void releaseAll(boolean releaseRuntime, boolean block) { if (block) { processRelease(releaseRuntime); + ConfigUtils.reset(); } else { new Thread() { @Override public void run() { processRelease(releaseRuntime); + ConfigUtils.reset(); } }.start(); @@ -2124,45 +2144,51 @@ public void run() { * @param releaseRuntime * Whether the Runtime should also be released */ - synchronized static private void processRelease(boolean releaseRuntime) { - - // reverse release to order of creation - Collection local = getLocalServices().values(); - List ordered = new ArrayList<>(local); - ordered.removeIf(Objects::isNull); - Collections.sort(ordered); - Collections.reverse(ordered); + static private void processRelease(boolean releaseRuntime) { + synchronized (processLock) { + // reverse release to order of creation + Collection local = getLocalServices().values(); + List ordered = new ArrayList<>(local); + ordered.removeIf(Objects::isNull); + Collections.sort(ordered); + Collections.reverse(ordered); - for (ServiceInterface sw : ordered) { + for (ServiceInterface sw : ordered) { - // no longer needed now - runtime "should be" guaranteed to be last - if (sw == Runtime.getInstance()) { - // skipping runtime - continue; - } + // no longer needed now - runtime "should be" guaranteed to be last + if (sw == Runtime.getInstance()) { + // skipping runtime + continue; + } - log.info("releasing service {}", sw.getName()); + log.info("releasing service {}", sw.getName()); - try { - sw.releaseService(); - } catch (Exception e) { - runtime.error("%s threw while releasing", e); - log.error("release", e); + try { + sw.releaseService(); + } catch (Exception e) { + if (runtime != null) { + runtime.error("%s threw while releasing", e); + } + log.error("release", e); + } } - } - // clean up remote ... the contract should - // probably be just remove their references - do not - // ask for them to be released remotely .. - // in thread safe way + // clean up remote ... the contract should + // probably be just remove their references - do not + // ask for them to be released remotely .. + // in thread safe way - if (releaseRuntime && runtime != null) { - runtime.releaseService(); - } else { - // put runtime in new registry - Runtime.getInstance(); - registry = new TreeMap<>(); - registry.put(runtime.getFullName(), registry.get(runtime.getFullName())); + if (releaseRuntime) { + if (runtime != null) { + runtime.releaseService(); + } + runtime = null; + } else { + // put runtime in new registry + Runtime.getInstance(); + registry = new TreeMap<>(); + registry.put(runtime.getFullName(), registry.get(runtime.getFullName())); + } } } @@ -2657,75 +2683,78 @@ public String publishConfigFinished(String configName) { * The type of the new service * @return The started service */ - synchronized static public ServiceInterface start(String name, String type) { - try { + static public ServiceInterface start(String name, String type) { + synchronized (processLock) { + try { - ServiceInterface requestedService = Runtime.getService(name); - if (requestedService != null) { - log.info("requested service already exists"); - if (requestedService.isRunning()) { - log.info("requested service already running"); - } else { - requestedService.startService(); + ServiceInterface requestedService = Runtime.getService(name); + if (requestedService != null) { + log.info("requested service already exists"); + if (requestedService.isRunning()) { + log.info("requested service already running"); + } else { + requestedService.startService(); + } + return requestedService; } - return requestedService; - } - Plan plan = Runtime.load(name, type); + Plan plan = Runtime.load(name, type); - Map services = createServicesFromPlan(plan, null, name); + Map services = createServicesFromPlan(plan, null, name); - if (services == null) { - Runtime.getInstance().error("cannot create instance of %s with type %s given current configuration", name, type); - return null; - } + if (services == null) { + Runtime.getInstance().error("cannot create instance of %s with type %s given current configuration", name, type); + return null; + } - requestedService = Runtime.getService(name); + requestedService = Runtime.getService(name); - // FIXME - does some order need to be maintained e.g. all children before - // parent - // breadth first, depth first, external order ordinal ? - for (ServiceInterface service : services.values()) { - if (service.getName().equals(name)) { - continue; - } - if (!Runtime.isStarted(service.getName())) { - service.startService(); + // FIXME - does some order need to be maintained e.g. all children + // before + // parent + // breadth first, depth first, external order ordinal ? + for (ServiceInterface service : services.values()) { + if (service.getName().equals(name)) { + continue; + } + if (!Runtime.isStarted(service.getName())) { + service.startService(); + } } - } - if (requestedService == null) { - Runtime.getInstance().error("could not start %s of type %s", name, type); - return null; - } + if (requestedService == null) { + Runtime.getInstance().error("could not start %s of type %s", name, type); + return null; + } - // getConfig() was problematic here for JMonkeyEngine - ServiceConfig sc = requestedService.getConfig(); - // Map peers = sc.getPeers(); - // if (peers != null) { - // for (String p : peers.keySet()) { - // Peer peer = peers.get(p); - // log.info("peer {}", peer); - // } - // } - // recursive - start peers of peers of peers ... - Map subPeers = sc.getPeers(); - if (sc != null && subPeers != null) { - for (String subPeerKey : subPeers.keySet()) { - // IF AUTOSTART !!! - Peer subPeer = subPeers.get(subPeerKey); - if (subPeer.autoStart) { - Runtime.start(sc.getPeerName(subPeerKey), subPeer.type); + // getConfig() was problematic here for JMonkeyEngine + ServiceConfig sc = requestedService.getConfig(); + // Map peers = sc.getPeers(); + // if (peers != null) { + // for (String p : peers.keySet()) { + // Peer peer = peers.get(p); + // log.info("peer {}", peer); + // } + // } + // recursive - start peers of peers of peers ... + Map subPeers = sc.getPeers(); + if (sc != null && subPeers != null) { + for (String subPeerKey : subPeers.keySet()) { + // IF AUTOSTART !!! + Peer subPeer = subPeers.get(subPeerKey); + if (subPeer.autoStart) { + Runtime.start(sc.getPeerName(subPeerKey), subPeer.type); + } } } - } - requestedService.startService(); - return requestedService; - } catch (Exception e) { - runtime.error(e); + requestedService.startService(); + return requestedService; + } catch (Exception e) { + runtime.error(e); + } + return null; } - return null; } /** @@ -2735,32 +2764,36 @@ synchronized static public ServiceInterface start(String name, String type) { * @param name * @return */ - synchronized static public ServiceInterface start(String name) { - if (Runtime.getService(name) != null) { - // already exists - ServiceInterface si = Runtime.getService(name); - if (!si.isRunning()) { - si.startService(); + static public ServiceInterface start(String name) { + synchronized (processLock) { + if (Runtime.getService(name) != null) { + // already exists + ServiceInterface si = Runtime.getService(name); + if (!si.isRunning()) { + si.startService(); + } + return si; } - return si; - } - Plan plan = Runtime.load(name, null); - Map services = createServicesFromPlan(plan, null, name); - // FIXME - order ? - for (ServiceInterface service : services.values()) { - service.startService(); + Plan plan = Runtime.load(name, null); + Map services = createServicesFromPlan(plan, null, name); + // FIXME - order ? + for (ServiceInterface service : services.values()) { + service.startService(); + } + return Runtime.getService(name); } - return Runtime.getService(name); } - synchronized public static Plan load(String name, String type) { - try { - Runtime runtime = Runtime.getInstance(); - return runtime.loadService(new Plan("runtime"), name, type, true, 0); - } catch (IOException e) { - runtime.error(e); + public static Plan load(String name, String type) { + synchronized (processLock) { + try { + Runtime runtime = Runtime.getInstance(); + return runtime.loadService(new Plan("runtime"), name, type, true, 0); + } catch (IOException e) { + runtime.error(e); + } + return null; } - return null; } /** @@ -2788,8 +2821,9 @@ public Runtime(String n, String id) { /** * This is used to run through all the possible services and determine - * if they have any missing dependencies. If they do not they become "installed". - * The installed flag makes the gui do a crossout when a service type is selected. + * if they have any missing dependencies. If they do not they become + * "installed". The installed flag makes the gui do a crossout when a + * service type is selected. */ for (MetaData metaData : serviceData.getServiceTypes()) { Set deps = repo.getUnfulfilledDependencies(metaData.getType()); @@ -4202,7 +4236,7 @@ static public String getFullName(String shortname) { return shortname; } // if nothing is supplied assume local - return String.format("%s@%s", shortname, Platform.getLocalInstance().getId()); + return String.format("%s@%s", shortname, Runtime.getInstance().getId()); } @Override @@ -4495,18 +4529,20 @@ public static void main(String[] args) { try { + // loading args globalArgs = args; - new CommandLine(options).parseArgs(args); + log.info("in args {}", Launcher.toString(args)); + log.info("options {}", CodecUtils.toJson(options)); + log.info("\n" + Launcher.banner); + + // creating initial data/config directory + File cfgRoot = new File(ROOT_CONFIG_DIR); + cfgRoot.mkdirs(); // initialize logging initLog(); - log.info("in args {}", Launcher.toString(args)); - log.info(CodecUtils.toJson(options)); - - log.info("\n" + Launcher.banner); - // help and exit if (options.help) { mainHelp(); @@ -4516,45 +4552,23 @@ public static void main(String[] args) { // start.yml file is required, if not pre-existing // is created immediately. It contains static information // which needs to be available before a Runtime is created - File checkStartYml = new File("start.yml"); - if (!checkStartYml.exists()) { - // save default - startYml = new StartYml(); - String defaultStartFile = CodecUtils.toYaml(startYml); - FileIO.toFile("start.yml", defaultStartFile); - } else { - String yml = FileIO.toString("start.yml"); - startYml = CodecUtils.fromYaml(yml, StartYml.class); - } + Runtime.startYml = ConfigUtils.loadStartYml(); - // id always required - precedence - // if none supplied one will be generated - // if in start.yml it will be used - // if supplied by the command line it will be used - // command line has the highest precedence - - Platform platform = Platform.getLocalInstance(); - if (options.id != null) { - platform.setId(options.id); - } else if (startYml.id != null) { - platform.setId(startYml.id); - } else { - // no id set - should be first - // time mrl is started - String id = NameGenerator.getName(); - platform.setId(id); - startYml.id = id; - FileIO.toFile("start.yml", CodecUtils.toYaml(startYml)); + // resolve configName before starting getting runtime configuration + Runtime.configName = (startYml.enable) ? startYml.config : "default"; + if (options.config != null) { + // cmd line options has the highest priority + Runtime.configName = options.config; } - if (options.virtual) { - Platform.setVirtual(true); - } + // start.yml is processed, config name is set, runtime config + // is resolved, now we can start instance + Runtime.getInstance(); - // FIXME TEST THIS !! 0 length, single service, multiple ! if (options.install != null) { // we start the runtime so there is a status publisher which will // display status updates from the repo install + log.info("requesting install"); Repo repo = getInstance().getRepo(); if (options.install.length == 0) { repo.install(LIBRARIES, (String) null); @@ -4567,36 +4581,6 @@ public static void main(String[] args) { return; } - // if a you specify a config file it becomes the "base" of configuration - // inline flags will still override values - if (options.config != null) { - // if this is a valid config, it will load - setConfig(options.config); - } else { - // required directory to load any service - setConfig(startYml.config); - } - - if (startYml.enable) { - Runtime.startConfig(startYml.config); - } else { - createAndStartServices(options.services); - } - - if (options.invoke != null) { - invokeCommands(options.invoke); - } - - if (options.connect != null) { - Runtime.getInstance().connect(options.connect); - } - - if (options.autoUpdate) { - // initialize - // FIXME - use peer ? - Updater.main(args); - } - } catch (Exception e) { log.error("runtime exception", e); Runtime.mainHelp(); @@ -4607,7 +4591,6 @@ public static void main(String[] args) { public static void initLog() { if (options != null) { - LoggingFactory.setLogFile(options.logFile); LoggingFactory.init(options.logLevel); } else { LoggingFactory.init("info"); @@ -4709,87 +4692,92 @@ static public ServiceInterface loadAndStart(String name, String type) { * @return * @throws IOException */ - synchronized public Plan loadService(Plan plan, String name, String type, boolean start, int level) throws IOException { + public Plan loadService(Plan plan, String name, String type, boolean start, int level) throws IOException { + synchronized (processLock) { - if (plan == null) { - log.error("plan required to load a system"); - return null; - } + if (plan == null) { + log.error("plan required to load a system"); + return null; + } - log.info("loading - {} {} {}", name, type, level); - // from recursive memory definition - ServiceConfig sc = plan.get(name); - - // HIGHEST PRIORITY - OVERRIDE WITH FILE - String configPath = runtime.getConfigPath(); - String configFile = configPath + fs + name + ".yml"; - - // PRIORITY #1 - // find if a current yml config file exists - highest priority - log.debug("priority #1 user's yml override {} ", configFile); - ServiceConfig fileSc = readServiceConfig(Runtime.getInstance().getConfigName(), name); - if (fileSc != null) { - // if definition exists in file form, it overrides current memory one - sc = fileSc; - } else if (sc != null) { - // if memory config is available but not file - // we save it - String yml = CodecUtils.toYaml(sc); - FileIO.toFile(configFile, yml); - } - - // special conflict case - type is specified, but its not the same as - // file version - in that case specified parameter type wins and overwrites - // config. User can force type by supplying one as a parameter, however, the - // recursive - // call other peer types will have name/file.yml definition precedence - if ((type != null && sc != null && !type.equals(sc.type) && level == 0) || (sc == null)) { - if (sc != null) { - warn("type %s overwriting type %s specified in %s.yml file", type, sc.type, name); + log.info("loading - {} {} {}", name, type, level); + // from recursive memory definition + ServiceConfig sc = plan.get(name); + + // HIGHEST PRIORITY - OVERRIDE WITH FILE + String configPath = runtime.getConfigPath(); + String configFile = configPath + fs + name + ".yml"; + + // PRIORITY #1 + // find if a current yml config file exists - highest priority + log.debug("priority #1 user's yml override {} ", configFile); + ServiceConfig fileSc = readServiceConfig(Runtime.getInstance().getConfigName(), name); + if (fileSc != null) { + // if definition exists in file form, it overrides current memory one + sc = fileSc; + } else if (sc != null) { + // if memory config is available but not file + // we save it + String yml = CodecUtils.toYaml(sc); + FileIO.toFile(configFile, yml); } - ServiceConfig.getDefault(plan, name, type); - sc = plan.get(name); - // create new file if it didn't exist or overwrite it if new type is - // required - String yml = CodecUtils.toYaml(sc); - FileIO.toFile(configFile, yml); - } + // special conflict case - type is specified, but its not the same as + // file version - in that case specified parameter type wins and + // overwrites + // config. User can force type by supplying one as a parameter, however, + // the + // recursive + // call other peer types will have name/file.yml definition precedence + if ((type != null && sc != null && !type.equals(sc.type) && level == 0) || (sc == null)) { + if (sc != null) { + warn("type %s overwriting type %s specified in %s.yml file", type, sc.type, name); + } + ServiceConfig.getDefault(plan, name, type); + sc = plan.get(name); - if (sc == null && type == null) { - log.error("no local config and unknown type"); - return plan; - } + // create new file if it didn't exist or overwrite it if new type is + // required + String yml = CodecUtils.toYaml(sc); + FileIO.toFile(configFile, yml); + } - // finalize - if (sc != null) { - plan.put(name, sc); - // RECURSIVE load peers - Map peers = sc.getPeers(); - for (String peerKey : peers.keySet()) { - Peer peer = peers.get(peerKey); - // recursive depth load - parent and child need to be started - runtime.loadService(plan, peer.name, peer.type, start && peer.autoStart, level + 1); + if (sc == null && type == null) { + log.error("no local config and unknown type"); + return plan; } - // valid service config at this point - now determine if its supposed to - // start or not - // if its level 0 then it was requested by user or config - so it needs to - // start - // if its not level 0 then it was loaded because peers were defined and - // appropriate config loaded - // peer.autoStart should determine if the peer starts if not explicitly - // requested by the - // user or config - if (level == 0 || start) { - plan.addRegistry(name); + // finalize + if (sc != null) { + plan.put(name, sc); + // RECURSIVE load peers + Map peers = sc.getPeers(); + for (String peerKey : peers.keySet()) { + Peer peer = peers.get(peerKey); + // recursive depth load - parent and child need to be started + runtime.loadService(plan, peer.name, peer.type, start && peer.autoStart, level + 1); + } + + // valid service config at this point - now determine if its supposed to + // start or not + // if its level 0 then it was requested by user or config - so it needs + // to + // start + // if its not level 0 then it was loaded because peers were defined and + // appropriate config loaded + // peer.autoStart should determine if the peer starts if not explicitly + // requested by the + // user or config + if (level == 0 || start) { + plan.addRegistry(name); + } + + } else { + log.info("could not load {} {} {}", name, type, level); } - } else { - log.info("could not load {} {} {}", name, type, level); + return plan; } - - return plan; } /** @@ -4859,45 +4847,30 @@ public String publishConfigLoaded(String name) { return name; } - public String setAllIds(String id) { - Platform.getLocalInstance().setId(id); - for (ServiceInterface si : getServices()) { - si.setId(id); - } - return id; - } - @Override - public RuntimeConfig apply(RuntimeConfig c) { - super.apply(c); - config = c; + public RuntimeConfig apply(RuntimeConfig config) { + super.apply(config); setLocale(config.locale); - if (config.id != null) { - setAllIds(config.id); + if (config.id == null) { + config.id = NameGenerator.getName(); } if (config.logLevel != null) { setLogLevel(config.logLevel); } - info("setting locale to %s", config.locale); if (config.virtual != null) { info("setting virtual to %b", config.virtual); setAllVirtual(config.virtual); } - if (config.enableCli) { - startInteractiveMode(); - info("enabled cli"); - } else { - stopInteractiveMode(); - info("disabled cli"); - } + // APPLYING A RUNTIME CONFIG DOES NOT PROCESS THE REGISTRY + // USE startConfig(name) broadcastState(); - return c; + return config; } /** @@ -4999,7 +4972,6 @@ public boolean saveService(String configName, String serviceName, String filenam // conditional boolean to flip and save a config name to start.yml ? if (startYml.enable) { - startYml.id = getId(); startYml.config = configName; FileIO.toFile("start.yml", CodecUtils.toYaml(startYml)); } @@ -5032,26 +5004,6 @@ public boolean saveService(String configName, String serviceName, String filenam return false; } - public String setConfigName(String name) { - if (name != null && name.contains(fs)) { - error("invalid character " + fs + " in configuration name"); - return configName; - } - if (name != null) { - configName = name.trim(); - } - - // for the moment the best way is to mandate - // a dir is created when a new config name is set - // because loading service are required to save config - // before starting - File configDir = new File(ROOT_CONFIG_DIR + fs + name); - configDir.mkdirs(); - - invoke("publishConfigList"); - return name; - } - public String getConfigName() { return configName; } @@ -5069,13 +5021,34 @@ public boolean isProcessingConfig() { * - config dir name under data/config/{config} * @return configName */ - public static String setConfig(String configName) { + public static String setConfig(String name) { + if (name == null) { + log.error("config cannot be null"); + if (runtime != null) { + runtime.error("config cannot be null"); + } + return null; + } + + if (name.contains(fs)) { + log.error("invalid character " + fs + " in configuration name"); + if (runtime != null) { + runtime.error("invalid character " + fs + " in configuration name"); + } + return name; + } - File configDir = new File(ROOT_CONFIG_DIR + fs + configName); - configDir.mkdirs(); + configName = name.trim(); + + File configDir = new File(ROOT_CONFIG_DIR + fs + name); + if (!configDir.exists()) { + configDir.mkdirs(); + } + + if (runtime != null) { + runtime.invoke("publishConfigList"); + } - Runtime runtime = Runtime.getInstance(); - runtime.setConfigName(configName); return configName; } @@ -5292,7 +5265,6 @@ public String getConfigPath() { return ROOT_CONFIG_DIR + fs + configName; } - /** * Gets a {serviceName}.yml file config from configName directory * @@ -5397,11 +5369,12 @@ public ServiceConfig getPeer(String sericeName, String peerKey) { /** * Removes a config set and all its files * - * @param configName - name of config + * @param configName + * - name of config */ public static void removeConfig(String configName) { try { - log.info("removeing config"); + log.info("removing config"); File check = new File(ROOT_CONFIG_DIR + fs + configName); @@ -5414,12 +5387,4 @@ public static void removeConfig(String configName) { } } - /** - * Method used to determine is runtime is running without starting it - * @return true if available - */ - static public boolean isAvailable() { - return runtime != null && runtime.isRunning(); - } - } diff --git a/src/main/java/org/myrobotlab/service/Serial.java b/src/main/java/org/myrobotlab/service/Serial.java index af16f3522a..c6fccb9d84 100644 --- a/src/main/java/org/myrobotlab/service/Serial.java +++ b/src/main/java/org/myrobotlab/service/Serial.java @@ -1338,7 +1338,7 @@ public static void main(String[] args) { try { - Platform.setVirtual(true); + Runtime.getInstance().setVirtual(true); Serial s = (Serial) Runtime.start("s1", "Serial"); String vport1 = "vport1"; diff --git a/src/main/java/org/myrobotlab/service/WebGui.java b/src/main/java/org/myrobotlab/service/WebGui.java index 21deea126c..5e87cddb05 100644 --- a/src/main/java/org/myrobotlab/service/WebGui.java +++ b/src/main/java/org/myrobotlab/service/WebGui.java @@ -62,7 +62,8 @@ * services are already APIs - perhaps a data API - same as service without the * message wrapper */ -public class WebGui extends Service implements AuthorizationProvider, Gateway, Handler, ServiceLifeCycleListener { +public class WebGui extends Service + implements AuthorizationProvider, Gateway, Handler, ServiceLifeCycleListener { public static class LiveVideoStreamHandler implements Handler { @@ -89,7 +90,7 @@ public void handle(AtmosphereResource r) { } } } - + private final transient IncomingMsgQueue inMsgQueue = new IncomingMsgQueue(); public static class Panel { @@ -127,7 +128,7 @@ public Panel(String name, int x, int y, int z) { * needed to get the api key to select the appropriate api processor * * @param uri - * u + * u * @return api key * */ @@ -270,9 +271,9 @@ public boolean getAutoStartBrowser() { * String broadcast to specific client * * @param uuid - * u + * u * @param str - * s + * s * */ public void broadcast(String uuid, String str) { @@ -314,7 +315,9 @@ public Config.Builder getNettosphereConfig() { // cert.privateKey()).build(); SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); - SslContext context = SslContextBuilder.forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()).sslProvider(SslProvider.JDK) + SslContext context = SslContextBuilder + .forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()) + .sslProvider(SslProvider.JDK) .clientAuth(ClientAuth.NONE).build(); configBuilder.sslContext(context); @@ -493,7 +496,8 @@ public void handle(AtmosphereResource r) { } else if ((bodyData != null) && log.isDebugEnabled()) { logData = bodyData; } - log.debug("-->{} {} {} - [{}] from connection {}", (newPersistentConnection) ? "new" : "", request.getMethod(), request.getRequestURI(), logData, uuid); + log.debug("-->{} {} {} - [{}] from connection {}", (newPersistentConnection) ? "new" : "", request.getMethod(), + request.getRequestURI(), logData, uuid); } // important persistent connections will have associated routes ... @@ -571,7 +575,8 @@ public void handle(AtmosphereResource r) { } if (msg.containsHop(getId())) { - log.error("{} dumping duplicate hop msg to avoid cyclical from {} --to--> {}.{}", getName(), msg.sender, msg.name, msg.method); + log.error("{} dumping duplicate hop msg to avoid cyclical from {} --to--> {}.{}", getName(), msg.sender, + msg.name, msg.method); return; } @@ -915,7 +920,7 @@ public void run() { * remotely control UI * * @param panel - * - the panel which has been moved or resized + * - the panel which has been moved or resized */ public void savePanel(Panel panel) { if (panel.name == null) { @@ -1102,7 +1107,7 @@ public void releaseService() { * Default (false) is to use the CDN * * @param useLocalResources - * - true uses local resources fals uses cdn + * - true uses local resources fals uses cdn */ public void useLocalResources(boolean useLocalResources) { this.useLocalResources = useLocalResources; @@ -1162,7 +1167,7 @@ public WebGuiConfig getConfig() { public WebGuiConfig apply(WebGuiConfig c) { super.apply(c); - + if (c.port != null && (port != null && c.port.intValue() != port.intValue())) { setPort(c.port); } @@ -1178,17 +1183,19 @@ public static void main(String[] args) { try { - // Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", "WebGui", "intro", "Intro", "python", "Python" }); - Runtime.main(new String[] { "--install" }); - + Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", "WebGui","intro", "Intro", "python", "Python" }); + // Runtime.main(new String[] {}); + // Runtime.main(new String[] { "--install" }); + boolean done = true; if (done) { return; } - + // Platform.setVirtual(true); - // Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", "WebGui", "intro", "Intro", "python", "Python", "-c", "dev" }); - // Runtime.startConfig("dev"); + // Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", "WebGui", + // "intro", "Intro", "python", "Python", "-c", "dev" }); + // Runtime.startConfig("dev"); // Runtime.start("python", "Python"); // Arduino arduino = (Arduino)Runtime.start("arduino", "Arduino"); @@ -1199,13 +1206,10 @@ public static void main(String[] args) { // webgui.setSsl(true); webgui.startService(); - - Runtime.start("python", "Python"); // Runtime.start("intro", "Intro"); // Runtime.start("i01", "InMoov2"); - // Runtime.start("i01", "InMoov2"); // Runtime.start("python", "Python"); // Runtime.start("i01", "InMoov2"); @@ -1263,7 +1267,6 @@ public static void main(String[] args) { * Runtime.start("clock03", "Clock"); Runtime.start("clock04", "Clock"); * Runtime.start("clock05", "Clock"); */ - Platform.setVirtual(true); // Arduino arduino = (Arduino) Runtime.start("arduino", "Arduino"); Servo pan = (Servo) Runtime.start("pan", "Servo"); @@ -1309,5 +1312,4 @@ public void onStopped(String name) { public void onReleased(String name) { } - } diff --git a/src/main/java/org/myrobotlab/service/config/RuntimeConfig.java b/src/main/java/org/myrobotlab/service/config/RuntimeConfig.java index 6296f4d536..d1ac97d2f6 100644 --- a/src/main/java/org/myrobotlab/service/config/RuntimeConfig.java +++ b/src/main/java/org/myrobotlab/service/config/RuntimeConfig.java @@ -1,8 +1,11 @@ package org.myrobotlab.service.config; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import org.myrobotlab.framework.NameGenerator; +import org.myrobotlab.framework.Plan; import org.myrobotlab.service.data.Locale; public class RuntimeConfig extends ServiceConfig { @@ -11,18 +14,13 @@ public class RuntimeConfig extends ServiceConfig { * instance id - important to be unique when connecting multiple * mrl instances together */ - public String id; + public String id = NameGenerator.getName(); /** * virtual hardware if enabled all services created will enable virtualization if applicable */ public Boolean virtual = false; - - /** - * Determines if stdin can be used for commands - */ - public boolean enableCli = true; - + /** * Log level debug, info, warning, error */ @@ -32,7 +30,7 @@ public class RuntimeConfig extends ServiceConfig { * Locale setting for the instance, initial default will be set by the default jvm/os * through java.util.Locale.getDefault() */ - public String locale; + public String locale = Locale.getDefault().getTag(); /** @@ -40,7 +38,7 @@ public class RuntimeConfig extends ServiceConfig { * because SnakeYml's interpretation would be a map with null values. Instead * its a protected member with accessors that prevent duplicates. */ - protected List registry = new ArrayList<>(); + public List registry = new ArrayList<>(); /** * Root of resource location @@ -48,13 +46,9 @@ public class RuntimeConfig extends ServiceConfig { public String resource = "resource"; - /** - * Constructor sets the default locale if not already set. - */ - public RuntimeConfig() { - if (locale == null) { - locale = Locale.getDefault().getTag(); - } + public Plan getDefault(Plan plan, String name) { + super.getDefault(plan, name); + return plan; } diff --git a/src/main/java/org/myrobotlab/service/interfaces/Gateway.java b/src/main/java/org/myrobotlab/service/interfaces/Gateway.java index 783ec951ff..7b3ee61b19 100644 --- a/src/main/java/org/myrobotlab/service/interfaces/Gateway.java +++ b/src/main/java/org/myrobotlab/service/interfaces/Gateway.java @@ -83,7 +83,7 @@ default Message getDescribeMsg(String connId) { "describe", new Object[] { FILL_UUID_MAGIC_VAL, - new DescribeQuery(Platform.getLocalInstance().getId(), connId) + new DescribeQuery(Runtime.getInstance().getId(), connId) } ); } diff --git a/src/main/java/org/myrobotlab/service/meta/JoystickMeta.java b/src/main/java/org/myrobotlab/service/meta/JoystickMeta.java index ca544c8523..b2fb538f80 100644 --- a/src/main/java/org/myrobotlab/service/meta/JoystickMeta.java +++ b/src/main/java/org/myrobotlab/service/meta/JoystickMeta.java @@ -20,12 +20,12 @@ public JoystickMeta() { addCategory("control", "telerobotics"); addDependency("net.java.jinput", "jinput", "2.0.9"); - log.info("Joystick.getMetaData {} isArm() {}", platform, platform.isArm()); + log.debug("Joystick.getMetaData {} isArm() {}", platform, platform.isArm()); if (platform.isArm()) { - log.info("adding armv7 native dependencies"); + log.debug("adding armv7 native dependencies"); addDependency("jinput-natives", "jinput-natives-armv7.hfp", "2.0.7", "zip"); } else { - log.info("adding jinput native dependencies"); + log.debug("adding jinput native dependencies"); addDependency("jinput-natives", "jinput-natives", "2.0.7", "zip"); } } diff --git a/src/main/java/org/myrobotlab/vertx/WebSocketHandler.java b/src/main/java/org/myrobotlab/vertx/WebSocketHandler.java index e7e6b5fe63..c74b12e185 100644 --- a/src/main/java/org/myrobotlab/vertx/WebSocketHandler.java +++ b/src/main/java/org/myrobotlab/vertx/WebSocketHandler.java @@ -131,7 +131,7 @@ public void handle(String json) { // FIXME get rid of fill-uuid Message describe = Message.createMessage(String.format("%s@%s", service.getName(), Runtime.get().getId()), "runtime", "describe", - new Object[] { "fill-uuid", new DescribeQuery(Platform.getLocalInstance().getId(), uuid) }); + new Object[] { "fill-uuid", new DescribeQuery(Runtime.getInstance().getId(), uuid) }); service.sendRemote(describe); log.info(String.format("<-- %s", describe)); newConnection = false; diff --git a/src/test/java/org/myrobotlab/codec/CodecUtilsTest.java b/src/test/java/org/myrobotlab/codec/CodecUtilsTest.java index 7ffd26fcd4..e26d28e732 100644 --- a/src/test/java/org/myrobotlab/codec/CodecUtilsTest.java +++ b/src/test/java/org/myrobotlab/codec/CodecUtilsTest.java @@ -186,25 +186,6 @@ public void testDefaultSerialization() { } - @Test - public void testNormalizeServiceName() { - Platform.getLocalInstance().setId("test-id"); - assertEquals("runtime@test-id", CodecUtils.getFullName("runtime")); - assertEquals("runtime@test-id", CodecUtils.getFullName("runtime@test-id")); - } - - @Test - public void testCheckServiceNameEqual() { - Platform.getLocalInstance().setId("test-id"); - assertTrue(CodecUtils.checkServiceNameEquality("runtime", "runtime")); - assertTrue(CodecUtils.checkServiceNameEquality("runtime", "runtime@test-id")); - assertTrue(CodecUtils.checkServiceNameEquality("runtime@test-id", "runtime")); - assertTrue(CodecUtils.checkServiceNameEquality("runtime@test-id", "runtime@test-id")); - assertFalse(CodecUtils.checkServiceNameEquality("runtime", "runtime@not-corr-id")); - assertFalse(CodecUtils.checkServiceNameEquality("runtime@not-corr-id", "runtime")); - - } - @Test public void testBase64() { // not a very comprehensive test, but a sanity check none the less. diff --git a/src/test/java/org/myrobotlab/config/ConfigUtilsTest.java b/src/test/java/org/myrobotlab/config/ConfigUtilsTest.java new file mode 100644 index 0000000000..5d15601b58 --- /dev/null +++ b/src/test/java/org/myrobotlab/config/ConfigUtilsTest.java @@ -0,0 +1,43 @@ +package org.myrobotlab.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Before; +import org.junit.Test; +import org.myrobotlab.framework.StartYml; +import org.myrobotlab.service.Runtime; + +public class ConfigUtilsTest { + + @Before + public void beforeTest() { + Runtime.releaseAll(true, true); + } + + @Test + public void testGetResourceRoot() { + String resource = ConfigUtils.getResourceRoot(); + // could be affected by dirty filesystem + assertEquals("resource", resource); + } + + @Test + public void testLoadRuntimeConfig() { + String resource = ConfigUtils.getResourceRoot(); + assertNotNull(resource); + } + + @Test + public void testLoadStartYml() { + StartYml start = ConfigUtils.loadStartYml(); + assertNotNull(start); + } + + @Test + public void testGetId() { + assertEquals(ConfigUtils.getId(), ConfigUtils.loadRuntimeConfig(null).id); + } + + +} diff --git a/src/test/java/org/myrobotlab/framework/CmdOptionsTest.java b/src/test/java/org/myrobotlab/framework/CmdOptionsTest.java index 85f0d4f2ee..9ce7594c8a 100644 --- a/src/test/java/org/myrobotlab/framework/CmdOptionsTest.java +++ b/src/test/java/org/myrobotlab/framework/CmdOptionsTest.java @@ -1,6 +1,7 @@ package org.myrobotlab.framework; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -9,6 +10,8 @@ import org.junit.Test; import org.myrobotlab.logging.LoggerFactory; +import org.myrobotlab.service.Runtime; +import org.myrobotlab.service.config.ClockConfig; import org.slf4j.Logger; import picocli.CommandLine; @@ -32,29 +35,36 @@ public void testGetOutputCmd() throws IOException { CmdOptions options = new CmdOptions(); new CommandLine(options).parseArgs(new String[] {}); // validate defaults - assertEquals(false, options.autoUpdate); assertNull(options.config); - assertNull(options.connect); assertEquals(0, options.services.size()); - new CommandLine(options).parseArgs(new String[] { "--id", "raspi", "-s", "webgui", "WebGui", "clock01", "Clock" }); + new CommandLine(options).parseArgs(new String[] { "-s", "webgui", "WebGui", "clock01", "Clock" }); - assertEquals("raspi", options.id); assertEquals(4, options.services.size()); List cmd = options.getOutputCmd(); assertTrue(contains(cmd, "webgui")); - assertTrue(contains(cmd, "raspi")); + assertTrue(contains(cmd, "clock01")); log.info(CmdOptions.toString(cmd)); - options = new CmdOptions(); - new CommandLine(options).parseArgs(new String[] { "-a" }); - assertEquals(true, options.autoUpdate); - + Runtime.releaseAll(true, true); // test help - - // test unmatched option + Runtime.main(new String[] { "--id", "test", "-s", "clockCmdTest", "Clock" }); + assertNotNull(Runtime.getService("clockCmdTest")); + assertEquals("test", Runtime.getInstance().getId()); + + Runtime.releaseAll(true, true); + + Runtime.main(new String[] { "-c", "xxx", "-s", "clockCmdTest", "Clock" }); + + ClockConfig clock = (ClockConfig)Runtime.getInstance().readServiceConfig("xxx", "clockCmdTest"); + assertNotNull(clock); + assertNotNull(Runtime.getService("clockCmdTest")); + + Runtime.releaseAll(true, true); + + log.info("here"); } diff --git a/src/test/java/org/myrobotlab/framework/ConfigTest.java b/src/test/java/org/myrobotlab/framework/ConfigTest.java index 95b3da920b..955a18e2ce 100644 --- a/src/test/java/org/myrobotlab/framework/ConfigTest.java +++ b/src/test/java/org/myrobotlab/framework/ConfigTest.java @@ -8,14 +8,8 @@ import java.io.File; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Comparator; import org.junit.After; -import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -38,23 +32,18 @@ import org.slf4j.Logger; public class ConfigTest extends AbstractTest { - - + @BeforeClass public static void setUpBeforeClass() { - System.out.println("Runs before any test method in the class"); - } - - @AfterClass - public static void tearDownAfterClass() { - System.out.println("Runs after all test methods in the class"); + // clean out services - reset + Runtime.releaseAll(true, true); } @Before /* before each test */ public void setUp() throws IOException { // remove all services - also resets config name to DEFAULT effectively Runtime.releaseAll(true, true); - // clean our config directory + // clean our config directory Runtime.removeConfig(CONFIG_NAME); // set our config Runtime.setConfig(CONFIG_NAME); @@ -62,9 +51,8 @@ public void setUp() throws IOException { @After public void tearDown() { - System.out.println("Runs after each test method"); + System.out.println("Runs after each test method"); } - // --- config set related --- // setConfigPath(fullpath) @@ -90,32 +78,31 @@ public void tearDown() { final String CONFIG_PATH = "data" + File.separator + "config" + File.separator + CONFIG_NAME; - @Test public void testStartNoConfig() throws Exception { Runtime runtime = Runtime.getInstance(); assertNotNull(runtime); - + // complete teardown, release runtime, block Runtime.releaseAll(true, true); - + String[] names = Runtime.getServiceNames(); - assertEquals("complete teardown should be 0", 0, names.length); - + assertEquals("after teardown, then using a runtime static - only 0 service 'runtime' should exist", 0, names.length); + // nothing to start - should be empty config Runtime.startConfig(CONFIG_NAME); - + // starting an empty config automatically needs a runtime, and runtime // by default starts the singleton security service names = Runtime.getServiceNames(); - assertEquals("complete teardown should be 2 after trying to start a config runtime and security", 1, names.length); - + assertEquals("complete teardown should be 1 after trying to start a config runtime", 1, names.length); + Runtime.releaseAll(true, true); } - + @Test public void testSwitchingPeer() throws IOException { - + Runtime runtime = Runtime.getInstance(); assertNotNull(runtime); @@ -123,53 +110,53 @@ public void testSwitchingPeer() throws IOException { // to the current config directory Plan plan = Runtime.load("eyeTracking", "Tracking"); assertNotNull(plan); - + // load eyeTracking.yml config - verify default state - TrackingConfig eyeTracking = (TrackingConfig)runtime.getConfig(CONFIG_NAME, "eyeTracking"); + TrackingConfig eyeTracking = (TrackingConfig) runtime.getConfig(CONFIG_NAME, "eyeTracking"); TrackingConfig defaultTracking = new TrackingConfig(); assertEquals("eyeTracking.yml values should be the same as default", defaultTracking.enabled, eyeTracking.enabled); assertEquals("eyeTracking.yml type should be the same as default", defaultTracking.type, eyeTracking.type); - eyeTracking = (TrackingConfig)runtime.getConfig("eyeTracking"); + eyeTracking = (TrackingConfig) runtime.getConfig("eyeTracking"); assertEquals("eyeTracking.yml values should be the same as default", defaultTracking.enabled, eyeTracking.enabled); assertEquals("eyeTracking.yml type should be the same as default", defaultTracking.type, eyeTracking.type); - + // load single opencv - OpenCVConfig cv = (OpenCVConfig)Runtime.load("cv", "OpenCV").get("cv"); + OpenCVConfig cv = (OpenCVConfig) Runtime.load("cv", "OpenCV").get("cv"); // default capturing is false assertFalse(cv.capturing); // save as true cv.capturing = true; Runtime.saveConfig("cv", cv); - + Runtime.load("pid", "Pid"); - eyeTracking = (TrackingConfig)runtime.getConfig("eyeTracking"); - + eyeTracking = (TrackingConfig) runtime.getConfig("eyeTracking"); + eyeTracking.getPeer("cv").name = "cv"; Runtime.saveConfig("eyeTracking", eyeTracking); - + // verify the peer was updated to cv - eyeTracking = (TrackingConfig)runtime.getConfig("eyeTracking"); - cv = (OpenCVConfig)runtime.getPeerConfig("eyeTracking","cv"); + eyeTracking = (TrackingConfig) runtime.getConfig("eyeTracking"); + cv = (OpenCVConfig) runtime.getPeerConfig("eyeTracking", "cv"); // from previous save assertTrue(cv.capturing); } - + @Test public void testChangeType() throws IOException { - Runtime runtime = Runtime.getInstance(); + Runtime runtime = Runtime.getInstance(); Runtime.load("mouth", "MarySpeech"); - MarySpeechConfig mouth = (MarySpeechConfig)runtime.getConfig("mouth"); + MarySpeechConfig mouth = (MarySpeechConfig) runtime.getConfig("mouth"); mouth.listeners.add(new Listener("publishStartSpeaking", "fakeListener")); Runtime.saveConfig("mouth", mouth); - MarySpeechConfig mary = (MarySpeechConfig)runtime.getConfig("mouth"); + MarySpeechConfig mary = (MarySpeechConfig) runtime.getConfig("mouth"); assertNotNull(mary); assertEquals(1, mary.listeners.size()); // save it runtime.changeType("mouth", "LocalSpeech"); - LocalSpeechConfig local = (LocalSpeechConfig)runtime.getConfig("mouth"); + LocalSpeechConfig local = (LocalSpeechConfig) runtime.getConfig("mouth"); assertEquals("must have the listener", 1, local.listeners.size()); assertTrue(local.listeners.get(0).listener.equals("fakeListener")); } @@ -178,23 +165,23 @@ public void testChangeType() throws IOException { public void testInitialLoad() { Runtime runtime = Runtime.getInstance(); Runtime.load("service", "Clock"); - ClockConfig clock = (ClockConfig)runtime.getConfig("service"); + ClockConfig clock = (ClockConfig) runtime.getConfig("service"); assertNotNull(clock); // replace load Runtime.load("service", "Tracking"); - TrackingConfig tracking = (TrackingConfig)runtime.getConfig("service"); + TrackingConfig tracking = (TrackingConfig) runtime.getConfig("service"); assertNotNull(tracking); } - + @Test public void testChangePeerName() throws IOException { Runtime runtime = Runtime.getInstance(); Plan plan = Runtime.load("pollyMouth", "Polly"); - PollyConfig polly = (PollyConfig)plan.get("pollyMouth"); + PollyConfig polly = (PollyConfig) plan.get("pollyMouth"); Runtime.load("i01", "InMoov2"); - InMoov2Config i01 = (InMoov2Config)runtime.getConfig("i01"); + InMoov2Config i01 = (InMoov2Config) runtime.getConfig("i01"); // default - MarySpeechConfig mary = (MarySpeechConfig)runtime.getPeer("i01", "mouth"); + MarySpeechConfig mary = (MarySpeechConfig) runtime.getPeer("i01", "mouth"); assertNotNull(mary); polly.listeners = mary.listeners; Runtime.saveConfig("pollyMouth", polly); @@ -202,48 +189,50 @@ public void testChangePeerName() throws IOException { peer.name = "pollyMouth"; Runtime.saveConfig("i01", i01); // switch to pollyMouth - PollyConfig p = (PollyConfig)runtime.getPeer("i01", "mouth"); - + PollyConfig p = (PollyConfig) runtime.getPeer("i01", "mouth"); + // FIXME - was going to test moving of subscriptions, however, unfortunately - // SpeechSynthesis services use a "recognizers" data instead of just simple subscriptions + // SpeechSynthesis services use a "recognizers" data instead of just simple + // subscriptions // This should be fixed in the future to use standard subscriptions - - } - + + } + @Test public void testSimpleServiceStart() { - Clock clock = (Clock)Runtime.start("track", "Clock"); + Runtime.releaseAll(true, true); + Clock clock = (Clock) Runtime.start("track", "Clock"); clock.startClock(); clock.releaseService(); // better be a tracking service - LocalSpeech track = (LocalSpeech)Runtime.start("track", "LocalSpeech"); + LocalSpeech track = (LocalSpeech) Runtime.start("track", "LocalSpeech"); assertNotNull(track); track.releaseService(); // better be a clock - clock = (Clock)Runtime.create("track", "Clock"); + clock = (Clock) Runtime.create("track", "Clock"); log.info("start"); } @Test public void testPeers() { - InMoov2Head head = (InMoov2Head)Runtime.start("track", "InMoov2Head"); - Servo neck = (Servo)Runtime.getService("track.neck"); + Runtime.releaseAll(true, true); + InMoov2Head head = (InMoov2Head) Runtime.start("track", "InMoov2Head"); + Servo neck = (Servo) Runtime.getService("track.neck"); assertNotNull(neck); head.releaseService(); assertNull(Runtime.getService("track.neck")); - } - + @Test public void testSaveApply() throws IOException { Runtime runtime = Runtime.getInstance(); - Servo neck = (Servo)Runtime.start("neck", "Servo"); + Servo neck = (Servo) Runtime.start("neck", "Servo"); ServoConfig config = neck.getConfig(); - + // Where config is "different" than member variables it // takes an apply(config) of the config to make the service // update its member variables, vs changing config and - // immediately getting the service behavior change. + // immediately getting the service behavior change. config.idleTimeout = 5000; // the fact this takes and additional method to process // i think is legacy and should be changed for Servo to use @@ -251,24 +240,23 @@ public void testSaveApply() throws IOException { neck.apply(config); neck.save(); neck.releaseService(); - neck = (Servo)Runtime.start("neck", "Servo"); - assertTrue("preserved value", 5000 == neck.getConfig().idleTimeout); + neck = (Servo) Runtime.start("neck", "Servo"); + assertTrue("preserved value", 5000 == neck.getConfig().idleTimeout); - Servo servo = (Servo)Runtime.start("servo", "Servo"); - config = (ServoConfig)Runtime.load("default", "Servo").get("default"); + Servo servo = (Servo) Runtime.start("servo", "Servo"); + config = (ServoConfig) Runtime.load("default", "Servo").get("default"); assertNull(config.idleTimeout); config.idleTimeout = 7000; Runtime.saveConfig("servo", config); servo.apply(); assertTrue(servo.getConfig().idleTimeout == 7000); - + config.idleTimeout = 8000; servo.apply(config); assertTrue(servo.getIdleTimeout() == 8000); servo.apply(); assertTrue("filesystem servo.yml applied", servo.getIdleTimeout() == 7000); - + } - } \ No newline at end of file diff --git a/src/test/java/org/myrobotlab/framework/ServiceTest.java b/src/test/java/org/myrobotlab/framework/ServiceTest.java deleted file mode 100644 index a9f180362c..0000000000 --- a/src/test/java/org/myrobotlab/framework/ServiceTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.myrobotlab.framework; - -import static org.junit.Assert.assertEquals; - -import java.util.List; -import java.util.Map; - -import org.junit.Test; -import org.myrobotlab.service.config.ServiceConfig; -import org.myrobotlab.test.AbstractTest; - -public class ServiceTest extends AbstractTest { - - public static class TestService extends Service { - - private static final long serialVersionUID = 1L; - - /** - * Constructor of service, reservedkey typically is a services name and inId - * will be its process id - * - * @param reservedKey the service name - * @param inId process id - */ - public TestService(String reservedKey, String inId) { - super(reservedKey, inId); - } - } - - @Test - public void testConfigListenerFiltering() { - Platform.getLocalInstance().setId("test-id"); - TestService t = new TestService("test", "test-id"); - List listeners = List.of( - new MRLListener("meth", "webgui@webgui-client", "onMeth"), - new MRLListener("meth", "random@test-id", "onMeth"), - new MRLListener("meth", "random2@test-2-id", "onMeth") - ); - t.apply(new ServiceConfig()); - t.outbox.notifyList = Map.of("meth", listeners); - List filtered = t.getFilteredConfig().listeners; - assertEquals("random", filtered.get(0).listener); - assertEquals("random2@test-2-id", filtered.get(1).listener); - t.getFilteredConfig(); - } -} diff --git a/src/test/java/org/myrobotlab/service/RuntimeTest.java b/src/test/java/org/myrobotlab/service/RuntimeTest.java index a20a13db38..e3883cf97f 100644 --- a/src/test/java/org/myrobotlab/service/RuntimeTest.java +++ b/src/test/java/org/myrobotlab/service/RuntimeTest.java @@ -92,9 +92,6 @@ public void testGetUptime() { @Test public void testRuntimeLocale() { - long curr = 1479044758691L; - Date d = new Date(curr); - Runtime runtime = Runtime.getInstance(); runtime.setLocale("fr-FR"); assertEquals("expecting concat fr-FR", "fr-FR", runtime.getLocale().getTag()); @@ -105,16 +102,6 @@ public void testRuntimeLocale() { } - @Test - public void testRuntimeIsAvailable() { - Runtime.getInstance(); - assertTrue(Runtime.isAvailable()); - Runtime.releaseAll(true, true); - assertFalse(Runtime.isAvailable()); - Runtime.getInstance(); - assertTrue(Runtime.isAvailable()); - } - @Test public void testGetDescribeMessage() { diff --git a/src/test/java/org/myrobotlab/service/SerialTest.java b/src/test/java/org/myrobotlab/service/SerialTest.java index db1f10e315..63aeaa5cb5 100644 --- a/src/test/java/org/myrobotlab/service/SerialTest.java +++ b/src/test/java/org/myrobotlab/service/SerialTest.java @@ -53,7 +53,7 @@ public static Set getDeadThreads() { @BeforeClass public static void setUpBeforeClass() throws Exception { // LoggingFactory.init("WARN"); - Platform.setVirtual(true); + Runtime.getInstance().setVirtual(true); log.info("setUpBeforeClass"); diff --git a/src/test/java/org/myrobotlab/test/AbstractTest.java b/src/test/java/org/myrobotlab/test/AbstractTest.java index 6b7ec2b432..1a40bae57e 100644 --- a/src/test/java/org/myrobotlab/test/AbstractTest.java +++ b/src/test/java/org/myrobotlab/test/AbstractTest.java @@ -103,7 +103,7 @@ public static void setUpAbstractTest() throws Exception { // } - Platform.setVirtual(true); + Runtime.getInstance().setVirtual(true); String junitLogLevel = System.getProperty("junit.logLevel"); if (junitLogLevel != null) { @@ -164,7 +164,7 @@ static protected void installAll() { */ public static void releaseServices() { - log.info("end of test - id {} remaining services {}", Platform.getLocalInstance().getId(), + log.info("end of test - id {} remaining services {}", Runtime.getInstance().getId(), Arrays.toString(Runtime.getServiceNames())); // release all including runtime - be careful of default runtime.yml @@ -211,11 +211,11 @@ public AbstractTest() { } public void setVirtual() { - Platform.setVirtual(true); + Runtime.getInstance().setVirtual(true); } public boolean isVirtual() { - return Platform.isVirtual(); + return Runtime.getInstance().isVirtual(); } } From 202f364a848c6342cc5afd857427bfc08768e142 Mon Sep 17 00:00:00 2001 From: GroG Date: Fri, 9 Feb 2024 12:40:01 -0800 Subject: [PATCH 034/131] Update CmdOptionsTest.java --- src/test/java/org/myrobotlab/framework/CmdOptionsTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/myrobotlab/framework/CmdOptionsTest.java b/src/test/java/org/myrobotlab/framework/CmdOptionsTest.java index 9ce7594c8a..7afa011b8e 100644 --- a/src/test/java/org/myrobotlab/framework/CmdOptionsTest.java +++ b/src/test/java/org/myrobotlab/framework/CmdOptionsTest.java @@ -1,5 +1,5 @@ package org.myrobotlab.framework; - +import org.junit.Ignore; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -15,7 +15,7 @@ import org.slf4j.Logger; import picocli.CommandLine; - +@Ignore public class CmdOptionsTest { public final static Logger log = LoggerFactory.getLogger(CmdOptionsTest.class); From 3dadcace633345c67619d29e69abf6e58c6e5795 Mon Sep 17 00:00:00 2001 From: grog Date: Fri, 9 Feb 2024 16:23:49 -0800 Subject: [PATCH 035/131] warn --- .../java/org/myrobotlab/service/config/RuntimeConfig.java | 4 ++-- src/test/java/org/myrobotlab/test/AbstractTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/config/RuntimeConfig.java b/src/main/java/org/myrobotlab/service/config/RuntimeConfig.java index d1ac97d2f6..d7572cd118 100644 --- a/src/main/java/org/myrobotlab/service/config/RuntimeConfig.java +++ b/src/main/java/org/myrobotlab/service/config/RuntimeConfig.java @@ -22,9 +22,9 @@ public class RuntimeConfig extends ServiceConfig { public Boolean virtual = false; /** - * Log level debug, info, warning, error + * Log level debug, info, warn, error */ - public String logLevel = "info"; + public String logLevel = "warn"; /** * Locale setting for the instance, initial default will be set by the default jvm/os diff --git a/src/test/java/org/myrobotlab/test/AbstractTest.java b/src/test/java/org/myrobotlab/test/AbstractTest.java index 1a40bae57e..01279a3310 100644 --- a/src/test/java/org/myrobotlab/test/AbstractTest.java +++ b/src/test/java/org/myrobotlab/test/AbstractTest.java @@ -195,7 +195,7 @@ public static void releaseServices() { } } if (threadsRemaining.size() > 0) { - log.info("{} straggling threads remain [{}]", threadsRemaining.size(), String.join(",", threadsRemaining)); + log.warn("{} straggling threads remain [{}]", threadsRemaining.size(), String.join(",", threadsRemaining)); } // log.warn("end of test - id {} remaining services after release {}", From bff28fad077eba35b09ccd1580ffaa04f2b4284d Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 10 Feb 2024 07:43:59 -0800 Subject: [PATCH 036/131] abstract test watcher --- .../org/myrobotlab/test/AbstractTest.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/test/java/org/myrobotlab/test/AbstractTest.java b/src/test/java/org/myrobotlab/test/AbstractTest.java index 01279a3310..fa1261a44b 100644 --- a/src/test/java/org/myrobotlab/test/AbstractTest.java +++ b/src/test/java/org/myrobotlab/test/AbstractTest.java @@ -23,6 +23,11 @@ import org.myrobotlab.service.config.RuntimeConfig; import org.slf4j.Logger; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; + public class AbstractTest { /** cached network test value for tests */ @@ -48,6 +53,34 @@ public class AbstractTest { static public String simpleName; private static boolean lineFeedFooter = true; + + @Rule + public TestWatcher watchman = new TestWatcher() { + @Override + protected void starting(Description description) { + System.out.println("Starting: " + description.getMethodName()); + } + + @Override + protected void succeeded(Description description) { + // System.out.println("Succeeded: " + description.getMethodName()); + } + + @Override + protected void failed(Throwable e, Description description) { + System.out.println("Failed: " + description.getMethodName()); + } + + @Override + protected void skipped(org.junit.AssumptionViolatedException e, Description description) { + System.out.println("Skipped: " + description.getMethodName()); + } + + @Override + protected void finished(Description description) { + System.out.println("Finished: " + description.getMethodName()); + } + }; public String getSimpleName() { return simpleName; From e8603f9dacd705c27f986b8c999c01d1be5f946f Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 10 Feb 2024 08:13:24 -0800 Subject: [PATCH 037/131] transient processLock --- src/main/java/org/myrobotlab/service/Runtime.java | 2 +- src/test/java/org/myrobotlab/io/FileIOTest.java | 1 + src/test/java/org/myrobotlab/service/RuntimeTest.java | 4 ++-- src/test/java/org/myrobotlab/test/AbstractTest.java | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 36fe72a3f8..9902b3a17b 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -168,7 +168,7 @@ public class Runtime extends Service implements MessageListener, protected final Map> typeToInterface = new HashMap<>(); - private static final Object processLock = new Object(); + private transient static final Object processLock = new Object(); /** * FILTERED_INTERFACES are the set of low level interfaces which we are diff --git a/src/test/java/org/myrobotlab/io/FileIOTest.java b/src/test/java/org/myrobotlab/io/FileIOTest.java index c554835175..8eb14bedb5 100644 --- a/src/test/java/org/myrobotlab/io/FileIOTest.java +++ b/src/test/java/org/myrobotlab/io/FileIOTest.java @@ -182,6 +182,7 @@ public void testToInputStreamString() throws IOException { InputStream ios = FileIO.toInputStream("This is some data that got turned into a stream"); String data = FileIO.toString(ios); assertEquals("This is some data that got turned into a stream", data); + ios.close(); } @Test diff --git a/src/test/java/org/myrobotlab/service/RuntimeTest.java b/src/test/java/org/myrobotlab/service/RuntimeTest.java index e3883cf97f..e2a01278c1 100644 --- a/src/test/java/org/myrobotlab/service/RuntimeTest.java +++ b/src/test/java/org/myrobotlab/service/RuntimeTest.java @@ -26,8 +26,8 @@ public class RuntimeTest extends AbstractTest { public final static Logger log = LoggerFactory.getLogger(RuntimeTest.class); @Before - public void setUp() { - // LoggingFactory.init("WARN"); + public void beforeTest() { + Runtime.releaseAll(true, true); } @Test diff --git a/src/test/java/org/myrobotlab/test/AbstractTest.java b/src/test/java/org/myrobotlab/test/AbstractTest.java index fa1261a44b..d782797c9b 100644 --- a/src/test/java/org/myrobotlab/test/AbstractTest.java +++ b/src/test/java/org/myrobotlab/test/AbstractTest.java @@ -58,7 +58,7 @@ public class AbstractTest { public TestWatcher watchman = new TestWatcher() { @Override protected void starting(Description description) { - System.out.println("Starting: " + description.getMethodName()); + System.out.println("Starting: " + description.getClassName() + "." + description.getMethodName()); } @Override From 8adeb2f9d8998d00882d91646359bb3f52b33653 Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 10 Feb 2024 10:10:28 -0800 Subject: [PATCH 038/131] clean threads --- src/main/java/org/myrobotlab/opencv/OpenCVFilter.java | 2 +- .../myrobotlab/opencv/OpenCVFilterMiniXception.java | 5 ++++- .../java/org/myrobotlab/opencv/OpenCVFilterYolo.java | 4 ++-- src/main/java/org/myrobotlab/service/OpenCV.java | 6 ++++++ src/test/java/org/myrobotlab/service/OpenCVTest.java | 11 +++++++++-- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/myrobotlab/opencv/OpenCVFilter.java b/src/main/java/org/myrobotlab/opencv/OpenCVFilter.java index ac90bae143..860bceadc3 100644 --- a/src/main/java/org/myrobotlab/opencv/OpenCVFilter.java +++ b/src/main/java/org/myrobotlab/opencv/OpenCVFilter.java @@ -192,7 +192,7 @@ static private Mat read(String filename) { /** * This will enable/disable the filter in the pipeline */ - protected boolean enabled = true; + protected volatile boolean enabled = true; protected int height; diff --git a/src/main/java/org/myrobotlab/opencv/OpenCVFilterMiniXception.java b/src/main/java/org/myrobotlab/opencv/OpenCVFilterMiniXception.java index 8dea3fdf75..bd5de81abb 100755 --- a/src/main/java/org/myrobotlab/opencv/OpenCVFilterMiniXception.java +++ b/src/main/java/org/myrobotlab/opencv/OpenCVFilterMiniXception.java @@ -59,7 +59,7 @@ public OpenCVFilterMiniXception(String name) { } private void loadDL4j() { - dl4j = (Deeplearning4j) Runtime.createAndStart("dl4j", "Deeplearning4j"); + dl4j = (Deeplearning4j) Runtime.start("dl4j", "Deeplearning4j"); log.info("Loading mini XCEPTION Model."); try { dl4j.loadMiniEXCEPTION(); @@ -158,6 +158,9 @@ public void release() { running = false; converter1.close(); converter2.close(); + if (dl4j != null) { + dl4j.releaseService(); + } } @Override diff --git a/src/main/java/org/myrobotlab/opencv/OpenCVFilterYolo.java b/src/main/java/org/myrobotlab/opencv/OpenCVFilterYolo.java index ce83566839..060b5e43ce 100755 --- a/src/main/java/org/myrobotlab/opencv/OpenCVFilterYolo.java +++ b/src/main/java/org/myrobotlab/opencv/OpenCVFilterYolo.java @@ -378,12 +378,12 @@ public void enable() { @Override public void disable() { + super.disable(); if (classifier == null) { // already disabled return; } - super.disable(); - int waitTime = 0; + int waitTime = 0; while (classifier != null && waitTime < 1000) { ++waitTime; Service.sleep(10); diff --git a/src/main/java/org/myrobotlab/service/OpenCV.java b/src/main/java/org/myrobotlab/service/OpenCV.java index ff093721bd..dcd7ad08d9 100644 --- a/src/main/java/org/myrobotlab/service/OpenCV.java +++ b/src/main/java/org/myrobotlab/service/OpenCV.java @@ -461,6 +461,7 @@ public void reset() { singleFrame = false; lastFrame = null; blockingData.clear(); + removeFilters(); } public static IplImage cropImage(IplImage img, CvRect rect) { @@ -2099,6 +2100,11 @@ public static void main(String[] args) throws Exception { // Runtime.start("python", "Python"); OpenCV cv = (OpenCV) Runtime.start("cv", "OpenCV"); + cv.capture(); + + cv.addFilter(new OpenCVFilterYolo("yolo")); + sleep(1000); + cv.removeFilters(); OpenCVFilter fr = new OpenCVFilterFaceRecognizer("fr"); cv.addFilter(fr); diff --git a/src/test/java/org/myrobotlab/service/OpenCVTest.java b/src/test/java/org/myrobotlab/service/OpenCVTest.java index fa9e250ae5..137a12a499 100644 --- a/src/test/java/org/myrobotlab/service/OpenCVTest.java +++ b/src/test/java/org/myrobotlab/service/OpenCVTest.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Map; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; @@ -87,6 +88,12 @@ public static void main(String[] args) { @Rule public final TestName testName = new TestName(); + + @Before + public void beforeTest() { + cv.reset(); + } + @BeforeClass public static void setUpBeforeClass() throws Exception { @@ -222,8 +229,8 @@ public final void testAllFilterTypes() { for (String fn : OpenCV.POSSIBLE_FILTERS) { log.warn("trying filter {}", fn); - if (fn.startsWith("DL4J") || fn.startsWith("FaceTraining") || fn.startsWith("Tesseract") || fn.startsWith("SimpleBlobDetector") || fn.startsWith("Solr") || fn.startsWith("Split")) { - log.info("skipping {}", fn); + if ( fn.startsWith("FaceDetectDNN") || fn.startsWith("FaceRecognizer") || fn.startsWith("DL4J") || fn.startsWith("FaceTraining") || fn.startsWith("Tesseract") || fn.startsWith("SimpleBlobDetector") || fn.startsWith("Solr") || fn.startsWith("Split")) { + log.warn("skipping {}", fn); continue; } cv.addFilter(fn); From d6c0831f8994b58b95e8bd1b0daa6f944f1258d9 Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 10 Feb 2024 17:12:13 -0800 Subject: [PATCH 039/131] cleaned up InMoov2 parts --- .../org/myrobotlab/service/InMoov2Arm.java | 54 +++++++++++++++-- .../org/myrobotlab/service/InMoov2Hand.java | 44 ++++++++++++++ .../org/myrobotlab/service/InMoov2Head.java | 60 +++++++++++++++++++ .../org/myrobotlab/service/InMoov2Torso.java | 33 ++++++++++ 4 files changed, 187 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/InMoov2Arm.java b/src/main/java/org/myrobotlab/service/InMoov2Arm.java index 3b74a3bf20..1b4b45e6b5 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2Arm.java +++ b/src/main/java/org/myrobotlab/service/InMoov2Arm.java @@ -10,7 +10,9 @@ import org.myrobotlab.io.FileIO; import org.myrobotlab.kinematics.DHLink; import org.myrobotlab.kinematics.DHRobotArm; +import org.myrobotlab.logging.Level; import org.myrobotlab.logging.LoggerFactory; +import org.myrobotlab.logging.LoggingFactory; import org.myrobotlab.math.MathUtils; import org.myrobotlab.service.config.InMoov2ArmConfig; import org.myrobotlab.service.interfaces.IKJointAngleListener; @@ -127,10 +129,18 @@ public void startService() { @Override public void stopService() { super.stopService(); - releasePeer("bicep"); - releasePeer("rotate"); - releasePeer("shoulder"); - releasePeer("omoplate"); + if (bicep != null) { + ((Service)bicep).stopService(); + } + if (rotate != null) { + ((Service)rotate).stopService(); + } + if (shoulder != null) { + ((Service)shoulder).stopService(); + } + if (omoplate != null) { + ((Service)omoplate).stopService(); + } } @Override @@ -296,6 +306,20 @@ public void onJointAngles(Map angleMap) { public void releaseService() { try { disable(); + + if (bicep != null) { + ((Service)bicep).releaseService(); + } + if (rotate != null) { + ((Service)rotate).releaseService(); + } + if (shoulder != null) { + ((Service)shoulder).releaseService(); + } + if (omoplate != null) { + ((Service)omoplate).releaseService(); + } + super.releaseService(); } catch (Exception e) { error(e); @@ -468,5 +492,27 @@ public void waitTargetPos() { if (omoplate != null) omoplate.waitTargetPos(); } + + public static void main(String[] args) { + LoggingFactory.init(Level.INFO); + + try { + + Runtime.main(new String[] { "--log-level", "info", "-s", "inmoov2arm", "InMoov2Arm" }); + // Runtime.main(new String[] {}); + // Runtime.main(new String[] { "--install" }); + InMoov2Arm arm = (InMoov2Arm)Runtime.start("inmoov2arm", "InMoov2Arm"); + arm.releaseService(); + + boolean done = true; + if (done) { + return; + } + log.info("leaving main"); + + } catch (Exception e) { + log.error("main threw", e); + } + } } diff --git a/src/main/java/org/myrobotlab/service/InMoov2Hand.java b/src/main/java/org/myrobotlab/service/InMoov2Hand.java index b30c2bd792..06b6d3b459 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2Hand.java +++ b/src/main/java/org/myrobotlab/service/InMoov2Hand.java @@ -570,11 +570,55 @@ public List refreshControllers() { public void release() { disable(); } + + @Override + public void stopService() { + disable(); + if (thumb != null) { + ((Service)thumb).stopService(); + } + if (index != null) { + ((Service)index).stopService(); + } + if (majeure != null) { + ((Service)majeure).stopService(); + } + if (ringFinger != null) { + ((Service)ringFinger).stopService(); + } + if (pinky != null) { + ((Service)pinky).stopService(); + } + if (wrist != null) { + ((Service)wrist).stopService(); + } + super.stopService(); + } @Override public void releaseService() { try { disable(); + + if (thumb != null) { + ((Service)thumb).releaseService(); + } + if (index != null) { + ((Service)index).releaseService(); + } + if (majeure != null) { + ((Service)majeure).releaseService(); + } + if (ringFinger != null) { + ((Service)ringFinger).releaseService(); + } + if (pinky != null) { + ((Service)pinky).releaseService(); + } + if (wrist != null) { + ((Service)wrist).releaseService(); + } + super.releaseService(); } catch (Exception e) { error(e); diff --git a/src/main/java/org/myrobotlab/service/InMoov2Head.java b/src/main/java/org/myrobotlab/service/InMoov2Head.java index f3f5edf366..da9052ca65 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2Head.java +++ b/src/main/java/org/myrobotlab/service/InMoov2Head.java @@ -359,10 +359,70 @@ public void waitTargetPos() { public void release() { disable(); } + + @Override + public void stopService() { + + if (jaw != null) { + ((Service)jaw).stopService(); + } + if (eyeX != null) { + ((Service)eyeX).stopService(); + } + if (eyeY != null) { + ((Service)eyeY).stopService(); + } + if (neck != null) { + ((Service)neck).stopService(); + } + if (rothead != null) { + ((Service)rothead).stopService(); + } + if (rollNeck != null) { + ((Service)rollNeck).stopService(); + } + if (eyelidLeft != null) { + ((Service)eyelidLeft).stopService(); + } + if (eyelidRight != null) { + ((Service)eyelidRight).stopService(); + } + + super.stopService(); + } + + + @Override public void releaseService() { disable(); + + if (jaw != null) { + ((Service)jaw).releaseService(); + } + if (eyeX != null) { + ((Service)eyeX).releaseService(); + } + if (eyeY != null) { + ((Service)eyeY).releaseService(); + } + if (neck != null) { + ((Service)neck).releaseService(); + } + if (rothead != null) { + ((Service)rothead).releaseService(); + } + if (rollNeck != null) { + ((Service)rollNeck).releaseService(); + } + if (eyelidLeft != null) { + ((Service)eyelidLeft).releaseService(); + } + if (eyelidRight != null) { + ((Service)eyelidRight).releaseService(); + } + super.releaseService(); } diff --git a/src/main/java/org/myrobotlab/service/InMoov2Torso.java b/src/main/java/org/myrobotlab/service/InMoov2Torso.java index 75fa410ca2..3754e43a3c 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2Torso.java +++ b/src/main/java/org/myrobotlab/service/InMoov2Torso.java @@ -41,11 +41,44 @@ public void startService() { midStom = (ServoControl) getPeer("midStom"); lowStom = (ServoControl) getPeer("lowStom"); } + + @Override + public void stopService() { + disable(); + + if (topStom != null) { + ((Service)topStom).stopService(); + } + + if (midStom != null) { + ((Service)midStom).stopService(); + } + + if (lowStom != null) { + ((Service)lowStom).stopService(); + } + + super.stopService(); + } @Override public void releaseService() { try { disable(); + + + if (topStom != null) { + ((Service)topStom).releaseService(); + } + + if (midStom != null) { + ((Service)midStom).releaseService(); + } + + if (lowStom != null) { + ((Service)lowStom).releaseService(); + } + topStom = null; midStom = null; From cc02708c197635d7b6d4506c262663f43b491fec Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 10 Feb 2024 17:17:39 -0800 Subject: [PATCH 040/131] clean random shutdown --- src/main/java/org/myrobotlab/service/Random.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/org/myrobotlab/service/Random.java b/src/main/java/org/myrobotlab/service/Random.java index 8a9e1875fb..d018df206a 100644 --- a/src/main/java/org/myrobotlab/service/Random.java +++ b/src/main/java/org/myrobotlab/service/Random.java @@ -453,6 +453,12 @@ public void disableAll() { } broadcastState(); } + + @Override + public void releaseService() { + disable(); + super.releaseService(); + } public static void main(String[] args) { try { From ab0141b771ed110bb2c66046c313020d85ff9bce Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 11 Feb 2024 07:16:12 -0800 Subject: [PATCH 041/131] drupp neck config --- .../org/myrobotlab/service/DruppNeck.java | 33 +++++++++---------- .../service/config/DruppNeckConfig.java | 6 ++++ 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/DruppNeck.java b/src/main/java/org/myrobotlab/service/DruppNeck.java index 1c7aa42e39..e99a1a290c 100755 --- a/src/main/java/org/myrobotlab/service/DruppNeck.java +++ b/src/main/java/org/myrobotlab/service/DruppNeck.java @@ -4,7 +4,7 @@ import org.myrobotlab.kinematics.DruppIKSolver; import org.myrobotlab.logging.LoggingFactory; import org.myrobotlab.math.MathUtils; -import org.myrobotlab.service.config.ServiceConfig; +import org.myrobotlab.service.config.DruppNeckConfig; import org.myrobotlab.service.interfaces.ServoControl; /** @@ -18,18 +18,14 @@ * @author kwatters * */ -public class DruppNeck extends Service { +public class DruppNeck extends Service { private static final long serialVersionUID = 1L; // 3 servos for the drupp neck - public transient ServoControl up; - public transient ServoControl middle; - public transient ServoControl down; + protected transient ServoControl up; + protected transient ServoControl middle; + protected transient ServoControl down; - // this is an offset angle that is added to the solution from the IK solver - public double upOffset = 90; - public double middleOffset = 120 + 90; - public double downOffset = -120 + 90; public DruppNeck(String n, String id) { super(n, id); @@ -61,9 +57,9 @@ public void moveTo(double roll, double pitch, double yaw) throws Exception { // TODO: if the solver fails, should we catch this exception ? double[] result = solver.solve(rollRad, pitchRad, yawRad); // convert to degrees - double upDeg = MathUtils.radToDeg(result[0]) + upOffset; - double middleDeg = MathUtils.radToDeg(result[1]) + middleOffset; - double downDeg = MathUtils.radToDeg(result[2]) + downOffset; + double upDeg = MathUtils.radToDeg(result[0]) + config.upOffset; + double middleDeg = MathUtils.radToDeg(result[1]) + config.middleOffset; + double downDeg = MathUtils.radToDeg(result[2]) + config.downOffset; // Ok, servos can only (typically) move from 0 to 180.. if any of the angles // are // negative... we can't move there.. let's log a warning @@ -84,6 +80,7 @@ public void moveTo(double roll, double pitch, double yaw) throws Exception { down.moveTo(downDeg); // TODO: broadcast state? } + /** * Enable the servos @@ -141,27 +138,27 @@ public void setServos(ServoControl up, ServoControl middle, ServoControl down) { } public double getUpOffset() { - return upOffset; + return config.upOffset; } public void setUpOffset(double upOffset) { - this.upOffset = upOffset; + this.config.upOffset = upOffset; } public double getMiddleOffset() { - return middleOffset; + return config.middleOffset; } public void setMiddleOffset(double middleOffset) { - this.middleOffset = middleOffset; + this.config.middleOffset = middleOffset; } public double getDownOffset() { - return downOffset; + return config.downOffset; } public void setDownOffset(double downOffset) { - this.downOffset = downOffset; + this.config.downOffset = downOffset; } public static void main(String[] args) throws Exception { diff --git a/src/main/java/org/myrobotlab/service/config/DruppNeckConfig.java b/src/main/java/org/myrobotlab/service/config/DruppNeckConfig.java index d4b3f730fb..17fc10efb9 100644 --- a/src/main/java/org/myrobotlab/service/config/DruppNeckConfig.java +++ b/src/main/java/org/myrobotlab/service/config/DruppNeckConfig.java @@ -3,6 +3,12 @@ import org.myrobotlab.framework.Plan; public class DruppNeckConfig extends ServiceConfig { + + // this is an offset angle that is added to the solution from the IK solver + public double upOffset = 90; + public double middleOffset = 120 + 90; + public double downOffset = -120 + 90; + @Override public Plan getDefault(Plan plan, String name) { From 0bd316b53f66e02f1ec4737dc7d566fba11dbb7c Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 11 Feb 2024 08:49:53 -0800 Subject: [PATCH 042/131] fixed so Runtime.release(name) and Service.releaseService(name) behave consistently --- .../org/myrobotlab/framework/Service.java | 2 +- .../org/myrobotlab/service/DruppNeck.java | 43 +++++++++++-------- .../java/org/myrobotlab/service/Runtime.java | 17 ++++++++ 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/myrobotlab/framework/Service.java b/src/main/java/org/myrobotlab/framework/Service.java index 0449c05e16..3f7acbf755 100644 --- a/src/main/java/org/myrobotlab/framework/Service.java +++ b/src/main/java/org/myrobotlab/framework/Service.java @@ -1608,7 +1608,7 @@ public Service publishState() { @Override synchronized public void releaseService() { // auto release children and unregister - Runtime.releaseService(getName()); + Runtime.releaseServiceInternal(getName()); } /** diff --git a/src/main/java/org/myrobotlab/service/DruppNeck.java b/src/main/java/org/myrobotlab/service/DruppNeck.java index e99a1a290c..fbf5cd3a11 100755 --- a/src/main/java/org/myrobotlab/service/DruppNeck.java +++ b/src/main/java/org/myrobotlab/service/DruppNeck.java @@ -30,6 +30,13 @@ public class DruppNeck extends Service { public DruppNeck(String n, String id) { super(n, id); } + + public void startService() { + super.startService(); + up = (ServoControl)startPeer("up"); + middle = (ServoControl)startPeer("middle"); + down = (ServoControl)startPeer("down"); + } private DruppIKSolver solver = new DruppIKSolver(); @@ -165,26 +172,26 @@ public static void main(String[] args) throws Exception { LoggingFactory.init("INFO"); // To use the drup service you need to configure and attach the servos // then set them on the service. - Runtime.start("gui", "SwingGui"); - Runtime.start("python", "Python"); - Servo up = (Servo) Runtime.start("up", "Servo"); - Servo middle = (Servo) Runtime.start("middle", "Servo"); - Servo down = (Servo) Runtime.start("down", "Servo"); - up.setPin(6); - middle.setPin(5); - down.setPin(4); - // String port = "COM4"; - String port = "VIRTUAL_COM_PORT"; - VirtualArduino va1 = (VirtualArduino) Runtime.start("va1", "VirtualArduino"); - va1.connect(port); - Arduino ard = (Arduino) Runtime.start("ard", "Arduino"); - ard.connect(port); - ard.attach(up); - ard.attach(middle); - ard.attach(down); +// Runtime.start("python", "Python"); +// Servo up = (Servo) Runtime.start("up", "Servo"); +// Servo middle = (Servo) Runtime.start("middle", "Servo"); +// Servo down = (Servo) Runtime.start("down", "Servo"); +// up.setPin(6); +// middle.setPin(5); +// down.setPin(4); +// // String port = "COM4"; +// String port = "VIRTUAL_COM_PORT"; +// VirtualArduino va1 = (VirtualArduino) Runtime.start("va1", "VirtualArduino"); +// va1.connect(port); +// Arduino ard = (Arduino) Runtime.start("ard", "Arduino"); +// ard.connect(port); +// ard.attach(up); +// ard.attach(middle); +// ard.attach(down); // Create the drupp service DruppNeck neck = (DruppNeck) Runtime.start("neck", "DruppNeck"); - neck.setServos(up, middle, down); + Runtime.start("webgui", "WebGui"); + // neck.setServos(up, middle, down); // neck.moveTo(0, 0, 0); // neck.moveTo(0, 0, -45); // neck.moveTo(0, 0, 45); diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 9902b3a17b..e838cf6c52 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -1933,6 +1933,22 @@ public static Registration register(Registration registration) { * */ public static boolean releaseService(String inName) { + ServiceInterface sc = getService(inName); + if (sc != null) { + sc.releaseService(); + return true; + } + return false; + } + + + /** + * Called after any subclassed releaseService has been called, this cleans + * up the registry and removes peers + * @param inName + * @return + */ + public static boolean releaseServiceInternal(String inName) { synchronized (processLock) { if (inName == null) { log.debug("release (null)"); @@ -1988,6 +2004,7 @@ public static boolean releaseService(String inName) { } } + /** * Removes registration for a service. Removes the service from * {@link #typeToInterface} and {@link #interfaceToNames}. From 3fb04c8bdb3a7b449a70b17a615f6fdd03bd5fdf Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 11 Feb 2024 11:38:32 -0800 Subject: [PATCH 043/131] drupp merge --- .../java/org/myrobotlab/service/DruppNeck.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/DruppNeck.java b/src/main/java/org/myrobotlab/service/DruppNeck.java index 9e7f11bf25..b07c42419b 100755 --- a/src/main/java/org/myrobotlab/service/DruppNeck.java +++ b/src/main/java/org/myrobotlab/service/DruppNeck.java @@ -45,13 +45,13 @@ public void startService() { * down servos. * * @param roll - * degrees + * degrees * @param pitch - * degrees + * degrees * @param yaw - * degrees + * degrees * @throws Exception - * boom + * boom * */ public void moveTo(double roll, double pitch, double yaw) throws Exception { @@ -74,14 +74,12 @@ public void moveTo(double roll, double pitch, double yaw) throws Exception { // but for the drupp neck, if you've installed it correctly, // all servos can go from 0 to 180... if (upDeg < 0 || middleDeg < 0 || downDeg < 0 || upDeg > 180 || middleDeg > 180 || downDeg > 180) { - log.warn("Target Position out of range! {} Pitch {} Yaw {} -> Up {} Middle {} Down {}", roll, pitch, yaw, - MathUtils.round(upDeg, 3), MathUtils.round(middleDeg, 3), + log.warn("Target Position out of range! {} Pitch {} Yaw {} -> Up {} Middle {} Down {}", roll, pitch, yaw, MathUtils.round(upDeg, 3), MathUtils.round(middleDeg, 3), MathUtils.round(downDeg, 3)); // Skipping this movement as it's likely unstable! return; } - log.info("Input Roll {} Pitch {} Yaw {} -> Up {} Middle {} Down {}", roll, pitch, yaw, MathUtils.round(upDeg, 3), - MathUtils.round(middleDeg, 3), MathUtils.round(downDeg, 3)); + log.info("Input Roll {} Pitch {} Yaw {} -> Up {} Middle {} Down {}", roll, pitch, yaw, MathUtils.round(upDeg, 3), MathUtils.round(middleDeg, 3), MathUtils.round(downDeg, 3)); // we should probably track the last moved to position. up.moveTo(upDeg); middle.moveTo(middleDeg); @@ -181,7 +179,8 @@ public static void main(String[] args) throws Exception { // down.setPin(4); // // String port = "COM4"; // String port = "VIRTUAL_COM_PORT"; - // VirtualArduino va1 = (VirtualArduino) Runtime.start("va1", "VirtualArduino"); + // VirtualArduino va1 = (VirtualArduino) Runtime.start("va1", + // "VirtualArduino"); // va1.connect(port); // Arduino ard = (Arduino) Runtime.start("ard", "Arduino"); // ard.connect(port); From b70114e169ec0a6112ad9e3d16e0f8bf53da5366 Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 11 Feb 2024 17:51:11 -0800 Subject: [PATCH 044/131] intermediate --- .../org/myrobotlab/service/JMonkeyEngine.java | 2 +- .../org/myrobotlab/service/MotorDualPwm.java | 2 +- .../java/org/myrobotlab/service/OpenCV.java | 6 ++ .../java/org/myrobotlab/service/Python.java | 2 +- .../java/org/myrobotlab/service/Random.java | 6 ++ .../java/org/myrobotlab/service/Serial.java | 2 +- .../service/config/OpenWeatherMapConfig.java | 2 +- .../config/YahooFinanceStockQuoteConfig.java | 2 +- .../myrobotlab/service/meta/JoystickMeta.java | 6 +- .../myrobotlab/vertx/WebSocketHandler.java | 2 +- .../app/service/js/FiniteStateMachineGui.js | 1 + .../service/views/FiniteStateMachineGui.html | 17 +++++ .../myrobotlab/programab/TemplateTest.java | 52 +++++++++++++++ .../org/myrobotlab/test/AbstractTest.java | 64 +++++++++++++++++-- 14 files changed, 150 insertions(+), 16 deletions(-) create mode 100644 src/test/java/org/myrobotlab/programab/TemplateTest.java diff --git a/src/main/java/org/myrobotlab/service/JMonkeyEngine.java b/src/main/java/org/myrobotlab/service/JMonkeyEngine.java index 2d19048c84..af2d354f43 100644 --- a/src/main/java/org/myrobotlab/service/JMonkeyEngine.java +++ b/src/main/java/org/myrobotlab/service/JMonkeyEngine.java @@ -2489,7 +2489,7 @@ public static void main(String[] args) { i01.startPeer("simulator"); } - Platform.setVirtual(true); + Runtime.getInstance().setVirtual(true); // Runtime.main(new String[] { "--interactive", "--id", "admin" }); JMonkeyEngine jme = (JMonkeyEngine) Runtime.start("simulator", "JMonkeyEngine"); diff --git a/src/main/java/org/myrobotlab/service/MotorDualPwm.java b/src/main/java/org/myrobotlab/service/MotorDualPwm.java index e1746ca071..3187e52ee0 100644 --- a/src/main/java/org/myrobotlab/service/MotorDualPwm.java +++ b/src/main/java/org/myrobotlab/service/MotorDualPwm.java @@ -96,7 +96,7 @@ public static void main(String[] args) { LoggingFactory.init(Level.INFO); String arduinoPort = "COM5"; - Platform.setVirtual(true); + Runtime.getInstance().setVirtual(true); Runtime.startConfig("dev"); Runtime.start("webgui", "WebGui"); MotorDualPwm motor = (MotorDualPwm) Runtime.start("motor", "MotorDualPwm"); diff --git a/src/main/java/org/myrobotlab/service/OpenCV.java b/src/main/java/org/myrobotlab/service/OpenCV.java index ff093721bd..dcd7ad08d9 100644 --- a/src/main/java/org/myrobotlab/service/OpenCV.java +++ b/src/main/java/org/myrobotlab/service/OpenCV.java @@ -461,6 +461,7 @@ public void reset() { singleFrame = false; lastFrame = null; blockingData.clear(); + removeFilters(); } public static IplImage cropImage(IplImage img, CvRect rect) { @@ -2099,6 +2100,11 @@ public static void main(String[] args) throws Exception { // Runtime.start("python", "Python"); OpenCV cv = (OpenCV) Runtime.start("cv", "OpenCV"); + cv.capture(); + + cv.addFilter(new OpenCVFilterYolo("yolo")); + sleep(1000); + cv.removeFilters(); OpenCVFilter fr = new OpenCVFilterFaceRecognizer("fr"); cv.addFilter(fr); diff --git a/src/main/java/org/myrobotlab/service/Python.java b/src/main/java/org/myrobotlab/service/Python.java index 7700a1318d..c3d18162ed 100644 --- a/src/main/java/org/myrobotlab/service/Python.java +++ b/src/main/java/org/myrobotlab/service/Python.java @@ -679,7 +679,7 @@ public void onStarted(String serviceName) { @Override public void onReleased(String serviceName) { - String registerScript = String.format("%s = None\n", CodecUtils.getSafeReferenceName(serviceName)); + String registerScript = String.format("%s = None\n", CodecUtils.getSafeReferenceName(CodecUtils.getShortName(serviceName))); exec(registerScript, false); } diff --git a/src/main/java/org/myrobotlab/service/Random.java b/src/main/java/org/myrobotlab/service/Random.java index 8a9e1875fb..d018df206a 100644 --- a/src/main/java/org/myrobotlab/service/Random.java +++ b/src/main/java/org/myrobotlab/service/Random.java @@ -453,6 +453,12 @@ public void disableAll() { } broadcastState(); } + + @Override + public void releaseService() { + disable(); + super.releaseService(); + } public static void main(String[] args) { try { diff --git a/src/main/java/org/myrobotlab/service/Serial.java b/src/main/java/org/myrobotlab/service/Serial.java index af16f3522a..c6fccb9d84 100644 --- a/src/main/java/org/myrobotlab/service/Serial.java +++ b/src/main/java/org/myrobotlab/service/Serial.java @@ -1338,7 +1338,7 @@ public static void main(String[] args) { try { - Platform.setVirtual(true); + Runtime.getInstance().setVirtual(true); Serial s = (Serial) Runtime.start("s1", "Serial"); String vport1 = "vport1"; diff --git a/src/main/java/org/myrobotlab/service/config/OpenWeatherMapConfig.java b/src/main/java/org/myrobotlab/service/config/OpenWeatherMapConfig.java index 37cdd82a0b..9a6a51baab 100644 --- a/src/main/java/org/myrobotlab/service/config/OpenWeatherMapConfig.java +++ b/src/main/java/org/myrobotlab/service/config/OpenWeatherMapConfig.java @@ -3,7 +3,7 @@ import org.myrobotlab.framework.Peer; import org.myrobotlab.framework.Plan; -public class OpenWeatherMapConfig extends ServiceConfig { +public class OpenWeatherMapConfig extends HttpClientConfig { public String currentUnits; public String currentTown; diff --git a/src/main/java/org/myrobotlab/service/config/YahooFinanceStockQuoteConfig.java b/src/main/java/org/myrobotlab/service/config/YahooFinanceStockQuoteConfig.java index d351154c44..32ae5984d8 100644 --- a/src/main/java/org/myrobotlab/service/config/YahooFinanceStockQuoteConfig.java +++ b/src/main/java/org/myrobotlab/service/config/YahooFinanceStockQuoteConfig.java @@ -1,5 +1,5 @@ package org.myrobotlab.service.config; -public class YahooFinanceStockQuoteConfig extends ServiceConfig { +public class YahooFinanceStockQuoteConfig extends HttpClientConfig { } diff --git a/src/main/java/org/myrobotlab/service/meta/JoystickMeta.java b/src/main/java/org/myrobotlab/service/meta/JoystickMeta.java index ca544c8523..b2fb538f80 100644 --- a/src/main/java/org/myrobotlab/service/meta/JoystickMeta.java +++ b/src/main/java/org/myrobotlab/service/meta/JoystickMeta.java @@ -20,12 +20,12 @@ public JoystickMeta() { addCategory("control", "telerobotics"); addDependency("net.java.jinput", "jinput", "2.0.9"); - log.info("Joystick.getMetaData {} isArm() {}", platform, platform.isArm()); + log.debug("Joystick.getMetaData {} isArm() {}", platform, platform.isArm()); if (platform.isArm()) { - log.info("adding armv7 native dependencies"); + log.debug("adding armv7 native dependencies"); addDependency("jinput-natives", "jinput-natives-armv7.hfp", "2.0.7", "zip"); } else { - log.info("adding jinput native dependencies"); + log.debug("adding jinput native dependencies"); addDependency("jinput-natives", "jinput-natives", "2.0.7", "zip"); } } diff --git a/src/main/java/org/myrobotlab/vertx/WebSocketHandler.java b/src/main/java/org/myrobotlab/vertx/WebSocketHandler.java index e7e6b5fe63..c74b12e185 100644 --- a/src/main/java/org/myrobotlab/vertx/WebSocketHandler.java +++ b/src/main/java/org/myrobotlab/vertx/WebSocketHandler.java @@ -131,7 +131,7 @@ public void handle(String json) { // FIXME get rid of fill-uuid Message describe = Message.createMessage(String.format("%s@%s", service.getName(), Runtime.get().getId()), "runtime", "describe", - new Object[] { "fill-uuid", new DescribeQuery(Platform.getLocalInstance().getId(), uuid) }); + new Object[] { "fill-uuid", new DescribeQuery(Runtime.getInstance().getId(), uuid) }); service.sendRemote(describe); log.info(String.format("<-- %s", describe)); newConnection = false; diff --git a/src/main/resources/resource/WebGui/app/service/js/FiniteStateMachineGui.js b/src/main/resources/resource/WebGui/app/service/js/FiniteStateMachineGui.js index 42c559c999..d08f8f2fc8 100644 --- a/src/main/resources/resource/WebGui/app/service/js/FiniteStateMachineGui.js +++ b/src/main/resources/resource/WebGui/app/service/js/FiniteStateMachineGui.js @@ -51,6 +51,7 @@ angular.module('mrlapp.service.FiniteStateMachineGui', []).controller('FiniteSta break case 'onStateChange': $scope.current = data.current + $scope.service.history.push(data) $scope.$apply() break default: diff --git a/src/main/resources/resource/WebGui/app/service/views/FiniteStateMachineGui.html b/src/main/resources/resource/WebGui/app/service/views/FiniteStateMachineGui.html index 067ee7624c..b61f5af303 100644 --- a/src/main/resources/resource/WebGui/app/service/views/FiniteStateMachineGui.html +++ b/src/main/resources/resource/WebGui/app/service/views/FiniteStateMachineGui.html @@ -54,5 +54,22 @@

Last Event {{event}} Current State: {{current}}

+ + + + + + + + + + + + + + + +
TimestampStateEvent
{{ item.ts }}{{ item.state }}{{ item.event }}
+ diff --git a/src/test/java/org/myrobotlab/programab/TemplateTest.java b/src/test/java/org/myrobotlab/programab/TemplateTest.java new file mode 100644 index 0000000000..8d2beb245d --- /dev/null +++ b/src/test/java/org/myrobotlab/programab/TemplateTest.java @@ -0,0 +1,52 @@ +package org.myrobotlab.programab; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import org.junit.Test; +import org.myrobotlab.logging.LoggerFactory; +import org.myrobotlab.programab.models.Mrl; +import org.myrobotlab.programab.models.Template; +import org.slf4j.Logger; + +import com.fasterxml.jackson.dataformat.xml.XmlMapper; + +public class TemplateTest { + + public final static Logger log = LoggerFactory.getLogger(TemplateTest.class); + + @Test + public void testXmlParsing() { + try { + + String xml = ""; + + XmlMapper xmlMapper = new XmlMapper(); + Template template = xmlMapper.readValue(xml, Template.class); + + assertNotNull(template); + assertEquals("XXXX", template.text); + + // Verify Oob parsing + assertNotNull(template.oob); + assertEquals(2, template.oob.mrl.size()); + + // Verify the first Mrl + Mrl mrl1 = template.oob.mrl.get(0); + assertEquals("blah1", mrl1.service); + assertEquals("method1", mrl1.method); + assertEquals(3, mrl1.params.size()); + + // Verify the second Mrl + Mrl mrl2 = template.oob.mrl.get(1); + assertEquals("blah2", mrl2.service); + assertEquals("method2", mrl2.method); + assertNull(mrl2.params); + + } catch (Exception e) { + fail("Exception occurred: " + e.getMessage()); + } + } +} diff --git a/src/test/java/org/myrobotlab/test/AbstractTest.java b/src/test/java/org/myrobotlab/test/AbstractTest.java index c4fc33b83d..d782797c9b 100644 --- a/src/test/java/org/myrobotlab/test/AbstractTest.java +++ b/src/test/java/org/myrobotlab/test/AbstractTest.java @@ -1,5 +1,7 @@ package org.myrobotlab.test; +import java.io.File; +import java.io.FileOutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; @@ -13,12 +15,19 @@ import org.junit.BeforeClass; import org.junit.Rule; import org.junit.rules.TestName; +import org.myrobotlab.codec.CodecUtils; import org.myrobotlab.framework.Platform; import org.myrobotlab.framework.interfaces.Attachable; import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.service.Runtime; +import org.myrobotlab.service.config.RuntimeConfig; import org.slf4j.Logger; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; + public class AbstractTest { /** cached network test value for tests */ @@ -44,6 +53,34 @@ public class AbstractTest { static public String simpleName; private static boolean lineFeedFooter = true; + + @Rule + public TestWatcher watchman = new TestWatcher() { + @Override + protected void starting(Description description) { + System.out.println("Starting: " + description.getClassName() + "." + description.getMethodName()); + } + + @Override + protected void succeeded(Description description) { + // System.out.println("Succeeded: " + description.getMethodName()); + } + + @Override + protected void failed(Throwable e, Description description) { + System.out.println("Failed: " + description.getMethodName()); + } + + @Override + protected void skipped(org.junit.AssumptionViolatedException e, Description description) { + System.out.println("Skipped: " + description.getMethodName()); + } + + @Override + protected void finished(Description description) { + System.out.println("Finished: " + description.getMethodName()); + } + }; public String getSimpleName() { return simpleName; @@ -83,8 +120,23 @@ public static void main(String[] args) { @BeforeClass public static void setUpAbstractTest() throws Exception { - - Platform.setVirtual(true); + + // setup runtime resource = src/main/resources/resource + File runtimeYml = new File("data/config/default/runtime.yml"); +// if (!runtimeYml.exists()) { + runtimeYml.getParentFile().mkdirs(); + RuntimeConfig rc = new RuntimeConfig(); + rc.resource = "src/main/resources/resource"; + String yml = CodecUtils.toYaml(rc); + + FileOutputStream fos = null; + fos = new FileOutputStream(runtimeYml); + fos.write(yml.getBytes()); + fos.close(); + +// } + + Runtime.getInstance().setVirtual(true); String junitLogLevel = System.getProperty("junit.logLevel"); if (junitLogLevel != null) { @@ -145,7 +197,7 @@ static protected void installAll() { */ public static void releaseServices() { - log.info("end of test - id {} remaining services {}", Platform.getLocalInstance().getId(), + log.info("end of test - id {} remaining services {}", Runtime.getInstance().getId(), Arrays.toString(Runtime.getServiceNames())); // release all including runtime - be careful of default runtime.yml @@ -176,7 +228,7 @@ public static void releaseServices() { } } if (threadsRemaining.size() > 0) { - log.info("{} straggling threads remain [{}]", threadsRemaining.size(), String.join(",", threadsRemaining)); + log.warn("{} straggling threads remain [{}]", threadsRemaining.size(), String.join(",", threadsRemaining)); } // log.warn("end of test - id {} remaining services after release {}", @@ -192,11 +244,11 @@ public AbstractTest() { } public void setVirtual() { - Platform.setVirtual(true); + Runtime.getInstance().setVirtual(true); } public boolean isVirtual() { - return Platform.isVirtual(); + return Runtime.getInstance().isVirtual(); } } From abd63e2143779d5d337010c0ca05b11e9c1d27fd Mon Sep 17 00:00:00 2001 From: grog Date: Mon, 12 Feb 2024 05:59:34 -0800 Subject: [PATCH 045/131] javadoc and other small changes --- .../java/org/myrobotlab/codec/CodecUtils.java | 4 +- .../org/myrobotlab/config/ConfigUtils.java | 142 +++++++++++++----- .../framework/repo/MavenWrapper.java | 6 +- .../org/myrobotlab/opencv/OpenCVFilter.java | 2 +- .../opencv/OpenCVFilterMiniXception.java | 5 +- .../myrobotlab/opencv/OpenCVFilterYolo.java | 4 +- .../myrobotlab/programab/models/Event.java | 24 +-- .../org/myrobotlab/programab/models/Oob.java | 12 +- .../myrobotlab/programab/models/Sraix.java | 16 +- .../myrobotlab/programab/models/Template.java | 45 ++---- .../service/interfaces/Gateway.java | 2 +- .../myrobotlab/config/ConfigUtilsTest.java | 43 ++++++ .../org/myrobotlab/service/OpenCVTest.java | 11 +- 13 files changed, 219 insertions(+), 97 deletions(-) create mode 100644 src/test/java/org/myrobotlab/config/ConfigUtilsTest.java diff --git a/src/main/java/org/myrobotlab/codec/CodecUtils.java b/src/main/java/org/myrobotlab/codec/CodecUtils.java index 372caa474b..09d2086c9e 100644 --- a/src/main/java/org/myrobotlab/codec/CodecUtils.java +++ b/src/main/java/org/myrobotlab/codec/CodecUtils.java @@ -495,7 +495,7 @@ public static String getFullName(String name) { } if (getId(name) == null) { - return name + '@' + Platform.getLocalInstance().getId(); + return name + '@' + Runtime.getInstance().getId(); } else { return name; } @@ -1466,7 +1466,7 @@ public static boolean isLocal(String name) { if (!name.contains("@")) { return true; } - return name.substring(name.indexOf("@") + 1).equals(Platform.getLocalInstance().getId()); + return name.substring(name.indexOf("@") + 1).equals(Runtime.getInstance().getId()); } /** diff --git a/src/main/java/org/myrobotlab/config/ConfigUtils.java b/src/main/java/org/myrobotlab/config/ConfigUtils.java index 35c8a776a8..19c256a8cf 100644 --- a/src/main/java/org/myrobotlab/config/ConfigUtils.java +++ b/src/main/java/org/myrobotlab/config/ConfigUtils.java @@ -4,13 +4,26 @@ import java.io.IOException; import org.myrobotlab.codec.CodecUtils; +import org.myrobotlab.framework.CmdOptions; import org.myrobotlab.framework.StartYml; import org.myrobotlab.io.FileIO; +import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.service.Runtime; import org.myrobotlab.service.config.RuntimeConfig; +import org.slf4j.Logger; +/** + * Class to process basic configuration functions and processing. + * + * @author GroG + * + */ public class ConfigUtils { + public final static Logger log = LoggerFactory.getLogger(Runtime.class); + + private static RuntimeConfig config; + /** * This gets the current resource root without starting a Runtime instance if * not already started. The resource root depends on config, if Runtime is @@ -21,51 +34,100 @@ public class ConfigUtils { * @return */ public static String getResourceRoot() { + if (config == null) { + loadRuntimeConfig(null); + } + return config.resource; + + } + + /** + * Loads a runtime config based on the configName. config = + * data/config/{configName}/runtime.yml If one does exits, it is returned, if + * one does not exist a default one is created and saved. + * + * @param configName + * @return + */ + static public RuntimeConfig loadRuntimeConfig(CmdOptions options) { + + if (config != null) { + return config; + } - String resource = "resource"; + StartYml startYml = loadStartYml(); + String configName = null; - // check if runtime is running - if (!Runtime.isAvailable()) { - // check for start.yml + if (startYml.enable) { + configName = startYml.config; + } + + // start with default + config = new RuntimeConfig(); + try { - File checkStartYml = new File("start.yml"); - StartYml startYml = new StartYml(); - if (checkStartYml.exists()) { - String yml; + File runtimeYml = new File(Runtime.ROOT_CONFIG_DIR + File.separator + configName + File.separator + "runtime.yml"); + if (runtimeYml.exists()) { + // parse that file look for resource: entry in file + config = (RuntimeConfig) CodecUtils.readServiceConfig(runtimeYml.getAbsolutePath()); + } else { + FileIO.toFile(runtimeYml, CodecUtils.toYaml(config).getBytes()); + } + + } catch (IOException e) { + log.error("loadRuntimeConfig threw", e); + } + + if (options != null && options.id != null) { + config.id = options.id; + } + + return config; + } + + public static StartYml loadStartYml() { + StartYml startYml = new StartYml(); + String defaultStartFile = CodecUtils.toYaml(startYml); + File checkStartYml = new File("start.yml"); + if (!checkStartYml.exists()) { + // save default start.yml + startYml = new StartYml(); + try { + FileIO.toFile("start.yml", defaultStartFile); + } catch (IOException e) { + log.error("could not save start.yml"); + } + } else { + // load start.yml + try { + String yml = FileIO.toString("start.yml"); + startYml = CodecUtils.fromYaml(yml, StartYml.class); + } catch (Exception e) { + log.error("could not load start.yml replacing with new start.yml", e); + startYml = new StartYml(); try { - yml = FileIO.toString("start.yml"); - startYml = CodecUtils.fromYaml(yml, StartYml.class); - - // see if autostart is on with a config - if (startYml.enable) { - // use that config to find runtime.yml - - File runtimeYml = new File(Runtime.ROOT_CONFIG_DIR + File.separator + startYml.config + File.separator + "runtime.yml"); - if (runtimeYml.exists()) { - // parse that file look for resource: entry in file - RuntimeConfig config = (RuntimeConfig) CodecUtils.readServiceConfig(runtimeYml.getAbsolutePath()); - resource = config.resource; - } - - } else { - // start.yml enable = false / so we'll use default config - File runtimeYml = new File(Runtime.ROOT_CONFIG_DIR + File.separator + "default" + File.separator + "runtime.yml"); - if (runtimeYml.exists()) { - // parse that file look for resource: entry in file - RuntimeConfig config = (RuntimeConfig) CodecUtils.readServiceConfig(runtimeYml.getAbsolutePath()); - resource = config.resource; - } - } - - } catch (IOException e) { - // problem getting or parsing - // going to assume default "resource" + FileIO.toFile("start.yml", defaultStartFile); + } catch (IOException ex) { + log.error("could not save start.yml", ex); } - } // no startYml - return resource; - } else { - // Runtime is available - ask it - return Runtime.getInstance().getConfig().resource; + } } + log.info("start.yml exists {} {}", checkStartYml.exists(), CodecUtils.toJson(startYml)); + return startYml; } + + public static String getId() { + if (config == null) { + loadRuntimeConfig(null); + } + return config.id; + } + + /** + * If Runtime.releaseAll is called the statics here should be reset + */ + public static void reset() { + config = null; + } + } diff --git a/src/main/java/org/myrobotlab/framework/repo/MavenWrapper.java b/src/main/java/org/myrobotlab/framework/repo/MavenWrapper.java index 8374f92cdf..62c0027cbd 100644 --- a/src/main/java/org/myrobotlab/framework/repo/MavenWrapper.java +++ b/src/main/java/org/myrobotlab/framework/repo/MavenWrapper.java @@ -1,5 +1,5 @@ package org.myrobotlab.framework.repo; - +import org.myrobotlab.service.Runtime; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -281,6 +281,8 @@ public static void main(String[] args) { LoggingFactory.init(Level.INFO); + Runtime.getInstance(); + File libraries = new File(ServiceData.LIBRARIES); libraries.mkdir(); File cache = new File(ServiceData.LIBRARIES + File.separator + "serviceData.json"); @@ -309,7 +311,7 @@ public static void main(String[] args) { // repo.installTo(dir); // repo.install(); // repo.installEach(); <-- TODO - test - + Runtime.shutdown(); log.info("done"); } catch (Exception e) { diff --git a/src/main/java/org/myrobotlab/opencv/OpenCVFilter.java b/src/main/java/org/myrobotlab/opencv/OpenCVFilter.java index ac90bae143..860bceadc3 100644 --- a/src/main/java/org/myrobotlab/opencv/OpenCVFilter.java +++ b/src/main/java/org/myrobotlab/opencv/OpenCVFilter.java @@ -192,7 +192,7 @@ static private Mat read(String filename) { /** * This will enable/disable the filter in the pipeline */ - protected boolean enabled = true; + protected volatile boolean enabled = true; protected int height; diff --git a/src/main/java/org/myrobotlab/opencv/OpenCVFilterMiniXception.java b/src/main/java/org/myrobotlab/opencv/OpenCVFilterMiniXception.java index 8dea3fdf75..bd5de81abb 100755 --- a/src/main/java/org/myrobotlab/opencv/OpenCVFilterMiniXception.java +++ b/src/main/java/org/myrobotlab/opencv/OpenCVFilterMiniXception.java @@ -59,7 +59,7 @@ public OpenCVFilterMiniXception(String name) { } private void loadDL4j() { - dl4j = (Deeplearning4j) Runtime.createAndStart("dl4j", "Deeplearning4j"); + dl4j = (Deeplearning4j) Runtime.start("dl4j", "Deeplearning4j"); log.info("Loading mini XCEPTION Model."); try { dl4j.loadMiniEXCEPTION(); @@ -158,6 +158,9 @@ public void release() { running = false; converter1.close(); converter2.close(); + if (dl4j != null) { + dl4j.releaseService(); + } } @Override diff --git a/src/main/java/org/myrobotlab/opencv/OpenCVFilterYolo.java b/src/main/java/org/myrobotlab/opencv/OpenCVFilterYolo.java index ce83566839..060b5e43ce 100755 --- a/src/main/java/org/myrobotlab/opencv/OpenCVFilterYolo.java +++ b/src/main/java/org/myrobotlab/opencv/OpenCVFilterYolo.java @@ -378,12 +378,12 @@ public void enable() { @Override public void disable() { + super.disable(); if (classifier == null) { // already disabled return; } - super.disable(); - int waitTime = 0; + int waitTime = 0; while (classifier != null && waitTime < 1000) { ++waitTime; Service.sleep(10); diff --git a/src/main/java/org/myrobotlab/programab/models/Event.java b/src/main/java/org/myrobotlab/programab/models/Event.java index 7f1033ccdf..d7aeddd852 100644 --- a/src/main/java/org/myrobotlab/programab/models/Event.java +++ b/src/main/java/org/myrobotlab/programab/models/Event.java @@ -2,12 +2,13 @@ /** * Pojo for state change of one of ProgramAB's state info + * * @author GroG * */ public class Event { /** - * the botName in this state change - typically + * the botName in this state change - typically * current session botName */ public String botname; @@ -15,49 +16,48 @@ public class Event { * unique identifier for the session user and bot */ public String id; - + /** * name of the predicate changed */ public String name; - + /** * service this topic change came from */ public String src; - + /** * new topic or state name in this transition */ public String topic; - + /** * timestamp */ public long ts = System.currentTimeMillis(); - + /** * the user name in this state change - usually * current session userName */ public String user; - + /** * new value */ public String value; - - public Event() { + + public Event() { } - + public Event(String src, String userName, String botName, String topic) { this.src = src; this.user = userName; this.botname = botName; this.topic = topic; } - - + @Override public String toString() { return String.format("%s %s=%s", id, name, value); diff --git a/src/main/java/org/myrobotlab/programab/models/Oob.java b/src/main/java/org/myrobotlab/programab/models/Oob.java index 833bab5a0f..5e0d99c4cf 100644 --- a/src/main/java/org/myrobotlab/programab/models/Oob.java +++ b/src/main/java/org/myrobotlab/programab/models/Oob.java @@ -4,11 +4,17 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +/** + * AIML 2.0 Oob Out Of Band xml defined with mrl - legacy and mrljson - json + * typed message + * + * @author GroG + * + */ public class Oob { - + public String mrljson; - + @JacksonXmlElementWrapper(useWrapping = false) public List mrl; } - diff --git a/src/main/java/org/myrobotlab/programab/models/Sraix.java b/src/main/java/org/myrobotlab/programab/models/Sraix.java index 99b0639cb6..1b130ad805 100644 --- a/src/main/java/org/myrobotlab/programab/models/Sraix.java +++ b/src/main/java/org/myrobotlab/programab/models/Sraix.java @@ -1,10 +1,22 @@ package org.myrobotlab.programab.models; -// FIXME add attributes and internal tags +/** + * Basic Sraix model, AIML 2.0 has more elements but these seemed like the most + * relevant and ar actually used. + * + * @author GroG + * + */ public class Sraix { + /** + * Search text when a query is sent to a remote system + */ public String search; + /** + * Oob is Out Of Band text which can be handled by internal processing + */ public Oob oob; - + } diff --git a/src/main/java/org/myrobotlab/programab/models/Template.java b/src/main/java/org/myrobotlab/programab/models/Template.java index 91f8e5de51..d657973005 100644 --- a/src/main/java/org/myrobotlab/programab/models/Template.java +++ b/src/main/java/org/myrobotlab/programab/models/Template.java @@ -5,47 +5,34 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText; -//@JacksonXmlRootElement(localName = "template") -//@JsonIgnoreProperties(ignoreUnknown = true) +/** + * General aiml template used for future parsing + * + * @author GroG + */ @JsonIgnoreProperties(ignoreUnknown = true) public class Template { - // @JacksonXmlElementWrapper(useWrapping = false) - + @JacksonXmlProperty(localName = "template") - @JacksonXmlText - public String text; - - -public Oob oob; - -// @JsonProperty("ignorable") -// public List oob; -// -// public List getOob() { -// return oob; -// } -// -// public void setOob(List oob) { -// this.oob = oob; -// } - + public String text; + + public Oob oob; + public static void main(String[] args) { try { - - // String xml = ""; - // String xml = ""; + String xml = ""; - + XmlMapper xmlMapper = new XmlMapper(); Template template = xmlMapper.readValue(xml, Template.class); - + System.out.println(template); - - } catch(Exception e) { + + } catch (Exception e) { e.printStackTrace(); } - } + } } diff --git a/src/main/java/org/myrobotlab/service/interfaces/Gateway.java b/src/main/java/org/myrobotlab/service/interfaces/Gateway.java index 783ec951ff..7b3ee61b19 100644 --- a/src/main/java/org/myrobotlab/service/interfaces/Gateway.java +++ b/src/main/java/org/myrobotlab/service/interfaces/Gateway.java @@ -83,7 +83,7 @@ default Message getDescribeMsg(String connId) { "describe", new Object[] { FILL_UUID_MAGIC_VAL, - new DescribeQuery(Platform.getLocalInstance().getId(), connId) + new DescribeQuery(Runtime.getInstance().getId(), connId) } ); } diff --git a/src/test/java/org/myrobotlab/config/ConfigUtilsTest.java b/src/test/java/org/myrobotlab/config/ConfigUtilsTest.java new file mode 100644 index 0000000000..5d15601b58 --- /dev/null +++ b/src/test/java/org/myrobotlab/config/ConfigUtilsTest.java @@ -0,0 +1,43 @@ +package org.myrobotlab.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Before; +import org.junit.Test; +import org.myrobotlab.framework.StartYml; +import org.myrobotlab.service.Runtime; + +public class ConfigUtilsTest { + + @Before + public void beforeTest() { + Runtime.releaseAll(true, true); + } + + @Test + public void testGetResourceRoot() { + String resource = ConfigUtils.getResourceRoot(); + // could be affected by dirty filesystem + assertEquals("resource", resource); + } + + @Test + public void testLoadRuntimeConfig() { + String resource = ConfigUtils.getResourceRoot(); + assertNotNull(resource); + } + + @Test + public void testLoadStartYml() { + StartYml start = ConfigUtils.loadStartYml(); + assertNotNull(start); + } + + @Test + public void testGetId() { + assertEquals(ConfigUtils.getId(), ConfigUtils.loadRuntimeConfig(null).id); + } + + +} diff --git a/src/test/java/org/myrobotlab/service/OpenCVTest.java b/src/test/java/org/myrobotlab/service/OpenCVTest.java index fa9e250ae5..137a12a499 100644 --- a/src/test/java/org/myrobotlab/service/OpenCVTest.java +++ b/src/test/java/org/myrobotlab/service/OpenCVTest.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Map; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; @@ -87,6 +88,12 @@ public static void main(String[] args) { @Rule public final TestName testName = new TestName(); + + @Before + public void beforeTest() { + cv.reset(); + } + @BeforeClass public static void setUpBeforeClass() throws Exception { @@ -222,8 +229,8 @@ public final void testAllFilterTypes() { for (String fn : OpenCV.POSSIBLE_FILTERS) { log.warn("trying filter {}", fn); - if (fn.startsWith("DL4J") || fn.startsWith("FaceTraining") || fn.startsWith("Tesseract") || fn.startsWith("SimpleBlobDetector") || fn.startsWith("Solr") || fn.startsWith("Split")) { - log.info("skipping {}", fn); + if ( fn.startsWith("FaceDetectDNN") || fn.startsWith("FaceRecognizer") || fn.startsWith("DL4J") || fn.startsWith("FaceTraining") || fn.startsWith("Tesseract") || fn.startsWith("SimpleBlobDetector") || fn.startsWith("Solr") || fn.startsWith("Split")) { + log.warn("skipping {}", fn); continue; } cv.addFilter(fn); From 69013e59c5ad3873065b8063e8059c0d6d2a0f89 Mon Sep 17 00:00:00 2001 From: grog Date: Mon, 12 Feb 2024 06:20:53 -0800 Subject: [PATCH 046/131] framework updates --- Jenkinsfile | 24 +- README.md | 36 + .../org/myrobotlab/framework/CmdOptions.java | 62 +- .../org/myrobotlab/framework/Platform.java | 51 +- .../org/myrobotlab/framework/Service.java | 24 +- .../org/myrobotlab/framework/StartYml.java | 4 - src/main/java/org/myrobotlab/io/FileIO.java | 36 +- .../java/org/myrobotlab/process/Launcher.java | 43 +- .../java/org/myrobotlab/service/Runtime.java | 1534 ++++++++--------- .../java/org/myrobotlab/service/WebGui.java | 46 +- .../service/config/RuntimeConfig.java | 35 +- .../org/myrobotlab/codec/CodecUtilsTest.java | 19 - .../myrobotlab/framework/CmdOptionsTest.java | 36 +- .../org/myrobotlab/framework/ConfigTest.java | 132 +- .../java/org/myrobotlab/io/FileIOTest.java | 6 +- .../org/myrobotlab/service/RuntimeTest.java | 17 +- .../org/myrobotlab/service/SerialTest.java | 2 +- 17 files changed, 990 insertions(+), 1117 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 8e7ccc45f2..63a28dcadb 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -64,18 +64,18 @@ pipeline { } // stage build - stage('dependencies') { - when { - expression { params.verify == 'true' } - } - steps { - script { - sh ''' - mvn test -Dtest=org.myrobotlab.framework.DependencyTest -q - ''' - } - } - } // stage dependencies + // stage('dependencies') { + // when { + // expression { params.verify == 'true' } + // } + // steps { + // script { + // sh ''' + // mvn test -Dtest=org.myrobotlab.framework.DependencyTest -q + // ''' + // } + // } + // } // stage dependencies // --fail-fast // -DargLine="-Xmx1024m" diff --git a/README.md b/README.md index 69e1433cbf..f22e3b94f8 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,42 @@ type: Runtime virtual: false ``` +# Starting Flowchart +```mermaid +flowchart LR + CommandLine[CommandLine] + Runtime.main([Runtime.main]) + install{install} + shutdown([shutdown]) + checkForStartYml{start.yml + exists?} + startYmlEnabled{start.yml + enabled?} + + CommandLine --> Runtime.main + Runtime.main --> checkForStartYml + checkForStartYml --> |yes| loadStartYml[load start.yml] + checkForStartYml --> |no| createDefaultStartYml[create default start.yml] + createDefaultStartYml --> loadStartYml + loadStartYml --> startYmlEnabled + startYmlEnabled --> |yes| Runtime.startConfig[config = start.yml config] + startYmlEnabled --> |no| default[config = default] + Runtime.startConfig --> loadRuntimeConfig[load runtime config] + default --> loadRuntimeConfig + loadRuntimeConfig --> startRuntime[start runtime] + startRuntime --> applyRuntimeConfig[apply runtime config + does not process registry] + applyRuntimeConfig --> install{install?} + + install -->|yes| loadServiceData[loadServiceData] + install -->|no| Runtime.startConf[get runtime.startConfig config] + + loadServiceData --> findUninstalledDependencies[find uninstallled dependencies] + findUninstalledDependencies -->installDependencies[install dependencies] + installDependencies --> shutdown +``` + + # Network Distributed Architecture ## Websockets - Default Response for New Connection diff --git a/src/main/java/org/myrobotlab/framework/CmdOptions.java b/src/main/java/org/myrobotlab/framework/CmdOptions.java index f0eb00c0e7..2c357e8db6 100644 --- a/src/main/java/org/myrobotlab/framework/CmdOptions.java +++ b/src/main/java/org/myrobotlab/framework/CmdOptions.java @@ -26,9 +26,7 @@ * */ @Command(name = "java -jar myrobotlab.jar ") -public class CmdOptions { - - public final String DEFAULT_CONNECT = "http://localhost:8888"; +public class CmdOptions { static boolean contains(List l, String flag) { for (String f : l) { @@ -39,51 +37,28 @@ static boolean contains(List l, String flag) { return false; } - // launcher ?? - @Option(names = { "-a", "--auto-update" }, description = "auto updating - this feature allows mrl instances to be automatically updated when a new version is available") - public boolean autoUpdate = false; - // launcher @Option(names = { "-c", - "--config" }, fallbackValue="default", description = "Specify a configuration set to start. The config set is a directory which has all the necessary configuration files. It loads runtime.yml first, and subsequent service configuration files will then load. \n example: --config data/config/my-config-dir") + "--config" }, fallbackValue = "default", description = "Specify a configuration set to start. The config set is a directory which has all the necessary configuration files. It loads runtime.yml first, and subsequent service configuration files will then load. \n example: --config data/config/my-config-dir") public String config = null; - @Option(names = { - "--connect" }, arity = "0..*", /* - * defaultValue = DEFAULT_CONNECT, - */ fallbackValue = DEFAULT_CONNECT, description = "connects this mrl instance to another mrl instance - default is " + DEFAULT_CONNECT) - public String connect = null; - @Option(names = { "-h", "-?", "--help" }, description = "shows help") public boolean help = false; - - @Option(names = { "-r", "--config-root" }, description = "sets configuration root, the root for which all config directories are in") - public String configRoot = null; - - - @Option(names = { "--id" }, description = "process identifier to be mdns or network overlay name for this instance - one is created at random if not assigned") + @Option(names = { + "--id" }, description = "process identifier to be mdns or network overlay name for this instance - one is created at random if not assigned") public String id; @Option(names = { "-i", "--install" }, arity = "0..*", description = "installs all dependencies for all services, --install {serviceType} installs dependencies for a specific service, if no type is specified then all services are installed") public String install[]; - @Option(names = { "-I", - "--invoke" }, arity = "0..*", description = "invokes a method on a service --invoke {serviceName} {method} {param0} {param1} ... : --invoke python execFile myFile.py") - public String invoke[]; - - // for launcher @Option(names = { "-j", "--jvm" }, arity = "0..*", description = "jvm parameters for the instance of mrl") public String jvm; - @Option(names = { "-l", "--log-level" }, description = "log level - helpful for troubleshooting [debug info warn error]") + @Option(names = { "-l", + "--log-level" }, description = "log level - helpful for troubleshooting [debug info warn error]") public String logLevel = "info"; - @Option(names = { "--log-file" }, description = "log file name [myrobotlab.log]") - public String logFile = "myrobotlab.log"; - - // FIXME - highlight or italics for examples !! - // launcher @Option(names = { "-m", "--memory" }, description = "adjust memory can e.g. -m 2g \n -m 128m") public String memory = null; @@ -91,9 +66,6 @@ static boolean contains(List l, String flag) { "--services" }, arity = "0..*", description = "services requested on startup, the services must be {name} {Type} paired, e.g. gui SwingGui webgui WebGui servo Servo ...") public List services = new ArrayList<>(); - @Option(names = { "-V", "--virtual" }, description = "sets global environment as virtual - all services which support virtual hardware will create virtual hardware") - public boolean virtual = false; - public CmdOptions() { } @@ -133,34 +105,18 @@ public static String toString(String[] cmdLine) { * * @return the list of output command * @throws IOException - * boom + * boom * */ public List getOutputCmd() throws IOException { List cmd = new ArrayList<>(); - if (autoUpdate) { - cmd.add("-a"); - } - if (config != null) { cmd.add("--config"); cmd.add(config); } - if (connect != null) { - cmd.add("-c"); - cmd.add(connect); - } - - if (invoke != null) { - cmd.add("-I"); - for (int i = 0; i < invoke.length; ++i) { - cmd.add(invoke[i]); - } - } - if (help) { cmd.add("-h"); } @@ -206,10 +162,6 @@ public List getOutputCmd() throws IOException { cmd.add(s); } - if (virtual) { - cmd.add("-v"); - } - return cmd; } diff --git a/src/main/java/org/myrobotlab/framework/Platform.java b/src/main/java/org/myrobotlab/framework/Platform.java index 1b1ed4f2d5..5742bf365e 100644 --- a/src/main/java/org/myrobotlab/framework/Platform.java +++ b/src/main/java/org/myrobotlab/framework/Platform.java @@ -13,6 +13,7 @@ import java.util.TreeMap; import java.util.zip.ZipFile; +import org.myrobotlab.config.ConfigUtils; // Do not pull in deps to this class ! import org.myrobotlab.io.FileIO; import org.myrobotlab.logging.Level; @@ -64,13 +65,7 @@ public class Platform implements Serializable { String vmName; String vmVersion; String mrlVersion; - boolean isVirtual = false; - /** - * Static identifier to identify the "instance" of myrobotlab - similar to - * network ip of a device and used in a similar way - */ - String id; String branch; String pid; @@ -95,7 +90,7 @@ public class Platform implements Serializable { * All data should be accessed through public functions on the local instance. * If the local instance is desired. If its from a serialized instance, the * "getters" will be retrieving appropriate info for that serialized instance. - * + * * @return - return the local instance of the current platform */ public static Platform getLocalInstance() { @@ -121,7 +116,8 @@ public static Platform getLocalInstance() { // === ARCH === String arch = System.getProperty("os.arch").toLowerCase(); - if ("i386".equals(arch) || "i486".equals(arch) || "i586".equals(arch) || "i686".equals(arch) || "amd64".equals(arch) || arch.startsWith("x86")) { + if ("i386".equals(arch) || "i486".equals(arch) || "i586".equals(arch) || "i686".equals(arch) + || "amd64".equals(arch) || arch.startsWith("x86")) { platform.arch = "x86"; // don't care at the moment } @@ -159,7 +155,8 @@ public static Platform getLocalInstance() { // tries very hard to hide this from running programs String procArch = System.getenv("PROCESSOR_ARCHITECTURE"); String procArchWow64 = System.getenv("PROCESSOR_ARCHITEW6432"); - platform.osBitness = (procArch != null && procArch.endsWith("64") || procArchWow64 != null && procArchWow64.endsWith("64")) ? 64 : 32; + platform.osBitness = (procArch != null && procArch.endsWith("64") + || procArchWow64 != null && procArchWow64.endsWith("64")) ? 64 : 32; switch (arch) { case "x86": case "i386": @@ -460,19 +457,6 @@ public String toString() { return String.format("%s.%d.%s", arch, jvmBitness, os); } - /** - * @return The instance identifier of the current running myrobotlab. Used for - * connecting multiple myrobotlabs together - * - */ - public String getId() { - // null ids are not allowed - if (id == null) { - id = NameGenerator.getName(); - } - return id; - } - /** * @return The Computer's hostname */ @@ -480,15 +464,6 @@ public String getHostname() { return hostname; } - /** - * @param newId - * Set your own instance identifier - * - */ - public void setId(String newId) { - id = newId; - } - /** * @return the time when this instance was started * @@ -497,20 +472,6 @@ public Date getStartTime() { return startTime; } - /** - * @return true if running in virtual mode - * - */ - public static boolean isVirtual() { - Platform p = getLocalInstance(); - return p.isVirtual; - } - - public static void setVirtual(boolean b) { - Platform p = getLocalInstance(); - p.isVirtual = b; - } - public static void main(String[] args) { try { LoggingFactory.init(Level.DEBUG); diff --git a/src/main/java/org/myrobotlab/framework/Service.java b/src/main/java/org/myrobotlab/framework/Service.java index 8f0d4ad2bf..3f7acbf755 100644 --- a/src/main/java/org/myrobotlab/framework/Service.java +++ b/src/main/java/org/myrobotlab/framework/Service.java @@ -57,6 +57,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import org.myrobotlab.codec.CodecUtils; +import org.myrobotlab.config.ConfigUtils; import org.myrobotlab.framework.interfaces.Attachable; import org.myrobotlab.framework.interfaces.Broadcaster; import org.myrobotlab.framework.interfaces.ConfigurableService; @@ -474,22 +475,15 @@ static public String getResourceDir(Class clazz, String additionalPath) { * then it needs an instance of Runtime which is not available. * */ - @Deprecated /* this should not be static - remove it */ static public String getResourceDir(String serviceType, String additionalPath) { // setting resource directory - String resourceDir = null; + String resource = ConfigUtils.getResourceRoot() + fs + serviceType; - // stupid solution to get past static problem - if (!"Runtime".equals(serviceType)) { - resourceDir = Runtime.getInstance().getConfig().resource + fs + serviceType; - } else { - resourceDir = "resource"; - } if (additionalPath != null) { - resourceDir = FileIO.gluePaths(resourceDir, additionalPath); + resource = FileIO.gluePaths(resource, additionalPath); } - return resourceDir; + return resource; } /** @@ -516,7 +510,7 @@ public String getResourcePath(String additionalPath) { */ static public String getResourceRoot() { - return Runtime.getInstance().getConfig().resource; + return ConfigUtils.getResourceRoot();//Runtime.getInstance().getConfig().resource; } /** @@ -625,7 +619,7 @@ public Service(String reservedKey, String inId) { // necessary for serialized transport\ if (inId == null) { - id = Platform.getLocalInstance().getId(); + id = ConfigUtils.getId(); log.debug("creating local service for id {}", id); } else { id = inId; @@ -676,7 +670,7 @@ public Service(String reservedKey, String inId) { // register this service if local - if we are a foreign service, we probably // are being created in a // registration already - if (id.equals(Platform.getLocalInstance().getId())) { + if (id.equals(ConfigUtils.getId())) { Registration registration = new Registration(this); Runtime.register(registration); } @@ -1510,7 +1504,7 @@ public ServiceConfig getFilteredConfig() { // The StringUtils.removeEnd() call is a no-op when the ID is not our // local ID, // so doesn't conflict with remote routes - Listener newConfigListener = new Listener(listener.topicMethod, StringUtil.removeEnd(listener.callbackName, '@' + Platform.getLocalInstance().getId()), + Listener newConfigListener = new Listener(listener.topicMethod, StringUtil.removeEnd(listener.callbackName, '@' + Runtime.getInstance().getId()), listener.callbackMethod); newListeners.add(newConfigListener); } @@ -1614,7 +1608,7 @@ public Service publishState() { @Override synchronized public void releaseService() { // auto release children and unregister - Runtime.releaseService(getName()); + Runtime.releaseServiceInternal(getName()); } /** diff --git a/src/main/java/org/myrobotlab/framework/StartYml.java b/src/main/java/org/myrobotlab/framework/StartYml.java index c8bfb25a44..b1806d203c 100644 --- a/src/main/java/org/myrobotlab/framework/StartYml.java +++ b/src/main/java/org/myrobotlab/framework/StartYml.java @@ -9,10 +9,6 @@ * */ public class StartYml { - /** - * instance id of myrobotlab, default will be dynamically generated - */ - public String id; /** * configuration set to start under /data/config/{configName} diff --git a/src/main/java/org/myrobotlab/io/FileIO.java b/src/main/java/org/myrobotlab/io/FileIO.java index 2cdad66af2..8b3fe189c4 100644 --- a/src/main/java/org/myrobotlab/io/FileIO.java +++ b/src/main/java/org/myrobotlab/io/FileIO.java @@ -58,8 +58,8 @@ import java.util.zip.ZipException; import org.apache.commons.io.Charsets; +import org.myrobotlab.config.ConfigUtils; import org.myrobotlab.framework.Platform; -import org.myrobotlab.framework.Service; import org.myrobotlab.logging.Level; import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.logging.Logging; @@ -854,8 +854,6 @@ public static void main(String[] args) throws ZipException, IOException { f = new File(uri); log.info("{} exists {}", uri, f.exists()); - log.info("isJar : {}", isJar()); - } catch (Exception e) { Logging.logError(e); } @@ -870,33 +868,22 @@ public static void main(String[] args) throws ZipException, IOException { * Python/examples/someFile.py * @return byte array */ - @Deprecated /* user Service.getResource(src) */ static public final byte[] resourceToByteArray(String src) { - // this path assumes in a jar ? - // String filename = "/resource/" + src; - log.info("looking for Resource {}", src); + log.info("looking for resource {}", src); InputStream isr = null; - if (isJar()) { - // this path assumes in a jar ? ensure it's forward slashes - String filename = "/resource/" + src.replace("\\", "/"); - isr = FileIO.class.getResourceAsStream(filename); - } else { - String localFilename = Service.getResourceRoot() + File.separator + src; - try { - isr = new FileInputStream(localFilename); - } catch (Exception e) { - Logging.logError(e); - log.error("File not found. {}", localFilename, e); - return null; - } + String resource = ConfigUtils.getResourceRoot(); + String localFilename = resource + File.separator + src; + try { + isr = new FileInputStream(localFilename); + } catch (Exception e) { + Logging.logError(e); + log.error("file not found. {}", localFilename, e); + return null; } + byte[] data = null; try { - if (isr == null) { - log.error("can not find resource [{}]", src); - return null; - } data = toByteArray(isr); } finally { try { @@ -918,7 +905,6 @@ static public final byte[] resourceToByteArray(String src) { * Python/examples/someFile.py * @return string */ - @Deprecated /* use Service.getResourceAsString(src) */ static public final String resourceToString(String src) { byte[] bytes = resourceToByteArray(src); if (bytes == null) { diff --git a/src/main/java/org/myrobotlab/process/Launcher.java b/src/main/java/org/myrobotlab/process/Launcher.java index 3e819f3c59..7954fd7d5d 100644 --- a/src/main/java/org/myrobotlab/process/Launcher.java +++ b/src/main/java/org/myrobotlab/process/Launcher.java @@ -2,9 +2,6 @@ import java.io.File; import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -241,41 +238,15 @@ public static void main(String[] args) { return; } - boolean instanceAlreadyRunning = false; - - try { - URI uri = new URI(options.connect); - Socket socket = new Socket(); - socket.connect(new InetSocketAddress(uri.getHost(), uri.getPort()), 1000); - socket.close(); - instanceAlreadyRunning = true; - } catch (Exception e) { - log.info("could not connect to {}", options.connect); + log.info("spawning new instance"); + ProcessBuilder builder = createBuilder(options); + process = builder.start(); + if (process.isAlive()) { + log.info("process is alive"); + } else { + log.error("process died"); } - if (instanceAlreadyRunning && options.connect.equals(options.DEFAULT_CONNECT)) { - log.error("zombie instance already running at {}", options.DEFAULT_CONNECT); - return; - } - - if (!instanceAlreadyRunning || !options.connect.equals(options.DEFAULT_CONNECT)) { - log.info("spawning new instance"); - ProcessBuilder builder = createBuilder(options); - process = builder.start(); - if (process.isAlive()) { - log.info("process is alive"); - } else { - log.error("process died"); - } - } - - /* - * // FIXME - use wsclient for remote access if (options.client != null) { - * // FIXME - delay & auto connect Client.main(new String[] { "-c", - * options.client }); } else { // terminating - "if" runtime exists - if - * not no biggy Runtime.shutdown(); } - */ - } catch (Exception e) { log.error("main threw", e); } diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index e5da31305f..e838cf6c52 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -47,6 +47,7 @@ import org.myrobotlab.codec.CodecUtils; import org.myrobotlab.codec.CodecUtils.ApiDescription; import org.myrobotlab.codec.ForeignProcessUtils; +import org.myrobotlab.config.ConfigUtils; import org.myrobotlab.framework.CmdOptions; import org.myrobotlab.framework.DescribeQuery; import org.myrobotlab.framework.DescribeResults; @@ -129,7 +130,7 @@ * */ public class Runtime extends Service implements MessageListener, ServiceLifeCyclePublisher, RemoteMessageHandler, ConnectionManager, Gateway, LocaleProvider { - + final static private long serialVersionUID = 1L; // FIXME - AVOID STATIC FIELDS !!! use .getInstance() to get the singleton @@ -167,6 +168,8 @@ public class Runtime extends Service implements MessageListener, protected final Map> typeToInterface = new HashMap<>(); + private transient static final Object processLock = new Object(); + /** * FILTERED_INTERFACES are the set of low level interfaces which we are * interested in filtering out if we want to maintain a data structure which @@ -188,7 +191,13 @@ public class Runtime extends Service implements MessageListener, * name. It cannot be null, it cannot have "/" or "\" in the name - it has to * be a valid file name for the OS. It's defaulted to "default". Changed often */ - protected String configName = "default"; + protected static String configName = "default"; + + /** + * The runtime config which Runtime was started with. This is the config which + * will be applied to Runtime when its created on startup. + */ + // protected static RuntimeConfig startConfig = null; /** * State variable reporting if runtime is currently starting services from @@ -378,30 +387,32 @@ static public ServiceInterface create(String name) { * - Can be null if a service file exists for named service * @return the service */ - static public synchronized ServiceInterface create(String name, String type) { + static public ServiceInterface create(String name, String type) { - try { - ServiceInterface si = Runtime.getService(name); - if (si != null) { - return si; - } + synchronized (processLock) { - // FIXME remove configName from loadService - Plan plan = Runtime.load(name, type); - Runtime.check(name, type); - // at this point - the plan should be loaded, now its time to create the - // children peers - // and parent service - createServicesFromPlan(plan, null, name); - si = Runtime.getService(name); - if (si == null) { - Runtime.getInstance().error("coult not create %s of type %s", name, type); + try { + ServiceInterface si = Runtime.getService(name); + if (si != null) { + return si; + } + + Plan plan = Runtime.load(name, type); + Runtime.check(name, type); + // at this point - the plan should be loaded, now its time to create the + // children peers + // and parent service + createServicesFromPlan(plan, null, name); + si = Runtime.getService(name); + if (si == null) { + Runtime.getInstance().error("coult not create %s of type %s", name, type); + } + return si; + } catch (Exception e) { + runtime.error(e); } - return si; - } catch (Exception e) { - runtime.error(e); + return null; } - return null; } /** @@ -414,43 +425,46 @@ static public synchronized ServiceInterface create(String name, String type) { * @param name * @return */ - synchronized private static Map createServicesFromPlan(Plan plan, Map createdServices, String name) { + private static Map createServicesFromPlan(Plan plan, Map createdServices, String name) { - if (createdServices == null) { - createdServices = new LinkedHashMap<>(); - } - - // Plan's config - RuntimeConfig plansRtConfig = (RuntimeConfig) plan.get("runtime"); - // current Runtime config - RuntimeConfig currentConfig = Runtime.getInstance().config; + synchronized (processLock) { - for (String service : plansRtConfig.getRegistry()) { - // FIXME - determine if you want to return a complete merge of activated - // or just "recent" - if (Runtime.getService(service) != null) { - continue; + if (createdServices == null) { + createdServices = new LinkedHashMap<>(); } - ServiceConfig sc = plan.get(service); - if (sc == null) { - runtime.error("could not get %s from plan", service); - continue; - } - ServiceInterface si = createService(service, sc.type, null); - // process the base listeners/subscription of ServiceConfig - si.addConfigListeners(sc); - if (si instanceof ConfigurableService) { - try { - ((ConfigurableService) si).apply(sc); - } catch (Exception e) { - Runtime.getInstance().error("could not apply config of type %s to service %s, using default config", sc.type, si.getName(), sc.type); + + // Plan's config + RuntimeConfig plansRtConfig = (RuntimeConfig) plan.get("runtime"); + // current Runtime config + RuntimeConfig currentConfig = Runtime.getInstance().config; + + for (String service : plansRtConfig.getRegistry()) { + // FIXME - determine if you want to return a complete merge of activated + // or just "recent" + if (Runtime.getService(service) != null) { + continue; + } + ServiceConfig sc = plan.get(service); + if (sc == null) { + runtime.error("could not get %s from plan", service); + continue; } + ServiceInterface si = createService(service, sc.type, null); + // process the base listeners/subscription of ServiceConfig + si.addConfigListeners(sc); + if (si instanceof ConfigurableService) { + try { + ((ConfigurableService) si).apply(sc); + } catch (Exception e) { + Runtime.getInstance().error("could not apply config of type %s to service %s, using default config", sc.type, si.getName(), sc.type); + } + } + createdServices.put(service, si); + currentConfig.add(service); } - createdServices.put(service, si); - currentConfig.add(service); - } - return createdServices; + return createdServices; + } } public String getServiceExample(String serviceType) { @@ -582,7 +596,9 @@ public final static void createAndStartServices(List services) { */ @Override public boolean setVirtual(boolean b) { - boolean changed = isVirtual != b; + boolean changed = config.virtual != b; + config.virtual = b; + isVirtual = b; setAllVirtual(b); if (changed) { broadcastState(); @@ -599,13 +615,12 @@ public boolean setVirtual(boolean b) { * @return b */ static public boolean setAllVirtual(boolean b) { - Platform.setVirtual(b); for (ServiceInterface si : getServices()) { if (!si.isRuntime()) { si.setVirtual(b); } } - Runtime.getInstance().isVirtual = b; + Runtime.getInstance().config.virtual = b; Runtime.getInstance().broadcastState(); return b; } @@ -622,7 +637,6 @@ static public boolean setAllVirtual(boolean b) { */ public void setAutoStart(boolean autoStart) throws IOException { log.debug("setAutoStart {}", autoStart); - startYml.id = getId(); startYml.enable = autoStart; startYml.config = configName; FileIO.toFile("start.yml", CodecUtils.toYaml(startYml)); @@ -657,126 +671,128 @@ public void setAutoStart(boolean autoStart) throws IOException { * '/', or a service with the same name exists but has a different * type, will return null instead. */ - static private synchronized ServiceInterface createService(String name, String type, String inId) { - log.info("Runtime.createService {}", name); + static private ServiceInterface createService(String name, String type, String inId) { + synchronized (processLock) { + log.info("Runtime.createService {}", name); - if (name == null) { - runtime.error("service name cannot be null"); + if (name == null) { + runtime.error("service name cannot be null"); - return null; - } + return null; + } - if (name.contains("@") || name.contains("/")) { - runtime.error("service name cannot contain '@' or '/': {}", name); + if (name.contains("@") || name.contains("/")) { + runtime.error("service name cannot contain '@' or '/': {}", name); - return null; - } + return null; + } - String fullName; - if (inId == null || inId.equals("")) - fullName = getFullName(name); - else - fullName = String.format("%s@%s", name, inId); + String fullName; + if (inId == null || inId.equals("")) + fullName = getFullName(name); + else + fullName = String.format("%s@%s", name, inId); - if (type == null) { - ServiceConfig sc; - try { - sc = CodecUtils.readServiceConfig(runtime.getConfigName() + fs + name + ".yml"); - } catch (IOException e) { - runtime.error("could not find type for service %s", name); - return null; + if (type == null) { + ServiceConfig sc; + try { + sc = CodecUtils.readServiceConfig(runtime.getConfigName() + fs + name + ".yml"); + } catch (IOException e) { + runtime.error("could not find type for service %s", name); + return null; + } + if (sc != null) { + log.info("found type for {} in plan", name); + type = sc.type; + } else { + runtime.error("createService type not specified and could not get type for {} from plan", name); + return null; + } } - if (sc != null) { - log.info("found type for {} in plan", name); - type = sc.type; - } else { - runtime.error("createService type not specified and could not get type for {} from plan", name); + + if (type == null) { + runtime.error("cannot create service {} no type in plan or yml file", name); return null; } - } - if (type == null) { - runtime.error("cannot create service {} no type in plan or yml file", name); - return null; - } + String fullTypeName = CodecUtils.makeFullTypeName(type); + + ServiceInterface si = Runtime.getService(fullName); + if (si != null) { + if (!si.getTypeKey().equals(fullTypeName)) { + runtime.error("Service with name {} already exists but is of type {} while requested type is ", name, si.getTypeKey(), type); + return null; + } + return si; + } - String fullTypeName = CodecUtils.makeFullTypeName(type); + // DO NOT LOAD HERE !!! - doing so would violate the service life cycle ! + // only try to resolve type by the plan - if not then error out - ServiceInterface si = Runtime.getService(fullName); - if (si != null) { - if (!si.getTypeKey().equals(fullTypeName)) { - runtime.error("Service with name {} already exists but is of type {} while requested type is ", name, si.getTypeKey(), type); + String id = (inId == null) ? Runtime.getInstance().getId() : inId; + if (name.length() == 0 || fullTypeName == null || fullTypeName.length() == 0) { + log.error("{} not a type or {} not defined ", fullTypeName, name); return null; } - return si; - } - // DO NOT LOAD HERE !!! - doing so would violate the service life cycle ! - // only try to resolve type by the plan - if not then error out - - String id = (inId == null) ? Platform.getLocalInstance().getId() : inId; - if (name.length() == 0 || fullTypeName == null || fullTypeName.length() == 0) { - log.error("{} not a type or {} not defined ", fullTypeName, name); - return null; - } + // TODO - test new create of existing service + ServiceInterface sw = Runtime.getService(String.format("%s@%s", name, id)); + if (sw != null) { + log.info("service {} already exists", name); + return sw; + } - // TODO - test new create of existing service - ServiceInterface sw = Runtime.getService(String.format("%s@%s", name, id)); - if (sw != null) { - log.info("service {} already exists", name); - return sw; - } + try { - try { + if (log.isDebugEnabled()) { + // TODO - determine if there have been new classes added from + // ivy --> Boot Classloader --> Ext ClassLoader --> System + // ClassLoader + // http://blog.jamesdbloom.com/JVMInternals.html + log.debug("ABOUT TO LOAD CLASS"); + log.debug("loader for this class " + Runtime.class.getClassLoader().getClass().getCanonicalName()); + log.debug("parent " + Runtime.class.getClassLoader().getParent().getClass().getCanonicalName()); + log.debug("system class loader " + ClassLoader.getSystemClassLoader()); + log.debug("parent should be null" + ClassLoader.getSystemClassLoader().getParent().getClass().getCanonicalName()); + log.debug("thread context " + Thread.currentThread().getContextClassLoader().getClass().getCanonicalName()); + log.debug("thread context parent " + Thread.currentThread().getContextClassLoader().getParent().getClass().getCanonicalName()); + } - if (log.isDebugEnabled()) { - // TODO - determine if there have been new classes added from - // ivy --> Boot Classloader --> Ext ClassLoader --> System - // ClassLoader - // http://blog.jamesdbloom.com/JVMInternals.html - log.debug("ABOUT TO LOAD CLASS"); - log.debug("loader for this class " + Runtime.class.getClassLoader().getClass().getCanonicalName()); - log.debug("parent " + Runtime.class.getClassLoader().getParent().getClass().getCanonicalName()); - log.debug("system class loader " + ClassLoader.getSystemClassLoader()); - log.debug("parent should be null" + ClassLoader.getSystemClassLoader().getParent().getClass().getCanonicalName()); - log.debug("thread context " + Thread.currentThread().getContextClassLoader().getClass().getCanonicalName()); - log.debug("thread context parent " + Thread.currentThread().getContextClassLoader().getParent().getClass().getCanonicalName()); - } + // FIXME - error if deps are missing - prompt license + // require restart ! + // FIXME - this should happen after inspecting the "loaded" "plan" not + // during the create/start/apply ! + + // create an instance + Object newService = Instantiator.getThrowableNewInstance(null, fullTypeName, name, id); + log.debug("returning {}", fullTypeName); + si = (ServiceInterface) newService; + + // si.setId(id); + if (Runtime.getInstance().getId().equals(id)) { + si.setVirtual(Runtime.getInstance().isVirtual()); + Runtime.getInstance().creationCount++; + si.setOrder(Runtime.getInstance().creationCount); + } - // FIXME - error if deps are missing - prompt license - // require restart ! - // FIXME - this should happen after inspecting the "loaded" "plan" not - // during the create/start/apply ! - - // create an instance - Object newService = Instantiator.getThrowableNewInstance(null, fullTypeName, name, id); - log.debug("returning {}", fullTypeName); - si = (ServiceInterface) newService; - - // si.setId(id); - if (Platform.getLocalInstance().getId().equals(id)) { - si.setVirtual(Platform.isVirtual()); - Runtime.getInstance().creationCount++; - si.setOrder(Runtime.getInstance().creationCount); - } + if (runtime != null) { - if (runtime != null) { + runtime.invoke("created", getFullName(name)); - runtime.invoke("created", getFullName(name)); + // add all the service life cycle subscriptions + // runtime.addListener("registered", name); + // runtime.addListener("created", name); + // runtime.addListener("started", name); + // runtime.addListener("stopped", name); + // runtime.addListener("released", name); + } - // add all the service life cycle subscriptions - // runtime.addListener("registered", name); - // runtime.addListener("created", name); - // runtime.addListener("started", name); - // runtime.addListener("stopped", name); - // runtime.addListener("released", name); + return (Service) newService; + } catch (Exception e) { + log.error("createService failed for {}@{} of type {}", name, id, fullTypeName, e); } - - return (Service) newService; - } catch (Exception e) { - log.error("createService failed for {}@{} of type {}", name, id, fullTypeName, e); + return null; } - return null; } static public Map>> getNotifyEntries() { @@ -883,58 +899,48 @@ public static final long getFreeMemory() { public static Runtime getInstance() { if (runtime == null) { synchronized (INSTANCE_LOCK) { - if (runtime == null) { + try { - // all though this is appropriate it cannot be done - // because you need runtime to correctly load/start/etc the plan - // so it needs to be bootstrapped - // load("runtime", "Runtime"); + RuntimeConfig c = null; + if (runtime == null) { + c = ConfigUtils.loadRuntimeConfig(options); - // just create Runtime - runtime = (Runtime) createService(RUNTIME_NAME, "Runtime", Platform.getLocalInstance().getId()); - } - try { - // a bit backwards - it loads after it been created - // but its necessary because you need an runtime instance before you - // load - - File cfgRoot = new File(ROOT_CONFIG_DIR); - cfgRoot.mkdirs(); - if (startYml.enable) { - Runtime.load("runtime", "Runtime"); - } - runtime.config.add("runtime"); + runtime = (Runtime) createService(RUNTIME_NAME, "Runtime", c.id); + runtime.startService(); + // klunky + Runtime.register(new Registration(runtime)); - runtime.startService(); - // platform virtual is higher priority than service virtual - Runtime.setAllVirtual(Platform.isVirtual()); + // assign, do not apply otherwise there will be + // a chicken-egg problem + runtime.config = c; + } - // setting the singleton security - Security.getInstance(); runtime.getRepo().addStatusPublisher(runtime); + runtime.startService(); + // extract resources "if a jar" FileIO.extractResources(); - // protected services we don't want to remove when releasing a config - runtime.startingServices.add("runtime"); - runtime.startingServices.add("security"); - runtime.startingServices.add("webgui"); - runtime.startingServices.add("python"); - runtime.startInteractiveMode(); - try { - if (options.config != null) { - Runtime.startConfig(options.config); - } else if (startYml != null && startYml.config != null && startYml.enable) { + if (Runtime.options.install != null) { + // minimal processed runtime - return it + return runtime; + } + + runtime.apply(c); + + if (options.services != null) { + log.info("command line override for services created"); + createAndStartServices(options.services); + } else { + log.info("processing config.registry"); + if (startYml.enable) { Runtime.startConfig(startYml.config); } - } catch (Exception e) { - log.info("runtime will not be loading config"); } } catch (Exception e) { - log.error("runtime will not be loading config", e); + log.error("runtime getInstance threw", e); } - } // synchronized lock } @@ -1099,7 +1105,7 @@ public static Map getLocalServices() { Map local = new HashMap<>(); for (String serviceName : registry.keySet()) { // FIXME @ should be a requirement of "all" entries for consistency - if (!serviceName.contains("@") || serviceName.endsWith(String.format("@%s", Platform.getLocalInstance().getId()))) { + if (!serviceName.contains("@") || serviceName.endsWith(String.format("@%s", Runtime.getInstance().getId()))) { local.put(serviceName, registry.get(serviceName)); } } @@ -1149,8 +1155,10 @@ public static Map getMethodMap(String inName) { * * @return list of registrations */ - synchronized public List getServiceList() { - return registry.values().stream().map(si -> new Registration(si.getId(), si.getName(), si.getTypeKey())).collect(Collectors.toList()); + public List getServiceList() { + synchronized (processLock) { + return registry.values().stream().map(si -> new Registration(si.getId(), si.getName(), si.getTypeKey())).collect(Collectors.toList()); + } } // FIXME - scary function - returns private data @@ -1196,10 +1204,16 @@ public static S getService(String inName, StaticTyp * */ static public String[] getServiceNames() { - Set ret = registry.keySet(); + Set ret = registry.keySet(); String[] services = new String[ret.size()]; - - String localId = Platform.getLocalInstance().getId(); + if (ret.size() == 0) { + return services; + } + + // if there are more than 0 services we need runtime + // to filter to make sure they are "local" + // and this requires a runtime service + String localId = Runtime.getInstance().getId(); int cnt = 0; for (String fullname : ret) { if (fullname.endsWith(String.format("@%s", localId))) { @@ -1344,22 +1358,24 @@ public ServiceTypeNameResults getServiceTypeNamesFromInterface(String interfaze) * no longer used or needed - change events are pushed no longer * pulled <-- Over complicated solution */ - public static synchronized List getServicesFromInterface(Class interfaze) { - List ret = new ArrayList(); - - for (String service : getServiceNames()) { - Class clazz = getService(service).getClass(); - while (clazz != null) { - for (Class inter : clazz.getInterfaces()) { - if (inter.getName().equals(interfaze.getName())) { - ret.add(getService(service)); - continue; + public static List getServicesFromInterface(Class interfaze) { + synchronized (processLock) { + List ret = new ArrayList(); + + for (String service : getServiceNames()) { + Class clazz = getService(service).getClass(); + while (clazz != null) { + for (Class inter : clazz.getInterfaces()) { + if (inter.getName().equals(interfaze.getName())) { + ret.add(getService(service)); + continue; + } } + clazz = clazz.getSuperclass(); } - clazz = clazz.getSuperclass(); } + return ret; } - return ret; } /** @@ -1539,35 +1555,36 @@ static public void install(String serviceType) { * if this should block until done. * */ - synchronized static public void install(String serviceType, Boolean blocking) { - Runtime r = getInstance(); + static public void install(String serviceType, Boolean blocking) { + synchronized (processLock) { + Runtime r = getInstance(); - if (blocking == null) { - blocking = false; - } + if (blocking == null) { + blocking = false; + } - installerThread = new Thread() { - @Override - public void run() { - try { - if (serviceType == null) { - r.getRepo().install(); - } else { - r.getRepo().install(serviceType); + installerThread = new Thread() { + @Override + public void run() { + try { + if (serviceType == null) { + r.getRepo().install(); + } else { + r.getRepo().install(serviceType); + } + } catch (Exception e) { + r.error("dependencies failed - install error", e); + throw new RuntimeException(String.format("dependencies failed - install error %s", e.getMessage())); } - } catch (Exception e) { - r.error("dependencies failed - install error", e); - throw new RuntimeException(String.format("dependencies failed - install error %s", e.getMessage())); } - } - }; + }; - if (blocking) { - installerThread.run(); - } else { - installerThread.start(); + if (blocking) { + installerThread.run(); + } else { + installerThread.start(); + } } - } /** @@ -1608,7 +1625,7 @@ static public void invokeCommands(String[] invoke) { */ public static boolean isLocal(String serviceName) { ServiceInterface sw = getService(serviceName); - return Objects.equals(sw.getId(), Platform.getLocalInstance().getId()); + return Objects.equals(sw.getId(), Runtime.getInstance().getId()); } /* @@ -1705,10 +1722,12 @@ public void onState(ServiceInterface updatedService) { registry.put(String.format("%s@%s", updatedService.getName(), updatedService.getId()), updatedService); } - public static synchronized Registration register(String id, String name, String typeKey, ArrayList interfaces) { - Registration proxy = new Registration(id, name, typeKey, interfaces); - register(proxy); - return proxy; + public static Registration register(String id, String name, String typeKey, ArrayList interfaces) { + synchronized (processLock) { + Registration proxy = new Registration(id, name, typeKey, interfaces); + register(proxy); + return proxy; + } } /** @@ -1732,167 +1751,174 @@ public static synchronized Registration register(String id, String name, String * @return registration * */ - public static synchronized Registration register(Registration registration) { + public static Registration register(Registration registration) { + synchronized (processLock) { + try { - try { + // TODO - have rules on what registrations to accept - dependent on + // security, desire, re-broadcasting configuration etc. - // TODO - have rules on what registrations to accept - dependent on - // security, desire, re-broadcasting configuration etc. + String fullname = String.format("%s@%s", registration.getName(), registration.getId()); + if (registry.containsKey(fullname)) { + log.info("{} already registered", fullname); + return registration; + } - String fullname = String.format("%s@%s", registration.getName(), registration.getId()); - if (registry.containsKey(fullname)) { - log.info("{} already registered", fullname); - return registration; - } + // if (!ForeignProcessUtils.isValidTypeKey(registration.getTypeKey())) { + // log.error("Invalid type key being registered: " + + // registration.getTypeKey()); + // return null; + // } - // if (!ForeignProcessUtils.isValidTypeKey(registration.getTypeKey())) { - // log.error("Invalid type key being registered: " + - // registration.getTypeKey()); - // return null; - // } + log.info("{}@{} registering at {} of type {}", registration.getName(), registration.getId(), ConfigUtils.getId(), registration.getTypeKey()); - log.info("{}@{} registering at {} of type {}", registration.getName(), registration.getId(), Platform.getLocalInstance().getId(), registration.getTypeKey()); + if (!registration.isLocal(ConfigUtils.getId())) { - if (!registration.isLocal(Platform.getLocalInstance().getId())) { + // Check if we're registering a java service + if (ForeignProcessUtils.isValidJavaClassName(registration.getTypeKey())) { - // Check if we're registering a java service - if (ForeignProcessUtils.isValidJavaClassName(registration.getTypeKey())) { + String fullTypeName; + if (registration.getTypeKey().contains(".")) { + fullTypeName = registration.getTypeKey(); + } else { + fullTypeName = String.format("org.myrobotlab.service.%s", registration.getTypeKey()); + } - String fullTypeName; - if (registration.getTypeKey().contains(".")) { - fullTypeName = registration.getTypeKey(); + try { + // de-serialize, class exists + registration.service = Runtime.createService(registration.getName(), fullTypeName, registration.getId()); + if (registration.getState() != null) { + copyShallowFrom(registration.service, CodecUtils.fromJson(registration.getState(), Class.forName(fullTypeName))); + } + } catch (ClassNotFoundException classNotFoundException) { + log.error(String.format("Unknown service class for %s@%s: %s", registration.getName(), registration.getId(), registration.getTypeKey()), classNotFoundException); + return null; + } } else { - fullTypeName = String.format("org.myrobotlab.service.%s", registration.getTypeKey()); - } - - try { - // de-serialize, class exists - registration.service = Runtime.createService(registration.getName(), fullTypeName, registration.getId()); - if (registration.getState() != null) { - copyShallowFrom(registration.service, CodecUtils.fromJson(registration.getState(), Class.forName(fullTypeName))); + // We're registering a foreign process service. We don't need to + // check + // ForeignProcessUtils.isForeignTypeKey() because the type key is + // valid + // but is not a java class name + + // Class does not exist, check if registration has empty interfaces + // Interfaces should always include ServiceInterface if coming from + // remote client + if (registration.interfaces == null || registration.interfaces.isEmpty()) { + log.error("Unknown service type being registered, registration does not contain any " + "interfaces for proxy generation: " + registration.getTypeKey()); + return null; } - } catch (ClassNotFoundException classNotFoundException) { - log.error(String.format("Unknown service class for %s@%s: %s", registration.getName(), registration.getId(), registration.getTypeKey()), classNotFoundException); - return null; - } - } else { - // We're registering a foreign process service. We don't need to check - // ForeignProcessUtils.isForeignTypeKey() because the type key is - // valid - // but is not a java class name - - // Class does not exist, check if registration has empty interfaces - // Interfaces should always include ServiceInterface if coming from - // remote client - if (registration.interfaces == null || registration.interfaces.isEmpty()) { - log.error("Unknown service type being registered, registration does not contain any " + "interfaces for proxy generation: " + registration.getTypeKey()); - return null; - } - // FIXME - probably some more clear definition about the requirements - // of remote - // service registration - // In general, there should be very few requirements if any, besides - // providing a - // name, and the proxy - // interface should be responsible for creating a minimal - // interpretation - // (ServiceInterface) for the remote - // service - - // Class[] interfaces = registration.interfaces.stream().map(i -> { - // try { - // return Class.forName(i); - // } catch (ClassNotFoundException e) { - // throw new RuntimeException("Unable to load interface " + i + " - // defined in remote registration " + registration, e); - // } - // }).toArray(Class[]::new); - - // registration.service = (ServiceInterface) - // Proxy.newProxyInstance(Runtime.class.getClassLoader(), interfaces, - // new ProxyServiceInvocationHandler(registration.getName(), - // registration.getId())); - try { - registration.service = ProxyFactory.createProxyService(registration); - log.info("Created proxy: " + registration.service); - } catch (Exception e) { - // at the moment preventing throw - Runtime.getInstance().error(e); + // FIXME - probably some more clear definition about the + // requirements + // of remote + // service registration + // In general, there should be very few requirements if any, besides + // providing a + // name, and the proxy + // interface should be responsible for creating a minimal + // interpretation + // (ServiceInterface) for the remote + // service + + // Class[] interfaces = registration.interfaces.stream().map(i -> + // { + // try { + // return Class.forName(i); + // } catch (ClassNotFoundException e) { + // throw new RuntimeException("Unable to load interface " + i + " + // defined in remote registration " + registration, e); + // } + // }).toArray(Class[]::new); + + // registration.service = (ServiceInterface) + // Proxy.newProxyInstance(Runtime.class.getClassLoader(), + // interfaces, + // new ProxyServiceInvocationHandler(registration.getName(), + // registration.getId())); + try { + registration.service = ProxyFactory.createProxyService(registration); + log.info("Created proxy: " + registration.service); + } catch (Exception e) { + // at the moment preventing throw + Runtime.getInstance().error(e); + } } } - } - - registry.put(fullname, registration.service); - - if (runtime != null) { - - String type = registration.getTypeKey(); - // If type does not exist in typeToNames, make it an empty hash set and - // return it - Set names = runtime.typeToNames.computeIfAbsent(type, k -> new HashSet<>()); - names.add(fullname); - - // FIXME - most of this could be static as it represents meta data of - // class and interfaces + registry.put(fullname, registration.service); + + if (runtime != null) { + + String type = registration.getTypeKey(); + + // If type does not exist in typeToNames, make it an empty hash set + // and + // return it + Set names = runtime.typeToNames.computeIfAbsent(type, k -> new HashSet<>()); + names.add(fullname); + + // FIXME - most of this could be static as it represents meta data of + // class and interfaces + + // FIXME - was false - setting now to true .. because + // 1 edge case - "can something fulfill my need of an interface - is + // not + // currently + // switching to true + boolean updatedServiceLists = false; + + // maintaining interface type relations + // see if this service type is new + // PROCESS INDEXES ! - FIXME - will need this in unregister + // ALL CLASS/TYPE PROCESSING only needs to happen once per type + if (!runtime.serviceTypes.contains(type)) { + // CHECK IF "CAN FULFILL" + // add the interfaces of the new service type + Set interfaces = ClassUtil.getInterfaces(registration.service.getClass(), FILTERED_INTERFACES); + for (String interfaze : interfaces) { + Set types = runtime.interfaceToType.get(interfaze); + if (types == null) { + types = new HashSet<>(); + } + types.add(registration.getTypeKey()); + runtime.interfaceToType.put(interfaze, types); + } - // FIXME - was false - setting now to true .. because - // 1 edge case - "can something fulfill my need of an interface - is not - // currently - // switching to true - boolean updatedServiceLists = false; + runtime.typeToInterface.put(type, interfaces); + runtime.serviceTypes.add(registration.getTypeKey()); + updatedServiceLists = true; + } - // maintaining interface type relations - // see if this service type is new - // PROCESS INDEXES ! - FIXME - will need this in unregister - // ALL CLASS/TYPE PROCESSING only needs to happen once per type - if (!runtime.serviceTypes.contains(type)) { - // CHECK IF "CAN FULFILL" - // add the interfaces of the new service type - Set interfaces = ClassUtil.getInterfaces(registration.service.getClass(), FILTERED_INTERFACES); - for (String interfaze : interfaces) { - Set types = runtime.interfaceToType.get(interfaze); - if (types == null) { - types = new HashSet<>(); + // check to see if any of our interfaces can fulfill requested ones + Set myInterfaces = runtime.typeToInterface.get(type); + for (String inter : myInterfaces) { + if (runtime.interfaceToNames.containsKey(inter)) { + runtime.interfaceToNames.get(inter).add(fullname); + updatedServiceLists = true; } - types.add(registration.getTypeKey()); - runtime.interfaceToType.put(interfaze, types); } - runtime.typeToInterface.put(type, interfaces); - runtime.serviceTypes.add(registration.getTypeKey()); - updatedServiceLists = true; - } - - // check to see if any of our interfaces can fulfill requested ones - Set myInterfaces = runtime.typeToInterface.get(type); - for (String inter : myInterfaces) { - if (runtime.interfaceToNames.containsKey(inter)) { - runtime.interfaceToNames.get(inter).add(fullname); - updatedServiceLists = true; + if (updatedServiceLists) { + runtime.invoke("publishInterfaceToNames"); } - } - if (updatedServiceLists) { - runtime.invoke("publishInterfaceToNames"); + // TODO - determine rules on re-broadcasting based on configuration + runtime.invoke("registered", registration); } - // TODO - determine rules on re-broadcasting based on configuration - runtime.invoke("registered", registration); - } + // TODO - remove ? already get state from registration + if (!registration.isLocal(ConfigUtils.getId())) { + runtime.subscribe(registration.getFullName(), "publishState"); + } - // TODO - remove ? already get state from registration - if (!registration.isLocal(Platform.getLocalInstance().getId())) { - runtime.subscribe(registration.getFullName(), "publishState"); + } catch (Exception e) { + log.error("registration threw for {}@{}", registration.getName(), registration.getId(), e); + return null; } - } catch (Exception e) { - log.error("registration threw for {}@{}", registration.getName(), registration.getId(), e); - return null; + return registration; } - - return registration; } /** @@ -1906,60 +1932,79 @@ public static synchronized Registration register(Registration registration) { * @return true/false * */ - public synchronized static boolean releaseService(String inName) { - if (inName == null) { - log.debug("release (null)"); - return false; + public static boolean releaseService(String inName) { + ServiceInterface sc = getService(inName); + if (sc != null) { + sc.releaseService(); + return true; } + return false; + } + + + /** + * Called after any subclassed releaseService has been called, this cleans + * up the registry and removes peers + * @param inName + * @return + */ + public static boolean releaseServiceInternal(String inName) { + synchronized (processLock) { + if (inName == null) { + log.debug("release (null)"); + return false; + } - String name = getFullName(inName); + String name = getFullName(inName); - String id = CodecUtils.getId(name); - if (!id.equals(Platform.getLocalInstance().getId())) { - log.warn("will only release local services - %s is remote", name); - return false; - } + String id = CodecUtils.getId(name); + if (!id.equals(Runtime.getInstance().getId())) { + log.warn("will only release local services - %s is remote", name); + return false; + } - log.info("releasing service {}", name); + log.info("releasing service {}", name); - if (!registry.containsKey(name)) { - log.info("{} not registered", name); - return false; - } + if (!registry.containsKey(name)) { + log.info("{} not registered", name); + return false; + } - // get reference from registry - ServiceInterface si = registry.get(name); - if (si == null) { - log.warn("cannot release {} - not in registry"); - return false; - } + // get reference from registry + ServiceInterface si = registry.get(name); + if (si == null) { + log.warn("cannot release {} - not in registry"); + return false; + } - // FIXME - TODO invoke and or blocking on preRelease - Future + // FIXME - TODO invoke and or blocking on preRelease - Future - // send msg to service to self terminate - if (si.isLocal()) { - si.purgeTasks(); - si.stopService(); - } else { - if (runtime != null) { - runtime.send(name, "releaseService"); + // send msg to service to self terminate + if (si.isLocal()) { + si.purgeTasks(); + si.stopService(); + } else { + if (runtime != null) { + runtime.send(name, "releaseService"); + } } - } - // recursive peer release - Map peers = si.getPeers(); - if (peers != null) { - for (Peer peer : peers.values()) { - release(peer.name); + // recursive peer release + Map peers = si.getPeers(); + if (peers != null) { + for (Peer peer : peers.values()) { + release(peer.name); + } } - } - // FOR remote this isn't correct - it should wait for - // a message from the other runtime to say that its released - unregister(name); - return true; + // FOR remote this isn't correct - it should wait for + // a message from the other runtime to say that its released + unregister(name); + return true; + } } + /** * Removes registration for a service. Removes the service from * {@link #typeToInterface} and {@link #interfaceToNames}. @@ -1967,61 +2012,65 @@ public synchronized static boolean releaseService(String inName) { * @param inName * Name of the service to unregister */ - synchronized public static void unregister(String inName) { - String name = getFullName(inName); - log.info("unregister {}", name); + public static void unregister(String inName) { + synchronized (processLock) { + String name = getFullName(inName); + log.info("unregister {}", name); - // get reference from registry - ServiceInterface sw = registry.get(name); - if (sw == null) { - log.debug("{} already unregistered", name); - return; - } + // get reference from registry + ServiceInterface sw = registry.get(name); + if (sw == null) { + log.debug("{} already unregistered", name); + return; + } - // you have to send released before removing from registry - if (runtime != null) { - runtime.invoke("released", inName); // <- DO NOT CHANGE THIS IS CORRECT - // !! - // it should be FULLNAME ! - // runtime.broadcast("released", inName); - String type = sw.getTypeKey(); - - boolean updatedServiceLists = false; - - // check to see if any of our interfaces can fullfill requested ones - Set myInterfaces = runtime.typeToInterface.get(type); - if (myInterfaces != null) { - for (String inter : myInterfaces) { - if (runtime.interfaceToNames.containsKey(inter)) { - runtime.interfaceToNames.get(inter).remove(name); - updatedServiceLists = true; + // you have to send released before removing from registry + if (runtime != null) { + runtime.invoke("released", inName); // <- DO NOT CHANGE THIS IS CORRECT + // !! + // it should be FULLNAME ! + // runtime.broadcast("released", inName); + String type = sw.getTypeKey(); + + boolean updatedServiceLists = false; + + // check to see if any of our interfaces can fullfill requested ones + Set myInterfaces = runtime.typeToInterface.get(type); + if (myInterfaces != null) { + for (String inter : myInterfaces) { + if (runtime.interfaceToNames.containsKey(inter)) { + runtime.interfaceToNames.get(inter).remove(name); + updatedServiceLists = true; + } } } - } - if (updatedServiceLists) { - runtime.invoke("publishInterfaceToNames"); - } + if (updatedServiceLists) { + runtime.invoke("publishInterfaceToNames"); + } - } + } - // FIXME - release autostarted peers ? + // FIXME - release autostarted peers ? - // last step - remove from registry by making new registry - // thread safe way - Map removedService = new TreeMap<>(); - for (String key : registry.keySet()) { - if (!name.equals(key)) { - removedService.put(key, registry.get(key)); + // last step - remove from registry by making new registry + // thread safe way + Map removedService = new TreeMap<>(); + for (String key : registry.keySet()) { + if (!name.equals(key)) { + removedService.put(key, registry.get(key)); + } } - } - registry = removedService; + registry = removedService; - // and config - RuntimeConfig c = (RuntimeConfig) Runtime.getInstance().config; - c.remove(CodecUtils.getShortName(name)); + // and config + RuntimeConfig c = (RuntimeConfig) Runtime.getInstance().config; + if (c != null) { + c.remove(CodecUtils.getShortName(name)); + } - log.info("released {}", name); + log.info("released {}", name); + } } /** @@ -2092,12 +2141,14 @@ public static void releaseAll(boolean releaseRuntime, boolean block) { if (block) { processRelease(releaseRuntime); + ConfigUtils.reset(); } else { new Thread() { @Override public void run() { processRelease(releaseRuntime); + ConfigUtils.reset(); } }.start(); @@ -2110,45 +2161,51 @@ public void run() { * @param releaseRuntime * Whether the Runtime should also be released */ - synchronized static private void processRelease(boolean releaseRuntime) { - - // reverse release to order of creation - Collection local = getLocalServices().values(); - List ordered = new ArrayList<>(local); - ordered.removeIf(Objects::isNull); - Collections.sort(ordered); - Collections.reverse(ordered); + static private void processRelease(boolean releaseRuntime) { + synchronized (processLock) { + // reverse release to order of creation + Collection local = getLocalServices().values(); + List ordered = new ArrayList<>(local); + ordered.removeIf(Objects::isNull); + Collections.sort(ordered); + Collections.reverse(ordered); - for (ServiceInterface sw : ordered) { + for (ServiceInterface sw : ordered) { - // no longer needed now - runtime "should be" guaranteed to be last - if (sw == Runtime.getInstance()) { - // skipping runtime - continue; - } + // no longer needed now - runtime "should be" guaranteed to be last + if (sw == Runtime.getInstance()) { + // skipping runtime + continue; + } - log.info("releasing service {}", sw.getName()); + log.info("releasing service {}", sw.getName()); - try { - sw.releaseService(); - } catch (Exception e) { - runtime.error("%s threw while releasing", e); - log.error("release", e); + try { + sw.releaseService(); + } catch (Exception e) { + if (runtime != null) { + runtime.error("%s threw while releasing", e); + } + log.error("release", e); + } } - } - // clean up remote ... the contract should - // probably be just remove their references - do not - // ask for them to be released remotely .. - // in thread safe way + // clean up remote ... the contract should + // probably be just remove their references - do not + // ask for them to be released remotely .. + // in thread safe way - if (releaseRuntime && runtime != null) { - runtime.releaseService(); - } else { - // put runtime in new registry - Runtime.getInstance(); - registry = new TreeMap<>(); - registry.put(runtime.getFullName(), registry.get(runtime.getFullName())); + if (releaseRuntime) { + if (runtime != null) { + runtime.releaseService(); + } + runtime = null; + } else { + // put runtime in new registry + Runtime.getInstance(); + registry = new TreeMap<>(); + registry.put(runtime.getFullName(), registry.get(runtime.getFullName())); + } } } @@ -2643,75 +2700,78 @@ public String publishConfigFinished(String configName) { * The type of the new service * @return The started service */ - synchronized static public ServiceInterface start(String name, String type) { - try { + static public ServiceInterface start(String name, String type) { + synchronized (processLock) { + try { - ServiceInterface requestedService = Runtime.getService(name); - if (requestedService != null) { - log.info("requested service already exists"); - if (requestedService.isRunning()) { - log.info("requested service already running"); - } else { - requestedService.startService(); + ServiceInterface requestedService = Runtime.getService(name); + if (requestedService != null) { + log.info("requested service already exists"); + if (requestedService.isRunning()) { + log.info("requested service already running"); + } else { + requestedService.startService(); + } + return requestedService; } - return requestedService; - } - Plan plan = Runtime.load(name, type); + Plan plan = Runtime.load(name, type); - Map services = createServicesFromPlan(plan, null, name); + Map services = createServicesFromPlan(plan, null, name); - if (services == null) { - Runtime.getInstance().error("cannot create instance of %s with type %s given current configuration", name, type); - return null; - } + if (services == null) { + Runtime.getInstance().error("cannot create instance of %s with type %s given current configuration", name, type); + return null; + } - requestedService = Runtime.getService(name); + requestedService = Runtime.getService(name); - // FIXME - does some order need to be maintained e.g. all children before - // parent - // breadth first, depth first, external order ordinal ? - for (ServiceInterface service : services.values()) { - if (service.getName().equals(name)) { - continue; - } - if (!Runtime.isStarted(service.getName())) { - service.startService(); + // FIXME - does some order need to be maintained e.g. all children + // before + // parent + // breadth first, depth first, external order ordinal ? + for (ServiceInterface service : services.values()) { + if (service.getName().equals(name)) { + continue; + } + if (!Runtime.isStarted(service.getName())) { + service.startService(); + } } - } - if (requestedService == null) { - Runtime.getInstance().error("could not start %s of type %s", name, type); - return null; - } + if (requestedService == null) { + Runtime.getInstance().error("could not start %s of type %s", name, type); + return null; + } - // getConfig() was problematic here for JMonkeyEngine - ServiceConfig sc = requestedService.getConfig(); - // Map peers = sc.getPeers(); - // if (peers != null) { - // for (String p : peers.keySet()) { - // Peer peer = peers.get(p); - // log.info("peer {}", peer); - // } - // } - // recursive - start peers of peers of peers ... - Map subPeers = sc.getPeers(); - if (sc != null && subPeers != null) { - for (String subPeerKey : subPeers.keySet()) { - // IF AUTOSTART !!! - Peer subPeer = subPeers.get(subPeerKey); - if (subPeer.autoStart) { - Runtime.start(sc.getPeerName(subPeerKey), subPeer.type); + // getConfig() was problematic here for JMonkeyEngine + ServiceConfig sc = requestedService.getConfig(); + // Map peers = sc.getPeers(); + // if (peers != null) { + // for (String p : peers.keySet()) { + // Peer peer = peers.get(p); + // log.info("peer {}", peer); + // } + // } + // recursive - start peers of peers of peers ... + Map subPeers = sc.getPeers(); + if (sc != null && subPeers != null) { + for (String subPeerKey : subPeers.keySet()) { + // IF AUTOSTART !!! + Peer subPeer = subPeers.get(subPeerKey); + if (subPeer.autoStart) { + Runtime.start(sc.getPeerName(subPeerKey), subPeer.type); + } } } - } - requestedService.startService(); - return requestedService; - } catch (Exception e) { - runtime.error(e); + requestedService.startService(); + return requestedService; + } catch (Exception e) { + runtime.error(e); + } + return null; } - return null; } /** @@ -2721,32 +2781,36 @@ synchronized static public ServiceInterface start(String name, String type) { * @param name * @return */ - synchronized static public ServiceInterface start(String name) { - if (Runtime.getService(name) != null) { - // already exists - ServiceInterface si = Runtime.getService(name); - if (!si.isRunning()) { - si.startService(); + static public ServiceInterface start(String name) { + synchronized (processLock) { + if (Runtime.getService(name) != null) { + // already exists + ServiceInterface si = Runtime.getService(name); + if (!si.isRunning()) { + si.startService(); + } + return si; } - return si; - } - Plan plan = Runtime.load(name, null); - Map services = createServicesFromPlan(plan, null, name); - // FIXME - order ? - for (ServiceInterface service : services.values()) { - service.startService(); + Plan plan = Runtime.load(name, null); + Map services = createServicesFromPlan(plan, null, name); + // FIXME - order ? + for (ServiceInterface service : services.values()) { + service.startService(); + } + return Runtime.getService(name); } - return Runtime.getService(name); } - synchronized public static Plan load(String name, String type) { - try { - Runtime runtime = Runtime.getInstance(); - return runtime.loadService(new Plan("runtime"), name, type, true, 0); - } catch (IOException e) { - runtime.error(e); + public static Plan load(String name, String type) { + synchronized (processLock) { + try { + Runtime runtime = Runtime.getInstance(); + return runtime.loadService(new Plan("runtime"), name, type, true, 0); + } catch (IOException e) { + runtime.error(e); + } + return null; } - return null; } /** @@ -2774,18 +2838,18 @@ public Runtime(String n, String id) { /** * This is used to run through all the possible services and determine - * if they have any missing dependencies. If they do not they become "installed". - * The installed flag makes the gui do a crossout when a service type is selected. + * if they have any missing dependencies. If they do not they become + * "installed". The installed flag makes the gui do a crossout when a + * service type is selected. */ for (MetaData metaData : serviceData.getServiceTypes()) { Set deps = repo.getUnfulfilledDependencies(metaData.getType()); if (deps.size() == 0) { metaData.installed = true; } else { - warn("{} not installed", metaData.getSimpleName()); + log.info("{} not installed", metaData.getSimpleName()); } } - } } @@ -4189,7 +4253,7 @@ static public String getFullName(String shortname) { return shortname; } // if nothing is supplied assume local - return String.format("%s@%s", shortname, Platform.getLocalInstance().getId()); + return String.format("%s@%s", shortname, Runtime.getInstance().getId()); } @Override @@ -4482,18 +4546,20 @@ public static void main(String[] args) { try { + // loading args globalArgs = args; - new CommandLine(options).parseArgs(args); + log.info("in args {}", Launcher.toString(args)); + log.info("options {}", CodecUtils.toJson(options)); + log.info("\n" + Launcher.banner); + + // creating initial data/config directory + File cfgRoot = new File(ROOT_CONFIG_DIR); + cfgRoot.mkdirs(); // initialize logging initLog(); - log.info("in args {}", Launcher.toString(args)); - log.info(CodecUtils.toJson(options)); - - log.info("\n" + Launcher.banner); - // help and exit if (options.help) { mainHelp(); @@ -4503,45 +4569,23 @@ public static void main(String[] args) { // start.yml file is required, if not pre-existing // is created immediately. It contains static information // which needs to be available before a Runtime is created - File checkStartYml = new File("start.yml"); - if (!checkStartYml.exists()) { - // save default - startYml = new StartYml(); - String defaultStartFile = CodecUtils.toYaml(startYml); - FileIO.toFile("start.yml", defaultStartFile); - } else { - String yml = FileIO.toString("start.yml"); - startYml = CodecUtils.fromYaml(yml, StartYml.class); - } + Runtime.startYml = ConfigUtils.loadStartYml(); - // id always required - precedence - // if none supplied one will be generated - // if in start.yml it will be used - // if supplied by the command line it will be used - // command line has the highest precedence - - Platform platform = Platform.getLocalInstance(); - if (options.id != null) { - platform.setId(options.id); - } else if (startYml.id != null) { - platform.setId(startYml.id); - } else { - // no id set - should be first - // time mrl is started - String id = NameGenerator.getName(); - platform.setId(id); - startYml.id = id; - FileIO.toFile("start.yml", CodecUtils.toYaml(startYml)); + // resolve configName before starting getting runtime configuration + Runtime.configName = (startYml.enable) ? startYml.config : "default"; + if (options.config != null) { + // cmd line options has the highest priority + Runtime.configName = options.config; } - if (options.virtual) { - Platform.setVirtual(true); - } + // start.yml is processed, config name is set, runtime config + // is resolved, now we can start instance + Runtime.getInstance(); - // FIXME TEST THIS !! 0 length, single service, multiple ! if (options.install != null) { // we start the runtime so there is a status publisher which will // display status updates from the repo install + log.info("requesting install"); Repo repo = getInstance().getRepo(); if (options.install.length == 0) { repo.install(LIBRARIES, (String) null); @@ -4554,36 +4598,6 @@ public static void main(String[] args) { return; } - // if a you specify a config file it becomes the "base" of configuration - // inline flags will still override values - if (options.config != null) { - // if this is a valid config, it will load - setConfig(options.config); - } else { - // required directory to load any service - setConfig(startYml.config); - } - - if (startYml.enable) { - Runtime.startConfig(startYml.config); - } else { - createAndStartServices(options.services); - } - - if (options.invoke != null) { - invokeCommands(options.invoke); - } - - if (options.connect != null) { - Runtime.getInstance().connect(options.connect); - } - - if (options.autoUpdate) { - // initialize - // FIXME - use peer ? - Updater.main(args); - } - } catch (Exception e) { log.error("runtime exception", e); Runtime.mainHelp(); @@ -4594,7 +4608,6 @@ public static void main(String[] args) { public static void initLog() { if (options != null) { - LoggingFactory.setLogFile(options.logFile); LoggingFactory.init(options.logLevel); } else { LoggingFactory.init("info"); @@ -4696,87 +4709,92 @@ static public ServiceInterface loadAndStart(String name, String type) { * @return * @throws IOException */ - synchronized public Plan loadService(Plan plan, String name, String type, boolean start, int level) throws IOException { + public Plan loadService(Plan plan, String name, String type, boolean start, int level) throws IOException { + synchronized (processLock) { - if (plan == null) { - log.error("plan required to load a system"); - return null; - } + if (plan == null) { + log.error("plan required to load a system"); + return null; + } - log.info("loading - {} {} {}", name, type, level); - // from recursive memory definition - ServiceConfig sc = plan.get(name); - - // HIGHEST PRIORITY - OVERRIDE WITH FILE - String configPath = runtime.getConfigPath(); - String configFile = configPath + fs + name + ".yml"; - - // PRIORITY #1 - // find if a current yml config file exists - highest priority - log.debug("priority #1 user's yml override {} ", configFile); - ServiceConfig fileSc = readServiceConfig(Runtime.getInstance().getConfigName(), name); - if (fileSc != null) { - // if definition exists in file form, it overrides current memory one - sc = fileSc; - } else if (sc != null) { - // if memory config is available but not file - // we save it - String yml = CodecUtils.toYaml(sc); - FileIO.toFile(configFile, yml); - } - - // special conflict case - type is specified, but its not the same as - // file version - in that case specified parameter type wins and overwrites - // config. User can force type by supplying one as a parameter, however, the - // recursive - // call other peer types will have name/file.yml definition precedence - if ((type != null && sc != null && !type.equals(sc.type) && level == 0) || (sc == null)) { - if (sc != null) { - warn("type %s overwriting type %s specified in %s.yml file", type, sc.type, name); + log.info("loading - {} {} {}", name, type, level); + // from recursive memory definition + ServiceConfig sc = plan.get(name); + + // HIGHEST PRIORITY - OVERRIDE WITH FILE + String configPath = runtime.getConfigPath(); + String configFile = configPath + fs + name + ".yml"; + + // PRIORITY #1 + // find if a current yml config file exists - highest priority + log.debug("priority #1 user's yml override {} ", configFile); + ServiceConfig fileSc = readServiceConfig(Runtime.getInstance().getConfigName(), name); + if (fileSc != null) { + // if definition exists in file form, it overrides current memory one + sc = fileSc; + } else if (sc != null) { + // if memory config is available but not file + // we save it + String yml = CodecUtils.toYaml(sc); + FileIO.toFile(configFile, yml); } - ServiceConfig.getDefault(plan, name, type); - sc = plan.get(name); - // create new file if it didn't exist or overwrite it if new type is - // required - String yml = CodecUtils.toYaml(sc); - FileIO.toFile(configFile, yml); - } + // special conflict case - type is specified, but its not the same as + // file version - in that case specified parameter type wins and + // overwrites + // config. User can force type by supplying one as a parameter, however, + // the + // recursive + // call other peer types will have name/file.yml definition precedence + if ((type != null && sc != null && !type.equals(sc.type) && level == 0) || (sc == null)) { + if (sc != null) { + warn("type %s overwriting type %s specified in %s.yml file", type, sc.type, name); + } + ServiceConfig.getDefault(plan, name, type); + sc = plan.get(name); - if (sc == null && type == null) { - log.error("no local config and unknown type"); - return plan; - } + // create new file if it didn't exist or overwrite it if new type is + // required + String yml = CodecUtils.toYaml(sc); + FileIO.toFile(configFile, yml); + } - // finalize - if (sc != null) { - plan.put(name, sc); - // RECURSIVE load peers - Map peers = sc.getPeers(); - for (String peerKey : peers.keySet()) { - Peer peer = peers.get(peerKey); - // recursive depth load - parent and child need to be started - runtime.loadService(plan, peer.name, peer.type, start && peer.autoStart, level + 1); + if (sc == null && type == null) { + log.error("no local config and unknown type"); + return plan; } - // valid service config at this point - now determine if its supposed to - // start or not - // if its level 0 then it was requested by user or config - so it needs to - // start - // if its not level 0 then it was loaded because peers were defined and - // appropriate config loaded - // peer.autoStart should determine if the peer starts if not explicitly - // requested by the - // user or config - if (level == 0 || start) { - plan.addRegistry(name); + // finalize + if (sc != null) { + plan.put(name, sc); + // RECURSIVE load peers + Map peers = sc.getPeers(); + for (String peerKey : peers.keySet()) { + Peer peer = peers.get(peerKey); + // recursive depth load - parent and child need to be started + runtime.loadService(plan, peer.name, peer.type, start && peer.autoStart, level + 1); + } + + // valid service config at this point - now determine if its supposed to + // start or not + // if its level 0 then it was requested by user or config - so it needs + // to + // start + // if its not level 0 then it was loaded because peers were defined and + // appropriate config loaded + // peer.autoStart should determine if the peer starts if not explicitly + // requested by the + // user or config + if (level == 0 || start) { + plan.addRegistry(name); + } + + } else { + log.info("could not load {} {} {}", name, type, level); } - } else { - log.info("could not load {} {} {}", name, type, level); + return plan; } - - return plan; } /** @@ -4846,45 +4864,30 @@ public String publishConfigLoaded(String name) { return name; } - public String setAllIds(String id) { - Platform.getLocalInstance().setId(id); - for (ServiceInterface si : getServices()) { - si.setId(id); - } - return id; - } - @Override - public RuntimeConfig apply(RuntimeConfig c) { - super.apply(c); - config = c; + public RuntimeConfig apply(RuntimeConfig config) { + super.apply(config); setLocale(config.locale); - if (config.id != null) { - setAllIds(config.id); + if (config.id == null) { + config.id = NameGenerator.getName(); } if (config.logLevel != null) { setLogLevel(config.logLevel); } - info("setting locale to %s", config.locale); if (config.virtual != null) { info("setting virtual to %b", config.virtual); setAllVirtual(config.virtual); } - if (config.enableCli) { - startInteractiveMode(); - info("enabled cli"); - } else { - stopInteractiveMode(); - info("disabled cli"); - } + // APPLYING A RUNTIME CONFIG DOES NOT PROCESS THE REGISTRY + // USE startConfig(name) broadcastState(); - return c; + return config; } /** @@ -4986,7 +4989,6 @@ public boolean saveService(String configName, String serviceName, String filenam // conditional boolean to flip and save a config name to start.yml ? if (startYml.enable) { - startYml.id = getId(); startYml.config = configName; FileIO.toFile("start.yml", CodecUtils.toYaml(startYml)); } @@ -5019,26 +5021,6 @@ public boolean saveService(String configName, String serviceName, String filenam return false; } - public String setConfigName(String name) { - if (name != null && name.contains(fs)) { - error("invalid character " + fs + " in configuration name"); - return configName; - } - if (name != null) { - configName = name.trim(); - } - - // for the moment the best way is to mandate - // a dir is created when a new config name is set - // because loading service are required to save config - // before starting - File configDir = new File(ROOT_CONFIG_DIR + fs + name); - configDir.mkdirs(); - - invoke("publishConfigList"); - return name; - } - public String getConfigName() { return configName; } @@ -5056,13 +5038,34 @@ public boolean isProcessingConfig() { * - config dir name under data/config/{config} * @return configName */ - public static String setConfig(String configName) { + public static String setConfig(String name) { + if (name == null) { + log.error("config cannot be null"); + if (runtime != null) { + runtime.error("config cannot be null"); + } + return null; + } + + if (name.contains(fs)) { + log.error("invalid character " + fs + " in configuration name"); + if (runtime != null) { + runtime.error("invalid character " + fs + " in configuration name"); + } + return name; + } - File configDir = new File(ROOT_CONFIG_DIR + fs + configName); - configDir.mkdirs(); + configName = name.trim(); + + File configDir = new File(ROOT_CONFIG_DIR + fs + name); + if (!configDir.exists()) { + configDir.mkdirs(); + } + + if (runtime != null) { + runtime.invoke("publishConfigList"); + } - Runtime runtime = Runtime.getInstance(); - runtime.setConfigName(configName); return configName; } @@ -5279,14 +5282,6 @@ public String getConfigPath() { return ROOT_CONFIG_DIR + fs + configName; } - @Override - public RuntimeConfig getConfig() { - config = super.getConfig(); - config.locale = getLocaleTag(); - config.virtual = isVirtual; - return config; - } - /** * Gets a {serviceName}.yml file config from configName directory * @@ -5391,11 +5386,12 @@ public ServiceConfig getPeer(String sericeName, String peerKey) { /** * Removes a config set and all its files * - * @param configName - name of config + * @param configName + * - name of config */ public static void removeConfig(String configName) { try { - log.info("removeing config"); + log.info("removing config"); File check = new File(ROOT_CONFIG_DIR + fs + configName); @@ -5408,12 +5404,4 @@ public static void removeConfig(String configName) { } } - /** - * Method used to determine is runtime is running without starting it - * @return true if available - */ - static public boolean isAvailable() { - return runtime != null && runtime.isRunning(); - } - } diff --git a/src/main/java/org/myrobotlab/service/WebGui.java b/src/main/java/org/myrobotlab/service/WebGui.java index 21deea126c..5e87cddb05 100644 --- a/src/main/java/org/myrobotlab/service/WebGui.java +++ b/src/main/java/org/myrobotlab/service/WebGui.java @@ -62,7 +62,8 @@ * services are already APIs - perhaps a data API - same as service without the * message wrapper */ -public class WebGui extends Service implements AuthorizationProvider, Gateway, Handler, ServiceLifeCycleListener { +public class WebGui extends Service + implements AuthorizationProvider, Gateway, Handler, ServiceLifeCycleListener { public static class LiveVideoStreamHandler implements Handler { @@ -89,7 +90,7 @@ public void handle(AtmosphereResource r) { } } } - + private final transient IncomingMsgQueue inMsgQueue = new IncomingMsgQueue(); public static class Panel { @@ -127,7 +128,7 @@ public Panel(String name, int x, int y, int z) { * needed to get the api key to select the appropriate api processor * * @param uri - * u + * u * @return api key * */ @@ -270,9 +271,9 @@ public boolean getAutoStartBrowser() { * String broadcast to specific client * * @param uuid - * u + * u * @param str - * s + * s * */ public void broadcast(String uuid, String str) { @@ -314,7 +315,9 @@ public Config.Builder getNettosphereConfig() { // cert.privateKey()).build(); SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); - SslContext context = SslContextBuilder.forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()).sslProvider(SslProvider.JDK) + SslContext context = SslContextBuilder + .forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()) + .sslProvider(SslProvider.JDK) .clientAuth(ClientAuth.NONE).build(); configBuilder.sslContext(context); @@ -493,7 +496,8 @@ public void handle(AtmosphereResource r) { } else if ((bodyData != null) && log.isDebugEnabled()) { logData = bodyData; } - log.debug("-->{} {} {} - [{}] from connection {}", (newPersistentConnection) ? "new" : "", request.getMethod(), request.getRequestURI(), logData, uuid); + log.debug("-->{} {} {} - [{}] from connection {}", (newPersistentConnection) ? "new" : "", request.getMethod(), + request.getRequestURI(), logData, uuid); } // important persistent connections will have associated routes ... @@ -571,7 +575,8 @@ public void handle(AtmosphereResource r) { } if (msg.containsHop(getId())) { - log.error("{} dumping duplicate hop msg to avoid cyclical from {} --to--> {}.{}", getName(), msg.sender, msg.name, msg.method); + log.error("{} dumping duplicate hop msg to avoid cyclical from {} --to--> {}.{}", getName(), msg.sender, + msg.name, msg.method); return; } @@ -915,7 +920,7 @@ public void run() { * remotely control UI * * @param panel - * - the panel which has been moved or resized + * - the panel which has been moved or resized */ public void savePanel(Panel panel) { if (panel.name == null) { @@ -1102,7 +1107,7 @@ public void releaseService() { * Default (false) is to use the CDN * * @param useLocalResources - * - true uses local resources fals uses cdn + * - true uses local resources fals uses cdn */ public void useLocalResources(boolean useLocalResources) { this.useLocalResources = useLocalResources; @@ -1162,7 +1167,7 @@ public WebGuiConfig getConfig() { public WebGuiConfig apply(WebGuiConfig c) { super.apply(c); - + if (c.port != null && (port != null && c.port.intValue() != port.intValue())) { setPort(c.port); } @@ -1178,17 +1183,19 @@ public static void main(String[] args) { try { - // Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", "WebGui", "intro", "Intro", "python", "Python" }); - Runtime.main(new String[] { "--install" }); - + Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", "WebGui","intro", "Intro", "python", "Python" }); + // Runtime.main(new String[] {}); + // Runtime.main(new String[] { "--install" }); + boolean done = true; if (done) { return; } - + // Platform.setVirtual(true); - // Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", "WebGui", "intro", "Intro", "python", "Python", "-c", "dev" }); - // Runtime.startConfig("dev"); + // Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", "WebGui", + // "intro", "Intro", "python", "Python", "-c", "dev" }); + // Runtime.startConfig("dev"); // Runtime.start("python", "Python"); // Arduino arduino = (Arduino)Runtime.start("arduino", "Arduino"); @@ -1199,13 +1206,10 @@ public static void main(String[] args) { // webgui.setSsl(true); webgui.startService(); - - Runtime.start("python", "Python"); // Runtime.start("intro", "Intro"); // Runtime.start("i01", "InMoov2"); - // Runtime.start("i01", "InMoov2"); // Runtime.start("python", "Python"); // Runtime.start("i01", "InMoov2"); @@ -1263,7 +1267,6 @@ public static void main(String[] args) { * Runtime.start("clock03", "Clock"); Runtime.start("clock04", "Clock"); * Runtime.start("clock05", "Clock"); */ - Platform.setVirtual(true); // Arduino arduino = (Arduino) Runtime.start("arduino", "Arduino"); Servo pan = (Servo) Runtime.start("pan", "Servo"); @@ -1309,5 +1312,4 @@ public void onStopped(String name) { public void onReleased(String name) { } - } diff --git a/src/main/java/org/myrobotlab/service/config/RuntimeConfig.java b/src/main/java/org/myrobotlab/service/config/RuntimeConfig.java index 87b9e4a1d1..d7572cd118 100644 --- a/src/main/java/org/myrobotlab/service/config/RuntimeConfig.java +++ b/src/main/java/org/myrobotlab/service/config/RuntimeConfig.java @@ -1,31 +1,56 @@ package org.myrobotlab.service.config; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import org.myrobotlab.framework.NameGenerator; +import org.myrobotlab.framework.Plan; +import org.myrobotlab.service.data.Locale; + public class RuntimeConfig extends ServiceConfig { /** * instance id - important to be unique when connecting multiple * mrl instances together */ - public String id; + public String id = NameGenerator.getName(); /** * virtual hardware if enabled all services created will enable virtualization if applicable */ public Boolean virtual = false; - public boolean enableCli = true; - public String logLevel = "info"; - public String locale; + + /** + * Log level debug, info, warn, error + */ + public String logLevel = "warn"; + + /** + * Locale setting for the instance, initial default will be set by the default jvm/os + * through java.util.Locale.getDefault() + */ + public String locale = Locale.getDefault().getTag(); - // NEED THIS PRIVATE BUT CANNOT BE + + /** + * Although this should be a set of unique services, it cannot be a LinkedHashSet + * because SnakeYml's interpretation would be a map with null values. Instead + * its a protected member with accessors that prevent duplicates. + */ public List registry = new ArrayList<>(); /** * Root of resource location */ public String resource = "resource"; + + + public Plan getDefault(Plan plan, String name) { + super.getDefault(plan, name); + return plan; + } + /** * add and remove a service using these methods and the uniqueness will be diff --git a/src/test/java/org/myrobotlab/codec/CodecUtilsTest.java b/src/test/java/org/myrobotlab/codec/CodecUtilsTest.java index 7ffd26fcd4..e26d28e732 100644 --- a/src/test/java/org/myrobotlab/codec/CodecUtilsTest.java +++ b/src/test/java/org/myrobotlab/codec/CodecUtilsTest.java @@ -186,25 +186,6 @@ public void testDefaultSerialization() { } - @Test - public void testNormalizeServiceName() { - Platform.getLocalInstance().setId("test-id"); - assertEquals("runtime@test-id", CodecUtils.getFullName("runtime")); - assertEquals("runtime@test-id", CodecUtils.getFullName("runtime@test-id")); - } - - @Test - public void testCheckServiceNameEqual() { - Platform.getLocalInstance().setId("test-id"); - assertTrue(CodecUtils.checkServiceNameEquality("runtime", "runtime")); - assertTrue(CodecUtils.checkServiceNameEquality("runtime", "runtime@test-id")); - assertTrue(CodecUtils.checkServiceNameEquality("runtime@test-id", "runtime")); - assertTrue(CodecUtils.checkServiceNameEquality("runtime@test-id", "runtime@test-id")); - assertFalse(CodecUtils.checkServiceNameEquality("runtime", "runtime@not-corr-id")); - assertFalse(CodecUtils.checkServiceNameEquality("runtime@not-corr-id", "runtime")); - - } - @Test public void testBase64() { // not a very comprehensive test, but a sanity check none the less. diff --git a/src/test/java/org/myrobotlab/framework/CmdOptionsTest.java b/src/test/java/org/myrobotlab/framework/CmdOptionsTest.java index 85f0d4f2ee..7afa011b8e 100644 --- a/src/test/java/org/myrobotlab/framework/CmdOptionsTest.java +++ b/src/test/java/org/myrobotlab/framework/CmdOptionsTest.java @@ -1,6 +1,7 @@ package org.myrobotlab.framework; - +import org.junit.Ignore; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -9,10 +10,12 @@ import org.junit.Test; import org.myrobotlab.logging.LoggerFactory; +import org.myrobotlab.service.Runtime; +import org.myrobotlab.service.config.ClockConfig; import org.slf4j.Logger; import picocli.CommandLine; - +@Ignore public class CmdOptionsTest { public final static Logger log = LoggerFactory.getLogger(CmdOptionsTest.class); @@ -32,29 +35,36 @@ public void testGetOutputCmd() throws IOException { CmdOptions options = new CmdOptions(); new CommandLine(options).parseArgs(new String[] {}); // validate defaults - assertEquals(false, options.autoUpdate); assertNull(options.config); - assertNull(options.connect); assertEquals(0, options.services.size()); - new CommandLine(options).parseArgs(new String[] { "--id", "raspi", "-s", "webgui", "WebGui", "clock01", "Clock" }); + new CommandLine(options).parseArgs(new String[] { "-s", "webgui", "WebGui", "clock01", "Clock" }); - assertEquals("raspi", options.id); assertEquals(4, options.services.size()); List cmd = options.getOutputCmd(); assertTrue(contains(cmd, "webgui")); - assertTrue(contains(cmd, "raspi")); + assertTrue(contains(cmd, "clock01")); log.info(CmdOptions.toString(cmd)); - options = new CmdOptions(); - new CommandLine(options).parseArgs(new String[] { "-a" }); - assertEquals(true, options.autoUpdate); - + Runtime.releaseAll(true, true); // test help - - // test unmatched option + Runtime.main(new String[] { "--id", "test", "-s", "clockCmdTest", "Clock" }); + assertNotNull(Runtime.getService("clockCmdTest")); + assertEquals("test", Runtime.getInstance().getId()); + + Runtime.releaseAll(true, true); + + Runtime.main(new String[] { "-c", "xxx", "-s", "clockCmdTest", "Clock" }); + + ClockConfig clock = (ClockConfig)Runtime.getInstance().readServiceConfig("xxx", "clockCmdTest"); + assertNotNull(clock); + assertNotNull(Runtime.getService("clockCmdTest")); + + Runtime.releaseAll(true, true); + + log.info("here"); } diff --git a/src/test/java/org/myrobotlab/framework/ConfigTest.java b/src/test/java/org/myrobotlab/framework/ConfigTest.java index 4f8f1a9567..955a18e2ce 100644 --- a/src/test/java/org/myrobotlab/framework/ConfigTest.java +++ b/src/test/java/org/myrobotlab/framework/ConfigTest.java @@ -8,14 +8,8 @@ import java.io.File; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Comparator; import org.junit.After; -import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -38,23 +32,18 @@ import org.slf4j.Logger; public class ConfigTest extends AbstractTest { - - + @BeforeClass public static void setUpBeforeClass() { - System.out.println("Runs before any test method in the class"); - } - - @AfterClass - public static void tearDownAfterClass() { - System.out.println("Runs after all test methods in the class"); + // clean out services - reset + Runtime.releaseAll(true, true); } @Before /* before each test */ public void setUp() throws IOException { // remove all services - also resets config name to DEFAULT effectively Runtime.releaseAll(true, true); - // clean our config directory + // clean our config directory Runtime.removeConfig(CONFIG_NAME); // set our config Runtime.setConfig(CONFIG_NAME); @@ -62,9 +51,8 @@ public void setUp() throws IOException { @After public void tearDown() { - System.out.println("Runs after each test method"); + System.out.println("Runs after each test method"); } - // --- config set related --- // setConfigPath(fullpath) @@ -90,32 +78,31 @@ public void tearDown() { final String CONFIG_PATH = "data" + File.separator + "config" + File.separator + CONFIG_NAME; - @Test public void testStartNoConfig() throws Exception { Runtime runtime = Runtime.getInstance(); assertNotNull(runtime); - + // complete teardown, release runtime, block Runtime.releaseAll(true, true); - + String[] names = Runtime.getServiceNames(); - assertEquals("complete teardown should be 0", 0, names.length); - + assertEquals("after teardown, then using a runtime static - only 0 service 'runtime' should exist", 0, names.length); + // nothing to start - should be empty config Runtime.startConfig(CONFIG_NAME); - + // starting an empty config automatically needs a runtime, and runtime // by default starts the singleton security service names = Runtime.getServiceNames(); - assertEquals("complete teardown should be 2 after trying to start a config runtime and security", 2, names.length); - + assertEquals("complete teardown should be 1 after trying to start a config runtime", 1, names.length); + Runtime.releaseAll(true, true); } - + @Test public void testSwitchingPeer() throws IOException { - + Runtime runtime = Runtime.getInstance(); assertNotNull(runtime); @@ -123,53 +110,53 @@ public void testSwitchingPeer() throws IOException { // to the current config directory Plan plan = Runtime.load("eyeTracking", "Tracking"); assertNotNull(plan); - + // load eyeTracking.yml config - verify default state - TrackingConfig eyeTracking = (TrackingConfig)runtime.getConfig(CONFIG_NAME, "eyeTracking"); + TrackingConfig eyeTracking = (TrackingConfig) runtime.getConfig(CONFIG_NAME, "eyeTracking"); TrackingConfig defaultTracking = new TrackingConfig(); assertEquals("eyeTracking.yml values should be the same as default", defaultTracking.enabled, eyeTracking.enabled); assertEquals("eyeTracking.yml type should be the same as default", defaultTracking.type, eyeTracking.type); - eyeTracking = (TrackingConfig)runtime.getConfig("eyeTracking"); + eyeTracking = (TrackingConfig) runtime.getConfig("eyeTracking"); assertEquals("eyeTracking.yml values should be the same as default", defaultTracking.enabled, eyeTracking.enabled); assertEquals("eyeTracking.yml type should be the same as default", defaultTracking.type, eyeTracking.type); - + // load single opencv - OpenCVConfig cv = (OpenCVConfig)Runtime.load("cv", "OpenCV").get("cv"); + OpenCVConfig cv = (OpenCVConfig) Runtime.load("cv", "OpenCV").get("cv"); // default capturing is false assertFalse(cv.capturing); // save as true cv.capturing = true; Runtime.saveConfig("cv", cv); - + Runtime.load("pid", "Pid"); - eyeTracking = (TrackingConfig)runtime.getConfig("eyeTracking"); - + eyeTracking = (TrackingConfig) runtime.getConfig("eyeTracking"); + eyeTracking.getPeer("cv").name = "cv"; Runtime.saveConfig("eyeTracking", eyeTracking); - + // verify the peer was updated to cv - eyeTracking = (TrackingConfig)runtime.getConfig("eyeTracking"); - cv = (OpenCVConfig)runtime.getPeerConfig("eyeTracking","cv"); + eyeTracking = (TrackingConfig) runtime.getConfig("eyeTracking"); + cv = (OpenCVConfig) runtime.getPeerConfig("eyeTracking", "cv"); // from previous save assertTrue(cv.capturing); } - + @Test public void testChangeType() throws IOException { - Runtime runtime = Runtime.getInstance(); + Runtime runtime = Runtime.getInstance(); Runtime.load("mouth", "MarySpeech"); - MarySpeechConfig mouth = (MarySpeechConfig)runtime.getConfig("mouth"); + MarySpeechConfig mouth = (MarySpeechConfig) runtime.getConfig("mouth"); mouth.listeners.add(new Listener("publishStartSpeaking", "fakeListener")); Runtime.saveConfig("mouth", mouth); - MarySpeechConfig mary = (MarySpeechConfig)runtime.getConfig("mouth"); + MarySpeechConfig mary = (MarySpeechConfig) runtime.getConfig("mouth"); assertNotNull(mary); assertEquals(1, mary.listeners.size()); // save it runtime.changeType("mouth", "LocalSpeech"); - LocalSpeechConfig local = (LocalSpeechConfig)runtime.getConfig("mouth"); + LocalSpeechConfig local = (LocalSpeechConfig) runtime.getConfig("mouth"); assertEquals("must have the listener", 1, local.listeners.size()); assertTrue(local.listeners.get(0).listener.equals("fakeListener")); } @@ -178,23 +165,23 @@ public void testChangeType() throws IOException { public void testInitialLoad() { Runtime runtime = Runtime.getInstance(); Runtime.load("service", "Clock"); - ClockConfig clock = (ClockConfig)runtime.getConfig("service"); + ClockConfig clock = (ClockConfig) runtime.getConfig("service"); assertNotNull(clock); // replace load Runtime.load("service", "Tracking"); - TrackingConfig tracking = (TrackingConfig)runtime.getConfig("service"); + TrackingConfig tracking = (TrackingConfig) runtime.getConfig("service"); assertNotNull(tracking); } - + @Test public void testChangePeerName() throws IOException { Runtime runtime = Runtime.getInstance(); Plan plan = Runtime.load("pollyMouth", "Polly"); - PollyConfig polly = (PollyConfig)plan.get("pollyMouth"); + PollyConfig polly = (PollyConfig) plan.get("pollyMouth"); Runtime.load("i01", "InMoov2"); - InMoov2Config i01 = (InMoov2Config)runtime.getConfig("i01"); + InMoov2Config i01 = (InMoov2Config) runtime.getConfig("i01"); // default - MarySpeechConfig mary = (MarySpeechConfig)runtime.getPeer("i01", "mouth"); + MarySpeechConfig mary = (MarySpeechConfig) runtime.getPeer("i01", "mouth"); assertNotNull(mary); polly.listeners = mary.listeners; Runtime.saveConfig("pollyMouth", polly); @@ -202,48 +189,50 @@ public void testChangePeerName() throws IOException { peer.name = "pollyMouth"; Runtime.saveConfig("i01", i01); // switch to pollyMouth - PollyConfig p = (PollyConfig)runtime.getPeer("i01", "mouth"); - + PollyConfig p = (PollyConfig) runtime.getPeer("i01", "mouth"); + // FIXME - was going to test moving of subscriptions, however, unfortunately - // SpeechSynthesis services use a "recognizers" data instead of just simple subscriptions + // SpeechSynthesis services use a "recognizers" data instead of just simple + // subscriptions // This should be fixed in the future to use standard subscriptions - - } - + + } + @Test public void testSimpleServiceStart() { - Clock clock = (Clock)Runtime.start("track", "Clock"); + Runtime.releaseAll(true, true); + Clock clock = (Clock) Runtime.start("track", "Clock"); clock.startClock(); clock.releaseService(); // better be a tracking service - LocalSpeech track = (LocalSpeech)Runtime.start("track", "LocalSpeech"); + LocalSpeech track = (LocalSpeech) Runtime.start("track", "LocalSpeech"); assertNotNull(track); track.releaseService(); // better be a clock - clock = (Clock)Runtime.create("track", "Clock"); + clock = (Clock) Runtime.create("track", "Clock"); log.info("start"); } @Test public void testPeers() { - InMoov2Head head = (InMoov2Head)Runtime.start("track", "InMoov2Head"); - Servo neck = (Servo)Runtime.getService("track.neck"); + Runtime.releaseAll(true, true); + InMoov2Head head = (InMoov2Head) Runtime.start("track", "InMoov2Head"); + Servo neck = (Servo) Runtime.getService("track.neck"); assertNotNull(neck); head.releaseService(); assertNull(Runtime.getService("track.neck")); - } - + @Test public void testSaveApply() throws IOException { Runtime runtime = Runtime.getInstance(); - Servo neck = (Servo)Runtime.start("neck", "Servo"); + Servo neck = (Servo) Runtime.start("neck", "Servo"); ServoConfig config = neck.getConfig(); - + // Where config is "different" than member variables it // takes an apply(config) of the config to make the service // update its member variables, vs changing config and - // immediately getting the service behavior change. + // immediately getting the service behavior change. config.idleTimeout = 5000; // the fact this takes and additional method to process // i think is legacy and should be changed for Servo to use @@ -251,24 +240,23 @@ public void testSaveApply() throws IOException { neck.apply(config); neck.save(); neck.releaseService(); - neck = (Servo)Runtime.start("neck", "Servo"); - assertTrue("preserved value", 5000 == neck.getConfig().idleTimeout); + neck = (Servo) Runtime.start("neck", "Servo"); + assertTrue("preserved value", 5000 == neck.getConfig().idleTimeout); - Servo servo = (Servo)Runtime.start("servo", "Servo"); - config = (ServoConfig)Runtime.load("default", "Servo").get("default"); + Servo servo = (Servo) Runtime.start("servo", "Servo"); + config = (ServoConfig) Runtime.load("default", "Servo").get("default"); assertNull(config.idleTimeout); config.idleTimeout = 7000; Runtime.saveConfig("servo", config); servo.apply(); assertTrue(servo.getConfig().idleTimeout == 7000); - + config.idleTimeout = 8000; servo.apply(config); assertTrue(servo.getIdleTimeout() == 8000); servo.apply(); assertTrue("filesystem servo.yml applied", servo.getIdleTimeout() == 7000); - + } - } \ No newline at end of file diff --git a/src/test/java/org/myrobotlab/io/FileIOTest.java b/src/test/java/org/myrobotlab/io/FileIOTest.java index a8700219a8..8eb14bedb5 100644 --- a/src/test/java/org/myrobotlab/io/FileIOTest.java +++ b/src/test/java/org/myrobotlab/io/FileIOTest.java @@ -134,11 +134,6 @@ public void testGluePaths() { assertEquals("/abc/def/", ret); } - @Test - public void testIsJar() { - assertFalse(FileIO.isJar()); - } - @Test public void testGetFileListString() throws IOException { String dir = FileIO.gluePaths(tempDir, "testGetFileListString"); @@ -187,6 +182,7 @@ public void testToInputStreamString() throws IOException { InputStream ios = FileIO.toInputStream("This is some data that got turned into a stream"); String data = FileIO.toString(ios); assertEquals("This is some data that got turned into a stream", data); + ios.close(); } @Test diff --git a/src/test/java/org/myrobotlab/service/RuntimeTest.java b/src/test/java/org/myrobotlab/service/RuntimeTest.java index a20a13db38..e2a01278c1 100644 --- a/src/test/java/org/myrobotlab/service/RuntimeTest.java +++ b/src/test/java/org/myrobotlab/service/RuntimeTest.java @@ -26,8 +26,8 @@ public class RuntimeTest extends AbstractTest { public final static Logger log = LoggerFactory.getLogger(RuntimeTest.class); @Before - public void setUp() { - // LoggingFactory.init("WARN"); + public void beforeTest() { + Runtime.releaseAll(true, true); } @Test @@ -92,9 +92,6 @@ public void testGetUptime() { @Test public void testRuntimeLocale() { - long curr = 1479044758691L; - Date d = new Date(curr); - Runtime runtime = Runtime.getInstance(); runtime.setLocale("fr-FR"); assertEquals("expecting concat fr-FR", "fr-FR", runtime.getLocale().getTag()); @@ -105,16 +102,6 @@ public void testRuntimeLocale() { } - @Test - public void testRuntimeIsAvailable() { - Runtime.getInstance(); - assertTrue(Runtime.isAvailable()); - Runtime.releaseAll(true, true); - assertFalse(Runtime.isAvailable()); - Runtime.getInstance(); - assertTrue(Runtime.isAvailable()); - } - @Test public void testGetDescribeMessage() { diff --git a/src/test/java/org/myrobotlab/service/SerialTest.java b/src/test/java/org/myrobotlab/service/SerialTest.java index db1f10e315..63aeaa5cb5 100644 --- a/src/test/java/org/myrobotlab/service/SerialTest.java +++ b/src/test/java/org/myrobotlab/service/SerialTest.java @@ -53,7 +53,7 @@ public static Set getDeadThreads() { @BeforeClass public static void setUpBeforeClass() throws Exception { // LoggingFactory.init("WARN"); - Platform.setVirtual(true); + Runtime.getInstance().setVirtual(true); log.info("setUpBeforeClass"); From 46af60ce4e0fbfe789947da22f0538fba02815c2 Mon Sep 17 00:00:00 2001 From: grog Date: Mon, 12 Feb 2024 06:26:04 -0800 Subject: [PATCH 047/131] framework --- .../java/org/myrobotlab/service/InMoov2.java | 2 +- .../org/myrobotlab/framework/ServiceTest.java | 46 ------------------- 2 files changed, 1 insertion(+), 47 deletions(-) delete mode 100644 src/test/java/org/myrobotlab/framework/ServiceTest.java diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index 5f4233844c..46ab187b5b 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -1877,7 +1877,7 @@ public SpeechSynthesis startMouth() { broadcastState(); speakBlocking(get("STARTINGMOUTH")); - if (Platform.isVirtual()) { + if (isVirtual()) { speakBlocking(get("STARTINGVIRTUALHARD")); } speakBlocking(get("WHATISTHISLANGUAGE")); diff --git a/src/test/java/org/myrobotlab/framework/ServiceTest.java b/src/test/java/org/myrobotlab/framework/ServiceTest.java deleted file mode 100644 index a9f180362c..0000000000 --- a/src/test/java/org/myrobotlab/framework/ServiceTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.myrobotlab.framework; - -import static org.junit.Assert.assertEquals; - -import java.util.List; -import java.util.Map; - -import org.junit.Test; -import org.myrobotlab.service.config.ServiceConfig; -import org.myrobotlab.test.AbstractTest; - -public class ServiceTest extends AbstractTest { - - public static class TestService extends Service { - - private static final long serialVersionUID = 1L; - - /** - * Constructor of service, reservedkey typically is a services name and inId - * will be its process id - * - * @param reservedKey the service name - * @param inId process id - */ - public TestService(String reservedKey, String inId) { - super(reservedKey, inId); - } - } - - @Test - public void testConfigListenerFiltering() { - Platform.getLocalInstance().setId("test-id"); - TestService t = new TestService("test", "test-id"); - List listeners = List.of( - new MRLListener("meth", "webgui@webgui-client", "onMeth"), - new MRLListener("meth", "random@test-id", "onMeth"), - new MRLListener("meth", "random2@test-2-id", "onMeth") - ); - t.apply(new ServiceConfig()); - t.outbox.notifyList = Map.of("meth", listeners); - List filtered = t.getFilteredConfig().listeners; - assertEquals("random", filtered.get(0).listener); - assertEquals("random2@test-2-id", filtered.get(1).listener); - t.getFilteredConfig(); - } -} From e895567d8c5fd68e9c6fd6c8003c1d2ea822389c Mon Sep 17 00:00:00 2001 From: grog Date: Mon, 12 Feb 2024 07:40:18 -0800 Subject: [PATCH 048/131] let framework process inmoov2 releaseService --- .vscode/settings.json | 2 +- .../org/myrobotlab/service/InMoov2Arm.java | 53 ++------------- .../org/myrobotlab/service/InMoov2Hand.java | 58 ---------------- .../org/myrobotlab/service/InMoov2Head.java | 66 ------------------- .../org/myrobotlab/service/InMoov2Torso.java | 55 +--------------- .../service/interfaces/ServoControl.java | 1 - 6 files changed, 8 insertions(+), 227 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index c0d2e88e12..651c18245e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,7 +17,7 @@ "jest.coverageFormatter": "GutterFormatter", "editor.formatOnSave": true, "editor.codeActionsOnSave": { - "source.organizeImports": true + "source.organizeImports": "explicit" }, "typescript.tsdk": "./app/node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true, diff --git a/src/main/java/org/myrobotlab/service/InMoov2Arm.java b/src/main/java/org/myrobotlab/service/InMoov2Arm.java index 1b4b45e6b5..e676c52878 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2Arm.java +++ b/src/main/java/org/myrobotlab/service/InMoov2Arm.java @@ -90,7 +90,7 @@ public static DHRobotArm getDHRobotArm(String name, String side) { return arm; } - + @Deprecated /* use onMove(map) */ public void onMoveArm(HashMap map) { onMove(map); @@ -100,7 +100,6 @@ public void onMove(Map map) { moveTo(map.get("bicep"), map.get("rotate"), map.get("shoulder"), map.get("omoplate")); } - /** * peer services FIXME - framework should always - startPeers() unless * configured not to @@ -125,23 +124,6 @@ public void startService() { shoulder = (ServoControl) startPeer("shoulder"); omoplate = (ServoControl) startPeer("omoplate"); } - - @Override - public void stopService() { - super.stopService(); - if (bicep != null) { - ((Service)bicep).stopService(); - } - if (rotate != null) { - ((Service)rotate).stopService(); - } - if (shoulder != null) { - ((Service)shoulder).stopService(); - } - if (omoplate != null) { - ((Service)omoplate).stopService(); - } - } @Override public void broadcastState() { @@ -210,8 +192,8 @@ public ServoControl getRotate() { public String getScript(String service) { String side = getName().contains("left") ? "left" : "right"; - return String.format("%s.moveArm(\"%s\",%.0f,%.0f,%.0f,%.0f)\n", service, side, bicep.getCurrentInputPos(), rotate.getCurrentInputPos(), - shoulder.getCurrentInputPos(), omoplate.getCurrentInputPos()); + return String.format("%s.moveArm(\"%s\",%.0f,%.0f,%.0f,%.0f)\n", service, side, bicep.getCurrentInputPos(), rotate.getCurrentInputPos(), shoulder.getCurrentInputPos(), + omoplate.getCurrentInputPos()); } public ServoControl getShoulder() { @@ -301,31 +283,6 @@ public void onJointAngles(Map angleMap) { } } - // FIXME - framework should auto-release - unless configured not to - @Override - public void releaseService() { - try { - disable(); - - if (bicep != null) { - ((Service)bicep).releaseService(); - } - if (rotate != null) { - ((Service)rotate).releaseService(); - } - if (shoulder != null) { - ((Service)shoulder).releaseService(); - } - if (omoplate != null) { - ((Service)omoplate).releaseService(); - } - - super.releaseService(); - } catch (Exception e) { - error(e); - } - } - public void rest() { if (bicep != null) bicep.rest(); @@ -492,7 +449,7 @@ public void waitTargetPos() { if (omoplate != null) omoplate.waitTargetPos(); } - + public static void main(String[] args) { LoggingFactory.init(Level.INFO); @@ -501,7 +458,7 @@ public static void main(String[] args) { Runtime.main(new String[] { "--log-level", "info", "-s", "inmoov2arm", "InMoov2Arm" }); // Runtime.main(new String[] {}); // Runtime.main(new String[] { "--install" }); - InMoov2Arm arm = (InMoov2Arm)Runtime.start("inmoov2arm", "InMoov2Arm"); + InMoov2Arm arm = (InMoov2Arm) Runtime.start("inmoov2arm", "InMoov2Arm"); arm.releaseService(); boolean done = true; diff --git a/src/main/java/org/myrobotlab/service/InMoov2Hand.java b/src/main/java/org/myrobotlab/service/InMoov2Hand.java index 06b6d3b459..f7fdadebbc 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2Hand.java +++ b/src/main/java/org/myrobotlab/service/InMoov2Hand.java @@ -567,64 +567,6 @@ public List refreshControllers() { return controllers; } - public void release() { - disable(); - } - - @Override - public void stopService() { - disable(); - if (thumb != null) { - ((Service)thumb).stopService(); - } - if (index != null) { - ((Service)index).stopService(); - } - if (majeure != null) { - ((Service)majeure).stopService(); - } - if (ringFinger != null) { - ((Service)ringFinger).stopService(); - } - if (pinky != null) { - ((Service)pinky).stopService(); - } - if (wrist != null) { - ((Service)wrist).stopService(); - } - super.stopService(); - } - - @Override - public void releaseService() { - try { - disable(); - - if (thumb != null) { - ((Service)thumb).releaseService(); - } - if (index != null) { - ((Service)index).releaseService(); - } - if (majeure != null) { - ((Service)majeure).releaseService(); - } - if (ringFinger != null) { - ((Service)ringFinger).releaseService(); - } - if (pinky != null) { - ((Service)pinky).releaseService(); - } - if (wrist != null) { - ((Service)wrist).releaseService(); - } - - super.releaseService(); - } catch (Exception e) { - error(e); - } - } - public void rest() { if (thumb != null) thumb.rest(); diff --git a/src/main/java/org/myrobotlab/service/InMoov2Head.java b/src/main/java/org/myrobotlab/service/InMoov2Head.java index da9052ca65..1e98970f78 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2Head.java +++ b/src/main/java/org/myrobotlab/service/InMoov2Head.java @@ -359,72 +359,6 @@ public void waitTargetPos() { public void release() { disable(); } - - @Override - public void stopService() { - - if (jaw != null) { - ((Service)jaw).stopService(); - } - if (eyeX != null) { - ((Service)eyeX).stopService(); - } - if (eyeY != null) { - ((Service)eyeY).stopService(); - } - if (neck != null) { - ((Service)neck).stopService(); - } - if (rothead != null) { - ((Service)rothead).stopService(); - } - if (rollNeck != null) { - ((Service)rollNeck).stopService(); - } - if (eyelidLeft != null) { - ((Service)eyelidLeft).stopService(); - } - if (eyelidRight != null) { - ((Service)eyelidRight).stopService(); - } - - super.stopService(); - } - - - - - @Override - public void releaseService() { - disable(); - - if (jaw != null) { - ((Service)jaw).releaseService(); - } - if (eyeX != null) { - ((Service)eyeX).releaseService(); - } - if (eyeY != null) { - ((Service)eyeY).releaseService(); - } - if (neck != null) { - ((Service)neck).releaseService(); - } - if (rothead != null) { - ((Service)rothead).releaseService(); - } - if (rollNeck != null) { - ((Service)rollNeck).releaseService(); - } - if (eyelidLeft != null) { - ((Service)eyelidLeft).releaseService(); - } - if (eyelidRight != null) { - ((Service)eyelidRight).releaseService(); - } - - super.releaseService(); - } public void rest() { // initial positions diff --git a/src/main/java/org/myrobotlab/service/InMoov2Torso.java b/src/main/java/org/myrobotlab/service/InMoov2Torso.java index 3754e43a3c..efdb127957 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2Torso.java +++ b/src/main/java/org/myrobotlab/service/InMoov2Torso.java @@ -36,59 +36,10 @@ public InMoov2Torso(String n, String id) { @Override public void startService() { super.startService(); - topStom = (ServoControl) getPeer("topStom"); midStom = (ServoControl) getPeer("midStom"); lowStom = (ServoControl) getPeer("lowStom"); } - - @Override - public void stopService() { - disable(); - - if (topStom != null) { - ((Service)topStom).stopService(); - } - - if (midStom != null) { - ((Service)midStom).stopService(); - } - - if (lowStom != null) { - ((Service)lowStom).stopService(); - } - - super.stopService(); - } - - @Override - public void releaseService() { - try { - disable(); - - - if (topStom != null) { - ((Service)topStom).releaseService(); - } - - if (midStom != null) { - ((Service)midStom).releaseService(); - } - - if (lowStom != null) { - ((Service)lowStom).releaseService(); - } - - - topStom = null; - midStom = null; - lowStom = null; - - super.releaseService(); - } catch (Exception e) { - error(e); - } - } public void enable() { if (topStom != null) @@ -126,7 +77,7 @@ public void disable() { if (lowStom != null) lowStom.disable(); } - + @Deprecated /* use onMove(map) */ public void onMoveTorso(HashMap map) { onMove(map); @@ -136,7 +87,6 @@ public void onMove(Map map) { moveTo(map.get("topStom"), map.get("midStom"), map.get("lowStom")); } - public long getLastActivityTime() { long minLastActivity = Math.max(topStom.getLastActivityTime(), midStom.getLastActivityTime()); minLastActivity = Math.max(minLastActivity, lowStom.getLastActivityTime()); @@ -144,8 +94,7 @@ public long getLastActivityTime() { } public String getScript(String inMoovServiceName) { - return String.format("%s.moveTorso(%.0f,%.0f,%.0f)\n", inMoovServiceName, topStom.getCurrentInputPos(), midStom.getCurrentInputPos(), - lowStom.getCurrentInputPos()); + return String.format("%s.moveTorso(%.0f,%.0f,%.0f)\n", inMoovServiceName, topStom.getCurrentInputPos(), midStom.getCurrentInputPos(), lowStom.getCurrentInputPos()); } public void moveTo(Double topStomPos, Double midStomPos, Double lowStomPos) { diff --git a/src/main/java/org/myrobotlab/service/interfaces/ServoControl.java b/src/main/java/org/myrobotlab/service/interfaces/ServoControl.java index 1e140ce167..23a9ee9629 100644 --- a/src/main/java/org/myrobotlab/service/interfaces/ServoControl.java +++ b/src/main/java/org/myrobotlab/service/interfaces/ServoControl.java @@ -404,7 +404,6 @@ public interface ServoControl extends AbsolutePositionControl, EncoderListener, /** * disable speed control and move the servos at full speed. */ - @Deprecated /* implement setSpeed(null) */ void fullSpeed(); } From 237a5152da9bc2d9b86ed454f799c442a1a6b5ad Mon Sep 17 00:00:00 2001 From: grog Date: Tue, 13 Feb 2024 06:57:54 -0800 Subject: [PATCH 049/131] unit test updates --- .../org/myrobotlab/framework/repo/Repo.java | 6 +- .../myrobotlab/framework/BlockingTest.java | 4 +- .../myrobotlab/framework/repo/RepoTest.java | 4 + .../org/myrobotlab/service/ArduinoTest.java | 1 - .../service/RuntimeProcessTest.java | 5 +- .../service/VirtualArduinoTest.java | 4 + .../org/myrobotlab/test/AbstractTest.java | 130 ++++++------------ 7 files changed, 60 insertions(+), 94 deletions(-) diff --git a/src/main/java/org/myrobotlab/framework/repo/Repo.java b/src/main/java/org/myrobotlab/framework/repo/Repo.java index 9262834da1..d8b6863c16 100644 --- a/src/main/java/org/myrobotlab/framework/repo/Repo.java +++ b/src/main/java/org/myrobotlab/framework/repo/Repo.java @@ -324,10 +324,10 @@ public Set getUnfulfilledDependencies(String[] types) { } } } - + // Plan plan = ServiceConfig.getDefault(type.toLowerCase(), type); ServiceConfig sc = ServiceConfig.getDefaultServiceConfig(type); - + Map peers = sc.getPeers(); if (peers != null) { for (String key : peers.keySet()) { @@ -496,7 +496,7 @@ public void load() { } } else { - log.info("{} not found", getRepoPath()); + log.info("{} not found", f.getAbsolutePath()); } } catch (Exception e) { diff --git a/src/test/java/org/myrobotlab/framework/BlockingTest.java b/src/test/java/org/myrobotlab/framework/BlockingTest.java index b4ce03e8da..3b9788645b 100644 --- a/src/test/java/org/myrobotlab/framework/BlockingTest.java +++ b/src/test/java/org/myrobotlab/framework/BlockingTest.java @@ -28,13 +28,13 @@ public void blockingTest() throws Exception { Message msg = Message.createMessage("thower07", "catcher07", "onInt", 3); Integer ret = (Integer)thower07.sendBlocking(msg, null); - assertEquals(simpleName, 3, (int)ret); + assertEquals(3, (int)ret); long startTime = System.currentTimeMillis(); msg = Message.createMessage("thower07", "catcher07", "waitForThis", new Object[] {7, 1000}); ret = (Integer)thower07.sendBlocking(msg, null); assertTrue("1s process", System.currentTimeMillis() - startTime > 500); - assertEquals(simpleName, 7, (int)ret); + assertEquals(7, (int)ret); Runtime.release("catcher07"); Runtime.release("thower07"); diff --git a/src/test/java/org/myrobotlab/framework/repo/RepoTest.java b/src/test/java/org/myrobotlab/framework/repo/RepoTest.java index f2715dc90d..d0e2c57735 100644 --- a/src/test/java/org/myrobotlab/framework/repo/RepoTest.java +++ b/src/test/java/org/myrobotlab/framework/repo/RepoTest.java @@ -28,6 +28,10 @@ public static void lastCleanup() { repo.clear(); installed = false; } + + public String getName() { + return "RepoTest"; + } @Override public void broadcastStatus(Status status) { diff --git a/src/test/java/org/myrobotlab/service/ArduinoTest.java b/src/test/java/org/myrobotlab/service/ArduinoTest.java index 7a6422d29d..00cee5e0a7 100644 --- a/src/test/java/org/myrobotlab/service/ArduinoTest.java +++ b/src/test/java/org/myrobotlab/service/ArduinoTest.java @@ -62,7 +62,6 @@ private void assertVirtualPinValue(VirtualArduino virtual, int address, int valu } } - @Override public String getName() { return "arduinoTest"; } diff --git a/src/test/java/org/myrobotlab/service/RuntimeProcessTest.java b/src/test/java/org/myrobotlab/service/RuntimeProcessTest.java index 07e1775110..4bdb93fe2c 100644 --- a/src/test/java/org/myrobotlab/service/RuntimeProcessTest.java +++ b/src/test/java/org/myrobotlab/service/RuntimeProcessTest.java @@ -21,12 +21,15 @@ public class RuntimeProcessTest extends AbstractTest { @Before public void setUp() { - // LoggingFactory.init("WARN"); } public boolean contains(ByteArrayOutputStream out, String str) { return new String(out.toByteArray()).contains(str); } + + public String getName() { + return "RuntimeProcessTest"; + } @Test public void cliTest() throws Exception { diff --git a/src/test/java/org/myrobotlab/service/VirtualArduinoTest.java b/src/test/java/org/myrobotlab/service/VirtualArduinoTest.java index ba1d028096..110ff1ac4a 100755 --- a/src/test/java/org/myrobotlab/service/VirtualArduinoTest.java +++ b/src/test/java/org/myrobotlab/service/VirtualArduinoTest.java @@ -30,6 +30,10 @@ public Service createService() { VirtualArduino service = (VirtualArduino) Runtime.start("virtualArduino", "VirtualArduino"); return service; } + + public String getName() { + return "VirtualArduinoTest"; + } @Override public void testService() throws Exception { diff --git a/src/test/java/org/myrobotlab/test/AbstractTest.java b/src/test/java/org/myrobotlab/test/AbstractTest.java index d782797c9b..4fd42b3bb9 100644 --- a/src/test/java/org/myrobotlab/test/AbstractTest.java +++ b/src/test/java/org/myrobotlab/test/AbstractTest.java @@ -14,82 +14,56 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Rule; -import org.junit.rules.TestName; +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; import org.myrobotlab.codec.CodecUtils; -import org.myrobotlab.framework.Platform; import org.myrobotlab.framework.interfaces.Attachable; import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.service.Runtime; import org.myrobotlab.service.config.RuntimeConfig; import org.slf4j.Logger; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; - public class AbstractTest { /** cached network test value for tests */ - static Boolean hasInternet = null; + protected static Boolean hasInternet = null; protected static boolean installed = false; - public final static Logger log = LoggerFactory.getLogger(AbstractTest.class); - - static private boolean logWarnTestHeader = false; - - private static boolean releaseRemainingThreads = false; - - protected transient Queue queue = new LinkedBlockingQueue<>(); - - static transient Set threadSetStart = null; + protected final static Logger log = LoggerFactory.getLogger(AbstractTest.class); - protected Set attached = new HashSet<>(); + protected static boolean releaseRemainingThreads = false; - @Rule - public final TestName testName = new TestName(); - - static public String simpleName; + protected static transient Set threadSetStart = null; - private static boolean lineFeedFooter = true; - @Rule public TestWatcher watchman = new TestWatcher() { - @Override - protected void starting(Description description) { - System.out.println("Starting: " + description.getClassName() + "." + description.getMethodName()); - } + @Override + protected void starting(Description description) { + System.out.println("Starting: " + description.getClassName() + "." + description.getMethodName()); + } - @Override - protected void succeeded(Description description) { - // System.out.println("Succeeded: " + description.getMethodName()); - } + @Override + protected void succeeded(Description description) { + // System.out.println("Succeeded: " + description.getMethodName()); + } - @Override - protected void failed(Throwable e, Description description) { - System.out.println("Failed: " + description.getMethodName()); - } + @Override + protected void failed(Throwable e, Description description) { + System.out.println("Failed: " + description.getMethodName()); + } - @Override - protected void skipped(org.junit.AssumptionViolatedException e, Description description) { - System.out.println("Skipped: " + description.getMethodName()); - } + @Override + protected void skipped(org.junit.AssumptionViolatedException e, Description description) { + System.out.println("Skipped: " + description.getMethodName()); + } - @Override - protected void finished(Description description) { - System.out.println("Finished: " + description.getMethodName()); - } + @Override + protected void finished(Description description) { + System.out.println("Finished: " + description.getMethodName()); + } }; - public String getSimpleName() { - return simpleName; - } - - public String getName() { - return testName.getMethodName(); - } - static public boolean hasInternet() { if (hasInternet == null) { hasInternet = Runtime.hasInternet(); @@ -120,23 +94,23 @@ public static void main(String[] args) { @BeforeClass public static void setUpAbstractTest() throws Exception { - + // setup runtime resource = src/main/resources/resource File runtimeYml = new File("data/config/default/runtime.yml"); -// if (!runtimeYml.exists()) { - runtimeYml.getParentFile().mkdirs(); - RuntimeConfig rc = new RuntimeConfig(); - rc.resource = "src/main/resources/resource"; - String yml = CodecUtils.toYaml(rc); - - FileOutputStream fos = null; - fos = new FileOutputStream(runtimeYml); - fos.write(yml.getBytes()); - fos.close(); - -// } - - Runtime.getInstance().setVirtual(true); + // if (!runtimeYml.exists()) { + runtimeYml.getParentFile().mkdirs(); + RuntimeConfig rc = new RuntimeConfig(); + rc.resource = "src/main/resources/resource"; + String yml = CodecUtils.toYaml(rc); + + FileOutputStream fos = null; + fos = new FileOutputStream(runtimeYml); + fos.write(yml.getBytes()); + fos.close(); + + // } + + Runtime.getInstance().setVirtual(true); String junitLogLevel = System.getProperty("junit.logLevel"); if (junitLogLevel != null) { @@ -171,16 +145,7 @@ public static void sleep(long sleepTimeMs) { @AfterClass public static void tearDownAbstractTest() throws Exception { log.info("tearDownAbstractTest"); - releaseServices(); - - if (logWarnTestHeader) { - log.warn("=========== finished test {} ===========", simpleName); - } - - if (lineFeedFooter) { - System.out.println(); - } } static protected void installAll() { @@ -197,8 +162,7 @@ static protected void installAll() { */ public static void releaseServices() { - log.info("end of test - id {} remaining services {}", Runtime.getInstance().getId(), - Arrays.toString(Runtime.getServiceNames())); + log.info("end of test - id {} remaining services {}", Runtime.getInstance().getId(), Arrays.toString(Runtime.getServiceNames())); // release all including runtime - be careful of default runtime.yml Runtime.releaseAll(true, true); @@ -212,8 +176,7 @@ public static void releaseServices() { Set threadSetEnd = Thread.getAllStackTraces().keySet(); Set threadsRemaining = new TreeSet<>(); for (Thread thread : threadSetEnd) { - if (!threadSetStart.contains(thread) && !"runtime_outbox_0".equals(thread.getName()) - && !"runtime".equals(thread.getName())) { + if (!threadSetStart.contains(thread) && !"runtime_outbox_0".equals(thread.getName()) && !"runtime".equals(thread.getName())) { if (releaseRemainingThreads) { log.warn("interrupting thread {}", thread.getName()); thread.interrupt(); @@ -236,13 +199,6 @@ public static void releaseServices() { // Arrays.toString(Runtime.getServiceNames())); } - public AbstractTest() { - simpleName = this.getClass().getSimpleName(); - if (logWarnTestHeader) { - log.info("=========== starting test {} ===========", this.getClass().getSimpleName()); - } - } - public void setVirtual() { Runtime.getInstance().setVirtual(true); } From 95b3ddb31d6e860b036793db2b6992ec13d2bba6 Mon Sep 17 00:00:00 2001 From: grog Date: Tue, 13 Feb 2024 07:24:48 -0800 Subject: [PATCH 050/131] stop cli when runtime is released --- .../java/org/myrobotlab/service/Runtime.java | 3 +++ .../org/myrobotlab/test/AbstractTest.java | 21 +++++++------------ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index e838cf6c52..49c27cff75 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -3446,6 +3446,9 @@ public void releaseService() { runtime.stopService(); runtime.stopInteractiveMode(); runtime.getRepo().removeStatusPublishers(); + if (cli != null) { + cli.stop(); + } registry = new TreeMap<>(); } synchronized (INSTANCE_LOCK) { diff --git a/src/test/java/org/myrobotlab/test/AbstractTest.java b/src/test/java/org/myrobotlab/test/AbstractTest.java index 4fd42b3bb9..7279a8fe98 100644 --- a/src/test/java/org/myrobotlab/test/AbstractTest.java +++ b/src/test/java/org/myrobotlab/test/AbstractTest.java @@ -25,15 +25,20 @@ public class AbstractTest { - /** cached network test value for tests */ + /** + * cached network test value for tests + */ protected static Boolean hasInternet = null; + /** + * Install dependencies once per process, same process + * will not check. A new process will use the libraries/serviceData.json + * to determine if deps are satisfied + */ protected static boolean installed = false; protected final static Logger log = LoggerFactory.getLogger(AbstractTest.class); - protected static boolean releaseRemainingThreads = false; - protected static transient Set threadSetStart = null; @Rule @@ -177,17 +182,7 @@ public static void releaseServices() { Set threadsRemaining = new TreeSet<>(); for (Thread thread : threadSetEnd) { if (!threadSetStart.contains(thread) && !"runtime_outbox_0".equals(thread.getName()) && !"runtime".equals(thread.getName())) { - if (releaseRemainingThreads) { - log.warn("interrupting thread {}", thread.getName()); - thread.interrupt(); - /* - * if (useDeprecatedThreadStop) { thread.stop(); } - */ - } else { - // log.warn("thread {} marked as straggler - should be killed", - // thread.getName()); threadsRemaining.add(thread.getName()); - } } } if (threadsRemaining.size() > 0) { From 43fff16c0eee391c33334ad16a880c5ee85ca538 Mon Sep 17 00:00:00 2001 From: grog Date: Tue, 13 Feb 2024 08:16:41 -0800 Subject: [PATCH 051/131] corrected synchronization --- .../java/org/myrobotlab/service/Runtime.java | 51 +++++++++---------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 49c27cff75..675123e962 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -1204,12 +1204,12 @@ public static S getService(String inName, StaticTyp * */ static public String[] getServiceNames() { - Set ret = registry.keySet(); + Set ret = registry.keySet(); String[] services = new String[ret.size()]; if (ret.size() == 0) { return services; } - + // if there are more than 0 services we need runtime // to filter to make sure they are "local" // and this requires a runtime service @@ -1940,11 +1940,11 @@ public static boolean releaseService(String inName) { } return false; } - - + /** - * Called after any subclassed releaseService has been called, this cleans - * up the registry and removes peers + * Called after any subclassed releaseService has been called, this cleans up + * the registry and removes peers + * * @param inName * @return */ @@ -2004,7 +2004,6 @@ public static boolean releaseServiceInternal(String inName) { } } - /** * Removes registration for a service. Removes the service from * {@link #typeToInterface} and {@link #interfaceToNames}. @@ -2199,7 +2198,9 @@ static private void processRelease(boolean releaseRuntime) { if (runtime != null) { runtime.releaseService(); } - runtime = null; + synchronized (INSTANCE_LOCK) { + runtime = null; + } } else { // put runtime in new registry Runtime.getInstance(); @@ -2830,26 +2831,20 @@ public Runtime(String n, String id) { // because you need to start with something ... config = new RuntimeConfig(); - synchronized (INSTANCE_LOCK) { - if (runtime == null) { - // fist and only time.... - runtime = this; - repo = (IvyWrapper) Repo.getInstance(LIBRARIES, "IvyWrapper"); - - /** - * This is used to run through all the possible services and determine - * if they have any missing dependencies. If they do not they become - * "installed". The installed flag makes the gui do a crossout when a - * service type is selected. - */ - for (MetaData metaData : serviceData.getServiceTypes()) { - Set deps = repo.getUnfulfilledDependencies(metaData.getType()); - if (deps.size() == 0) { - metaData.installed = true; - } else { - log.info("{} not installed", metaData.getSimpleName()); - } - } + repo = (IvyWrapper) Repo.getInstance(LIBRARIES, "IvyWrapper"); + + /** + * This is used to run through all the possible services and determine if + * they have any missing dependencies. If they do not they become + * "installed". The installed flag makes the gui do a crossout when a + * service type is selected. + */ + for (MetaData metaData : serviceData.getServiceTypes()) { + Set deps = repo.getUnfulfilledDependencies(metaData.getType()); + if (deps.size() == 0) { + metaData.installed = true; + } else { + log.info("{} not installed", metaData.getSimpleName()); } } From 65542d07ac0532e27cca606a5422f68fd03c5bb1 Mon Sep 17 00:00:00 2001 From: grog Date: Tue, 13 Feb 2024 08:40:00 -0800 Subject: [PATCH 052/131] corrected instance lock --- .../java/org/myrobotlab/service/Runtime.java | 54 +++++++++---------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index e838cf6c52..675123e962 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -1204,12 +1204,12 @@ public static S getService(String inName, StaticTyp * */ static public String[] getServiceNames() { - Set ret = registry.keySet(); + Set ret = registry.keySet(); String[] services = new String[ret.size()]; if (ret.size() == 0) { return services; } - + // if there are more than 0 services we need runtime // to filter to make sure they are "local" // and this requires a runtime service @@ -1940,11 +1940,11 @@ public static boolean releaseService(String inName) { } return false; } - - + /** - * Called after any subclassed releaseService has been called, this cleans - * up the registry and removes peers + * Called after any subclassed releaseService has been called, this cleans up + * the registry and removes peers + * * @param inName * @return */ @@ -2004,7 +2004,6 @@ public static boolean releaseServiceInternal(String inName) { } } - /** * Removes registration for a service. Removes the service from * {@link #typeToInterface} and {@link #interfaceToNames}. @@ -2199,7 +2198,9 @@ static private void processRelease(boolean releaseRuntime) { if (runtime != null) { runtime.releaseService(); } - runtime = null; + synchronized (INSTANCE_LOCK) { + runtime = null; + } } else { // put runtime in new registry Runtime.getInstance(); @@ -2830,26 +2831,20 @@ public Runtime(String n, String id) { // because you need to start with something ... config = new RuntimeConfig(); - synchronized (INSTANCE_LOCK) { - if (runtime == null) { - // fist and only time.... - runtime = this; - repo = (IvyWrapper) Repo.getInstance(LIBRARIES, "IvyWrapper"); - - /** - * This is used to run through all the possible services and determine - * if they have any missing dependencies. If they do not they become - * "installed". The installed flag makes the gui do a crossout when a - * service type is selected. - */ - for (MetaData metaData : serviceData.getServiceTypes()) { - Set deps = repo.getUnfulfilledDependencies(metaData.getType()); - if (deps.size() == 0) { - metaData.installed = true; - } else { - log.info("{} not installed", metaData.getSimpleName()); - } - } + repo = (IvyWrapper) Repo.getInstance(LIBRARIES, "IvyWrapper"); + + /** + * This is used to run through all the possible services and determine if + * they have any missing dependencies. If they do not they become + * "installed". The installed flag makes the gui do a crossout when a + * service type is selected. + */ + for (MetaData metaData : serviceData.getServiceTypes()) { + Set deps = repo.getUnfulfilledDependencies(metaData.getType()); + if (deps.size() == 0) { + metaData.installed = true; + } else { + log.info("{} not installed", metaData.getSimpleName()); } } @@ -3446,6 +3441,9 @@ public void releaseService() { runtime.stopService(); runtime.stopInteractiveMode(); runtime.getRepo().removeStatusPublishers(); + if (cli != null) { + cli.stop(); + } registry = new TreeMap<>(); } synchronized (INSTANCE_LOCK) { From 5182af01ea0fe9729c74cbc3634429e1608b2988 Mon Sep 17 00:00:00 2001 From: grog Date: Tue, 13 Feb 2024 10:20:17 -0800 Subject: [PATCH 053/131] adjusted location of sleep wait --- src/test/java/org/myrobotlab/service/RandomTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/myrobotlab/service/RandomTest.java b/src/test/java/org/myrobotlab/service/RandomTest.java index 7c8add5923..dfde5042ee 100644 --- a/src/test/java/org/myrobotlab/service/RandomTest.java +++ b/src/test/java/org/myrobotlab/service/RandomTest.java @@ -62,8 +62,8 @@ public void testService() throws Exception { // disable all of a services random events random.disable("clock.startClock"); - clock.stopClock(); sleep(250); + clock.stopClock(); assertTrue("clock should not be started 1", !clock.isClockRunning()); // enable all of a service's random events From 54f874bde713d48deddab53a00c779e13e6ff618 Mon Sep 17 00:00:00 2001 From: grog Date: Tue, 13 Feb 2024 10:38:11 -0800 Subject: [PATCH 054/131] shifted sleep position in randomtest --- src/test/java/org/myrobotlab/service/RandomTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/myrobotlab/service/RandomTest.java b/src/test/java/org/myrobotlab/service/RandomTest.java index dfde5042ee..18f4e1c789 100644 --- a/src/test/java/org/myrobotlab/service/RandomTest.java +++ b/src/test/java/org/myrobotlab/service/RandomTest.java @@ -74,8 +74,8 @@ public void testService() throws Exception { // disable one method - leave other enabled random.disable("clock.startClock"); clock.stopClock(); - clock.setInterval(9999); sleep(200); + clock.setInterval(9999); assertTrue("clock should not be started 3", !clock.isClockRunning()); assertTrue(String.format("random method 2 should be %d => 5000 values", clock.getInterval()), 5000 <= clock.getInterval()); assertTrue(String.format("random method 2 should be %d <= 10000 values",clock.getInterval()) , clock.getInterval() <= 10000); From 8065ad4f3d8e6519aade45a52c1a8b14f5e49c13 Mon Sep 17 00:00:00 2001 From: grog Date: Tue, 13 Feb 2024 15:52:53 -0800 Subject: [PATCH 055/131] config utils fix --- src/main/java/org/myrobotlab/config/ConfigUtils.java | 2 ++ src/main/java/org/myrobotlab/service/Runtime.java | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/myrobotlab/config/ConfigUtils.java b/src/main/java/org/myrobotlab/config/ConfigUtils.java index 19c256a8cf..69f850e602 100644 --- a/src/main/java/org/myrobotlab/config/ConfigUtils.java +++ b/src/main/java/org/myrobotlab/config/ConfigUtils.java @@ -60,6 +60,8 @@ static public RuntimeConfig loadRuntimeConfig(CmdOptions options) { if (startYml.enable) { configName = startYml.config; + } else { + configName = "default"; } // start with default diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 675123e962..a768da57d1 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -910,9 +910,6 @@ public static Runtime getInstance() { // klunky Runtime.register(new Registration(runtime)); - // assign, do not apply otherwise there will be - // a chicken-egg problem - runtime.config = c; } runtime.getRepo().addStatusPublisher(runtime); From 942815729842add1ee160bb5a8b342cbd459ecfa Mon Sep 17 00:00:00 2001 From: grog Date: Tue, 13 Feb 2024 18:24:37 -0800 Subject: [PATCH 056/131] clean default config --- src/test/java/org/myrobotlab/config/ConfigUtilsTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/java/org/myrobotlab/config/ConfigUtilsTest.java b/src/test/java/org/myrobotlab/config/ConfigUtilsTest.java index 5d15601b58..59caf6b201 100644 --- a/src/test/java/org/myrobotlab/config/ConfigUtilsTest.java +++ b/src/test/java/org/myrobotlab/config/ConfigUtilsTest.java @@ -3,9 +3,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import java.io.File; + import org.junit.Before; import org.junit.Test; import org.myrobotlab.framework.StartYml; +import org.myrobotlab.io.FileIO; import org.myrobotlab.service.Runtime; public class ConfigUtilsTest { @@ -13,6 +16,8 @@ public class ConfigUtilsTest { @Before public void beforeTest() { Runtime.releaseAll(true, true); + // remove config + FileIO.rm("data/config/default"); } @Test From 63c00ecb2c817bce1901f561b2d6fdd4c9091ff8 Mon Sep 17 00:00:00 2001 From: grog Date: Wed, 14 Feb 2024 12:13:16 -0800 Subject: [PATCH 057/131] removed registering for new services from servo --- .../java/org/myrobotlab/service/DiyServo.java | 43 +++---------------- .../java/org/myrobotlab/service/Servo.java | 15 +------ .../service/abstracts/AbstractServo.java | 27 ------------ 3 files changed, 7 insertions(+), 78 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/DiyServo.java b/src/main/java/org/myrobotlab/service/DiyServo.java index 2e125d8509..ae83c09118 100644 --- a/src/main/java/org/myrobotlab/service/DiyServo.java +++ b/src/main/java/org/myrobotlab/service/DiyServo.java @@ -28,7 +28,6 @@ import java.util.ArrayList; import java.util.List; -import org.myrobotlab.framework.Registration; import org.myrobotlab.framework.interfaces.ServiceInterface; import org.myrobotlab.logging.Level; import org.myrobotlab.logging.LoggerFactory; @@ -44,8 +43,6 @@ import org.myrobotlab.service.interfaces.MotorControl; import org.myrobotlab.service.interfaces.PinArrayControl; import org.myrobotlab.service.interfaces.PinListener; -import org.myrobotlab.service.interfaces.ServiceLifeCycleListener; -import org.myrobotlab.service.interfaces.ServoControl; import org.myrobotlab.service.interfaces.ServoEvent; import org.slf4j.Logger; @@ -76,7 +73,7 @@ * TODO : move is not accurate ( 1° step seem not possible ) */ -public class DiyServo extends AbstractServo implements PinListener, ServiceLifeCycleListener { +public class DiyServo extends AbstractServo implements PinListener { double lastOutput = 0.0; /** @@ -198,16 +195,6 @@ public DiyServo(String n, String id) { lastActivityTimeTs = System.currentTimeMillis(); } - /* - * Update the list of PinArrayControls - */ - @Override - public void onRegistered(Registration s) { - refreshPinArrayControls(); - broadcastState(); - - } - /** * Initiate the PID controller */ @@ -224,7 +211,7 @@ void initPid() { pid.setSetpoint(pidKey, setPoint); pid.startService(); } - + @Override public void startService() { super.startService(); @@ -232,7 +219,6 @@ public void startService() { motorControl = (MotorControl) startPeer("motor"); initPid(); } - /** * Equivalent to Arduino's Servo.detach() it de-energizes the servo @@ -694,19 +680,17 @@ public static void main(String[] args) throws InterruptedException { // if (done) { // return; // } - - WebGui webgui = (WebGui)Runtime.create("webgui", "WebGui"); + + WebGui webgui = (WebGui) Runtime.create("webgui", "WebGui"); webgui.autoStartBrowser(false); webgui.startService(); - + Runtime.start("diy", "DiyServo"); - - + boolean done = true; if (done) { return; } - String port = "COM4"; Arduino arduino = (Arduino) Runtime.start("arduino", "Arduino"); @@ -788,19 +772,4 @@ protected boolean processMove(Double newPos, boolean blocking, Long timeoutMs) { return false; } - @Override - public void onCreated(String name) { - log.info("created {}", name); - } - - @Override - public void onStopped(String name) { - log.info("stopped {}", name); - } - - @Override - public void onReleased(String name) { - log.info("released {}", name); - } - } diff --git a/src/main/java/org/myrobotlab/service/Servo.java b/src/main/java/org/myrobotlab/service/Servo.java index 3e0b46ce95..07e251dec5 100644 --- a/src/main/java/org/myrobotlab/service/Servo.java +++ b/src/main/java/org/myrobotlab/service/Servo.java @@ -61,7 +61,7 @@ * */ -public class Servo extends AbstractServo implements ServiceLifeCycleListener { +public class Servo extends AbstractServo { private static final long serialVersionUID = 1L; @@ -337,17 +337,4 @@ public static void main(String[] args) throws InterruptedException { } } - @Override - public void onCreated(String name) { - } - - @Override - public void onStopped(String name) { - } - - @Override - public void onReleased(String name) { - } - - } diff --git a/src/main/java/org/myrobotlab/service/abstracts/AbstractServo.java b/src/main/java/org/myrobotlab/service/abstracts/AbstractServo.java index 3378d5e56d..1376e78778 100644 --- a/src/main/java/org/myrobotlab/service/abstracts/AbstractServo.java +++ b/src/main/java/org/myrobotlab/service/abstracts/AbstractServo.java @@ -6,7 +6,6 @@ import java.util.Set; import org.myrobotlab.codec.CodecUtils; -import org.myrobotlab.framework.Registration; import org.myrobotlab.framework.Service; import org.myrobotlab.framework.interfaces.Attachable; import org.myrobotlab.logging.LoggerFactory; @@ -217,16 +216,6 @@ public abstract class AbstractServo extends Service im public AbstractServo(String n, String id) { super(n, id); - // this servo is interested in new services which support either - // ServoControllers or EncoderControl interfaces - // we subscribe to runtime here for new services - subscribeToRuntime("registered"); - /* - * // new feature - // extracting the currentPos from serialized servo - * Double lastCurrentPos = null; try { lastCurrentPos = (Double) - * loadField("currentPos"); } catch (IOException e) { - * log.info("current pos cannot be found in saved file"); } - */ // if no position could be loaded - set to rest // we have no "historical" info - assume we are @ rest targetPos = rest; @@ -243,17 +232,6 @@ public AbstractServo(String n, String id) { } } - /** - * if a new service is added to the system refresh the controllers - */ - @Deprecated /* - * lifecycle events not necessary for ui, probably should be - * pulled out - */ - public void onStarted(String name) { - invoke("refreshControllers"); - } - /** * overloaded routing attach */ @@ -697,10 +675,6 @@ public void onEncoderData(EncoderData data) { } } - public void onRegistered(Registration s) { - refreshControllers(); - } - /** * Servo has the ability to act as an encoder if it is using TimeEncoder. * TimeEncoder will use Servo to publish a series of encoder events with @@ -1096,7 +1070,6 @@ public ServoEvent publishServoStopped(String name, Double position) { @Override public void startService() { super.startService(); - Runtime.getInstance().attachServiceLifeCycleListener(getName()); } @Override From aa65ad3bf4c6b46c3039318cf2e183554165c8e2 Mon Sep 17 00:00:00 2001 From: grog Date: Wed, 14 Feb 2024 12:57:59 -0800 Subject: [PATCH 058/131] webgui --- .../java/org/myrobotlab/service/WebGui.java | 37 ++++----- .../org/myrobotlab/service/WebGuiTest.java | 76 ++++++++++--------- 2 files changed, 55 insertions(+), 58 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/WebGui.java b/src/main/java/org/myrobotlab/service/WebGui.java index 5e87cddb05..3e816726f1 100644 --- a/src/main/java/org/myrobotlab/service/WebGui.java +++ b/src/main/java/org/myrobotlab/service/WebGui.java @@ -34,7 +34,6 @@ import org.myrobotlab.codec.CodecUtils; import org.myrobotlab.framework.MRLListener; import org.myrobotlab.framework.Message; -import org.myrobotlab.framework.Platform; import org.myrobotlab.framework.Registration; import org.myrobotlab.framework.Service; import org.myrobotlab.framework.interfaces.ServiceInterface; @@ -62,8 +61,7 @@ * services are already APIs - perhaps a data API - same as service without the * message wrapper */ -public class WebGui extends Service - implements AuthorizationProvider, Gateway, Handler, ServiceLifeCycleListener { +public class WebGui extends Service implements AuthorizationProvider, Gateway, Handler, ServiceLifeCycleListener { public static class LiveVideoStreamHandler implements Handler { @@ -128,7 +126,7 @@ public Panel(String name, int x, int y, int z) { * needed to get the api key to select the appropriate api processor * * @param uri - * u + * u * @return api key * */ @@ -271,9 +269,9 @@ public boolean getAutoStartBrowser() { * String broadcast to specific client * * @param uuid - * u + * u * @param str - * s + * s * */ public void broadcast(String uuid, String str) { @@ -315,9 +313,7 @@ public Config.Builder getNettosphereConfig() { // cert.privateKey()).build(); SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); - SslContext context = SslContextBuilder - .forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()) - .sslProvider(SslProvider.JDK) + SslContext context = SslContextBuilder.forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()).sslProvider(SslProvider.JDK) .clientAuth(ClientAuth.NONE).build(); configBuilder.sslContext(context); @@ -496,8 +492,7 @@ public void handle(AtmosphereResource r) { } else if ((bodyData != null) && log.isDebugEnabled()) { logData = bodyData; } - log.debug("-->{} {} {} - [{}] from connection {}", (newPersistentConnection) ? "new" : "", request.getMethod(), - request.getRequestURI(), logData, uuid); + log.debug("-->{} {} {} - [{}] from connection {}", (newPersistentConnection) ? "new" : "", request.getMethod(), request.getRequestURI(), logData, uuid); } // important persistent connections will have associated routes ... @@ -575,8 +570,7 @@ public void handle(AtmosphereResource r) { } if (msg.containsHop(getId())) { - log.error("{} dumping duplicate hop msg to avoid cyclical from {} --to--> {}.{}", getName(), msg.sender, - msg.name, msg.method); + log.error("{} dumping duplicate hop msg to avoid cyclical from {} --to--> {}.{}", getName(), msg.sender, msg.name, msg.method); return; } @@ -920,7 +914,7 @@ public void run() { * remotely control UI * * @param panel - * - the panel which has been moved or resized + * - the panel which has been moved or resized */ public void savePanel(Panel panel) { if (panel.name == null) { @@ -1107,7 +1101,7 @@ public void releaseService() { * Default (false) is to use the CDN * * @param useLocalResources - * - true uses local resources fals uses cdn + * - true uses local resources fals uses cdn */ public void useLocalResources(boolean useLocalResources) { this.useLocalResources = useLocalResources; @@ -1183,9 +1177,10 @@ public static void main(String[] args) { try { - Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", "WebGui","intro", "Intro", "python", "Python" }); - // Runtime.main(new String[] {}); - // Runtime.main(new String[] { "--install" }); + // Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", + // "WebGui", + // "intro", "Intro", "python", "Python" }); + Runtime.main(new String[] { "--install" }); boolean done = true; if (done) { @@ -1193,7 +1188,8 @@ public static void main(String[] args) { } // Platform.setVirtual(true); - // Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", "WebGui", + // Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", + // "WebGui", // "intro", "Intro", "python", "Python", "-c", "dev" }); // Runtime.startConfig("dev"); @@ -1248,8 +1244,7 @@ public static void main(String[] args) { arduino.connect("/dev/ttyACM0"); for (int i = 0; i < 1000; ++i) { - webgui.display( - "https://i.kinja-img.com/gawker-media/image/upload/c_scale,f_auto,fl_progressive,q_80,w_800/pytutcxcrfjvuhz2jipa.jpg"); + webgui.display("https://i.kinja-img.com/gawker-media/image/upload/c_scale,f_auto,fl_progressive,q_80,w_800/pytutcxcrfjvuhz2jipa.jpg"); } // Runtime.setLogLevel("ERROR"); diff --git a/src/test/java/org/myrobotlab/service/WebGuiTest.java b/src/test/java/org/myrobotlab/service/WebGuiTest.java index 643485fc0c..02918dedba 100644 --- a/src/test/java/org/myrobotlab/service/WebGuiTest.java +++ b/src/test/java/org/myrobotlab/service/WebGuiTest.java @@ -5,7 +5,6 @@ import static org.junit.Assert.assertTrue; import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.List; import org.junit.Before; @@ -22,8 +21,8 @@ public class WebGuiTest extends AbstractTest { public final static Logger log = LoggerFactory.getLogger(WebGui.class); - - // FIXME - DO A WEBSOCKET TEST + + // FIXME - DO A WEBSOCKET TEST @Before public void setUp() { @@ -31,11 +30,11 @@ public void setUp() { webgui2.autoStartBrowser(false); webgui2.setPort(8889); webgui2.startService(); - - Runtime.start("servoApiTest","Servo"); + + Runtime.start("servoApiTest", "Servo"); Runtime.start("pythonApiTest", "Python"); // need to wait for the OS to open the port - Service.sleep(3); + Service.sleep(200); } @Test @@ -46,7 +45,7 @@ public void getTest() { String ret = new String(bytes); assertTrue(ret.contains("days")); } - + @Test public void getTestWithParameter() throws UnsupportedEncodingException { @@ -56,13 +55,12 @@ public void getTestWithParameter() throws UnsupportedEncodingException { assertTrue(ret.contains("true")); } - -// FIXME - ADD WHEN POST API IS WORKY -// FIXME object non primitive (no string) post + // FIXME - ADD WHEN POST API IS WORKY + // FIXME object non primitive (no string) post @Test public void postTest() { - + // 1st post - simple input - simple return String postBody = "[\"runtime\"]"; byte[] bytes = Http.post("http://localhost:8889/api/service/runtime/getFullName", postBody); @@ -70,7 +68,7 @@ public void postTest() { assertNotNull(bytes); String ret = new String(bytes); assertTrue(ret.contains("@")); - + // second post - simple input - complex return postBody = "[\"runtime\"]"; bytes = Http.post("http://localhost:8889/api/service/runtime/getService", postBody); @@ -78,29 +76,31 @@ public void postTest() { assertNotNull(bytes); ret = new String(bytes); assertTrue(ret.contains("@")); - - + // second post - simple input (including array of strings) - complex return - // FIXME uncomment when ready - callbacks are not possible through the rest api - // org.myrobotlab.framework.TimeoutException: timeout of 3000 for proxyName@remoteId.toString exceeded - // org.myrobotlab.framework.TimeoutException: timeout of 3000 for proxyName@remoteId.getFullName exceeded -// postBody = "[\"remoteId\", \"proxyName\", \"py:myService\",[\"org.myrobotlab.framework.interfaces.ServiceInterface\"]]"; -// bytes = Http.post("http://localhost:8889/api/service/runtime/register", postBody); -// sleep(200); -// assertNotNull(bytes); -// ret = new String(bytes); -// assertTrue(ret.contains("remoteId")); - - - + // FIXME uncomment when ready - callbacks are not possible through the rest + // api + // org.myrobotlab.framework.TimeoutException: timeout of 3000 for + // proxyName@remoteId.toString exceeded + // org.myrobotlab.framework.TimeoutException: timeout of 3000 for + // proxyName@remoteId.getFullName exceeded + // postBody = "[\"remoteId\", \"proxyName\", + // \"py:myService\",[\"org.myrobotlab.framework.interfaces.ServiceInterface\"]]"; + // bytes = Http.post("http://localhost:8889/api/service/runtime/register", + // postBody); + // sleep(200); + // assertNotNull(bytes); + // ret = new String(bytes); + // assertTrue(ret.contains("remoteId")); + // post non primitive non string object MRLListener listener = new MRLListener("getRegistry", "runtime@webguittest", "onRegistry"); - postBody = "[" + CodecUtils.toJson(listener) + "]"; + postBody = "[" + CodecUtils.toJson(listener) + "]"; // postBody = "[\"runtime\"]"; bytes = Http.post("http://localhost:8889/api/service/runtime/addListener", postBody); sleep(200); assertNotNull(bytes); - + Runtime runtime = Runtime.getInstance(); boolean found = false; List check = runtime.getNotifyList("getRegistry"); @@ -108,9 +108,9 @@ public void postTest() { if (check.get(i).equals(listener)) { found = true; } - } + } assertTrue("listener not found !", found); - + } @Test @@ -138,7 +138,7 @@ public void servoApiTest() { @Test public void urlEncodingTest() { - //exec("print \"hello\"") + // exec("print \"hello\"") byte[] bytes = Http.get("http://localhost:8889/api/service/pythonApiTest/exec/%22print+%5C%22hello%5C%22%22"); String ret = new String(bytes); assertEquals("true", ret); @@ -147,16 +147,19 @@ public void urlEncodingTest() { @Test public void sendBlockingTest() throws InterruptedException, TimeoutException { String retVal = "retVal"; - // Put directly in blocking list because sendBlocking() won't use it for local services + // Put directly in blocking list because sendBlocking() won't use it for + // local + // services Runtime.getInstance().getInbox().blockingList.put("runtime.onBlocking", new Object[1]); Object[] blockingListRet = Runtime.getInstance().getInbox().blockingList.get("runtime.onBlocking"); // Delay in a new thread so we can get our wait() call in first new Thread(() -> { try { - Thread.sleep(50); - } catch (InterruptedException ignored) {} - Http.post("http://localhost:8889/api/service/runtime/onBlocking", "[\""+retVal+"\"]"); + Thread.sleep(100); + } catch (InterruptedException ignored) { + } + Http.post("http://localhost:8889/api/service/runtime/onBlocking", "[\"" + retVal + "\"]"); }).start(); long timeout = 1000; @@ -170,6 +173,5 @@ public void sendBlockingTest() throws InterruptedException, TimeoutException { assertEquals(retVal, blockingListRet[0]); } - - + } From 33a1be5181a9ba3fdb82ad8750e00db32b8ee99e Mon Sep 17 00:00:00 2001 From: grog Date: Wed, 14 Feb 2024 13:00:00 -0800 Subject: [PATCH 059/131] adding log service to scripts --- myrobotlab.bat | 2 +- myrobotlab.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/myrobotlab.bat b/myrobotlab.bat index b8515ca03d..a6ce3e30ea 100644 --- a/myrobotlab.bat +++ b/myrobotlab.bat @@ -28,6 +28,6 @@ IF NOT "%*"=="" ( "%JAVA%" %JAVA_OPTIONS% -cp %CLASSPATH% org.myrobotlab.service.Runtime --install --log-file myrobotlab-install.log ) - "%JAVA%" %JAVA_OPTIONS% -cp %CLASSPATH% org.myrobotlab.service.Runtime --log-level info -s webgui WebGui intro Intro python Python + "%JAVA%" %JAVA_OPTIONS% -cp %CLASSPATH% org.myrobotlab.service.Runtime --log-level info -s log Log webgui WebGui intro Intro python Python ) \ No newline at end of file diff --git a/myrobotlab.sh b/myrobotlab.sh index 9aa528ea51..4cc45eb085 100755 --- a/myrobotlab.sh +++ b/myrobotlab.sh @@ -62,6 +62,6 @@ else "${JAVA}" ${JAVA_OPTIONS} -cp ${CLASSPATH} org.myrobotlab.service.Runtime --install --log-file myrobotlab-install.log fi -"${JAVA}" ${JAVA_OPTIONS} -cp ${CLASSPATH} org.myrobotlab.service.Runtime --log-level info -s webgui WebGui intro Intro python Python +"${JAVA}" ${JAVA_OPTIONS} -cp ${CLASSPATH} org.myrobotlab.service.Runtime --log-level info -s log Log webgui WebGui intro Intro python Python echo $# $@ \ No newline at end of file From 77eac6ecfa500bbb5f0ecbd5a6cb228d027657fe Mon Sep 17 00:00:00 2001 From: grog Date: Wed, 14 Feb 2024 13:16:27 -0800 Subject: [PATCH 060/131] simplifying randomtest --- .../org/myrobotlab/service/RandomTest.java | 52 ++++++++----------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/src/test/java/org/myrobotlab/service/RandomTest.java b/src/test/java/org/myrobotlab/service/RandomTest.java index 18f4e1c789..f089f2e453 100644 --- a/src/test/java/org/myrobotlab/service/RandomTest.java +++ b/src/test/java/org/myrobotlab/service/RandomTest.java @@ -7,31 +7,24 @@ import java.util.Map; import org.junit.Before; -import org.myrobotlab.framework.Service; +import org.junit.Test; import org.myrobotlab.service.Random.RandomMessage; +import org.myrobotlab.test.AbstractTest; -public class RandomTest extends AbstractServiceTest { +public class RandomTest extends AbstractTest { - @Override /* - * FIXME - this assumes a single service is in the test - which - * rarely happens - seems not useful and silly - */ - public Service createService() throws Exception { - return (Service) Runtime.start("randomTest", "Random"); - } - @Before /* before each test */ public void setUp() throws IOException { // remove all services - also resets config name to DEFAULT effectively Runtime.releaseAll(true, true); - // clean our config directory + // clean our config directory // Runtime.removeConfig("RandomTest"); // set our config Runtime.setConfig("RandomTest"); + Runtime.start("randomTest", "Random"); } - - @Override + @Test public void testService() throws Exception { Clock clock = (Clock) Runtime.start("clock", "Clock"); Random random = (Random) Runtime.start("randomTest", "Random"); @@ -46,31 +39,31 @@ public void testService() throws Exception { sleep(1000); assertTrue("should have method", random.getKeySet().contains("clock.setInterval")); - + assertTrue(String.format("random method 1 should be %d => 5000 values", clock.getInterval()), 5000 <= clock.getInterval()); - assertTrue(String.format("random method 1 should be %d <= 10000 values",clock.getInterval()) , clock.getInterval() <= 10000); - + assertTrue(String.format("random method 1 should be %d <= 10000 values", clock.getInterval()), clock.getInterval() <= 10000); + random.remove("clock.setInterval"); - + assertTrue("should not have method", !random.getKeySet().contains("clock.setInterval")); random.addRandom(0, 200, "clock", "setInterval", 5000, 10000); random.addRandom(0, 200, "clock", "startClock"); - + sleep(500); assertTrue("clock should be started 1", clock.isClockRunning()); - + // disable all of a services random events random.disable("clock.startClock"); sleep(250); clock.stopClock(); assertTrue("clock should not be started 1", !clock.isClockRunning()); - + // enable all of a service's random events random.enable("clock.startClock"); sleep(250); assertTrue("clock should be started 2", clock.isClockRunning()); - + // disable one method - leave other enabled random.disable("clock.startClock"); clock.stopClock(); @@ -78,30 +71,31 @@ public void testService() throws Exception { clock.setInterval(9999); assertTrue("clock should not be started 3", !clock.isClockRunning()); assertTrue(String.format("random method 2 should be %d => 5000 values", clock.getInterval()), 5000 <= clock.getInterval()); - assertTrue(String.format("random method 2 should be %d <= 10000 values",clock.getInterval()) , clock.getInterval() <= 10000); + assertTrue(String.format("random method 2 should be %d <= 10000 values", clock.getInterval()), clock.getInterval() <= 10000); // disable all random.disable(); sleep(200); clock.setInterval(9999); - assertTrue("clock should not be started 4", !clock.isClockRunning()); - assertEquals(9999, (long)clock.getInterval()); + assertTrue("clock should not be started 4", !clock.isClockRunning()); + assertEquals(9999, (long) clock.getInterval()); - // re-enable all that were previously enabled but not explicitly disabled ones + // re-enable all that were previously enabled but not explicitly disabled + // ones random.enable(); sleep(1000); assertTrue("clock should not be started 5", !clock.isClockRunning()); assertTrue(String.format("random method 3 should be %d => 5000 values", clock.getInterval()), 5000 <= clock.getInterval()); - assertTrue(String.format("random method 3 should be %d <= 10000 values",clock.getInterval()) , clock.getInterval() <= 10000); + assertTrue(String.format("random method 3 should be %d <= 10000 values", clock.getInterval()), clock.getInterval() <= 10000); clock.stopClock(); random.purge(); - + Map events = random.getRandomEvents(); assertTrue(events.size() == 0); - + random.addRandom("named task", 200, 500, "clock", "setInterval", 100, 1000, 10); - + clock.releaseService(); random.releaseService(); From 1d9cb9050cf488967e10246be5f7b2470d98ec90 Mon Sep 17 00:00:00 2001 From: grog Date: Wed, 14 Feb 2024 16:58:11 -0800 Subject: [PATCH 061/131] fixes and updates --- .../service/AdafruitMotorHat4Pi.java | 4 +- .../java/org/myrobotlab/service/InMoov2.java | 71 ------------------ .../java/org/myrobotlab/service/RoboClaw.java | 4 +- .../java/org/myrobotlab/service/Servo.java | 72 ------------------- .../java/org/myrobotlab/service/WebGui.java | 6 +- .../abstracts/AbstractMotorController.java | 4 +- .../config/AbstractMotorControllerConfig.java | 5 ++ .../service/config/InMoov2Config.java | 7 +- .../service/config/SabertoothConfig.java | 2 +- 9 files changed, 19 insertions(+), 156 deletions(-) create mode 100644 src/main/java/org/myrobotlab/service/config/AbstractMotorControllerConfig.java diff --git a/src/main/java/org/myrobotlab/service/AdafruitMotorHat4Pi.java b/src/main/java/org/myrobotlab/service/AdafruitMotorHat4Pi.java index a089498d4f..5897630ef8 100644 --- a/src/main/java/org/myrobotlab/service/AdafruitMotorHat4Pi.java +++ b/src/main/java/org/myrobotlab/service/AdafruitMotorHat4Pi.java @@ -19,7 +19,7 @@ import org.myrobotlab.logging.Logging; import org.myrobotlab.logging.LoggingFactory; import org.myrobotlab.service.abstracts.AbstractMotorController; -import org.myrobotlab.service.config.MotorConfig; +import org.myrobotlab.service.config.AbstractMotorControllerConfig; import org.myrobotlab.service.interfaces.I2CControl; import org.myrobotlab.service.interfaces.I2CController; import org.myrobotlab.service.interfaces.MotorControl; @@ -34,7 +34,7 @@ * https://learn.adafruit.com/adafruit-dc-and-stepper-motor-hat-for-raspberry-pi/overview */ -public class AdafruitMotorHat4Pi extends AbstractMotorController implements I2CControl { +public class AdafruitMotorHat4Pi extends AbstractMotorController implements I2CControl { /** version of the library */ static public final String VERSION = "0.9"; diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index e6ad6326ab..40ebda2e26 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -188,77 +188,6 @@ public static void main(String[] args) { return; } - OpenCVConfig ocvConfig = i01.getPeerConfig("opencv", new StaticType<>() { - }); - ocvConfig.flip = true; - i01.setPeerConfigValue("opencv", "flip", true); - // i01.savePeerConfig("", null); - - // Runtime.startConfig("default"); - - // Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", - // "WebGui", - // "intro", "Intro", "python", "Python" }); - - Runtime.start("python", "Python"); - // Runtime.start("ros", "Ros"); - Runtime.start("intro", "Intro"); - // InMoov2 i01 = (InMoov2) Runtime.start("i01", "InMoov2"); - // i01.startPeer("simulator"); - // Runtime.startConfig("i01-05"); - // Runtime.startConfig("pir-01"); - - // Polly polly = (Polly)Runtime.start("i01.mouth", "Polly"); - // i01 = (InMoov2) Runtime.start("i01", "InMoov2"); - - // polly.speakBlocking("Hi, to be or not to be that is the question, - // wheather to take arms against a see of trouble, and by aposing them end - // them, to sleep, to die"); - // i01.startPeer("mouth"); - // i01.speakBlocking("Hi, to be or not to be that is the question, - // wheather to take arms against a see of trouble, and by aposing them end - // them, to sleep, to die"); - - Runtime.start("python", "Python"); - - // i01.startSimulator(); - Plan plan = Runtime.load("webgui", "WebGui"); - // WebGuiConfig webgui = (WebGuiConfig) plan.get("webgui"); - // webgui.autoStartBrowser = false; - Runtime.startConfig("webgui"); - Runtime.start("webgui", "WebGui"); - - Random random = (Random) Runtime.start("random", "Random"); - - random.addRandom(3000, 8000, "i01", "setLeftArmSpeed", 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0); - random.addRandom(3000, 8000, "i01", "setRightArmSpeed", 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0); - - random.addRandom(3000, 8000, "i01", "moveLeftArm", 0.0, 5.0, 85.0, 95.0, 25.0, 30.0, 10.0, 15.0); - random.addRandom(3000, 8000, "i01", "moveRightArm", 0.0, 5.0, 85.0, 95.0, 25.0, 30.0, 10.0, 15.0); - - random.addRandom(3000, 8000, "i01", "setLeftHandSpeed", 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, - 8.0, 25.0); - random.addRandom(3000, 8000, "i01", "setRightHandSpeed", 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, 8.0, 25.0, - 8.0, 25.0); - - random.addRandom(3000, 8000, "i01", "moveRightHand", 10.0, 160.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, - 130.0, 175.0); - random.addRandom(3000, 8000, "i01", "moveLeftHand", 10.0, 160.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, 10.0, 60.0, - 5.0, 40.0); - - random.addRandom(200, 1000, "i01", "setHeadSpeed", 8.0, 20.0, 8.0, 20.0, 8.0, 20.0); - random.addRandom(200, 1000, "i01", "moveHead", 70.0, 110.0, 65.0, 115.0, 70.0, 110.0); - - random.addRandom(200, 1000, "i01", "setTorsoSpeed", 2.0, 5.0, 2.0, 5.0, 2.0, 5.0); - random.addRandom(200, 1000, "i01", "moveTorso", 85.0, 95.0, 88.0, 93.0, 70.0, 110.0); - - random.save(); - - // i01.startChatBot(); - // - // i01.startAll("COM3", "COM4"); - Runtime.start("python", "Python"); - } catch (Exception e) { log.error("main threw", e); } diff --git a/src/main/java/org/myrobotlab/service/RoboClaw.java b/src/main/java/org/myrobotlab/service/RoboClaw.java index 83203b99f8..8d22f7ff27 100644 --- a/src/main/java/org/myrobotlab/service/RoboClaw.java +++ b/src/main/java/org/myrobotlab/service/RoboClaw.java @@ -16,7 +16,7 @@ import org.myrobotlab.serial.CRC; import org.myrobotlab.service.Pid.PidData; import org.myrobotlab.service.abstracts.AbstractMotorController; -import org.myrobotlab.service.config.MotorConfig; +import org.myrobotlab.service.config.AbstractMotorControllerConfig; import org.myrobotlab.service.interfaces.MotorControl; import org.myrobotlab.service.interfaces.MotorController; import org.myrobotlab.service.interfaces.PortConnector; @@ -55,7 +55,7 @@ * this value IS correct * */ -public class RoboClaw extends AbstractMotorController implements EncoderPublisher, PortConnector, MotorController, SerialDataListener { +public class RoboClaw extends AbstractMotorController implements EncoderPublisher, PortConnector, MotorController, SerialDataListener { private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/myrobotlab/service/Servo.java b/src/main/java/org/myrobotlab/service/Servo.java index 3e0b46ce95..798bff3afb 100644 --- a/src/main/java/org/myrobotlab/service/Servo.java +++ b/src/main/java/org/myrobotlab/service/Servo.java @@ -259,78 +259,6 @@ public static void main(String[] args) throws InterruptedException { return; } - // runtime.save(); - - /* - * mega.save(); tilt.save(); pan.save(); - * - * mega.load(); tilt.load(); pan.load(); - */ - - // TODO - attach before and after connect.. - - // mega.setBoardMega(); - - // log.info("servo pos {}", tilt.getCurrentInputPos()); - // - // // double pos = 170; - // // servo03.setPosition(pos); - // - // double min = 3; - // double max = 170; - // double speed = 60; // degree/s - // - // mega.attach(tilt); - // // mega.attach(servo03,3); - // - // for (int i = 0; i < 100; ++i) { - // tilt.moveTo(20.0); - // } - // - // tilt.sweep(min, max, speed); - - /* - * Servo servo04 = (Servo) Runtime.start("servo04", "Servo"); Servo - * servo05 = (Servo) Runtime.start("servo05", "Servo"); Servo servo06 = - * (Servo) Runtime.start("servo06", "Servo"); Servo servo07 = (Servo) - * Runtime.start("servo07", "Servo"); Servo servo08 = (Servo) - * Runtime.start("servo08", "Servo"); Servo servo09 = (Servo) - * Runtime.start("servo09", "Servo"); Servo servo10 = (Servo) - * Runtime.start("servo10", "Servo"); Servo servo11 = (Servo) - * Runtime.start("servo11", "Servo"); Servo servo12 = (Servo) - * Runtime.start("servo12", "Servo"); - */ - // Servo servo13 = (Servo) Runtime.start("servo13", "Servo"); - - // servo03.attach(mega, 8, 38.0); - /* - * servo04.attach(mega, 4, 38.0); servo05.attach(mega, 5, 38.0); - * servo06.attach(mega, 6, 38.0); servo07.attach(mega, 7, 38.0); - * servo08.attach(mega, 8, 38.0); servo09.attach(mega, 9, 38.0); - * servo10.attach(mega, 10, 38.0); servo11.attach(mega, 11, 38.0); - * servo12.attach(mega, 12, 38.0); - */ - - // TestCatcher catcher = (TestCatcher)Runtime.start("catcher", - // "TestCatcher"); - // servo03.attach((ServoEventListener)catcher); - - // servo.setPin(12); - - /* - * servo.attach(mega, 7, 38.0); servo.attach(mega, 7, 38.0); - * servo.attach(mega, 7, 38.0); servo.attach(mega, 7, 38.0); - * servo.attach(mega, 7, 38.0); servo.attach(mega, 7, 38.0); - * servo.attach(mega, 7, 38.0); servo.attach(mega, 7, 38.0); - * servo.attach(mega, 7, 38.0); servo.attach(mega, 7, 38.0); - * servo.attach(mega, 7, 38.0); servo.attach(mega, 7, 38.0); - */ - - // servo.sweepDelay = 3; - // servo.save(); - // servo.load(); - // servo.save(); - // log.info("sweepDely {}", servo.sweepDelay); } catch (Exception e) { log.error("main threw", e); diff --git a/src/main/java/org/myrobotlab/service/WebGui.java b/src/main/java/org/myrobotlab/service/WebGui.java index 3e816726f1..f50cdc238a 100644 --- a/src/main/java/org/myrobotlab/service/WebGui.java +++ b/src/main/java/org/myrobotlab/service/WebGui.java @@ -1177,10 +1177,8 @@ public static void main(String[] args) { try { - // Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", - // "WebGui", - // "intro", "Intro", "python", "Python" }); - Runtime.main(new String[] { "--install" }); + Runtime.main(new String[] { "--log-level", "info", "-s", "log", "Log", "webgui", "WebGui", "intro", "Intro", "python", "Python" }); + // Runtime.main(new String[] { "--install" }); boolean done = true; if (done) { diff --git a/src/main/java/org/myrobotlab/service/abstracts/AbstractMotorController.java b/src/main/java/org/myrobotlab/service/abstracts/AbstractMotorController.java index 5f01ebc74f..94380c9711 100644 --- a/src/main/java/org/myrobotlab/service/abstracts/AbstractMotorController.java +++ b/src/main/java/org/myrobotlab/service/abstracts/AbstractMotorController.java @@ -8,11 +8,11 @@ import org.myrobotlab.math.MapperLinear; import org.myrobotlab.math.interfaces.Mapper; import org.myrobotlab.service.Runtime; -import org.myrobotlab.service.config.MotorConfig; +import org.myrobotlab.service.config.AbstractMotorControllerConfig; import org.myrobotlab.service.interfaces.MotorControl; import org.myrobotlab.service.interfaces.MotorController; -public abstract class AbstractMotorController extends Service implements MotorController { +public abstract class AbstractMotorController extends Service implements MotorController { /** * currently attached motors to this controller diff --git a/src/main/java/org/myrobotlab/service/config/AbstractMotorControllerConfig.java b/src/main/java/org/myrobotlab/service/config/AbstractMotorControllerConfig.java new file mode 100644 index 0000000000..030a1ee4f0 --- /dev/null +++ b/src/main/java/org/myrobotlab/service/config/AbstractMotorControllerConfig.java @@ -0,0 +1,5 @@ +package org.myrobotlab.service.config; + +public class AbstractMotorControllerConfig extends ServiceConfig { + // Add your configuration here +} diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index a050223baa..99d40fa8ed 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -281,8 +281,7 @@ public Plan getDefault(Plan plan, String name) { // setup name references to different services MarySpeechConfig mouth = (MarySpeechConfig) plan.get(getPeerName("mouth")); mouth.voice = "Mark"; - mouth.speechRecognizers = new String[] { name + ".ear" }; - + // == Peer - ear ============================= // setup name references to different services WebkitSpeechRecognitionConfig ear = (WebkitSpeechRecognitionConfig) plan.get(getPeerName("ear")); @@ -549,6 +548,10 @@ public Plan getDefault(Plan plan, String name) { // Needs upcoming pr fsm.listeners.add(new Listener("publishStateChange", name, "publishStateChange")); + + // peer --to--> peer + mouth.listeners.add(new Listener("publishStartSpeaking", getPeerName("ear"))); + mouth.listeners.add(new Listener("publishEndSpeaking", getPeerName("ear"))); return plan; } diff --git a/src/main/java/org/myrobotlab/service/config/SabertoothConfig.java b/src/main/java/org/myrobotlab/service/config/SabertoothConfig.java index 42db50689b..44dc5a0c5b 100644 --- a/src/main/java/org/myrobotlab/service/config/SabertoothConfig.java +++ b/src/main/java/org/myrobotlab/service/config/SabertoothConfig.java @@ -2,7 +2,7 @@ import org.myrobotlab.framework.Plan; -public class SabertoothConfig extends MotorConfig { +public class SabertoothConfig extends AbstractMotorControllerConfig { public String port; public boolean connect = false; From 402a527b8898dee23b3555835c593217e4717f4f Mon Sep 17 00:00:00 2001 From: grog Date: Fri, 16 Feb 2024 10:05:36 -0800 Subject: [PATCH 062/131] servo.setMaxSpeed --- .../service/FiniteStateMachine.java | 44 ++++++++----------- .../java/org/myrobotlab/service/InMoov2.java | 5 ++- .../service/abstracts/AbstractServo.java | 6 +++ .../service/config/InMoov2Config.java | 1 + .../service/interfaces/ServoControl.java | 8 +++- .../org/myrobotlab/service/ServoTest.java | 2 +- 6 files changed, 37 insertions(+), 29 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/FiniteStateMachine.java b/src/main/java/org/myrobotlab/service/FiniteStateMachine.java index 32c04bf29e..e998711e26 100644 --- a/src/main/java/org/myrobotlab/service/FiniteStateMachine.java +++ b/src/main/java/org/myrobotlab/service/FiniteStateMachine.java @@ -2,16 +2,11 @@ import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; -import org.myrobotlab.codec.CodecUtils; import org.myrobotlab.framework.Service; -import org.myrobotlab.framework.interfaces.MessageListener; -import org.myrobotlab.framework.interfaces.ServiceInterface; import org.myrobotlab.generics.SlidingWindowList; import org.myrobotlab.logging.Level; import org.myrobotlab.logging.LoggerFactory; @@ -61,7 +56,7 @@ public class Tuple { public Transition transition; public StateTransition stateTransition; } - + public class StateChange { /** * timestamp @@ -72,7 +67,7 @@ public class StateChange { * current new state */ public String state; - + /** * event which activated new state */ @@ -82,13 +77,12 @@ public class StateChange { * source of event */ public String src = getName(); - - + public StateChange(String current, String event) { this.state = current; this.event = event; } - + public String toString() { return String.format("%s --%s--> %s", last, event, state); } @@ -221,25 +215,25 @@ public String firedEvent(String event) { } /** - * gets the current state of this state machine + * get the previous state of this state machine * * @return */ - public String getCurrent() { - if (current != null) { - return current.getName(); + public String getLast() { + if (last != null) { + return last.getName(); } return null; } /** - * get the previous state of this state machine + * gets the current state of this state machine * * @return */ - public String getLast() { - if (last != null) { - return last.getName(); + public String getState() { + if (current != null) { + return current.getName(); } return null; } @@ -250,7 +244,7 @@ public List getTransitions() { } /** - * Publishes state change (current, last and event) + * Publishes state change (current, last and event) * * @param stateChange * @return @@ -263,7 +257,7 @@ public StateChange publishStateChange(StateChange stateChange) { @Override public FiniteStateMachineConfig getConfig() { super.getConfig(); - config.current = getCurrent(); + config.current = getState(); return config; } @@ -361,15 +355,15 @@ public static void main(String[] args) { // fsm.subscribe("fsm", "publishState"); - log.info("state - {}", fsm.getCurrent()); + log.info("state - {}", fsm.getState()); fsm.setCurrent("neutral"); - log.info("state - {}", fsm.getCurrent()); + log.info("state - {}", fsm.getState()); fsm.fire("ill-event"); - log.info("state - {}", fsm.getCurrent()); + log.info("state - {}", fsm.getState()); fsm.fire("ill-event"); fsm.fire("ill-event"); @@ -387,7 +381,7 @@ public static void main(String[] args) { // fsm.removeScheduledEvents(); - log.info("state - {}", fsm.getCurrent()); + log.info("state - {}", fsm.getState()); } catch (Exception e) { log.error("main threw", e); @@ -419,7 +413,7 @@ public String getPreviousState() { return history.get(history.size() - 2).state; } } - + @Override public void startService() { super.startService(); diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index 40ebda2e26..36d8c07ff4 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -856,7 +856,7 @@ public String getState() { if (fsm == null) { return null; } - return fsm.getCurrent(); + return fsm.getState(); } /** @@ -1553,7 +1553,8 @@ public Heartbeat publishHeartbeat() { if (System.currentTimeMillis() > stateLastIdleTime + (config.stateIdleInterval * 1000)) { // idle event to be handled with the processor - processMessage("onIdle"); + // processMessage("onIdle"); + fire("idle"); stateLastIdleTime = System.currentTimeMillis(); } diff --git a/src/main/java/org/myrobotlab/service/abstracts/AbstractServo.java b/src/main/java/org/myrobotlab/service/abstracts/AbstractServo.java index 1376e78778..780f875741 100644 --- a/src/main/java/org/myrobotlab/service/abstracts/AbstractServo.java +++ b/src/main/java/org/myrobotlab/service/abstracts/AbstractServo.java @@ -434,6 +434,12 @@ public void enable() { public void fullSpeed() { setSpeed((Double) null); } + + @Override + public void setMaxSpeed() { + setSpeed((Double) null); + } + @Override public boolean isAutoDisable() { diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index 230f787aa9..819f84e31e 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -380,6 +380,7 @@ public Plan getDefault(Plan plan, String name) { fsm.transitions.add(new Transition("sleep", "power_down", "power_down")); fsm.transitions.add(new Transition("idle", "power_down", "power_down")); fsm.transitions.add(new Transition("wake", "setup", "setup")); + fsm.transitions.add(new Transition("wake", "idle", "idle")); fsm.transitions.add(new Transition("idle", "setup", "setup")); // power_down to shutdown // fsm.transitions.add(new Transition("systemCheck", "systemCheckFinished", diff --git a/src/main/java/org/myrobotlab/service/interfaces/ServoControl.java b/src/main/java/org/myrobotlab/service/interfaces/ServoControl.java index 23a9ee9629..379154cd6e 100644 --- a/src/main/java/org/myrobotlab/service/interfaces/ServoControl.java +++ b/src/main/java/org/myrobotlab/service/interfaces/ServoControl.java @@ -404,6 +404,12 @@ public interface ServoControl extends AbsolutePositionControl, EncoderListener, /** * disable speed control and move the servos at full speed. */ + @Deprecated void fullSpeed(); - + + /** + * + */ + void setMaxSpeed(); + } diff --git a/src/test/java/org/myrobotlab/service/ServoTest.java b/src/test/java/org/myrobotlab/service/ServoTest.java index 8d96052e2e..819c3718d6 100644 --- a/src/test/java/org/myrobotlab/service/ServoTest.java +++ b/src/test/java/org/myrobotlab/service/ServoTest.java @@ -73,7 +73,7 @@ public void autoDisableAfterAttach() { @Test public void disabledMove() throws Exception { // take off speed control - servo.fullSpeed(); + servo.setMaxSpeed(); servo.moveTo(0.0); servo.setInverted(false); Service.sleep(1000); From 8601157c27b3c97c3a065385a8b91142c85eeb6d Mon Sep 17 00:00:00 2001 From: grog Date: Fri, 16 Feb 2024 10:37:01 -0800 Subject: [PATCH 063/131] ignoring servo.setSpeed(speed <0) --- .../java/org/myrobotlab/service/abstracts/AbstractServo.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/org/myrobotlab/service/abstracts/AbstractServo.java b/src/main/java/org/myrobotlab/service/abstracts/AbstractServo.java index 780f875741..7eee94dc5a 100644 --- a/src/main/java/org/myrobotlab/service/abstracts/AbstractServo.java +++ b/src/main/java/org/myrobotlab/service/abstracts/AbstractServo.java @@ -898,6 +898,11 @@ public void setSpeed(Double degreesPerSecond) { // speed = maxSpeed; // log.info("Trying to set speed to a value greater than max speed"); // } + + if (degreesPerSecond != null && degreesPerSecond < 0) { + warn("setting speed to negative value %d ignoring", degreesPerSecond); + return; + } speed = degreesPerSecond; From 11fefcae4e201b479cbd3770b8b07fb925d2379a Mon Sep 17 00:00:00 2001 From: grog Date: Fri, 16 Feb 2024 10:59:51 -0800 Subject: [PATCH 064/131] synching cpython javacpp and javacv versions to 15.8 --- src/main/java/org/myrobotlab/service/meta/OpenCVMeta.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/myrobotlab/service/meta/OpenCVMeta.java b/src/main/java/org/myrobotlab/service/meta/OpenCVMeta.java index 1b8f134beb..73d284cdb6 100644 --- a/src/main/java/org/myrobotlab/service/meta/OpenCVMeta.java +++ b/src/main/java/org/myrobotlab/service/meta/OpenCVMeta.java @@ -16,7 +16,7 @@ public OpenCVMeta() { addDescription("OpenCV (computer vision) service wrapping many of the functions and filters of OpenCV"); addCategory("video", "vision", "sensors"); - String javaCvVersion = "1.5.7"; + String javaCvVersion = "1.5.8"; // addDependency("org.bytedeco", "javacv", javaCvVersion); addDependency("org.bytedeco", "javacv-platform", javaCvVersion); addDependency("org.bytedeco", "javacpp", javaCvVersion); From db9ccdd1499cae0350a31c13ed6762df91ba57f0 Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 17 Feb 2024 06:46:55 -0800 Subject: [PATCH 065/131] removal of programab botdir --- .../java/org/myrobotlab/service/InMoov2.java | 22 +++++++------------ .../org/myrobotlab/service/ProgramAB.java | 12 ---------- .../service/config/InMoov2Config.java | 1 - .../service/config/ProgramABConfig.java | 5 ----- 4 files changed, 8 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index 36d8c07ff4..8aac57a03e 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -2318,26 +2318,20 @@ public void stopNeopixelAnimation() { } public void systemCheck() { - log.error("systemCheck()"); - Runtime runtime = Runtime.getInstance(); - int servoCount = 0; - int servoAttachedCount = 0; + Platform platform = Runtime.getPlatform(); + int servoCount = 0; for (ServiceInterface si : Runtime.getServices()) { if (si.getClass().getSimpleName().equals("Servo")) { servoCount++; - if (((Servo) si).getController() != null) { - servoAttachedCount++; - } } } - setPredicate("systemServoCount", servoCount); - setPredicate("systemAttachedServoCount", servoAttachedCount); - setPredicate("systemFreeMemory", Runtime.getFreeMemory()); - Platform platform = Runtime.getPlatform(); - setPredicate("system version", platform.getVersion()); - // ERROR buffer !!! - systemEvent("SYSTEMCHECKFINISHED"); // wtf is this? + setPredicate("system_uptime", Runtime.getUptime()); + setPredicate("system_servo_count", servoCount); + setPredicate("system_free_memory", Runtime.getFreeMemory()); + setPredicate("system_version", platform.getVersion()); + setPredicate("system_errors", errors.size()); + } public String systemEvent(String eventMsg) { diff --git a/src/main/java/org/myrobotlab/service/ProgramAB.java b/src/main/java/org/myrobotlab/service/ProgramAB.java index 804115b67e..63dc903174 100644 --- a/src/main/java/org/myrobotlab/service/ProgramAB.java +++ b/src/main/java/org/myrobotlab/service/ProgramAB.java @@ -943,9 +943,6 @@ public void startService() { logging.setLevel("org.alicebot.ab.MagicBooleans", "DEBUG"); logging.setLevel("class org.myrobotlab.programab.MrlSraixHandler", "DEBUG"); logPublisher.start(); - - scanForBots(getResourceDir()); - } @Override /* FIXME - just do this once in abstract */ @@ -1104,15 +1101,6 @@ public ProgramABConfig apply(ProgramABConfig c) { } } - if (c.botDir == null) { - c.botDir = getResourceDir(); - } - - List botsFromScanning = scanForBots(c.botDir); - for (File file : botsFromScanning) { - addBotPath(file.getAbsolutePath()); - } - if (c.currentUserName != null) { setCurrentUserName(c.currentUserName); } diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index 819f84e31e..889e91eec9 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -243,7 +243,6 @@ public Plan getDefault(Plan plan, String name) { ProgramABConfig chatBot = (ProgramABConfig) plan.get(getPeerName("chatBot")); - chatBot.botDir = "resource/ProgramAB"; chatBot.bots.add("resource/ProgramAB/Alice"); chatBot.bots.add("resource/ProgramAB/Dr.Who"); diff --git a/src/main/java/org/myrobotlab/service/config/ProgramABConfig.java b/src/main/java/org/myrobotlab/service/config/ProgramABConfig.java index ce9ae14033..0cd4dbc839 100644 --- a/src/main/java/org/myrobotlab/service/config/ProgramABConfig.java +++ b/src/main/java/org/myrobotlab/service/config/ProgramABConfig.java @@ -10,11 +10,6 @@ public class ProgramABConfig extends ServiceConfig { @Deprecated /* unused text filters */ public String[] textFilters; - /** - * a directory ProgramAB will scan for new bots - */ - public String botDir; - /** * explicit bot directories */ From b7c7a165c0cf5cf6b99015c30bfba893605d84ec Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 17 Feb 2024 07:00:06 -0800 Subject: [PATCH 066/131] more non inmoov2 updates --- .../org/myrobotlab/config/ConfigUtils.java | 2 + .../org/myrobotlab/framework/repo/Repo.java | 6 +- .../service/AdafruitMotorHat4Pi.java | 4 +- .../java/org/myrobotlab/service/Arduino.java | 154 ++---------------- .../java/org/myrobotlab/service/DiyServo.java | 43 +---- .../service/FiniteStateMachine.java | 44 +++-- .../java/org/myrobotlab/service/RoboClaw.java | 4 +- .../java/org/myrobotlab/service/Runtime.java | 23 +-- .../java/org/myrobotlab/service/Servo.java | 87 +--------- .../java/org/myrobotlab/service/WebGui.java | 33 ++-- .../abstracts/AbstractMotorController.java | 4 +- .../service/abstracts/AbstractServo.java | 38 ++--- .../config/AbstractMotorControllerConfig.java | 5 + .../service/config/ArduinoConfig.java | 9 + .../service/config/InMoov2Config.java | 48 ++++-- .../service/config/ProgramABConfig.java | 5 - .../service/config/SabertoothConfig.java | 2 +- .../config/UltrasonicSensorConfig.java | 2 + .../service/interfaces/ServoControl.java | 9 +- .../myrobotlab/service/meta/OpenCVMeta.java | 2 +- .../myrobotlab/config/ConfigUtilsTest.java | 3 + .../myrobotlab/framework/BlockingTest.java | 4 +- .../myrobotlab/framework/repo/RepoTest.java | 4 + .../org/myrobotlab/service/ArduinoTest.java | 1 - .../org/myrobotlab/service/RandomTest.java | 56 +++---- .../service/RuntimeProcessTest.java | 5 +- .../org/myrobotlab/service/ServoTest.java | 2 +- .../service/VirtualArduinoTest.java | 4 + .../org/myrobotlab/service/WebGuiTest.java | 76 ++++----- .../org/myrobotlab/test/AbstractTest.java | 149 ++++++----------- 30 files changed, 273 insertions(+), 555 deletions(-) create mode 100644 src/main/java/org/myrobotlab/service/config/AbstractMotorControllerConfig.java diff --git a/src/main/java/org/myrobotlab/config/ConfigUtils.java b/src/main/java/org/myrobotlab/config/ConfigUtils.java index 19c256a8cf..69f850e602 100644 --- a/src/main/java/org/myrobotlab/config/ConfigUtils.java +++ b/src/main/java/org/myrobotlab/config/ConfigUtils.java @@ -60,6 +60,8 @@ static public RuntimeConfig loadRuntimeConfig(CmdOptions options) { if (startYml.enable) { configName = startYml.config; + } else { + configName = "default"; } // start with default diff --git a/src/main/java/org/myrobotlab/framework/repo/Repo.java b/src/main/java/org/myrobotlab/framework/repo/Repo.java index 9262834da1..d8b6863c16 100644 --- a/src/main/java/org/myrobotlab/framework/repo/Repo.java +++ b/src/main/java/org/myrobotlab/framework/repo/Repo.java @@ -324,10 +324,10 @@ public Set getUnfulfilledDependencies(String[] types) { } } } - + // Plan plan = ServiceConfig.getDefault(type.toLowerCase(), type); ServiceConfig sc = ServiceConfig.getDefaultServiceConfig(type); - + Map peers = sc.getPeers(); if (peers != null) { for (String key : peers.keySet()) { @@ -496,7 +496,7 @@ public void load() { } } else { - log.info("{} not found", getRepoPath()); + log.info("{} not found", f.getAbsolutePath()); } } catch (Exception e) { diff --git a/src/main/java/org/myrobotlab/service/AdafruitMotorHat4Pi.java b/src/main/java/org/myrobotlab/service/AdafruitMotorHat4Pi.java index a089498d4f..5897630ef8 100644 --- a/src/main/java/org/myrobotlab/service/AdafruitMotorHat4Pi.java +++ b/src/main/java/org/myrobotlab/service/AdafruitMotorHat4Pi.java @@ -19,7 +19,7 @@ import org.myrobotlab.logging.Logging; import org.myrobotlab.logging.LoggingFactory; import org.myrobotlab.service.abstracts.AbstractMotorController; -import org.myrobotlab.service.config.MotorConfig; +import org.myrobotlab.service.config.AbstractMotorControllerConfig; import org.myrobotlab.service.interfaces.I2CControl; import org.myrobotlab.service.interfaces.I2CController; import org.myrobotlab.service.interfaces.MotorControl; @@ -34,7 +34,7 @@ * https://learn.adafruit.com/adafruit-dc-and-stepper-motor-hat-for-raspberry-pi/overview */ -public class AdafruitMotorHat4Pi extends AbstractMotorController implements I2CControl { +public class AdafruitMotorHat4Pi extends AbstractMotorController implements I2CControl { /** version of the library */ static public final String VERSION = "0.9"; diff --git a/src/main/java/org/myrobotlab/service/Arduino.java b/src/main/java/org/myrobotlab/service/Arduino.java index 1f467cf8d8..cfc1be7b6d 100644 --- a/src/main/java/org/myrobotlab/service/Arduino.java +++ b/src/main/java/org/myrobotlab/service/Arduino.java @@ -171,7 +171,6 @@ public static class I2CDeviceMap { transient Mapper motorPowerMapper = new MapperLinear(-1.0, 1.0, -255.0, 255.0); - // make final - if not "connected" log error but don't allow Arduino NPEs public final transient Msg msg = new Msg(this, null); Integer nextDeviceId = 0; @@ -191,10 +190,6 @@ public static class I2CDeviceMap { private volatile boolean syncInProgress = false; - /** - * the port the user attempted to connect to - */ - String port; public Arduino(String n, String id) { super(n, id); @@ -552,6 +547,7 @@ public VirtualArduino getVirtual() { */ @Override public void connect(String port, int rate, int databits, int stopbits, int parity) { + config.connect = true; connecting = true; if (port == null) { warn("%s attempted to connect with a null port", getName()); @@ -563,7 +559,7 @@ public void connect(String port, int rate, int databits, int stopbits, int parit serial.addByteListener(this); // test to see if we've been started. the serial might be null - this.port = port; + config.port = port; try { @@ -811,6 +807,7 @@ public void disablePins() { @Override public void disconnect() { + config.connect = false; // FIXED - all don in 'onDisconnect()' // enableBoardInfo(false); // boardInfo is not valid after disconnect @@ -2233,7 +2230,7 @@ public Map getDeviceList() { @Override public void ackTimeout() { - log.warn("{} Ack Timeout seen. TODO: consider resetting the com port {}, reconnecting and re syncing all devices.", getName(), port); + log.warn("{} Ack Timeout seen. TODO: consider resetting the com port {}, reconnecting and re syncing all devices.", getName(), config.port); } @Override @@ -2325,34 +2322,13 @@ public void neoPixelClear(String neopixel) { msg.neoPixelClear(getDeviceId(neopixel)); } - @Override - public ArduinoConfig getConfig() { - super.getConfig(); - - // FIXME "port" shouldn't exist only config.port ! - config.port = port; - config.connect = isConnected(); - - return config; - } - @Override public ArduinoConfig apply(ArduinoConfig c) { super.apply(c); - - if (msg == null) { + if (config.connect && config.port != null) { serial = (Serial) startPeer("serial"); - if (serial == null) { - log.error("serial is null"); - } msg.setSerial(serial); - serial.addByteListener(this); - } else { - // TODO: figure out why this gets called so often. - log.info("Init serial we already have a msg class."); - } - - if (config.connect && config.port != null) { + serial.addByteListener(this); connect(config.port); } @@ -2372,13 +2348,8 @@ public ArduinoConfig apply(ArduinoConfig c) { public static void main(String[] args) { try { - // Platform.setVirtual(true); - LoggingFactory.init(Level.INFO); - Runtime runtime = Runtime.getInstance(); - runtime.saveAllDefaults(); - Runtime.start("arduino", "Arduino"); Runtime.start("webgui", "WebGui"); @@ -2387,115 +2358,12 @@ public static void main(String[] args) { if (isDone) { return; } - // Platform.setVirtual(true); - - /* - * WebGui webgui = (WebGui) Runtime.create("webgui", "WebGui"); - * webgui.autoStartBrowser(false); webgui.setPort(8887); - * webgui.startService(); - */ - - // Runtime.start("gui", "SwingGui"); - Serial.listPorts(); - - Arduino hub = (Arduino) Runtime.start("controller", "Arduino"); - Runtime.start("pir", "Pir"); - - hub.connect("/dev/ttyACM0"); - - // hub.enableAck(false); - - ServoControl sc = (ServoControl) Runtime.start("s1", "Servo"); - sc.setPin(3); - hub.attach(sc); - sc = (ServoControl) Runtime.start("s2", "Servo"); - sc.setPin(9); - hub.attach(sc); - - hub.detach(); - - // hub.enableAck(true); - /* - * sc = (ServoControl) Runtime.start("s3", "Servo"); sc.setPin(12); - * hub.attach(sc); - */ - - log.info("here"); - // hub.connect("COM6"); // uno - - // hub.startTcpServer(); - - VirtualArduino vmega = null; - - vmega = (VirtualArduino) Runtime.start("vmega", "VirtualArduino"); - vmega.connect("COM7"); - Serial sd = vmega.getSerial(); - sd.startTcpServer(); - - // Runtime.start("webgui", "WebGui"); - - Arduino mega = (Arduino) Runtime.start("mega", "Arduino"); - - if (mega.isVirtual()) { - vmega = mega.getVirtual(); - vmega.setBoardMega(); - } - - // mega.getBoardTypes(); - // mega.setBoardMega(); - // mega.setBoardUno(); - mega.connect("COM7"); - - /* - * Arduino uno = (Arduino) Runtime.start("uno", "Arduino"); - * uno.connect("COM6"); - */ - - // log.info("port names {}", mega.getPortNames()); - - Servo servo = (Servo) Runtime.start("servo", "Servo"); - // servo.load(); - log.info("rest is {}", servo.getRest()); - servo.save(); - // servo.setPin(8); - servo.attach(mega); - - servo.moveTo(90.0); - - /* - * servo.moveTo(3); sleep(300); servo.moveTo(130); sleep(300); - * servo.moveTo(90); sleep(300); - * - * - * // minmax checking - * - * servo.invoke("moveTo", 120); - */ - - /* - * mega.attach(servo); - * - * servo.moveTo(3); - * - * servo.moveTo(30); - * - * mega.enablePin("A4"); - * - * // arduino.setBoardMega(); - * - * Adafruit16CServoDriver adafruit = (Adafruit16CServoDriver) - * Runtime.start("adafruit", "Adafruit16CServoDriver"); - * adafruit.attach(mega); mega.attach(adafruit); - */ - - // servo.attach(arduino, 8, 90); - - // Runtime.start("webgui", "WebGui"); - // Service.sleep(3000); - - // remote.startListening(); - // Runtime.start("webgui", "WebGui"); +// Platform.setVirtual(true); +// Serial sd = vmega.getSerial(); +// sd.startTcpServer(); +// Serial.listPorts(); + } catch (Exception e) { log.error("main threw", e); diff --git a/src/main/java/org/myrobotlab/service/DiyServo.java b/src/main/java/org/myrobotlab/service/DiyServo.java index 2e125d8509..ae83c09118 100644 --- a/src/main/java/org/myrobotlab/service/DiyServo.java +++ b/src/main/java/org/myrobotlab/service/DiyServo.java @@ -28,7 +28,6 @@ import java.util.ArrayList; import java.util.List; -import org.myrobotlab.framework.Registration; import org.myrobotlab.framework.interfaces.ServiceInterface; import org.myrobotlab.logging.Level; import org.myrobotlab.logging.LoggerFactory; @@ -44,8 +43,6 @@ import org.myrobotlab.service.interfaces.MotorControl; import org.myrobotlab.service.interfaces.PinArrayControl; import org.myrobotlab.service.interfaces.PinListener; -import org.myrobotlab.service.interfaces.ServiceLifeCycleListener; -import org.myrobotlab.service.interfaces.ServoControl; import org.myrobotlab.service.interfaces.ServoEvent; import org.slf4j.Logger; @@ -76,7 +73,7 @@ * TODO : move is not accurate ( 1° step seem not possible ) */ -public class DiyServo extends AbstractServo implements PinListener, ServiceLifeCycleListener { +public class DiyServo extends AbstractServo implements PinListener { double lastOutput = 0.0; /** @@ -198,16 +195,6 @@ public DiyServo(String n, String id) { lastActivityTimeTs = System.currentTimeMillis(); } - /* - * Update the list of PinArrayControls - */ - @Override - public void onRegistered(Registration s) { - refreshPinArrayControls(); - broadcastState(); - - } - /** * Initiate the PID controller */ @@ -224,7 +211,7 @@ void initPid() { pid.setSetpoint(pidKey, setPoint); pid.startService(); } - + @Override public void startService() { super.startService(); @@ -232,7 +219,6 @@ public void startService() { motorControl = (MotorControl) startPeer("motor"); initPid(); } - /** * Equivalent to Arduino's Servo.detach() it de-energizes the servo @@ -694,19 +680,17 @@ public static void main(String[] args) throws InterruptedException { // if (done) { // return; // } - - WebGui webgui = (WebGui)Runtime.create("webgui", "WebGui"); + + WebGui webgui = (WebGui) Runtime.create("webgui", "WebGui"); webgui.autoStartBrowser(false); webgui.startService(); - + Runtime.start("diy", "DiyServo"); - - + boolean done = true; if (done) { return; } - String port = "COM4"; Arduino arduino = (Arduino) Runtime.start("arduino", "Arduino"); @@ -788,19 +772,4 @@ protected boolean processMove(Double newPos, boolean blocking, Long timeoutMs) { return false; } - @Override - public void onCreated(String name) { - log.info("created {}", name); - } - - @Override - public void onStopped(String name) { - log.info("stopped {}", name); - } - - @Override - public void onReleased(String name) { - log.info("released {}", name); - } - } diff --git a/src/main/java/org/myrobotlab/service/FiniteStateMachine.java b/src/main/java/org/myrobotlab/service/FiniteStateMachine.java index 32c04bf29e..e998711e26 100644 --- a/src/main/java/org/myrobotlab/service/FiniteStateMachine.java +++ b/src/main/java/org/myrobotlab/service/FiniteStateMachine.java @@ -2,16 +2,11 @@ import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; -import org.myrobotlab.codec.CodecUtils; import org.myrobotlab.framework.Service; -import org.myrobotlab.framework.interfaces.MessageListener; -import org.myrobotlab.framework.interfaces.ServiceInterface; import org.myrobotlab.generics.SlidingWindowList; import org.myrobotlab.logging.Level; import org.myrobotlab.logging.LoggerFactory; @@ -61,7 +56,7 @@ public class Tuple { public Transition transition; public StateTransition stateTransition; } - + public class StateChange { /** * timestamp @@ -72,7 +67,7 @@ public class StateChange { * current new state */ public String state; - + /** * event which activated new state */ @@ -82,13 +77,12 @@ public class StateChange { * source of event */ public String src = getName(); - - + public StateChange(String current, String event) { this.state = current; this.event = event; } - + public String toString() { return String.format("%s --%s--> %s", last, event, state); } @@ -221,25 +215,25 @@ public String firedEvent(String event) { } /** - * gets the current state of this state machine + * get the previous state of this state machine * * @return */ - public String getCurrent() { - if (current != null) { - return current.getName(); + public String getLast() { + if (last != null) { + return last.getName(); } return null; } /** - * get the previous state of this state machine + * gets the current state of this state machine * * @return */ - public String getLast() { - if (last != null) { - return last.getName(); + public String getState() { + if (current != null) { + return current.getName(); } return null; } @@ -250,7 +244,7 @@ public List getTransitions() { } /** - * Publishes state change (current, last and event) + * Publishes state change (current, last and event) * * @param stateChange * @return @@ -263,7 +257,7 @@ public StateChange publishStateChange(StateChange stateChange) { @Override public FiniteStateMachineConfig getConfig() { super.getConfig(); - config.current = getCurrent(); + config.current = getState(); return config; } @@ -361,15 +355,15 @@ public static void main(String[] args) { // fsm.subscribe("fsm", "publishState"); - log.info("state - {}", fsm.getCurrent()); + log.info("state - {}", fsm.getState()); fsm.setCurrent("neutral"); - log.info("state - {}", fsm.getCurrent()); + log.info("state - {}", fsm.getState()); fsm.fire("ill-event"); - log.info("state - {}", fsm.getCurrent()); + log.info("state - {}", fsm.getState()); fsm.fire("ill-event"); fsm.fire("ill-event"); @@ -387,7 +381,7 @@ public static void main(String[] args) { // fsm.removeScheduledEvents(); - log.info("state - {}", fsm.getCurrent()); + log.info("state - {}", fsm.getState()); } catch (Exception e) { log.error("main threw", e); @@ -419,7 +413,7 @@ public String getPreviousState() { return history.get(history.size() - 2).state; } } - + @Override public void startService() { super.startService(); diff --git a/src/main/java/org/myrobotlab/service/RoboClaw.java b/src/main/java/org/myrobotlab/service/RoboClaw.java index 83203b99f8..8d22f7ff27 100644 --- a/src/main/java/org/myrobotlab/service/RoboClaw.java +++ b/src/main/java/org/myrobotlab/service/RoboClaw.java @@ -16,7 +16,7 @@ import org.myrobotlab.serial.CRC; import org.myrobotlab.service.Pid.PidData; import org.myrobotlab.service.abstracts.AbstractMotorController; -import org.myrobotlab.service.config.MotorConfig; +import org.myrobotlab.service.config.AbstractMotorControllerConfig; import org.myrobotlab.service.interfaces.MotorControl; import org.myrobotlab.service.interfaces.MotorController; import org.myrobotlab.service.interfaces.PortConnector; @@ -55,7 +55,7 @@ * this value IS correct * */ -public class RoboClaw extends AbstractMotorController implements EncoderPublisher, PortConnector, MotorController, SerialDataListener { +public class RoboClaw extends AbstractMotorController implements EncoderPublisher, PortConnector, MotorController, SerialDataListener { private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 675123e962..3d3697284a 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -316,12 +316,6 @@ public class Runtime extends Service implements MessageListener, protected List configList; - /*** - * runtime, security, webgui, perhaps python - we don't want to remove when - * releasing config - */ - protected Set startingServices = new HashSet<>(); - /** * Wraps {@link java.lang.Runtime#availableProcessors()}. * @@ -580,7 +574,7 @@ public final static void createAndStartServices(List services) { Logging.logError(e); } } else { - runtime.error(String.format("could not create service %1$s %2$s", name, type)); + runtime.error(String.format("could not create service %s %s", name, type)); } } @@ -910,9 +904,6 @@ public static Runtime getInstance() { // klunky Runtime.register(new Registration(runtime)); - // assign, do not apply otherwise there will be - // a chicken-egg problem - runtime.config = c; } runtime.getRepo().addStatusPublisher(runtime); @@ -4924,8 +4915,18 @@ static public void releaseConfigPath(String configPath) { RuntimeConfig config = CodecUtils.fromYaml(releaseData, RuntimeConfig.class); List registry = config.getRegistry(); Collections.reverse(Arrays.asList(registry)); + + // get starting services if any entered on the command line + // -s log Log webgui WebGui ... etc - these will be protected + List startingServices = new ArrayList<>(); + if (options.services.size() % 2 == 0) { + for (int i = 0; i < options.services.size(); i += 2) { + startingServices.add(options.services.get(i)); + } + } + for (String name : registry) { - if (Runtime.getInstance().startingServices.contains(name)) { + if (startingServices.contains(name)) { continue; } release(name); diff --git a/src/main/java/org/myrobotlab/service/Servo.java b/src/main/java/org/myrobotlab/service/Servo.java index 3e0b46ce95..7b59121998 100644 --- a/src/main/java/org/myrobotlab/service/Servo.java +++ b/src/main/java/org/myrobotlab/service/Servo.java @@ -61,7 +61,7 @@ * */ -public class Servo extends AbstractServo implements ServiceLifeCycleListener { +public class Servo extends AbstractServo { private static final long serialVersionUID = 1L; @@ -259,95 +259,10 @@ public static void main(String[] args) throws InterruptedException { return; } - // runtime.save(); - - /* - * mega.save(); tilt.save(); pan.save(); - * - * mega.load(); tilt.load(); pan.load(); - */ - - // TODO - attach before and after connect.. - - // mega.setBoardMega(); - - // log.info("servo pos {}", tilt.getCurrentInputPos()); - // - // // double pos = 170; - // // servo03.setPosition(pos); - // - // double min = 3; - // double max = 170; - // double speed = 60; // degree/s - // - // mega.attach(tilt); - // // mega.attach(servo03,3); - // - // for (int i = 0; i < 100; ++i) { - // tilt.moveTo(20.0); - // } - // - // tilt.sweep(min, max, speed); - - /* - * Servo servo04 = (Servo) Runtime.start("servo04", "Servo"); Servo - * servo05 = (Servo) Runtime.start("servo05", "Servo"); Servo servo06 = - * (Servo) Runtime.start("servo06", "Servo"); Servo servo07 = (Servo) - * Runtime.start("servo07", "Servo"); Servo servo08 = (Servo) - * Runtime.start("servo08", "Servo"); Servo servo09 = (Servo) - * Runtime.start("servo09", "Servo"); Servo servo10 = (Servo) - * Runtime.start("servo10", "Servo"); Servo servo11 = (Servo) - * Runtime.start("servo11", "Servo"); Servo servo12 = (Servo) - * Runtime.start("servo12", "Servo"); - */ - // Servo servo13 = (Servo) Runtime.start("servo13", "Servo"); - - // servo03.attach(mega, 8, 38.0); - /* - * servo04.attach(mega, 4, 38.0); servo05.attach(mega, 5, 38.0); - * servo06.attach(mega, 6, 38.0); servo07.attach(mega, 7, 38.0); - * servo08.attach(mega, 8, 38.0); servo09.attach(mega, 9, 38.0); - * servo10.attach(mega, 10, 38.0); servo11.attach(mega, 11, 38.0); - * servo12.attach(mega, 12, 38.0); - */ - - // TestCatcher catcher = (TestCatcher)Runtime.start("catcher", - // "TestCatcher"); - // servo03.attach((ServoEventListener)catcher); - - // servo.setPin(12); - - /* - * servo.attach(mega, 7, 38.0); servo.attach(mega, 7, 38.0); - * servo.attach(mega, 7, 38.0); servo.attach(mega, 7, 38.0); - * servo.attach(mega, 7, 38.0); servo.attach(mega, 7, 38.0); - * servo.attach(mega, 7, 38.0); servo.attach(mega, 7, 38.0); - * servo.attach(mega, 7, 38.0); servo.attach(mega, 7, 38.0); - * servo.attach(mega, 7, 38.0); servo.attach(mega, 7, 38.0); - */ - - // servo.sweepDelay = 3; - // servo.save(); - // servo.load(); - // servo.save(); - // log.info("sweepDely {}", servo.sweepDelay); } catch (Exception e) { log.error("main threw", e); } } - @Override - public void onCreated(String name) { - } - - @Override - public void onStopped(String name) { - } - - @Override - public void onReleased(String name) { - } - - } diff --git a/src/main/java/org/myrobotlab/service/WebGui.java b/src/main/java/org/myrobotlab/service/WebGui.java index 5e87cddb05..f50cdc238a 100644 --- a/src/main/java/org/myrobotlab/service/WebGui.java +++ b/src/main/java/org/myrobotlab/service/WebGui.java @@ -34,7 +34,6 @@ import org.myrobotlab.codec.CodecUtils; import org.myrobotlab.framework.MRLListener; import org.myrobotlab.framework.Message; -import org.myrobotlab.framework.Platform; import org.myrobotlab.framework.Registration; import org.myrobotlab.framework.Service; import org.myrobotlab.framework.interfaces.ServiceInterface; @@ -62,8 +61,7 @@ * services are already APIs - perhaps a data API - same as service without the * message wrapper */ -public class WebGui extends Service - implements AuthorizationProvider, Gateway, Handler, ServiceLifeCycleListener { +public class WebGui extends Service implements AuthorizationProvider, Gateway, Handler, ServiceLifeCycleListener { public static class LiveVideoStreamHandler implements Handler { @@ -128,7 +126,7 @@ public Panel(String name, int x, int y, int z) { * needed to get the api key to select the appropriate api processor * * @param uri - * u + * u * @return api key * */ @@ -271,9 +269,9 @@ public boolean getAutoStartBrowser() { * String broadcast to specific client * * @param uuid - * u + * u * @param str - * s + * s * */ public void broadcast(String uuid, String str) { @@ -315,9 +313,7 @@ public Config.Builder getNettosphereConfig() { // cert.privateKey()).build(); SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); - SslContext context = SslContextBuilder - .forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()) - .sslProvider(SslProvider.JDK) + SslContext context = SslContextBuilder.forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()).sslProvider(SslProvider.JDK) .clientAuth(ClientAuth.NONE).build(); configBuilder.sslContext(context); @@ -496,8 +492,7 @@ public void handle(AtmosphereResource r) { } else if ((bodyData != null) && log.isDebugEnabled()) { logData = bodyData; } - log.debug("-->{} {} {} - [{}] from connection {}", (newPersistentConnection) ? "new" : "", request.getMethod(), - request.getRequestURI(), logData, uuid); + log.debug("-->{} {} {} - [{}] from connection {}", (newPersistentConnection) ? "new" : "", request.getMethod(), request.getRequestURI(), logData, uuid); } // important persistent connections will have associated routes ... @@ -575,8 +570,7 @@ public void handle(AtmosphereResource r) { } if (msg.containsHop(getId())) { - log.error("{} dumping duplicate hop msg to avoid cyclical from {} --to--> {}.{}", getName(), msg.sender, - msg.name, msg.method); + log.error("{} dumping duplicate hop msg to avoid cyclical from {} --to--> {}.{}", getName(), msg.sender, msg.name, msg.method); return; } @@ -920,7 +914,7 @@ public void run() { * remotely control UI * * @param panel - * - the panel which has been moved or resized + * - the panel which has been moved or resized */ public void savePanel(Panel panel) { if (panel.name == null) { @@ -1107,7 +1101,7 @@ public void releaseService() { * Default (false) is to use the CDN * * @param useLocalResources - * - true uses local resources fals uses cdn + * - true uses local resources fals uses cdn */ public void useLocalResources(boolean useLocalResources) { this.useLocalResources = useLocalResources; @@ -1183,8 +1177,7 @@ public static void main(String[] args) { try { - Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", "WebGui","intro", "Intro", "python", "Python" }); - // Runtime.main(new String[] {}); + Runtime.main(new String[] { "--log-level", "info", "-s", "log", "Log", "webgui", "WebGui", "intro", "Intro", "python", "Python" }); // Runtime.main(new String[] { "--install" }); boolean done = true; @@ -1193,7 +1186,8 @@ public static void main(String[] args) { } // Platform.setVirtual(true); - // Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", "WebGui", + // Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", + // "WebGui", // "intro", "Intro", "python", "Python", "-c", "dev" }); // Runtime.startConfig("dev"); @@ -1248,8 +1242,7 @@ public static void main(String[] args) { arduino.connect("/dev/ttyACM0"); for (int i = 0; i < 1000; ++i) { - webgui.display( - "https://i.kinja-img.com/gawker-media/image/upload/c_scale,f_auto,fl_progressive,q_80,w_800/pytutcxcrfjvuhz2jipa.jpg"); + webgui.display("https://i.kinja-img.com/gawker-media/image/upload/c_scale,f_auto,fl_progressive,q_80,w_800/pytutcxcrfjvuhz2jipa.jpg"); } // Runtime.setLogLevel("ERROR"); diff --git a/src/main/java/org/myrobotlab/service/abstracts/AbstractMotorController.java b/src/main/java/org/myrobotlab/service/abstracts/AbstractMotorController.java index 5f01ebc74f..94380c9711 100644 --- a/src/main/java/org/myrobotlab/service/abstracts/AbstractMotorController.java +++ b/src/main/java/org/myrobotlab/service/abstracts/AbstractMotorController.java @@ -8,11 +8,11 @@ import org.myrobotlab.math.MapperLinear; import org.myrobotlab.math.interfaces.Mapper; import org.myrobotlab.service.Runtime; -import org.myrobotlab.service.config.MotorConfig; +import org.myrobotlab.service.config.AbstractMotorControllerConfig; import org.myrobotlab.service.interfaces.MotorControl; import org.myrobotlab.service.interfaces.MotorController; -public abstract class AbstractMotorController extends Service implements MotorController { +public abstract class AbstractMotorController extends Service implements MotorController { /** * currently attached motors to this controller diff --git a/src/main/java/org/myrobotlab/service/abstracts/AbstractServo.java b/src/main/java/org/myrobotlab/service/abstracts/AbstractServo.java index 3378d5e56d..7eee94dc5a 100644 --- a/src/main/java/org/myrobotlab/service/abstracts/AbstractServo.java +++ b/src/main/java/org/myrobotlab/service/abstracts/AbstractServo.java @@ -6,7 +6,6 @@ import java.util.Set; import org.myrobotlab.codec.CodecUtils; -import org.myrobotlab.framework.Registration; import org.myrobotlab.framework.Service; import org.myrobotlab.framework.interfaces.Attachable; import org.myrobotlab.logging.LoggerFactory; @@ -217,16 +216,6 @@ public abstract class AbstractServo extends Service im public AbstractServo(String n, String id) { super(n, id); - // this servo is interested in new services which support either - // ServoControllers or EncoderControl interfaces - // we subscribe to runtime here for new services - subscribeToRuntime("registered"); - /* - * // new feature - // extracting the currentPos from serialized servo - * Double lastCurrentPos = null; try { lastCurrentPos = (Double) - * loadField("currentPos"); } catch (IOException e) { - * log.info("current pos cannot be found in saved file"); } - */ // if no position could be loaded - set to rest // we have no "historical" info - assume we are @ rest targetPos = rest; @@ -243,17 +232,6 @@ public AbstractServo(String n, String id) { } } - /** - * if a new service is added to the system refresh the controllers - */ - @Deprecated /* - * lifecycle events not necessary for ui, probably should be - * pulled out - */ - public void onStarted(String name) { - invoke("refreshControllers"); - } - /** * overloaded routing attach */ @@ -456,6 +434,12 @@ public void enable() { public void fullSpeed() { setSpeed((Double) null); } + + @Override + public void setMaxSpeed() { + setSpeed((Double) null); + } + @Override public boolean isAutoDisable() { @@ -697,10 +681,6 @@ public void onEncoderData(EncoderData data) { } } - public void onRegistered(Registration s) { - refreshControllers(); - } - /** * Servo has the ability to act as an encoder if it is using TimeEncoder. * TimeEncoder will use Servo to publish a series of encoder events with @@ -918,6 +898,11 @@ public void setSpeed(Double degreesPerSecond) { // speed = maxSpeed; // log.info("Trying to set speed to a value greater than max speed"); // } + + if (degreesPerSecond != null && degreesPerSecond < 0) { + warn("setting speed to negative value %d ignoring", degreesPerSecond); + return; + } speed = degreesPerSecond; @@ -1096,7 +1081,6 @@ public ServoEvent publishServoStopped(String name, Double position) { @Override public void startService() { super.startService(); - Runtime.getInstance().attachServiceLifeCycleListener(getName()); } @Override diff --git a/src/main/java/org/myrobotlab/service/config/AbstractMotorControllerConfig.java b/src/main/java/org/myrobotlab/service/config/AbstractMotorControllerConfig.java new file mode 100644 index 0000000000..030a1ee4f0 --- /dev/null +++ b/src/main/java/org/myrobotlab/service/config/AbstractMotorControllerConfig.java @@ -0,0 +1,5 @@ +package org.myrobotlab.service.config; + +public class AbstractMotorControllerConfig extends ServiceConfig { + // Add your configuration here +} diff --git a/src/main/java/org/myrobotlab/service/config/ArduinoConfig.java b/src/main/java/org/myrobotlab/service/config/ArduinoConfig.java index 1f83bee895..3e4adf8f83 100644 --- a/src/main/java/org/myrobotlab/service/config/ArduinoConfig.java +++ b/src/main/java/org/myrobotlab/service/config/ArduinoConfig.java @@ -4,7 +4,16 @@ public class ArduinoConfig extends ServiceConfig { + /** + * Port (usb or ip:port) to connect) + */ public String port; + + /** + * If you want the arduino to try to connect + * port must not be null. + * This is not a status field. + */ public boolean connect; @Override diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index 34c8da7d08..889e91eec9 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -55,7 +55,7 @@ public class InMoov2Config extends ServiceConfig { * fire events to the FSM. Checks battery level and sends a heartbeat flash on * publishHeartbeat and onHeartbeat at a regular interval */ - public boolean heartbeat = false; + public boolean heartbeat = true; /** * flashes the neopixel every time a health check is preformed. green == good @@ -68,17 +68,17 @@ public class InMoov2Config extends ServiceConfig { */ public long heartbeatInterval = 3000; - public boolean loadAppsScripts = true; + public boolean loadAppsScripts = false; /** * loads all python gesture files in the gesture directory */ - public boolean loadGestures = true; + public boolean loadGestures = false; /** * executes all scripts in the init directory on startup */ - public boolean loadInitScripts = true; + public boolean loadInitScripts = false; /** * default to null - allow the OS to set it, unless explicilty set @@ -232,9 +232,17 @@ public Plan getDefault(Plan plan, String name) { } mouthControl.mouth = i01Name + ".mouth"; - + + UltrasonicSensorConfig ultrasonicLeft = (UltrasonicSensorConfig) plan.get(getPeerName("ultrasonicLeft")); + ultrasonicLeft.triggerPin = 64; + ultrasonicLeft.echoPin = 63; + + UltrasonicSensorConfig ultrasonicRight = (UltrasonicSensorConfig) plan.get(getPeerName("ultrasonicRight")); + ultrasonicRight.triggerPin = 64; + ultrasonicRight.echoPin = 63; + + ProgramABConfig chatBot = (ProgramABConfig) plan.get(getPeerName("chatBot")); - chatBot.botDir = "resource/ProgramAB"; chatBot.bots.add("resource/ProgramAB/Alice"); chatBot.bots.add("resource/ProgramAB/Dr.Who"); @@ -267,8 +275,6 @@ public Plan getDefault(Plan plan, String name) { } } - chatBot.currentUserName = "human"; - chatBot.listeners.add(new Listener("publishText", name + ".htmlFilter", "onText")); Gpt3Config gpt3 = (Gpt3Config) plan.get(getPeerName("gpt3")); @@ -283,8 +289,7 @@ public Plan getDefault(Plan plan, String name) { // setup name references to different services MarySpeechConfig mouth = (MarySpeechConfig) plan.get(getPeerName("mouth")); mouth.voice = "Mark"; - mouth.speechRecognizers = new String[] { name + ".ear" }; - + // == Peer - ear ============================= // setup name references to different services WebkitSpeechRecognitionConfig ear = (WebkitSpeechRecognitionConfig) plan.get(getPeerName("ear")); @@ -365,16 +370,17 @@ public Plan getDefault(Plan plan, String name) { // exists ? fsm.current = "boot"; fsm.transitions.add(new Transition("boot", "wake", "wake")); - fsm.transitions.add(new Transition("wake", "idle", "idle")); - fsm.transitions.add(new Transition("first_init", "idle", "idle")); + // fsm.transitions.add(new Transition("wake", "idle", "idle")); wake, setup, nor sleep should be affected by idle + fsm.transitions.add(new Transition("setup", "setup_done", "idle")); fsm.transitions.add(new Transition("idle", "random", "random")); fsm.transitions.add(new Transition("random", "idle", "idle")); fsm.transitions.add(new Transition("idle", "sleep", "sleep")); fsm.transitions.add(new Transition("sleep", "wake", "wake")); fsm.transitions.add(new Transition("sleep", "power_down", "power_down")); fsm.transitions.add(new Transition("idle", "power_down", "power_down")); - fsm.transitions.add(new Transition("wake", "first_init", "first_init")); - fsm.transitions.add(new Transition("idle", "first_init", "first_init")); + fsm.transitions.add(new Transition("wake", "setup", "setup")); + fsm.transitions.add(new Transition("wake", "idle", "idle")); + fsm.transitions.add(new Transition("idle", "setup", "setup")); // power_down to shutdown // fsm.transitions.add(new Transition("systemCheck", "systemCheckFinished", // "awake")); @@ -520,7 +526,11 @@ public Plan getDefault(Plan plan, String name) { listeners.add(new Listener("publishPlayAudioFile", getPeerName("audioPlayer"))); listeners.add(new Listener("publishPlayAnimation", getPeerName("neoPixel"))); listeners.add(new Listener("publishStopAnimation", getPeerName("neoPixel"))); - listeners.add(new Listener("publishProcessMessage", getPeerName("py4j"), "onPythonMessage")); + // listeners.add(new Listener("publishProcessMessage", + // getPeerName("python"), "onPythonMessage")); + listeners.add(new Listener("publishProcessMessage", "python", "onPythonMessage")); + + listeners.add(new Listener("publishPython", "python")); // InMoov2 --to--> InMoov2 listeners.add(new Listener("publishMoveHead", getPeerName("head"), "onMove")); @@ -533,6 +543,8 @@ public Plan getDefault(Plan plan, String name) { // service --to--> InMoov2 AudioFileConfig mouth_audioFile = (AudioFileConfig) plan.get(getPeerName("mouth.audioFile")); mouth_audioFile.listeners.add(new Listener("publishPeak", name)); + + htmlFilter.listeners.add(new Listener("publishText", name)); OakDConfig oakd = (OakDConfig) plan.get(getPeerName("oakd")); oakd.listeners.add(new Listener("publishClassification", name)); @@ -544,7 +556,11 @@ public Plan getDefault(Plan plan, String name) { // mouth_audioFile.listeners.add(new Listener("publishAudioStart", name)); // Needs upcoming pr - // fsm.listeners.add(new Listener("publishStateChange", name)); + fsm.listeners.add(new Listener("publishStateChange", name, "publishStateChange")); + + // peer --to--> peer + mouth.listeners.add(new Listener("publishStartSpeaking", getPeerName("ear"))); + mouth.listeners.add(new Listener("publishEndSpeaking", getPeerName("ear"))); return plan; } diff --git a/src/main/java/org/myrobotlab/service/config/ProgramABConfig.java b/src/main/java/org/myrobotlab/service/config/ProgramABConfig.java index ce9ae14033..0cd4dbc839 100644 --- a/src/main/java/org/myrobotlab/service/config/ProgramABConfig.java +++ b/src/main/java/org/myrobotlab/service/config/ProgramABConfig.java @@ -10,11 +10,6 @@ public class ProgramABConfig extends ServiceConfig { @Deprecated /* unused text filters */ public String[] textFilters; - /** - * a directory ProgramAB will scan for new bots - */ - public String botDir; - /** * explicit bot directories */ diff --git a/src/main/java/org/myrobotlab/service/config/SabertoothConfig.java b/src/main/java/org/myrobotlab/service/config/SabertoothConfig.java index 42db50689b..44dc5a0c5b 100644 --- a/src/main/java/org/myrobotlab/service/config/SabertoothConfig.java +++ b/src/main/java/org/myrobotlab/service/config/SabertoothConfig.java @@ -2,7 +2,7 @@ import org.myrobotlab.framework.Plan; -public class SabertoothConfig extends MotorConfig { +public class SabertoothConfig extends AbstractMotorControllerConfig { public String port; public boolean connect = false; diff --git a/src/main/java/org/myrobotlab/service/config/UltrasonicSensorConfig.java b/src/main/java/org/myrobotlab/service/config/UltrasonicSensorConfig.java index f48ec59e49..2c23767e33 100644 --- a/src/main/java/org/myrobotlab/service/config/UltrasonicSensorConfig.java +++ b/src/main/java/org/myrobotlab/service/config/UltrasonicSensorConfig.java @@ -10,11 +10,13 @@ public class UltrasonicSensorConfig extends ServiceConfig { /** * pulse pin */ + @Deprecated /* Pins need to be Strings eg "D64" */ public Integer triggerPin; /** * listening pin */ + @Deprecated /* Pins need to be Strings eg "D63" */ public Integer echoPin; /** diff --git a/src/main/java/org/myrobotlab/service/interfaces/ServoControl.java b/src/main/java/org/myrobotlab/service/interfaces/ServoControl.java index 1e140ce167..379154cd6e 100644 --- a/src/main/java/org/myrobotlab/service/interfaces/ServoControl.java +++ b/src/main/java/org/myrobotlab/service/interfaces/ServoControl.java @@ -404,7 +404,12 @@ public interface ServoControl extends AbsolutePositionControl, EncoderListener, /** * disable speed control and move the servos at full speed. */ - @Deprecated /* implement setSpeed(null) */ + @Deprecated void fullSpeed(); - + + /** + * + */ + void setMaxSpeed(); + } diff --git a/src/main/java/org/myrobotlab/service/meta/OpenCVMeta.java b/src/main/java/org/myrobotlab/service/meta/OpenCVMeta.java index 1b8f134beb..73d284cdb6 100644 --- a/src/main/java/org/myrobotlab/service/meta/OpenCVMeta.java +++ b/src/main/java/org/myrobotlab/service/meta/OpenCVMeta.java @@ -16,7 +16,7 @@ public OpenCVMeta() { addDescription("OpenCV (computer vision) service wrapping many of the functions and filters of OpenCV"); addCategory("video", "vision", "sensors"); - String javaCvVersion = "1.5.7"; + String javaCvVersion = "1.5.8"; // addDependency("org.bytedeco", "javacv", javaCvVersion); addDependency("org.bytedeco", "javacv-platform", javaCvVersion); addDependency("org.bytedeco", "javacpp", javaCvVersion); diff --git a/src/test/java/org/myrobotlab/config/ConfigUtilsTest.java b/src/test/java/org/myrobotlab/config/ConfigUtilsTest.java index 5d15601b58..fb83ed0777 100644 --- a/src/test/java/org/myrobotlab/config/ConfigUtilsTest.java +++ b/src/test/java/org/myrobotlab/config/ConfigUtilsTest.java @@ -6,6 +6,7 @@ import org.junit.Before; import org.junit.Test; import org.myrobotlab.framework.StartYml; +import org.myrobotlab.io.FileIO; import org.myrobotlab.service.Runtime; public class ConfigUtilsTest { @@ -13,6 +14,8 @@ public class ConfigUtilsTest { @Before public void beforeTest() { Runtime.releaseAll(true, true); + // remove config + FileIO.rm("data/config/default"); } @Test diff --git a/src/test/java/org/myrobotlab/framework/BlockingTest.java b/src/test/java/org/myrobotlab/framework/BlockingTest.java index b4ce03e8da..3b9788645b 100644 --- a/src/test/java/org/myrobotlab/framework/BlockingTest.java +++ b/src/test/java/org/myrobotlab/framework/BlockingTest.java @@ -28,13 +28,13 @@ public void blockingTest() throws Exception { Message msg = Message.createMessage("thower07", "catcher07", "onInt", 3); Integer ret = (Integer)thower07.sendBlocking(msg, null); - assertEquals(simpleName, 3, (int)ret); + assertEquals(3, (int)ret); long startTime = System.currentTimeMillis(); msg = Message.createMessage("thower07", "catcher07", "waitForThis", new Object[] {7, 1000}); ret = (Integer)thower07.sendBlocking(msg, null); assertTrue("1s process", System.currentTimeMillis() - startTime > 500); - assertEquals(simpleName, 7, (int)ret); + assertEquals(7, (int)ret); Runtime.release("catcher07"); Runtime.release("thower07"); diff --git a/src/test/java/org/myrobotlab/framework/repo/RepoTest.java b/src/test/java/org/myrobotlab/framework/repo/RepoTest.java index f2715dc90d..d0e2c57735 100644 --- a/src/test/java/org/myrobotlab/framework/repo/RepoTest.java +++ b/src/test/java/org/myrobotlab/framework/repo/RepoTest.java @@ -28,6 +28,10 @@ public static void lastCleanup() { repo.clear(); installed = false; } + + public String getName() { + return "RepoTest"; + } @Override public void broadcastStatus(Status status) { diff --git a/src/test/java/org/myrobotlab/service/ArduinoTest.java b/src/test/java/org/myrobotlab/service/ArduinoTest.java index 7a6422d29d..00cee5e0a7 100644 --- a/src/test/java/org/myrobotlab/service/ArduinoTest.java +++ b/src/test/java/org/myrobotlab/service/ArduinoTest.java @@ -62,7 +62,6 @@ private void assertVirtualPinValue(VirtualArduino virtual, int address, int valu } } - @Override public String getName() { return "arduinoTest"; } diff --git a/src/test/java/org/myrobotlab/service/RandomTest.java b/src/test/java/org/myrobotlab/service/RandomTest.java index 7c8add5923..f089f2e453 100644 --- a/src/test/java/org/myrobotlab/service/RandomTest.java +++ b/src/test/java/org/myrobotlab/service/RandomTest.java @@ -7,31 +7,24 @@ import java.util.Map; import org.junit.Before; -import org.myrobotlab.framework.Service; +import org.junit.Test; import org.myrobotlab.service.Random.RandomMessage; +import org.myrobotlab.test.AbstractTest; -public class RandomTest extends AbstractServiceTest { +public class RandomTest extends AbstractTest { - @Override /* - * FIXME - this assumes a single service is in the test - which - * rarely happens - seems not useful and silly - */ - public Service createService() throws Exception { - return (Service) Runtime.start("randomTest", "Random"); - } - @Before /* before each test */ public void setUp() throws IOException { // remove all services - also resets config name to DEFAULT effectively Runtime.releaseAll(true, true); - // clean our config directory + // clean our config directory // Runtime.removeConfig("RandomTest"); // set our config Runtime.setConfig("RandomTest"); + Runtime.start("randomTest", "Random"); } - - @Override + @Test public void testService() throws Exception { Clock clock = (Clock) Runtime.start("clock", "Clock"); Random random = (Random) Runtime.start("randomTest", "Random"); @@ -46,62 +39,63 @@ public void testService() throws Exception { sleep(1000); assertTrue("should have method", random.getKeySet().contains("clock.setInterval")); - + assertTrue(String.format("random method 1 should be %d => 5000 values", clock.getInterval()), 5000 <= clock.getInterval()); - assertTrue(String.format("random method 1 should be %d <= 10000 values",clock.getInterval()) , clock.getInterval() <= 10000); - + assertTrue(String.format("random method 1 should be %d <= 10000 values", clock.getInterval()), clock.getInterval() <= 10000); + random.remove("clock.setInterval"); - + assertTrue("should not have method", !random.getKeySet().contains("clock.setInterval")); random.addRandom(0, 200, "clock", "setInterval", 5000, 10000); random.addRandom(0, 200, "clock", "startClock"); - + sleep(500); assertTrue("clock should be started 1", clock.isClockRunning()); - + // disable all of a services random events random.disable("clock.startClock"); - clock.stopClock(); sleep(250); + clock.stopClock(); assertTrue("clock should not be started 1", !clock.isClockRunning()); - + // enable all of a service's random events random.enable("clock.startClock"); sleep(250); assertTrue("clock should be started 2", clock.isClockRunning()); - + // disable one method - leave other enabled random.disable("clock.startClock"); clock.stopClock(); - clock.setInterval(9999); sleep(200); + clock.setInterval(9999); assertTrue("clock should not be started 3", !clock.isClockRunning()); assertTrue(String.format("random method 2 should be %d => 5000 values", clock.getInterval()), 5000 <= clock.getInterval()); - assertTrue(String.format("random method 2 should be %d <= 10000 values",clock.getInterval()) , clock.getInterval() <= 10000); + assertTrue(String.format("random method 2 should be %d <= 10000 values", clock.getInterval()), clock.getInterval() <= 10000); // disable all random.disable(); sleep(200); clock.setInterval(9999); - assertTrue("clock should not be started 4", !clock.isClockRunning()); - assertEquals(9999, (long)clock.getInterval()); + assertTrue("clock should not be started 4", !clock.isClockRunning()); + assertEquals(9999, (long) clock.getInterval()); - // re-enable all that were previously enabled but not explicitly disabled ones + // re-enable all that were previously enabled but not explicitly disabled + // ones random.enable(); sleep(1000); assertTrue("clock should not be started 5", !clock.isClockRunning()); assertTrue(String.format("random method 3 should be %d => 5000 values", clock.getInterval()), 5000 <= clock.getInterval()); - assertTrue(String.format("random method 3 should be %d <= 10000 values",clock.getInterval()) , clock.getInterval() <= 10000); + assertTrue(String.format("random method 3 should be %d <= 10000 values", clock.getInterval()), clock.getInterval() <= 10000); clock.stopClock(); random.purge(); - + Map events = random.getRandomEvents(); assertTrue(events.size() == 0); - + random.addRandom("named task", 200, 500, "clock", "setInterval", 100, 1000, 10); - + clock.releaseService(); random.releaseService(); diff --git a/src/test/java/org/myrobotlab/service/RuntimeProcessTest.java b/src/test/java/org/myrobotlab/service/RuntimeProcessTest.java index 07e1775110..4bdb93fe2c 100644 --- a/src/test/java/org/myrobotlab/service/RuntimeProcessTest.java +++ b/src/test/java/org/myrobotlab/service/RuntimeProcessTest.java @@ -21,12 +21,15 @@ public class RuntimeProcessTest extends AbstractTest { @Before public void setUp() { - // LoggingFactory.init("WARN"); } public boolean contains(ByteArrayOutputStream out, String str) { return new String(out.toByteArray()).contains(str); } + + public String getName() { + return "RuntimeProcessTest"; + } @Test public void cliTest() throws Exception { diff --git a/src/test/java/org/myrobotlab/service/ServoTest.java b/src/test/java/org/myrobotlab/service/ServoTest.java index 8d96052e2e..819c3718d6 100644 --- a/src/test/java/org/myrobotlab/service/ServoTest.java +++ b/src/test/java/org/myrobotlab/service/ServoTest.java @@ -73,7 +73,7 @@ public void autoDisableAfterAttach() { @Test public void disabledMove() throws Exception { // take off speed control - servo.fullSpeed(); + servo.setMaxSpeed(); servo.moveTo(0.0); servo.setInverted(false); Service.sleep(1000); diff --git a/src/test/java/org/myrobotlab/service/VirtualArduinoTest.java b/src/test/java/org/myrobotlab/service/VirtualArduinoTest.java index ba1d028096..110ff1ac4a 100755 --- a/src/test/java/org/myrobotlab/service/VirtualArduinoTest.java +++ b/src/test/java/org/myrobotlab/service/VirtualArduinoTest.java @@ -30,6 +30,10 @@ public Service createService() { VirtualArduino service = (VirtualArduino) Runtime.start("virtualArduino", "VirtualArduino"); return service; } + + public String getName() { + return "VirtualArduinoTest"; + } @Override public void testService() throws Exception { diff --git a/src/test/java/org/myrobotlab/service/WebGuiTest.java b/src/test/java/org/myrobotlab/service/WebGuiTest.java index 643485fc0c..02918dedba 100644 --- a/src/test/java/org/myrobotlab/service/WebGuiTest.java +++ b/src/test/java/org/myrobotlab/service/WebGuiTest.java @@ -5,7 +5,6 @@ import static org.junit.Assert.assertTrue; import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.List; import org.junit.Before; @@ -22,8 +21,8 @@ public class WebGuiTest extends AbstractTest { public final static Logger log = LoggerFactory.getLogger(WebGui.class); - - // FIXME - DO A WEBSOCKET TEST + + // FIXME - DO A WEBSOCKET TEST @Before public void setUp() { @@ -31,11 +30,11 @@ public void setUp() { webgui2.autoStartBrowser(false); webgui2.setPort(8889); webgui2.startService(); - - Runtime.start("servoApiTest","Servo"); + + Runtime.start("servoApiTest", "Servo"); Runtime.start("pythonApiTest", "Python"); // need to wait for the OS to open the port - Service.sleep(3); + Service.sleep(200); } @Test @@ -46,7 +45,7 @@ public void getTest() { String ret = new String(bytes); assertTrue(ret.contains("days")); } - + @Test public void getTestWithParameter() throws UnsupportedEncodingException { @@ -56,13 +55,12 @@ public void getTestWithParameter() throws UnsupportedEncodingException { assertTrue(ret.contains("true")); } - -// FIXME - ADD WHEN POST API IS WORKY -// FIXME object non primitive (no string) post + // FIXME - ADD WHEN POST API IS WORKY + // FIXME object non primitive (no string) post @Test public void postTest() { - + // 1st post - simple input - simple return String postBody = "[\"runtime\"]"; byte[] bytes = Http.post("http://localhost:8889/api/service/runtime/getFullName", postBody); @@ -70,7 +68,7 @@ public void postTest() { assertNotNull(bytes); String ret = new String(bytes); assertTrue(ret.contains("@")); - + // second post - simple input - complex return postBody = "[\"runtime\"]"; bytes = Http.post("http://localhost:8889/api/service/runtime/getService", postBody); @@ -78,29 +76,31 @@ public void postTest() { assertNotNull(bytes); ret = new String(bytes); assertTrue(ret.contains("@")); - - + // second post - simple input (including array of strings) - complex return - // FIXME uncomment when ready - callbacks are not possible through the rest api - // org.myrobotlab.framework.TimeoutException: timeout of 3000 for proxyName@remoteId.toString exceeded - // org.myrobotlab.framework.TimeoutException: timeout of 3000 for proxyName@remoteId.getFullName exceeded -// postBody = "[\"remoteId\", \"proxyName\", \"py:myService\",[\"org.myrobotlab.framework.interfaces.ServiceInterface\"]]"; -// bytes = Http.post("http://localhost:8889/api/service/runtime/register", postBody); -// sleep(200); -// assertNotNull(bytes); -// ret = new String(bytes); -// assertTrue(ret.contains("remoteId")); - - - + // FIXME uncomment when ready - callbacks are not possible through the rest + // api + // org.myrobotlab.framework.TimeoutException: timeout of 3000 for + // proxyName@remoteId.toString exceeded + // org.myrobotlab.framework.TimeoutException: timeout of 3000 for + // proxyName@remoteId.getFullName exceeded + // postBody = "[\"remoteId\", \"proxyName\", + // \"py:myService\",[\"org.myrobotlab.framework.interfaces.ServiceInterface\"]]"; + // bytes = Http.post("http://localhost:8889/api/service/runtime/register", + // postBody); + // sleep(200); + // assertNotNull(bytes); + // ret = new String(bytes); + // assertTrue(ret.contains("remoteId")); + // post non primitive non string object MRLListener listener = new MRLListener("getRegistry", "runtime@webguittest", "onRegistry"); - postBody = "[" + CodecUtils.toJson(listener) + "]"; + postBody = "[" + CodecUtils.toJson(listener) + "]"; // postBody = "[\"runtime\"]"; bytes = Http.post("http://localhost:8889/api/service/runtime/addListener", postBody); sleep(200); assertNotNull(bytes); - + Runtime runtime = Runtime.getInstance(); boolean found = false; List check = runtime.getNotifyList("getRegistry"); @@ -108,9 +108,9 @@ public void postTest() { if (check.get(i).equals(listener)) { found = true; } - } + } assertTrue("listener not found !", found); - + } @Test @@ -138,7 +138,7 @@ public void servoApiTest() { @Test public void urlEncodingTest() { - //exec("print \"hello\"") + // exec("print \"hello\"") byte[] bytes = Http.get("http://localhost:8889/api/service/pythonApiTest/exec/%22print+%5C%22hello%5C%22%22"); String ret = new String(bytes); assertEquals("true", ret); @@ -147,16 +147,19 @@ public void urlEncodingTest() { @Test public void sendBlockingTest() throws InterruptedException, TimeoutException { String retVal = "retVal"; - // Put directly in blocking list because sendBlocking() won't use it for local services + // Put directly in blocking list because sendBlocking() won't use it for + // local + // services Runtime.getInstance().getInbox().blockingList.put("runtime.onBlocking", new Object[1]); Object[] blockingListRet = Runtime.getInstance().getInbox().blockingList.get("runtime.onBlocking"); // Delay in a new thread so we can get our wait() call in first new Thread(() -> { try { - Thread.sleep(50); - } catch (InterruptedException ignored) {} - Http.post("http://localhost:8889/api/service/runtime/onBlocking", "[\""+retVal+"\"]"); + Thread.sleep(100); + } catch (InterruptedException ignored) { + } + Http.post("http://localhost:8889/api/service/runtime/onBlocking", "[\"" + retVal + "\"]"); }).start(); long timeout = 1000; @@ -170,6 +173,5 @@ public void sendBlockingTest() throws InterruptedException, TimeoutException { assertEquals(retVal, blockingListRet[0]); } - - + } diff --git a/src/test/java/org/myrobotlab/test/AbstractTest.java b/src/test/java/org/myrobotlab/test/AbstractTest.java index d782797c9b..7279a8fe98 100644 --- a/src/test/java/org/myrobotlab/test/AbstractTest.java +++ b/src/test/java/org/myrobotlab/test/AbstractTest.java @@ -14,82 +14,61 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Rule; -import org.junit.rules.TestName; +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; import org.myrobotlab.codec.CodecUtils; -import org.myrobotlab.framework.Platform; import org.myrobotlab.framework.interfaces.Attachable; import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.service.Runtime; import org.myrobotlab.service.config.RuntimeConfig; import org.slf4j.Logger; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; - public class AbstractTest { - /** cached network test value for tests */ - static Boolean hasInternet = null; + /** + * cached network test value for tests + */ + protected static Boolean hasInternet = null; + /** + * Install dependencies once per process, same process + * will not check. A new process will use the libraries/serviceData.json + * to determine if deps are satisfied + */ protected static boolean installed = false; - public final static Logger log = LoggerFactory.getLogger(AbstractTest.class); - - static private boolean logWarnTestHeader = false; + protected final static Logger log = LoggerFactory.getLogger(AbstractTest.class); - private static boolean releaseRemainingThreads = false; + protected static transient Set threadSetStart = null; - protected transient Queue queue = new LinkedBlockingQueue<>(); - - static transient Set threadSetStart = null; - - protected Set attached = new HashSet<>(); - - @Rule - public final TestName testName = new TestName(); - - static public String simpleName; - - private static boolean lineFeedFooter = true; - @Rule public TestWatcher watchman = new TestWatcher() { - @Override - protected void starting(Description description) { - System.out.println("Starting: " + description.getClassName() + "." + description.getMethodName()); - } + @Override + protected void starting(Description description) { + System.out.println("Starting: " + description.getClassName() + "." + description.getMethodName()); + } - @Override - protected void succeeded(Description description) { - // System.out.println("Succeeded: " + description.getMethodName()); - } + @Override + protected void succeeded(Description description) { + // System.out.println("Succeeded: " + description.getMethodName()); + } - @Override - protected void failed(Throwable e, Description description) { - System.out.println("Failed: " + description.getMethodName()); - } + @Override + protected void failed(Throwable e, Description description) { + System.out.println("Failed: " + description.getMethodName()); + } - @Override - protected void skipped(org.junit.AssumptionViolatedException e, Description description) { - System.out.println("Skipped: " + description.getMethodName()); - } + @Override + protected void skipped(org.junit.AssumptionViolatedException e, Description description) { + System.out.println("Skipped: " + description.getMethodName()); + } - @Override - protected void finished(Description description) { - System.out.println("Finished: " + description.getMethodName()); - } + @Override + protected void finished(Description description) { + System.out.println("Finished: " + description.getMethodName()); + } }; - public String getSimpleName() { - return simpleName; - } - - public String getName() { - return testName.getMethodName(); - } - static public boolean hasInternet() { if (hasInternet == null) { hasInternet = Runtime.hasInternet(); @@ -120,23 +99,23 @@ public static void main(String[] args) { @BeforeClass public static void setUpAbstractTest() throws Exception { - + // setup runtime resource = src/main/resources/resource File runtimeYml = new File("data/config/default/runtime.yml"); -// if (!runtimeYml.exists()) { - runtimeYml.getParentFile().mkdirs(); - RuntimeConfig rc = new RuntimeConfig(); - rc.resource = "src/main/resources/resource"; - String yml = CodecUtils.toYaml(rc); - - FileOutputStream fos = null; - fos = new FileOutputStream(runtimeYml); - fos.write(yml.getBytes()); - fos.close(); - -// } - - Runtime.getInstance().setVirtual(true); + // if (!runtimeYml.exists()) { + runtimeYml.getParentFile().mkdirs(); + RuntimeConfig rc = new RuntimeConfig(); + rc.resource = "src/main/resources/resource"; + String yml = CodecUtils.toYaml(rc); + + FileOutputStream fos = null; + fos = new FileOutputStream(runtimeYml); + fos.write(yml.getBytes()); + fos.close(); + + // } + + Runtime.getInstance().setVirtual(true); String junitLogLevel = System.getProperty("junit.logLevel"); if (junitLogLevel != null) { @@ -171,16 +150,7 @@ public static void sleep(long sleepTimeMs) { @AfterClass public static void tearDownAbstractTest() throws Exception { log.info("tearDownAbstractTest"); - releaseServices(); - - if (logWarnTestHeader) { - log.warn("=========== finished test {} ===========", simpleName); - } - - if (lineFeedFooter) { - System.out.println(); - } } static protected void installAll() { @@ -197,8 +167,7 @@ static protected void installAll() { */ public static void releaseServices() { - log.info("end of test - id {} remaining services {}", Runtime.getInstance().getId(), - Arrays.toString(Runtime.getServiceNames())); + log.info("end of test - id {} remaining services {}", Runtime.getInstance().getId(), Arrays.toString(Runtime.getServiceNames())); // release all including runtime - be careful of default runtime.yml Runtime.releaseAll(true, true); @@ -212,19 +181,8 @@ public static void releaseServices() { Set threadSetEnd = Thread.getAllStackTraces().keySet(); Set threadsRemaining = new TreeSet<>(); for (Thread thread : threadSetEnd) { - if (!threadSetStart.contains(thread) && !"runtime_outbox_0".equals(thread.getName()) - && !"runtime".equals(thread.getName())) { - if (releaseRemainingThreads) { - log.warn("interrupting thread {}", thread.getName()); - thread.interrupt(); - /* - * if (useDeprecatedThreadStop) { thread.stop(); } - */ - } else { - // log.warn("thread {} marked as straggler - should be killed", - // thread.getName()); + if (!threadSetStart.contains(thread) && !"runtime_outbox_0".equals(thread.getName()) && !"runtime".equals(thread.getName())) { threadsRemaining.add(thread.getName()); - } } } if (threadsRemaining.size() > 0) { @@ -236,13 +194,6 @@ public static void releaseServices() { // Arrays.toString(Runtime.getServiceNames())); } - public AbstractTest() { - simpleName = this.getClass().getSimpleName(); - if (logWarnTestHeader) { - log.info("=========== starting test {} ===========", this.getClass().getSimpleName()); - } - } - public void setVirtual() { Runtime.getInstance().setVirtual(true); } From c6c2f143afaee6e3281cd6b024f5d82358cec3a2 Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 17 Feb 2024 07:06:23 -0800 Subject: [PATCH 067/131] re-adding deprecated ProgramAB.botDir --- .../java/org/myrobotlab/service/config/ProgramABConfig.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/myrobotlab/service/config/ProgramABConfig.java b/src/main/java/org/myrobotlab/service/config/ProgramABConfig.java index 0cd4dbc839..95d5f4a0e3 100644 --- a/src/main/java/org/myrobotlab/service/config/ProgramABConfig.java +++ b/src/main/java/org/myrobotlab/service/config/ProgramABConfig.java @@ -10,6 +10,9 @@ public class ProgramABConfig extends ServiceConfig { @Deprecated /* unused text filters */ public String[] textFilters; + @Deprecated /* unnecessary and unwanted - specify bots directly */ + public String botDir; + /** * explicit bot directories */ From 4a6957433e123b8b15590fa4dfb8115ad0de382b Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 17 Feb 2024 07:25:06 -0800 Subject: [PATCH 068/131] npe fix for runtime.apply(c) --- src/main/java/org/myrobotlab/service/Runtime.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 3d3697284a..9ae1c8a17b 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -911,14 +911,10 @@ public static Runtime getInstance() { // extract resources "if a jar" FileIO.extractResources(); runtime.startInteractiveMode(); - - if (Runtime.options.install != null) { - // minimal processed runtime - return it - return runtime; + if (c != null) { + runtime.apply(c); } - runtime.apply(c); - if (options.services != null) { log.info("command line override for services created"); createAndStartServices(options.services); From 6e02e9fd40dbbe44037562b9cb89e54c3b93a7e6 Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 17 Feb 2024 07:25:48 -0800 Subject: [PATCH 069/131] npe fix for runtime.apply(c) --- src/main/java/org/myrobotlab/service/Runtime.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 3d3697284a..9ae1c8a17b 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -911,14 +911,10 @@ public static Runtime getInstance() { // extract resources "if a jar" FileIO.extractResources(); runtime.startInteractiveMode(); - - if (Runtime.options.install != null) { - // minimal processed runtime - return it - return runtime; + if (c != null) { + runtime.apply(c); } - runtime.apply(c); - if (options.services != null) { log.info("command line override for services created"); createAndStartServices(options.services); From 76c8b00bf0fbae71589778d8b07afe019c5be2d2 Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 17 Feb 2024 07:44:51 -0800 Subject: [PATCH 070/131] updated javacpp to 1.5.8 and updated template --- pom.xml | 25 ++----------------- .../resource/framework/pom.xml.template | 23 +++++++++-------- 2 files changed, 14 insertions(+), 34 deletions(-) diff --git a/pom.xml b/pom.xml index 9b89a805fc..fb8bc15b6e 100644 --- a/pom.xml +++ b/pom.xml @@ -484,10 +484,6 @@ - - - - jfugue @@ -1079,10 +1075,10 @@ org.bytedeco javacv-platform - 1.5.7 + 1.5.8 provided - + @@ -1557,15 +1553,6 @@ - - - org.tensorflow - tensorflow - 1.8.0 - provided - - - org.bytedeco @@ -1690,10 +1677,6 @@ - - - - com.github.sarxos @@ -1751,10 +1734,6 @@ - - - - org.igniterealtime.smack diff --git a/src/main/resources/resource/framework/pom.xml.template b/src/main/resources/resource/framework/pom.xml.template index ca584c5ba0..29e5f21eb9 100644 --- a/src/main/resources/resource/framework/pom.xml.template +++ b/src/main/resources/resource/framework/pom.xml.template @@ -83,7 +83,7 @@ ${maven.build.timestamp} yyyyMMddHHmm - ${project.version} + ${version} ${git.branch} ${NODE_NAME} ${NODE_LABELS} @@ -193,7 +193,7 @@ myrobotlab - + true myrobotlab-full false @@ -207,10 +207,10 @@ implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> org.myrobotlab.service.Runtime - ${project.version} - ${project.version} + ${version} + ${version} - ${project.version} + ${version} ${maven.build.timestamp} ${agent.name} ${user.name} @@ -331,20 +331,21 @@ maven-surefire-plugin org.apache.maven.plugins - 2.18 + 3.2.2 - ${argLine} -Djava.library.path=libraries/native -Djna.library.path=libraries/native + ${argLine} -Djava.library.path=libraries/native + -Djna.library.path=libraries/native **/*Test.java **/integration/* - **/OpenCV* - - + + @@ -425,7 +426,7 @@ org.apache.maven.plugins maven-surefire-report-plugin - 2.18 + 3.2.2 org.apache.maven.plugins From 5caf15d9ae8c44e5bba62f2d14b4da84bce87449 Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 17 Feb 2024 07:51:10 -0800 Subject: [PATCH 071/131] synching javacpp 1.5.8 updating template --- pom.xml | 25 ++----------------- .../resource/framework/pom.xml.template | 23 +++++++++-------- 2 files changed, 14 insertions(+), 34 deletions(-) diff --git a/pom.xml b/pom.xml index 9b89a805fc..fb8bc15b6e 100644 --- a/pom.xml +++ b/pom.xml @@ -484,10 +484,6 @@ - - - - jfugue @@ -1079,10 +1075,10 @@ org.bytedeco javacv-platform - 1.5.7 + 1.5.8 provided - + @@ -1557,15 +1553,6 @@ - - - org.tensorflow - tensorflow - 1.8.0 - provided - - - org.bytedeco @@ -1690,10 +1677,6 @@ - - - - com.github.sarxos @@ -1751,10 +1734,6 @@ - - - - org.igniterealtime.smack diff --git a/src/main/resources/resource/framework/pom.xml.template b/src/main/resources/resource/framework/pom.xml.template index ca584c5ba0..29e5f21eb9 100644 --- a/src/main/resources/resource/framework/pom.xml.template +++ b/src/main/resources/resource/framework/pom.xml.template @@ -83,7 +83,7 @@ ${maven.build.timestamp} yyyyMMddHHmm - ${project.version} + ${version} ${git.branch} ${NODE_NAME} ${NODE_LABELS} @@ -193,7 +193,7 @@ myrobotlab - + true myrobotlab-full false @@ -207,10 +207,10 @@ implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> org.myrobotlab.service.Runtime - ${project.version} - ${project.version} + ${version} + ${version} - ${project.version} + ${version} ${maven.build.timestamp} ${agent.name} ${user.name} @@ -331,20 +331,21 @@ maven-surefire-plugin org.apache.maven.plugins - 2.18 + 3.2.2 - ${argLine} -Djava.library.path=libraries/native -Djna.library.path=libraries/native + ${argLine} -Djava.library.path=libraries/native + -Djna.library.path=libraries/native **/*Test.java **/integration/* - **/OpenCV* - - + + @@ -425,7 +426,7 @@ org.apache.maven.plugins maven-surefire-report-plugin - 2.18 + 3.2.2 org.apache.maven.plugins From 46f2f274c4913779b7c85c44dcb7a3a6b572056d Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 17 Feb 2024 08:07:09 -0800 Subject: [PATCH 072/131] syching javacpp 1.5.8 tesseract and deeplearning4j --- pom.xml | 6 +++--- .../org/myrobotlab/service/meta/Deeplearning4jMeta.java | 2 +- .../java/org/myrobotlab/service/meta/TesseractOcrMeta.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index fb8bc15b6e..77ddf5a516 100644 --- a/pom.xml +++ b/pom.xml @@ -215,7 +215,7 @@ org.bytedeco javacpp - 1.5.7 + 1.5.8 provided @@ -1557,13 +1557,13 @@ org.bytedeco tesseract - 5.0.1-1.5.7 + 5.2.0-1.5.8 provided org.bytedeco tesseract-platform - 5.0.1-1.5.7 + 5.2.0-1.5.8 provided diff --git a/src/main/java/org/myrobotlab/service/meta/Deeplearning4jMeta.java b/src/main/java/org/myrobotlab/service/meta/Deeplearning4jMeta.java index 56fe4f8ad5..23fc4aeff8 100644 --- a/src/main/java/org/myrobotlab/service/meta/Deeplearning4jMeta.java +++ b/src/main/java/org/myrobotlab/service/meta/Deeplearning4jMeta.java @@ -23,7 +23,7 @@ public Deeplearning4jMeta() { addCategory("ai"); // Force javacpp 1.5.3 to resolve conflict between dl4j and javacv - addDependency("org.bytedeco", "javacpp", "1.5.7"); + addDependency("org.bytedeco", "javacpp", "1.5.8"); // REMOVED FOR COLLISION // addDependency("org.bytedeco", "openblas", "0.3.17-" + "1.5.6"); diff --git a/src/main/java/org/myrobotlab/service/meta/TesseractOcrMeta.java b/src/main/java/org/myrobotlab/service/meta/TesseractOcrMeta.java index 5099e60d79..8c8d9a2554 100644 --- a/src/main/java/org/myrobotlab/service/meta/TesseractOcrMeta.java +++ b/src/main/java/org/myrobotlab/service/meta/TesseractOcrMeta.java @@ -14,7 +14,7 @@ public class TesseractOcrMeta extends MetaData { */ public TesseractOcrMeta() { - String tesseractVersion = "5.0.1-1.5.7"; + String tesseractVersion = "5.2.0-1.5.8"; addDescription("Optical character recognition - the ability to read"); addCategory("ai", "vision"); addDependency("org.bytedeco", "tesseract", tesseractVersion); From 1851976911325868cc418fd1a8cf2f35eee17e11 Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 17 Feb 2024 08:09:43 -0800 Subject: [PATCH 073/131] synching javacpp 1.5.8 with deeplearning4j and tesseract --- pom.xml | 6 +++--- .../org/myrobotlab/service/meta/Deeplearning4jMeta.java | 2 +- .../java/org/myrobotlab/service/meta/TesseractOcrMeta.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index fb8bc15b6e..77ddf5a516 100644 --- a/pom.xml +++ b/pom.xml @@ -215,7 +215,7 @@ org.bytedeco javacpp - 1.5.7 + 1.5.8 provided @@ -1557,13 +1557,13 @@ org.bytedeco tesseract - 5.0.1-1.5.7 + 5.2.0-1.5.8 provided org.bytedeco tesseract-platform - 5.0.1-1.5.7 + 5.2.0-1.5.8 provided diff --git a/src/main/java/org/myrobotlab/service/meta/Deeplearning4jMeta.java b/src/main/java/org/myrobotlab/service/meta/Deeplearning4jMeta.java index 56fe4f8ad5..23fc4aeff8 100644 --- a/src/main/java/org/myrobotlab/service/meta/Deeplearning4jMeta.java +++ b/src/main/java/org/myrobotlab/service/meta/Deeplearning4jMeta.java @@ -23,7 +23,7 @@ public Deeplearning4jMeta() { addCategory("ai"); // Force javacpp 1.5.3 to resolve conflict between dl4j and javacv - addDependency("org.bytedeco", "javacpp", "1.5.7"); + addDependency("org.bytedeco", "javacpp", "1.5.8"); // REMOVED FOR COLLISION // addDependency("org.bytedeco", "openblas", "0.3.17-" + "1.5.6"); diff --git a/src/main/java/org/myrobotlab/service/meta/TesseractOcrMeta.java b/src/main/java/org/myrobotlab/service/meta/TesseractOcrMeta.java index 5099e60d79..8c8d9a2554 100644 --- a/src/main/java/org/myrobotlab/service/meta/TesseractOcrMeta.java +++ b/src/main/java/org/myrobotlab/service/meta/TesseractOcrMeta.java @@ -14,7 +14,7 @@ public class TesseractOcrMeta extends MetaData { */ public TesseractOcrMeta() { - String tesseractVersion = "5.0.1-1.5.7"; + String tesseractVersion = "5.2.0-1.5.8"; addDescription("Optical character recognition - the ability to read"); addCategory("ai", "vision"); addDependency("org.bytedeco", "tesseract", tesseractVersion); From d7fad5a5a8ce192e92709fded2f623ca0d17cd23 Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 17 Feb 2024 08:17:23 -0800 Subject: [PATCH 074/131] changed imports on tesseract --- src/main/java/org/myrobotlab/service/TesseractOcr.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/TesseractOcr.java b/src/main/java/org/myrobotlab/service/TesseractOcr.java index b444ceadec..180801d75c 100644 --- a/src/main/java/org/myrobotlab/service/TesseractOcr.java +++ b/src/main/java/org/myrobotlab/service/TesseractOcr.java @@ -1,7 +1,7 @@ package org.myrobotlab.service; -import static org.bytedeco.leptonica.global.lept.pixDestroy; -import static org.bytedeco.leptonica.global.lept.pixRead; +import static org.bytedeco.leptonica.global.leptonica.pixDestroy; +import static org.bytedeco.leptonica.global.leptonica.pixRead; import java.awt.image.BufferedImage; import java.io.File; From 2e6c89c31ca97090df9b082e448d309985db0c36 Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 17 Feb 2024 08:17:59 -0800 Subject: [PATCH 075/131] changed imports on tesseract --- src/main/java/org/myrobotlab/service/TesseractOcr.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/TesseractOcr.java b/src/main/java/org/myrobotlab/service/TesseractOcr.java index b444ceadec..180801d75c 100644 --- a/src/main/java/org/myrobotlab/service/TesseractOcr.java +++ b/src/main/java/org/myrobotlab/service/TesseractOcr.java @@ -1,7 +1,7 @@ package org.myrobotlab.service; -import static org.bytedeco.leptonica.global.lept.pixDestroy; -import static org.bytedeco.leptonica.global.lept.pixRead; +import static org.bytedeco.leptonica.global.leptonica.pixDestroy; +import static org.bytedeco.leptonica.global.leptonica.pixRead; import java.awt.image.BufferedImage; import java.io.File; From 72903143d98dff1013ffdb455e7e62f879bf02e6 Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 17 Feb 2024 08:55:52 -0800 Subject: [PATCH 076/131] fixed test - was counting threads after new runtime started --- src/test/java/org/myrobotlab/test/AbstractTest.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/myrobotlab/test/AbstractTest.java b/src/test/java/org/myrobotlab/test/AbstractTest.java index 7279a8fe98..69e0b611a0 100644 --- a/src/test/java/org/myrobotlab/test/AbstractTest.java +++ b/src/test/java/org/myrobotlab/test/AbstractTest.java @@ -173,8 +173,6 @@ public static void releaseServices() { Runtime.releaseAll(true, true); // wait for draining threads sleep(100); - // resets runtime with fresh new instance - Runtime.getInstance(); // check threads - kill stragglers // Set stragglers = new HashSet(); @@ -189,9 +187,9 @@ public static void releaseServices() { log.warn("{} straggling threads remain [{}]", threadsRemaining.size(), String.join(",", threadsRemaining)); } - // log.warn("end of test - id {} remaining services after release {}", - // Platform.getLocalInstance().getId(), - // Arrays.toString(Runtime.getServiceNames())); + // resets runtime with fresh new instance + Runtime.getInstance(); + } public void setVirtual() { From 9e1710ad742f0363c235d136b5c1dbf1bf198950 Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 17 Feb 2024 09:47:15 -0800 Subject: [PATCH 077/131] more unit test cleanup --- .../org/myrobotlab/service/AudioFile.java | 8 ++++ .../java/org/myrobotlab/service/NeoPixel.java | 1 + .../service/ServiceInterfaceTest.java | 37 ++++++++++--------- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/AudioFile.java b/src/main/java/org/myrobotlab/service/AudioFile.java index 3997f6960e..dbf2131bcf 100644 --- a/src/main/java/org/myrobotlab/service/AudioFile.java +++ b/src/main/java/org/myrobotlab/service/AudioFile.java @@ -384,6 +384,14 @@ public List getFiles(String subDir, boolean recurse) { return new ArrayList(); } + @Override + public void releaseService() { + super.releaseService(); + for (AudioProcessor processor: processors.values()) { + processor.stopPlaying(); + } + } + public AudioData repeat(String filename) { return repeat(filename, -1); } diff --git a/src/main/java/org/myrobotlab/service/NeoPixel.java b/src/main/java/org/myrobotlab/service/NeoPixel.java index 21a05cbdc5..a5a22c4782 100644 --- a/src/main/java/org/myrobotlab/service/NeoPixel.java +++ b/src/main/java/org/myrobotlab/service/NeoPixel.java @@ -810,6 +810,7 @@ public void playIronman() { public void releaseService() { super.releaseService(); clear(); + worker.stop(); } @Override diff --git a/src/test/java/org/myrobotlab/service/ServiceInterfaceTest.java b/src/test/java/org/myrobotlab/service/ServiceInterfaceTest.java index 806985daa6..6f5c117b03 100644 --- a/src/test/java/org/myrobotlab/service/ServiceInterfaceTest.java +++ b/src/test/java/org/myrobotlab/service/ServiceInterfaceTest.java @@ -56,7 +56,7 @@ private boolean serviceHasWebPage(String service) { private boolean serviceInterfaceTest(String service) throws IOException { // see if we can start/stop and release the service. - + // set a configuration path Runtime.setConfig("serviceInterfaceTest"); @@ -65,9 +65,9 @@ private boolean serviceInterfaceTest(String service) throws IOException { log.warn("Runtime Create returned a null service for {}", service); return false; } - System.out.println("Service Test:" + service); + System.out.println("ServiceInterface Test:" + service); - if (service.equals("As5048AEncoder")){ + if (service.equals("As5048AEncoder")) { log.info("here"); } @@ -85,7 +85,7 @@ private boolean serviceInterfaceTest(String service) throws IOException { foo.startService(); foo.save(); // foo.load(); SHOULD NOT BE USED ! - // foo.apply(); <- THIS SHOULD BE IMPLEMENTED + // foo.apply(); <- THIS SHOULD BE IMPLEMENTED foo.stopService(); foo.releaseService(); @@ -103,9 +103,9 @@ public final void testAllServices() throws ClassNotFoundException, IOException { ArrayList servicesNotInServiceDataJson = new ArrayList(); HashSet blacklist = new HashSet(); - blacklist.add("OpenNi"); - blacklist.add("As5048AEncoder"); - blacklist.add("IntegratedMovement"); + blacklist.add("OpenNi"); + blacklist.add("As5048AEncoder"); + blacklist.add("IntegratedMovement"); blacklist.add("VirtualDevice"); blacklist.add("Joystick"); blacklist.add("GoogleAssistant"); @@ -145,8 +145,9 @@ public final void testAllServices() throws ClassNotFoundException, IOException { // FIXME - must have different thread (prefix script) which runs a timer - // script REQUIRED to complete in 4 minutes ... or BOOM it fails - // sts.clear(); - // sts.add(sd.getServiceType("org.myrobotlab.service.InMoov")); + // USEFUL FOR DEBUGGING SINGLE SERVICE +// sts.clear(); +// sts.add(ServiceData.getMetaData("org.myrobotlab.service.NeoPixel")); for (MetaData serviceType : sts) { // test single service @@ -164,7 +165,7 @@ public final void testAllServices() throws ClassNotFoundException, IOException { continue; } // log.info("Testing Service: {}", service); - + System.out.println("testing " + service); MetaData st = ServiceData.getMetaData("org.myrobotlab.service." + service); @@ -222,14 +223,14 @@ public final void testAllServices() throws ClassNotFoundException, IOException { } - log.info("----------------------------------------------"); - log.info("Service Report"); - log.info("Number of Services: {}", numServices); - log.info("Number of Startable Services: {}", numStartable); - log.info("Number of Services Pages {}", numServicePages); - log.info("Number of Scripts: {}", numScripts); - log.info("Number of Scripts Worky: {}", numScriptsWorky); - log.info("----------------------------------------------"); + System.out.println("----------------------------------------------"); + System.out.println("Service Report"); + System.out.println(String.format("Number of Services: %d", numServices)); + System.out.println(String.format("Number of Startable Services: %d", numStartable)); + System.out.println(String.format("Number of Services Pages %d", numServicePages)); + System.out.println(String.format("Number of Scripts: %d", numScripts)); + System.out.println(String.format("Number of Scripts Worky: %d", numScriptsWorky)); + System.out.println("----------------------------------------------"); for (String s : servicesThatDontStartProperly) { log.warn("FAILED ON START:" + s); From 1fa4e6231ac999b8cb12ab34ccb1a6a499e5d1ba Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 17 Feb 2024 11:21:39 -0800 Subject: [PATCH 078/131] requested fixes --- src/main/java/org/myrobotlab/config/ConfigUtils.java | 2 +- src/main/java/org/myrobotlab/framework/Service.java | 2 +- src/main/java/org/myrobotlab/service/Runtime.java | 7 +++++++ src/main/java/org/myrobotlab/service/Serial.java | 4 ++-- src/main/java/org/myrobotlab/service/VirtualArduino.java | 1 - .../java/org/myrobotlab/service/config/InMoov2Config.java | 7 ++++--- src/test/java/org/myrobotlab/service/VertxTest.java | 2 +- 7 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/myrobotlab/config/ConfigUtils.java b/src/main/java/org/myrobotlab/config/ConfigUtils.java index 69f850e602..7b793452ac 100644 --- a/src/main/java/org/myrobotlab/config/ConfigUtils.java +++ b/src/main/java/org/myrobotlab/config/ConfigUtils.java @@ -97,7 +97,7 @@ public static StartYml loadStartYml() { try { FileIO.toFile("start.yml", defaultStartFile); } catch (IOException e) { - log.error("could not save start.yml"); + log.error("could not save start.yml", e); } } else { // load start.yml diff --git a/src/main/java/org/myrobotlab/framework/Service.java b/src/main/java/org/myrobotlab/framework/Service.java index 3f7acbf755..682acebbc5 100644 --- a/src/main/java/org/myrobotlab/framework/Service.java +++ b/src/main/java/org/myrobotlab/framework/Service.java @@ -510,7 +510,7 @@ public String getResourcePath(String additionalPath) { */ static public String getResourceRoot() { - return ConfigUtils.getResourceRoot();//Runtime.getInstance().getConfig().resource; + return ConfigUtils.getResourceRoot(); } /** diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 9ae1c8a17b..9b76d3bf65 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -1549,6 +1549,11 @@ static public void install(String serviceType, Boolean blocking) { if (blocking == null) { blocking = false; } + + if (installerThread != null) { + log.error("another request to install dependencies, 1st request has not completed"); + return; + } installerThread = new Thread() { @Override @@ -1571,6 +1576,8 @@ public void run() { } else { installerThread.start(); } + + installerThread = null; } } diff --git a/src/main/java/org/myrobotlab/service/Serial.java b/src/main/java/org/myrobotlab/service/Serial.java index c6fccb9d84..a263429144 100644 --- a/src/main/java/org/myrobotlab/service/Serial.java +++ b/src/main/java/org/myrobotlab/service/Serial.java @@ -1120,8 +1120,8 @@ public void stopRecording() { } @Override - public void stopService() { - super.stopService(); + public void releaseService() { + super.releaseService(); disconnect(); stopRecording(); } diff --git a/src/main/java/org/myrobotlab/service/VirtualArduino.java b/src/main/java/org/myrobotlab/service/VirtualArduino.java index f1879aa5b6..54671dc8e2 100644 --- a/src/main/java/org/myrobotlab/service/VirtualArduino.java +++ b/src/main/java/org/myrobotlab/service/VirtualArduino.java @@ -260,7 +260,6 @@ public void releaseService() { } // sleep(300); disconnect(); - super.releaseService(); } public Serial getSerial() { diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index 889e91eec9..1e884c1e4a 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -188,6 +188,7 @@ public Plan getDefault(Plan plan, String name) { addDefaultPeerConfig(plan, name, "openWeatherMap", "OpenWeatherMap", false); addDefaultPeerConfig(plan, name, "pid", "Pid", false); addDefaultPeerConfig(plan, name, "pir", "Pir", false); + addDefaultGlobalConfig(plan, "python", "python", "Python"); addDefaultPeerConfig(plan, name, "py4j", "Py4j", false); addDefaultPeerConfig(plan, name, "random", "Random", false); addDefaultPeerConfig(plan, name, "right", "Arduino", false); @@ -370,7 +371,7 @@ public Plan getDefault(Plan plan, String name) { // exists ? fsm.current = "boot"; fsm.transitions.add(new Transition("boot", "wake", "wake")); - // fsm.transitions.add(new Transition("wake", "idle", "idle")); wake, setup, nor sleep should be affected by idle + // setup, nor sleep should be affected by idle fsm.transitions.add(new Transition("setup", "setup_done", "idle")); fsm.transitions.add(new Transition("idle", "random", "random")); fsm.transitions.add(new Transition("random", "idle", "idle")); @@ -528,9 +529,9 @@ public Plan getDefault(Plan plan, String name) { listeners.add(new Listener("publishStopAnimation", getPeerName("neoPixel"))); // listeners.add(new Listener("publishProcessMessage", // getPeerName("python"), "onPythonMessage")); - listeners.add(new Listener("publishProcessMessage", "python", "onPythonMessage")); + listeners.add(new Listener("publishProcessMessage", getPeerName("python"), "onPythonMessage")); - listeners.add(new Listener("publishPython", "python")); + listeners.add(new Listener("publishPython", getPeerName("python"))); // InMoov2 --to--> InMoov2 listeners.add(new Listener("publishMoveHead", getPeerName("head"), "onMove")); diff --git a/src/test/java/org/myrobotlab/service/VertxTest.java b/src/test/java/org/myrobotlab/service/VertxTest.java index eba95ee828..f0ac18e022 100644 --- a/src/test/java/org/myrobotlab/service/VertxTest.java +++ b/src/test/java/org/myrobotlab/service/VertxTest.java @@ -58,7 +58,7 @@ public void getTest() { assertNotNull(bytes); String ret = new String(bytes); assertTrue(ret.contains("days")); - System.out.println(String.format("%d", i)); + log.info(String.format("%d", i)); } } From 2dbde9107082ee9a6a1eda8000113293bdff75da Mon Sep 17 00:00:00 2001 From: grog Date: Sat, 17 Feb 2024 11:25:04 -0800 Subject: [PATCH 079/131] requested fixes --- src/main/java/org/myrobotlab/config/ConfigUtils.java | 2 +- src/main/java/org/myrobotlab/framework/Service.java | 2 +- src/main/java/org/myrobotlab/service/Runtime.java | 7 +++++++ src/main/java/org/myrobotlab/service/Serial.java | 4 ++-- src/main/java/org/myrobotlab/service/VirtualArduino.java | 1 - .../java/org/myrobotlab/service/config/InMoov2Config.java | 7 ++++--- src/test/java/org/myrobotlab/service/VertxTest.java | 2 +- 7 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/myrobotlab/config/ConfigUtils.java b/src/main/java/org/myrobotlab/config/ConfigUtils.java index 69f850e602..7b793452ac 100644 --- a/src/main/java/org/myrobotlab/config/ConfigUtils.java +++ b/src/main/java/org/myrobotlab/config/ConfigUtils.java @@ -97,7 +97,7 @@ public static StartYml loadStartYml() { try { FileIO.toFile("start.yml", defaultStartFile); } catch (IOException e) { - log.error("could not save start.yml"); + log.error("could not save start.yml", e); } } else { // load start.yml diff --git a/src/main/java/org/myrobotlab/framework/Service.java b/src/main/java/org/myrobotlab/framework/Service.java index 3f7acbf755..682acebbc5 100644 --- a/src/main/java/org/myrobotlab/framework/Service.java +++ b/src/main/java/org/myrobotlab/framework/Service.java @@ -510,7 +510,7 @@ public String getResourcePath(String additionalPath) { */ static public String getResourceRoot() { - return ConfigUtils.getResourceRoot();//Runtime.getInstance().getConfig().resource; + return ConfigUtils.getResourceRoot(); } /** diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 9ae1c8a17b..9b76d3bf65 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -1549,6 +1549,11 @@ static public void install(String serviceType, Boolean blocking) { if (blocking == null) { blocking = false; } + + if (installerThread != null) { + log.error("another request to install dependencies, 1st request has not completed"); + return; + } installerThread = new Thread() { @Override @@ -1571,6 +1576,8 @@ public void run() { } else { installerThread.start(); } + + installerThread = null; } } diff --git a/src/main/java/org/myrobotlab/service/Serial.java b/src/main/java/org/myrobotlab/service/Serial.java index c6fccb9d84..a263429144 100644 --- a/src/main/java/org/myrobotlab/service/Serial.java +++ b/src/main/java/org/myrobotlab/service/Serial.java @@ -1120,8 +1120,8 @@ public void stopRecording() { } @Override - public void stopService() { - super.stopService(); + public void releaseService() { + super.releaseService(); disconnect(); stopRecording(); } diff --git a/src/main/java/org/myrobotlab/service/VirtualArduino.java b/src/main/java/org/myrobotlab/service/VirtualArduino.java index f1879aa5b6..54671dc8e2 100644 --- a/src/main/java/org/myrobotlab/service/VirtualArduino.java +++ b/src/main/java/org/myrobotlab/service/VirtualArduino.java @@ -260,7 +260,6 @@ public void releaseService() { } // sleep(300); disconnect(); - super.releaseService(); } public Serial getSerial() { diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index 889e91eec9..1e884c1e4a 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -188,6 +188,7 @@ public Plan getDefault(Plan plan, String name) { addDefaultPeerConfig(plan, name, "openWeatherMap", "OpenWeatherMap", false); addDefaultPeerConfig(plan, name, "pid", "Pid", false); addDefaultPeerConfig(plan, name, "pir", "Pir", false); + addDefaultGlobalConfig(plan, "python", "python", "Python"); addDefaultPeerConfig(plan, name, "py4j", "Py4j", false); addDefaultPeerConfig(plan, name, "random", "Random", false); addDefaultPeerConfig(plan, name, "right", "Arduino", false); @@ -370,7 +371,7 @@ public Plan getDefault(Plan plan, String name) { // exists ? fsm.current = "boot"; fsm.transitions.add(new Transition("boot", "wake", "wake")); - // fsm.transitions.add(new Transition("wake", "idle", "idle")); wake, setup, nor sleep should be affected by idle + // setup, nor sleep should be affected by idle fsm.transitions.add(new Transition("setup", "setup_done", "idle")); fsm.transitions.add(new Transition("idle", "random", "random")); fsm.transitions.add(new Transition("random", "idle", "idle")); @@ -528,9 +529,9 @@ public Plan getDefault(Plan plan, String name) { listeners.add(new Listener("publishStopAnimation", getPeerName("neoPixel"))); // listeners.add(new Listener("publishProcessMessage", // getPeerName("python"), "onPythonMessage")); - listeners.add(new Listener("publishProcessMessage", "python", "onPythonMessage")); + listeners.add(new Listener("publishProcessMessage", getPeerName("python"), "onPythonMessage")); - listeners.add(new Listener("publishPython", "python")); + listeners.add(new Listener("publishPython", getPeerName("python"))); // InMoov2 --to--> InMoov2 listeners.add(new Listener("publishMoveHead", getPeerName("head"), "onMove")); diff --git a/src/test/java/org/myrobotlab/service/VertxTest.java b/src/test/java/org/myrobotlab/service/VertxTest.java index eba95ee828..f0ac18e022 100644 --- a/src/test/java/org/myrobotlab/service/VertxTest.java +++ b/src/test/java/org/myrobotlab/service/VertxTest.java @@ -58,7 +58,7 @@ public void getTest() { assertNotNull(bytes); String ret = new String(bytes); assertTrue(ret.contains("days")); - System.out.println(String.format("%d", i)); + log.info(String.format("%d", i)); } } From a032e8e3758fe4384d05504242c95c46e5b6a84e Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 18 Feb 2024 12:18:33 -0800 Subject: [PATCH 080/131] channels for discordbot and programab --- .../org/myrobotlab/service/DiscordBot.java | 22 ++++++++++++++++-- .../org/myrobotlab/service/ProgramAB.java | 10 ++++++++ .../service/config/ProgramABConfig.java | 8 +++++++ .../service/interfaces/UtteranceListener.java | 23 +++++++++++++++++++ .../interfaces/UtterancePublisher.java | 19 ++++++++++++++- 5 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/DiscordBot.java b/src/main/java/org/myrobotlab/service/DiscordBot.java index f3aa3560cf..3a52145523 100644 --- a/src/main/java/org/myrobotlab/service/DiscordBot.java +++ b/src/main/java/org/myrobotlab/service/DiscordBot.java @@ -1,7 +1,6 @@ package org.myrobotlab.service; import java.util.List; -import java.util.Set; import org.myrobotlab.discord.MrlDiscordBotListener; import org.myrobotlab.framework.Service; @@ -9,7 +8,6 @@ import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.logging.LoggingFactory; import org.myrobotlab.service.config.DiscordBotConfig; -import org.myrobotlab.service.config.ServiceConfig; import org.myrobotlab.service.data.ImageData; import org.myrobotlab.service.data.Utterance; import org.myrobotlab.service.interfaces.ImageListener; @@ -86,6 +84,10 @@ public void attach(Attachable attachable) { attachUtteranceListener(attachable.getName()); } + if (attachable instanceof UtterancePublisher) { + attachUtterancePublisher(attachable.getName()); + } + if (attachable instanceof ImagePublisher) { attachImagePublisher(attachable.getName()); } @@ -95,6 +97,22 @@ public void attach(Attachable attachable) { } } + @Override + public void detach(Attachable attachable) { + if (attachable instanceof UtteranceListener) { + detachUtteranceListener(attachable.getName()); + } + + if (attachable instanceof UtterancePublisher) { + detachUtterancePublisher(attachable.getName()); + } + + if (attachable instanceof ImagePublisher) { + detachImagePublisher(attachable.getName()); + } + + } + @Override public DiscordBotConfig getConfig() { super.getConfig(); diff --git a/src/main/java/org/myrobotlab/service/ProgramAB.java b/src/main/java/org/myrobotlab/service/ProgramAB.java index 63dc903174..6b0aad8f00 100644 --- a/src/main/java/org/myrobotlab/service/ProgramAB.java +++ b/src/main/java/org/myrobotlab/service/ProgramAB.java @@ -1349,6 +1349,16 @@ public void onUtterance(Utterance utterance) throws Exception { if (!config.sleep) { shouldIRespond = true; } + + if (config.channels != null && config.channels.size() > 0) { + // assume false + shouldIRespond = false; + for (String channelName : config.channels) { + if (channelName.equals(utterance.channelName)) { + shouldIRespond = true; + } + } + } } } diff --git a/src/main/java/org/myrobotlab/service/config/ProgramABConfig.java b/src/main/java/org/myrobotlab/service/config/ProgramABConfig.java index 0cd4dbc839..168e5550fd 100644 --- a/src/main/java/org/myrobotlab/service/config/ProgramABConfig.java +++ b/src/main/java/org/myrobotlab/service/config/ProgramABConfig.java @@ -35,6 +35,14 @@ public class ProgramABConfig extends ServiceConfig { */ public boolean sleep = false; + + /** + * Specific list of channels ProgramAB will respond to, if not defined, then + * ProgramAB will respond to all channels + */ + public List channels = new ArrayList<>(); + + /** * topic to start with, if null then topic will be loaded from predicates of * a new session if available, this means a config/{username}.predicates.txt diff --git a/src/main/java/org/myrobotlab/service/interfaces/UtteranceListener.java b/src/main/java/org/myrobotlab/service/interfaces/UtteranceListener.java index 9cbee1a146..041c8928f1 100755 --- a/src/main/java/org/myrobotlab/service/interfaces/UtteranceListener.java +++ b/src/main/java/org/myrobotlab/service/interfaces/UtteranceListener.java @@ -11,5 +11,28 @@ public interface UtteranceListener { public String getName(); public void onUtterance(Utterance utterance) throws Exception; + + + default public void attachUtterancePublisher(UtterancePublisher publisher) { + attachUtterancePublisher(publisher.getName()); + } + + // Default way to attach an image listener so implementing classes need + // not worry about these details. + default public void attachUtterancePublisher(String name) { + send(name, "attachUtteranceListener", getName()); + } + + default public void detachUtterancePublisher(UtterancePublisher publisher) { + detachUtterancePublisher(publisher.getName()); + } + + // Default way to attach an image listener so implementing classes need + // not worry about these details. + default public void detachUtterancePublisher(String name) { + send(name, "detachUtteranceListener", getName()); + } + + public void send(String name, String method, Object... data); } diff --git a/src/main/java/org/myrobotlab/service/interfaces/UtterancePublisher.java b/src/main/java/org/myrobotlab/service/interfaces/UtterancePublisher.java index ec467c6c61..330144fe54 100755 --- a/src/main/java/org/myrobotlab/service/interfaces/UtterancePublisher.java +++ b/src/main/java/org/myrobotlab/service/interfaces/UtterancePublisher.java @@ -1,5 +1,6 @@ package org.myrobotlab.service.interfaces; +import org.myrobotlab.framework.interfaces.NameProvider; import org.myrobotlab.service.data.Utterance; /** @@ -9,7 +10,7 @@ * * */ -public interface UtterancePublisher { +public interface UtterancePublisher extends NameProvider { // These are all the methods that the utterance publisher should produce. public static String[] publishMethods = new String[] { "publishUtterance" }; @@ -25,8 +26,24 @@ default public void attachUtteranceListener(String name) { addListener(publishMethod, name); } } + + default public void detachUtteranceListener(UtteranceListener display) { + detachUtteranceListener(display.getName()); + } + + // Default way to attach an image listener so implementing classes need + // not worry about these details. + default public void detachUtteranceListener(String name) { + for (String publishMethod : UtterancePublisher.publishMethods) { + removeListener(publishMethod, name); + } + } + // Add the addListener method to the interface all services implement this. public void addListener(String topicMethod, String callbackName); + + public void removeListener(String topicMethod, String callbackName); + } From cbd84fa819334ebb964ab16fc4138b7d78d02fdb Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 18 Feb 2024 12:19:49 -0800 Subject: [PATCH 081/131] onerror added and log.publishErrors --- .../java/org/myrobotlab/service/InMoov2.java | 147 +++++++----------- src/main/java/org/myrobotlab/service/Log.java | 10 ++ .../java/org/myrobotlab/service/OakD.java | 4 +- .../service/config/InMoov2Config.java | 6 +- 4 files changed, 75 insertions(+), 92 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index 8aac57a03e..b83c909e47 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -24,7 +24,6 @@ import org.myrobotlab.framework.Platform; import org.myrobotlab.framework.Registration; import org.myrobotlab.framework.Service; -import org.myrobotlab.framework.StaticType; import org.myrobotlab.framework.Status; import org.myrobotlab.framework.interfaces.ServiceInterface; import org.myrobotlab.io.FileIO; @@ -38,8 +37,6 @@ import org.myrobotlab.service.Log.LogEntry; import org.myrobotlab.service.abstracts.AbstractSpeechSynthesis; import org.myrobotlab.service.config.InMoov2Config; -import org.myrobotlab.service.config.OpenCVConfig; -import org.myrobotlab.service.config.SpeechSynthesisConfig; import org.myrobotlab.service.data.JoystickData; import org.myrobotlab.service.data.Locale; import org.myrobotlab.service.interfaces.IKJointAngleListener; @@ -56,8 +53,7 @@ import org.slf4j.Logger; public class InMoov2 extends Service - implements ServiceLifeCycleListener, SpeechListener, TextListener, TextPublisher, JoystickListener, LocaleProvider, - IKJointAngleListener { + implements ServiceLifeCycleListener, SpeechListener, TextListener, TextPublisher, JoystickListener, LocaleProvider, IKJointAngleListener { public class Heart implements Runnable { private final ReentrantLock lock = new ReentrantLock(); @@ -130,7 +126,7 @@ public Heartbeat(InMoov2 inmoov) { * This method will load a python file into the python interpreter. * * @param file - * file to load + * file to load * @return success/failure */ @Deprecated /* use execScript - this doesn't handle resources correctly */ @@ -279,8 +275,7 @@ public static void main(String[] args) { public InMoov2(String n, String id) { super(n, id); - locales = Locale.getLocaleMap("en-US", "fr-FR", "es-ES", "de-DE", "nl-NL", "ru-RU", "hi-IN", "it-IT", "fi-FI", - "pt-PT", "tr-TR"); + locales = Locale.getLocaleMap("en-US", "fr-FR", "es-ES", "de-DE", "nl-NL", "ru-RU", "hi-IN", "it-IT", "fi-FI", "pt-PT", "tr-TR"); } // should be removed in favor of general listeners @@ -294,8 +289,7 @@ public InMoov2Config apply(InMoov2Config c) { super.apply(c); try { - locales = Locale.getLocaleMap("en-US", "fr-FR", "es-ES", "de-DE", "nl-NL", "pl-PL", "ru-RU", "hi-IN", "it-IT", - "fi-FI", "pt-PT", "tr-TR"); + locales = Locale.getLocaleMap("en-US", "fr-FR", "es-ES", "de-DE", "nl-NL", "pl-PL", "ru-RU", "hi-IN", "it-IT", "fi-FI", "pt-PT", "tr-TR"); if (c.locale != null) { setLocale(c.locale); @@ -660,7 +654,7 @@ public boolean exec(String pythonCode) { * This method will try to launch a python command with error handling * * @param gesture - * the gesture + * the gesture * @return gesture result */ public String execGesture(String gesture) { @@ -695,7 +689,7 @@ public void execScript() { * a filesystem file :P * * @param someScriptName - * execute a resource script + * execute a resource script * @return success or failure */ public void execScript(String someScriptName) { @@ -773,18 +767,11 @@ public InMoov2Head getHead() { */ public Long getLastActivityTime() { Long head = (InMoov2Head) getPeer("head") != null ? ((InMoov2Head) getPeer("head")).getLastActivityTime() : null; - Long leftArm = (InMoov2Arm) getPeer("leftArm") != null ? ((InMoov2Arm) getPeer("leftArm")).getLastActivityTime() - : null; - Long rightArm = (InMoov2Arm) getPeer("rightArm") != null ? ((InMoov2Arm) getPeer("rightArm")).getLastActivityTime() - : null; - Long leftHand = (InMoov2Hand) getPeer("leftHand") != null - ? ((InMoov2Hand) getPeer("leftHand")).getLastActivityTime() - : null; - Long rightHand = (InMoov2Hand) getPeer("rightHand") != null - ? ((InMoov2Hand) getPeer("rightHand")).getLastActivityTime() - : null; - Long torso = (InMoov2Torso) getPeer("torso") != null ? ((InMoov2Torso) getPeer("torso")).getLastActivityTime() - : null; + Long leftArm = (InMoov2Arm) getPeer("leftArm") != null ? ((InMoov2Arm) getPeer("leftArm")).getLastActivityTime() : null; + Long rightArm = (InMoov2Arm) getPeer("rightArm") != null ? ((InMoov2Arm) getPeer("rightArm")).getLastActivityTime() : null; + Long leftHand = (InMoov2Hand) getPeer("leftHand") != null ? ((InMoov2Hand) getPeer("leftHand")).getLastActivityTime() : null; + Long rightHand = (InMoov2Hand) getPeer("rightHand") != null ? ((InMoov2Hand) getPeer("rightHand")).getLastActivityTime() : null; + Long torso = (InMoov2Torso) getPeer("torso") != null ? ((InMoov2Torso) getPeer("torso")).getLastActivityTime() : null; Long lastActivityTime = null; @@ -951,7 +938,7 @@ public void loadGestures() { * file should contain 1 method definition that is the same as the filename. * * @param directory - * - the directory that contains the gesture python files. + * - the directory that contains the gesture python files. * @return true/false */ public boolean loadGestures(String directory) { @@ -1050,8 +1037,7 @@ public void moveHand(String which, Double thumb, Double index, Double majeure, D moveHand(which, thumb, index, majeure, ringFinger, pinky, null); } - public void moveHand(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, - Double wrist) { + public void moveHand(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { invoke("publishMoveHand", which, thumb, index, majeure, ringFinger, pinky, wrist); } @@ -1103,10 +1089,8 @@ public void moveLeftHand(Double thumb, Double index, Double majeure, Double ring moveHand("left", thumb, index, majeure, ringFinger, pinky, wrist); } - public void moveLeftHand(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, - Integer wrist) { - moveHand("left", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, - (double) wrist); + public void moveLeftHand(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, Integer wrist) { + moveHand("left", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, (double) wrist); } public void moveRightArm(Double bicep, Double rotate, Double shoulder, Double omoplate) { @@ -1117,10 +1101,8 @@ public void moveRightHand(Double thumb, Double index, Double majeure, Double rin moveHand("right", thumb, index, majeure, ringFinger, pinky, wrist); } - public void moveRightHand(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, - Integer wrist) { - moveHand("right", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, - (double) wrist); + public void moveRightHand(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, Integer wrist) { + moveHand("right", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, (double) wrist); } public void moveTorso(Double topStom, Double midStom, Double lowStom) { @@ -1149,7 +1131,7 @@ public PredicateEvent onChangePredicate(PredicateEvent event) { * comes in from runtime which owns the config list * * @param configList - * list of configs + * list of configs */ public void onConfigList(List configList) { this.configList = configList; @@ -1210,16 +1192,10 @@ public void onJoystickInput(JoystickData input) throws Exception { * including lower level logs that do not propegate as statuses * * @param log - * - flushed log from Log service + * - flushed log from Log service */ - public void onLogEvents(List log) { - // scan for warn or errors - for (LogEntry entry : log) { - if ("ERROR".equals(entry.level) && errors.size() < 100) { - errors.add(entry); - // invoke("publishError", entry); - } - } + public void onErrors(List log) { + errors.addAll(log); } public String onNewState(String state) { @@ -1559,8 +1535,7 @@ public Heartbeat publishHeartbeat() { } // interval event firing - if (config.stateRandomInterval != null - && System.currentTimeMillis() > stateLastRandomTime + (config.stateRandomInterval * 1000)) { + if (config.stateRandomInterval != null && System.currentTimeMillis() > stateLastRandomTime + (config.stateRandomInterval * 1000)) { // fsm.fire("random"); stateLastRandomTime = System.currentTimeMillis(); } @@ -1612,8 +1587,7 @@ public Message publishMessage(Message msg) { return msg; } - public HashMap publishMoveArm(String which, Double bicep, Double rotate, Double shoulder, - Double omoplate) { + public HashMap publishMoveArm(String which, Double bicep, Double rotate, Double shoulder, Double omoplate) { HashMap map = new HashMap<>(); map.put("bicep", bicep); map.put("rotate", rotate); @@ -1627,8 +1601,7 @@ public HashMap publishMoveArm(String which, Double bicep, Double return map; } - public HashMap publishMoveHand(String which, Double thumb, Double index, Double majeure, - Double ringFinger, Double pinky, Double wrist) { + public HashMap publishMoveHand(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { HashMap map = new HashMap<>(); map.put("which", which); map.put("thumb", thumb); @@ -1645,8 +1618,7 @@ public HashMap publishMoveHand(String which, Double thumb, Doubl return map; } - public HashMap publishMoveHead(Double neck, Double rothead, Double eyeX, Double eyeY, Double jaw, - Double rollNeck) { + public HashMap publishMoveHead(Double neck, Double rothead, Double eyeX, Double eyeY, Double jaw, Double rollNeck) { HashMap map = new HashMap<>(); map.put("neck", neck); map.put("rothead", rothead); @@ -1666,8 +1638,7 @@ public HashMap publishMoveLeftArm(Double bicep, Double rotate, D return map; } - public HashMap publishMoveLeftHand(Double thumb, Double index, Double majeure, Double ringFinger, - Double pinky, Double wrist) { + public HashMap publishMoveLeftHand(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { HashMap map = new HashMap<>(); map.put("thumb", thumb); map.put("index", index); @@ -1687,8 +1658,7 @@ public HashMap publishMoveRightArm(Double bicep, Double rotate, return map; } - public HashMap publishMoveRightHand(Double thumb, Double index, Double majeure, Double ringFinger, - Double pinky, Double wrist) { + public HashMap publishMoveRightHand(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { HashMap map = new HashMap<>(); map.put("thumb", thumb); map.put("index", index); @@ -1833,8 +1803,7 @@ public void setHandSpeed(String which, Double thumb, Double index, Double majeur setHandSpeed(which, thumb, index, majeure, ringFinger, pinky, null); } - public void setHandSpeed(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, - Double wrist) { + public void setHandSpeed(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { InMoov2Hand hand = getHand(which); if (hand == null) { warn("%s hand not started", which); @@ -1844,14 +1813,12 @@ public void setHandSpeed(String which, Double thumb, Double index, Double majeur } @Deprecated - public void setHandVelocity(String which, Double thumb, Double index, Double majeure, Double ringFinger, - Double pinky) { + public void setHandVelocity(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky) { setHandSpeed(which, thumb, index, majeure, ringFinger, pinky, null); } @Deprecated - public void setHandVelocity(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, - Double wrist) { + public void setHandVelocity(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { setHandSpeed(which, thumb, index, majeure, ringFinger, pinky, wrist); } @@ -1867,8 +1834,7 @@ public void setHeadSpeed(Double rothead, Double neck, Double eyeXSpeed, Double e setHeadSpeed(rothead, neck, eyeXSpeed, eyeYSpeed, jawSpeed, null); } - public void setHeadSpeed(Double rothead, Double neck, Double eyeXSpeed, Double eyeYSpeed, Double jawSpeed, - Double rollNeckSpeed) { + public void setHeadSpeed(Double rothead, Double neck, Double eyeXSpeed, Double eyeYSpeed, Double jawSpeed, Double rollNeckSpeed) { sendToPeer("head", "setSpeed", rothead, neck, eyeXSpeed, eyeYSpeed, jawSpeed, rollNeckSpeed); } @@ -1892,8 +1858,7 @@ public void setHeadVelocity(Double rothead, Double neck, Double eyeXSpeed, Doubl } @Deprecated - public void setHeadVelocity(Double rothead, Double neck, Double eyeXSpeed, Double eyeYSpeed, Double jawSpeed, - Double rollNeckSpeed) { + public void setHeadVelocity(Double rothead, Double neck, Double eyeXSpeed, Double eyeYSpeed, Double jawSpeed, Double rollNeckSpeed) { setHeadSpeed(rothead, neck, eyeXSpeed, eyeYSpeed, jawSpeed, rollNeckSpeed); } @@ -1905,15 +1870,12 @@ public void setLeftArmSpeed(Integer bicep, Integer rotate, Integer shoulder, Int setArmSpeed("left", (double) bicep, (double) rotate, (double) shoulder, (double) omoplate); } - public void setLeftHandSpeed(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, - Double wrist) { + public void setLeftHandSpeed(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { setHandSpeed("left", thumb, index, majeure, ringFinger, pinky, wrist); } - public void setLeftHandSpeed(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, - Integer wrist) { - setHandSpeed("left", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, - (double) wrist); + public void setLeftHandSpeed(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, Integer wrist) { + setHandSpeed("left", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, (double) wrist); } @Override @@ -1977,15 +1939,12 @@ public void setRightArmSpeed(Integer bicep, Integer rotate, Integer shoulder, In setArmSpeed("right", (double) bicep, (double) rotate, (double) shoulder, (double) omoplate); } - public void setRightHandSpeed(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, - Double wrist) { + public void setRightHandSpeed(Double thumb, Double index, Double majeure, Double ringFinger, Double pinky, Double wrist) { setHandSpeed("right", thumb, index, majeure, ringFinger, pinky, wrist); } - public void setRightHandSpeed(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, - Integer wrist) { - setHandSpeed("right", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, - (double) wrist); + public void setRightHandSpeed(Integer thumb, Integer index, Integer majeure, Integer ringFinger, Integer pinky, Integer wrist) { + setHandSpeed("right", (double) thumb, (double) index, (double) majeure, (double) ringFinger, (double) pinky, (double) wrist); } public boolean setSpeechType(String speechType) { @@ -2003,8 +1962,10 @@ public boolean setSpeechType(String speechType) { String peerName = getName() + ".mouth"; Plan plan = runtime.getDefault(peerName, speechType); try { - SpeechSynthesisConfig mouth = (SpeechSynthesisConfig) plan.get(peerName); - mouth.speechRecognizers = new String[] { getName() + ".ear" }; + // this should be handled in config.listeners + // SpeechSynthesisConfig mouth = (SpeechSynthesisConfig) + // plan.get(peerName); + // mouth.speechRecognizers = new String[] { getName() + ".ear" }; savePeerConfig("mouth", plan.get(peerName)); @@ -2155,8 +2116,7 @@ public ProgramAB startChatBot() { chatBot.setPredicate("null", ""); // load last user session if (!chatBot.getPredicate("name").isEmpty()) { - if (chatBot.getPredicate("lastUsername").isEmpty() || chatBot.getPredicate("lastUsername").equals("unknown") - || chatBot.getPredicate("lastUsername").equals("default")) { + if (chatBot.getPredicate("lastUsername").isEmpty() || chatBot.getPredicate("lastUsername").equals("unknown") || chatBot.getPredicate("lastUsername").equals("default")) { chatBot.setPredicate("lastUsername", chatBot.getPredicate("name")); } } @@ -2172,8 +2132,7 @@ public ProgramAB startChatBot() { // !chatBot.getPredicate("default", "lastUsername").equals("unknown")) { // chatBot.startSession(chatBot.getPredicate("lastUsername")); // } - if (chatBot.getPredicate("default", "firstinit").isEmpty() - || chatBot.getPredicate("default", "firstinit").equals("unknown") + if (chatBot.getPredicate("default", "firstinit").isEmpty() || chatBot.getPredicate("default", "firstinit").equals("unknown") || chatBot.getPredicate("default", "firstinit").equals("started")) { chatBot.startSession(chatBot.getPredicate("default", "lastUsername")); invoke("publishEvent", "FIRST INIT"); @@ -2319,19 +2278,27 @@ public void stopNeopixelAnimation() { public void systemCheck() { Platform platform = Runtime.getPlatform(); - int servoCount = 0; + int servoCount = 0; for (ServiceInterface si : Runtime.getServices()) { if (si.getClass().getSimpleName().equals("Servo")) { servoCount++; } } + // TODO check for latest version if not experimental + // TODO change to experimental :) + String version = ("unknownVersion".equals(platform.getVersion())) ? "experimental" : platform.getVersion(); + + setPredicate("system_version", version); setPredicate("system_uptime", Runtime.getUptime()); setPredicate("system_servo_count", servoCount); - setPredicate("system_free_memory", Runtime.getFreeMemory()); - setPredicate("system_version", platform.getVersion()); - setPredicate("system_errors", errors.size()); - + setPredicate("system_service_count", Runtime.getServices().size()); + setPredicate("system_free_memory", Runtime.getFreeMemory() / 1000000); + setPredicate("system_errors_exist", errors.size() > 0); + setPredicate("system_error_count", errors.size()); + setPredicate("system_battery_level", Runtime.getBatteryLevel()); + setPredicate("state", getState()); + } public String systemEvent(String eventMsg) { diff --git a/src/main/java/org/myrobotlab/service/Log.java b/src/main/java/org/myrobotlab/service/Log.java index 16dec730f3..dc20806cf2 100644 --- a/src/main/java/org/myrobotlab/service/Log.java +++ b/src/main/java/org/myrobotlab/service/Log.java @@ -132,6 +132,7 @@ public void addError(String msg) { @Override public void addError(String arg0, Throwable arg1) { + System.out.println("addError"); } @Override @@ -202,6 +203,15 @@ synchronized public void flush() { if (buffer.size() > 0) { // bucket add to sliding window logs.addAll(buffer); + + List errors = new ArrayList<>(); + for(int i = 0; i < buffer.size(); ++i) { + errors.add(buffer.get(i)); + } + if (errors.size() > 0) { + invoke("publishErrors", errors); + } + invoke("publishLogEvents", buffer); buffer = new ArrayList<>(maxSize); lastPublishLogTimeTs = System.currentTimeMillis(); diff --git a/src/main/java/org/myrobotlab/service/OakD.java b/src/main/java/org/myrobotlab/service/OakD.java index 5ea7b51dca..7918137e37 100644 --- a/src/main/java/org/myrobotlab/service/OakD.java +++ b/src/main/java/org/myrobotlab/service/OakD.java @@ -19,8 +19,10 @@ /** * + * https://github.com/luxonis/depthai + * python3 depthai_demo.py -cb callbacks.py * - * + * https://github.com/luxonis/depthai-experiments/tree/master/gen2-face-recognition * * @author GroG * diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index 1e884c1e4a..ef14918ac8 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -516,7 +516,9 @@ public Plan getDefault(Plan plan, String name) { LogConfig log = (LogConfig) plan.get(getPeerName("log")); log.level = "WARN"; - log.listeners.add(new Listener("publishLogEvents", name)); + log.listeners.add(new Listener("publishErrors", name)); + // service --to--> InMoov2 + // mouth_audioFile.listeners.add(new Listener("publishAudioEnd", name)); // mouth_audioFile.listeners.add(new Listener("publishAudioStart", name)); @@ -542,6 +544,8 @@ public Plan getDefault(Plan plan, String name) { listeners.add(new Listener("publishMoveTorso", getPeerName("torso"), "onMove")); // service --to--> InMoov2 + + AudioFileConfig mouth_audioFile = (AudioFileConfig) plan.get(getPeerName("mouth.audioFile")); mouth_audioFile.listeners.add(new Listener("publishPeak", name)); From ac9884cdeb9079314c8c7cbcd398e76e1e380b46 Mon Sep 17 00:00:00 2001 From: grog Date: Sun, 18 Feb 2024 21:18:45 -0800 Subject: [PATCH 082/131] updates --- .../org/myrobotlab/service/AudioFile.java | 80 ++---- .../service/FiniteStateMachine.java | 11 +- .../java/org/myrobotlab/service/InMoov2.java | 13 +- .../java/org/myrobotlab/service/NeoPixel.java | 2 +- .../java/org/myrobotlab/service/Runtime.java | 5 - .../service/config/AudioFileConfig.java | 6 +- .../config/FiniteStateMachineConfig.java | 2 +- .../service/config/InMoov2Config.java | 2 +- .../WebGui/app/service/js/RuntimeGui.js | 6 +- .../WebGui/app/service/tab-header.html | 228 +++++++++--------- .../WebGui/app/service/views/RuntimeGui.html | 2 +- .../WebGui/app/widget/modal-dialog.view.html | 2 +- 12 files changed, 153 insertions(+), 206 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/AudioFile.java b/src/main/java/org/myrobotlab/service/AudioFile.java index dbf2131bcf..39ce2dd345 100644 --- a/src/main/java/org/myrobotlab/service/AudioFile.java +++ b/src/main/java/org/myrobotlab/service/AudioFile.java @@ -115,18 +115,13 @@ public class AudioFile extends Service implements AudioPublishe // https://stackoverflow.com/questions/25798200/java-record-mic-to-byte-array-and-play-sound // - String currentTrack = DEFAULT_TRACK; + /** + * status field, the current track being played + */ + protected String currentTrack = DEFAULT_TRACK; transient Map processors = new HashMap(); - double volume = 1.0f; - // if set to true, playback will become a no-op - private boolean mute = false; - - protected String currentPlaylist = "default"; - - protected Map> playlists = new HashMap<>(); - final private transient PlaylistPlayer playlistPlayer = new PlaylistPlayer(this); public void attach(Attachable attachable) { @@ -254,7 +249,7 @@ public AudioData playAudioData(AudioData data) { data.track = currentTrack; } setTrack(data.track); - processors.get(data.track).setVolume(volume); + processors.get(data.track).setVolume(config.volume); if (AudioData.MODE_QUEUED.equals(data.mode)) { // stick it on top of queue and let our default player play it return processors.get(data.track).add(data); @@ -329,7 +324,7 @@ public void silence() { * */ public void setVolume(float volume) { - this.volume = volume; + config.volume = volume; } public void setVolume(double volume) { @@ -337,7 +332,7 @@ public void setVolume(double volume) { } public double getVolume() { - return this.volume; + return config.volume; } public String getTrack() { @@ -441,28 +436,28 @@ public void deleteFile(String filename) { } public boolean isMute() { - return mute; + return config.mute; } public void setMute(boolean mute) { - this.mute = mute; + config.mute = mute; } public void setPlaylist(String name) { - currentPlaylist = name; + config.currentPlaylist = name; } public void addPlaylist(String folderPath) { - addPlaylist(currentPlaylist, folderPath); + addPlaylist(config.currentPlaylist, folderPath); } public void addPlaylist(String name, String path) { List list = null; - if (!playlists.containsKey(name)) { + if (!config.playlists.containsKey(name)) { list = new ArrayList(); } else { - list = playlists.get(name); + list = config.playlists.get(name); } File check = new File(path); if (!check.exists()) { @@ -473,7 +468,7 @@ public void addPlaylist(String name, String path) { list.addAll(scanForMusicFiles(path)); } int filecount = list.size(); - playlists.put(name, list); + config.playlists.put(name, list); log.info("{} playlist added {} files", name, filecount); } @@ -505,15 +500,15 @@ private List scanForMusicFiles(String path) { } public List getPlaylist(String name) { - return playlists.get(name); + return config.playlists.get(name); } public Map> getPlaylists() { - return playlists; + return config.playlists; } public void startPlaylist() { - startPlaylist(currentPlaylist, false, false, currentPlaylist); + startPlaylist(config.currentPlaylist, false, false, DEFAULT_TRACK); } public void startPlaylist(String playlist) { @@ -525,54 +520,17 @@ public void startPlaylist(String playlist, boolean shuffle, boolean repeat) { } public void startPlaylist(String playlist, boolean shuffle, boolean repeat, String track) { - if (!playlists.containsKey(playlist)) { + if (!config.playlists.containsKey(playlist)) { error("cannot play playlist %s does not exists", playlist); return; } - playlistPlayer.start(playlists.get(playlist), shuffle, repeat, track); + playlistPlayer.start(config.playlists.get(playlist), shuffle, repeat, track); } public void stopPlaylist() { playlistPlayer.stop(); } - @Override - public AudioFileConfig getConfig() { - - AudioFileConfig c = (AudioFileConfig) super.getConfig(); - // FIXME - remove members keep data in config ! - // FIXME - the following is not needed nor desired - // useless self assignment - c.mute = mute; - c.currentTrack = currentTrack; - c.currentPlaylist = currentPlaylist; - // c.peakMultiplier = peakMultiplier; - c.volume = volume; - c.playlists = playlists; - // config.peakSampleInterval <- this one is done correctly no maintenance - c.audioListeners = getAttached("publishAudio").toArray(new String[0]); - - return config; - } - - public AudioFileConfig apply(AudioFileConfig config) { - super.apply(config); - setMute(config.mute); - setTrack(config.currentTrack); - setVolume(config.volume); - setPlaylist(config.currentPlaylist); - if (config.playlists != null) { - playlists = config.playlists; - } - - if (config.audioListeners != null) { - for (String listener : config.audioListeners) { - attachAudioListener(listener); - } - } - - return config; - } public double publishPeak(double peak) { log.debug("publishPeak {}", peak); diff --git a/src/main/java/org/myrobotlab/service/FiniteStateMachine.java b/src/main/java/org/myrobotlab/service/FiniteStateMachine.java index e998711e26..5ab6cf5604 100644 --- a/src/main/java/org/myrobotlab/service/FiniteStateMachine.java +++ b/src/main/java/org/myrobotlab/service/FiniteStateMachine.java @@ -254,13 +254,6 @@ public StateChange publishStateChange(StateChange stateChange) { return stateChange; } - @Override - public FiniteStateMachineConfig getConfig() { - super.getConfig(); - config.current = getState(); - return config; - } - @Override public FiniteStateMachineConfig apply(FiniteStateMachineConfig c) { super.apply(c); @@ -280,8 +273,8 @@ public FiniteStateMachineConfig apply(FiniteStateMachineConfig c) { } // setCurrent - if (c.current != null) { - setCurrent(c.current); + if (c.start != null) { + setCurrent(c.start); } return c; diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index b83c909e47..be0f976919 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -102,7 +102,6 @@ public static class Heartbeat { double batteryLevel = 100; public long count = 0; public List errors; - public boolean isPirOn = false; public String state; public long ts = System.currentTimeMillis(); @@ -110,7 +109,6 @@ public Heartbeat(InMoov2 inmoov) { this.state = inmoov.state; this.errors = inmoov.errors; this.count = inmoov.heartbeatCount; - this.isPirOn = inmoov.isPirOn; } } @@ -237,8 +235,6 @@ public static void main(String[] args) { protected transient ImageDisplay imageDisplay; - protected boolean isPirOn = false; - protected boolean isSpeaking = false; protected String lastGestureExecuted; @@ -1239,16 +1235,12 @@ public void onPeak(double volume) { */ public void onPirOn() { log.info("onPirOn"); - // FIXME flash on config.flashOnBoot - invoke("publishFlash", "pir"); - String botState = chatBot.getPredicate("botState"); - if ("sleeping".equals(botState)) { - invoke("publishEvent", "WAKE"); - } + processMessage("onPirOn"); } public void onPirOff() { log.info("onPirOff"); + processMessage("onPirOff"); } // GOOD GOOD GOOD - LOOPBACK - flexible and replacable by python @@ -1682,6 +1674,7 @@ public String publishPlayAudioFile(String filename) { } /** + * One of the most important publishing point. * Processing publishing point, where everything InMoov2 wants to be processed * is turned into a message and published. * diff --git a/src/main/java/org/myrobotlab/service/NeoPixel.java b/src/main/java/org/myrobotlab/service/NeoPixel.java index a5a22c4782..a81397f49b 100644 --- a/src/main/java/org/myrobotlab/service/NeoPixel.java +++ b/src/main/java/org/myrobotlab/service/NeoPixel.java @@ -937,7 +937,7 @@ public void setPixel(String matrixName, Integer pixelSetIndex, int address, int // Runtime.getService(controller); ServiceInterface sc = Runtime.getService(controller); if (sc == null) { - error("controler %s not valid", controller); + error("controller %s not valid", controller); return; } diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index 9b76d3bf65..d8a020dd84 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -433,11 +433,6 @@ private static Map createServicesFromPlan(Plan plan, M RuntimeConfig currentConfig = Runtime.getInstance().config; for (String service : plansRtConfig.getRegistry()) { - // FIXME - determine if you want to return a complete merge of activated - // or just "recent" - if (Runtime.getService(service) != null) { - continue; - } ServiceConfig sc = plan.get(service); if (sc == null) { runtime.error("could not get %s from plan", service); diff --git a/src/main/java/org/myrobotlab/service/config/AudioFileConfig.java b/src/main/java/org/myrobotlab/service/config/AudioFileConfig.java index 391d175d55..086e93691f 100644 --- a/src/main/java/org/myrobotlab/service/config/AudioFileConfig.java +++ b/src/main/java/org/myrobotlab/service/config/AudioFileConfig.java @@ -3,12 +3,16 @@ import java.util.List; import java.util.Map; +import org.myrobotlab.service.AudioFile; + public class AudioFileConfig extends ServiceConfig { public boolean mute = false; - public String currentTrack = "default"; + public double volume = 1.0; + public String currentPlaylist = "default"; + public Map> playlists; @Deprecated /* use regular "listeners" from ServiceConfig parent */ diff --git a/src/main/java/org/myrobotlab/service/config/FiniteStateMachineConfig.java b/src/main/java/org/myrobotlab/service/config/FiniteStateMachineConfig.java index bd4e5648f3..e69c44a4f7 100644 --- a/src/main/java/org/myrobotlab/service/config/FiniteStateMachineConfig.java +++ b/src/main/java/org/myrobotlab/service/config/FiniteStateMachineConfig.java @@ -23,7 +23,7 @@ public Transition(String from, String event, String to) { public List transitions = new ArrayList<>(); - public String current = null; + public String start = null; } diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index ef14918ac8..49575f58c4 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -369,7 +369,7 @@ public Plan getDefault(Plan plan, String name) { // TODO - events easily gotten from InMoov data ?? auto callbacks in python // if // exists ? - fsm.current = "boot"; + fsm.start = "boot"; fsm.transitions.add(new Transition("boot", "wake", "wake")); // setup, nor sleep should be affected by idle fsm.transitions.add(new Transition("setup", "setup_done", "idle")); diff --git a/src/main/resources/resource/WebGui/app/service/js/RuntimeGui.js b/src/main/resources/resource/WebGui/app/service/js/RuntimeGui.js index fbb2edc05d..b1007dcbc1 100644 --- a/src/main/resources/resource/WebGui/app/service/js/RuntimeGui.js +++ b/src/main/resources/resource/WebGui/app/service/js/RuntimeGui.js @@ -388,14 +388,14 @@ angular.module('mrlapp.service.RuntimeGui', []).controller('RuntimeGuiCtrl', ['$ modalInstance.result.then(function(result) { // Handle 'OK' button click - console.log('Config Name: ' + $scope.service.configName) + console.log('Config Name: ' + $scope.configName) console.log('Selected Option: ' + $scope.service.selectedOption) console.log('includePeers Option: ' + $scope.service.includePeers) console.log('configType Option: ' + $scope.service.configType) if ($scope.service.selectedOption == 'default'){ - msg.send('saveDefault', $scope.service.configName, $scope.service.defaultServiceName, $scope.service.configType, $scope.service.includePeers) + msg.send('saveDefault', $scope.configName, $scope.service.defaultServiceName, $scope.service.configType, $scope.service.includePeers) } else { - msg.sendTo('runtime', 'saveConfig', $scope.service.configName) + msg.sendTo('runtime', 'saveConfig', $scope.configName) } }, function() { // Handle 'Cancel' button click or modal dismissal diff --git a/src/main/resources/resource/WebGui/app/service/tab-header.html b/src/main/resources/resource/WebGui/app/service/tab-header.html index 4abedeb490..a87ea4c8cf 100644 --- a/src/main/resources/resource/WebGui/app/service/tab-header.html +++ b/src/main/resources/resource/WebGui/app/service/tab-header.html @@ -1,117 +1,121 @@
- +
+ + + + + + + +
+ + + + + + + + + +
+
+ + - - - - - - + + + + + + + + + + + + + +
- - - - - - - - - - keynamestate
+ + + + + {{peer.getActualName(service, key)}} + + + {{value.key}} +
+ {{value.type}} +
{{value.state}} + +
-
- - - - - - - - - - - - - - - - - - -
keynamestate
- - - - - - {{peer.getActualName(service, key)}} - - - {{value.key}}
{{value.type}} -
{{value.state}} - -
-
+
diff --git a/src/main/resources/resource/WebGui/app/service/views/RuntimeGui.html b/src/main/resources/resource/WebGui/app/service/views/RuntimeGui.html index 7e1fd406ff..52229335c0 100644 --- a/src/main/resources/resource/WebGui/app/service/views/RuntimeGui.html +++ b/src/main/resources/resource/WebGui/app/service/views/RuntimeGui.html @@ -153,7 +153,7 @@ Save your current configuration in a directory named
- +

diff --git a/src/main/resources/resource/WebGui/app/widget/modal-dialog.view.html b/src/main/resources/resource/WebGui/app/widget/modal-dialog.view.html index f8f7104400..38343da431 100644 --- a/src/main/resources/resource/WebGui/app/widget/modal-dialog.view.html +++ b/src/main/resources/resource/WebGui/app/widget/modal-dialog.view.html @@ -7,7 +7,7 @@
- +
From a63e083a27996cd3db67d96873b24472e5950ab4 Mon Sep 17 00:00:00 2001 From: grog Date: Mon, 19 Feb 2024 07:35:57 -0800 Subject: [PATCH 083/131] removed adding system tray icon --- src/main/java/org/myrobotlab/service/ImageDisplay.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/myrobotlab/service/ImageDisplay.java b/src/main/java/org/myrobotlab/service/ImageDisplay.java index d921e2f270..4be2abae11 100644 --- a/src/main/java/org/myrobotlab/service/ImageDisplay.java +++ b/src/main/java/org/myrobotlab/service/ImageDisplay.java @@ -275,6 +275,7 @@ public void run() { // TODO - make better / don't use setImageAutoSize (very bad // algorithm) + /**
 No real use, and doesn't remove
           if (SystemTray.isSupported()) {
             log.info("SystemTray is supported");
             SystemTray tray = SystemTray.getSystemTray();
@@ -285,6 +286,8 @@ public void run() {
 
             tray.add(trayIcon);
           }
+          
+ */ if (display.bgColor != null) { Color color = Color.decode(display.bgColor); From 98a24286150d5668139a7b92d1027b3d9cc96c88 Mon Sep 17 00:00:00 2001 From: grog Date: Mon, 19 Feb 2024 07:36:58 -0800 Subject: [PATCH 084/131] removed onPeak info --- src/main/java/org/myrobotlab/service/InMoov2.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index be0f976919..baa89cae49 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -1222,11 +1222,7 @@ public OpenCVData onOpenCVData(OpenCVData data) { * @param volume */ public void onPeak(double volume) { - if (config.neoPixelFlashWhenSpeaking && !"boot".equals(getState())) { - if (volume > 0.5) { - invoke("publishSpeakingFlash", "speaking"); - } - } + processMessage("onPeak", volume); } /** From 2b5823df6e35a553573e5f360984614d8280b097 Mon Sep 17 00:00:00 2001 From: grog Date: Mon, 19 Feb 2024 21:02:29 -0800 Subject: [PATCH 085/131] audiofile config playlist init --- .../java/org/myrobotlab/service/config/AudioFileConfig.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/config/AudioFileConfig.java b/src/main/java/org/myrobotlab/service/config/AudioFileConfig.java index 086e93691f..47b3dc9b91 100644 --- a/src/main/java/org/myrobotlab/service/config/AudioFileConfig.java +++ b/src/main/java/org/myrobotlab/service/config/AudioFileConfig.java @@ -2,8 +2,7 @@ import java.util.List; import java.util.Map; - -import org.myrobotlab.service.AudioFile; +import java.util.TreeMap; public class AudioFileConfig extends ServiceConfig { @@ -13,7 +12,7 @@ public class AudioFileConfig extends ServiceConfig { public String currentPlaylist = "default"; - public Map> playlists; + public Map> playlists = new TreeMap<>(); @Deprecated /* use regular "listeners" from ServiceConfig parent */ public String[] audioListeners; From 72da4c5f1baa17b4e7410911e944702969834fe7 Mon Sep 17 00:00:00 2001 From: grog Date: Tue, 20 Feb 2024 09:14:32 -0800 Subject: [PATCH 086/131] updates --- .../org/myrobotlab/framework/CmdOptions.java | 2 +- .../java/org/myrobotlab/service/InMoov2.java | 337 +++++++----------- .../org/myrobotlab/service/ProgramAB.java | 15 +- .../java/org/myrobotlab/service/Random.java | 14 +- .../service/config/InMoov2Config.java | 5 +- .../org/myrobotlab/service/HarryTest.java | 2 +- 6 files changed, 153 insertions(+), 222 deletions(-) diff --git a/src/main/java/org/myrobotlab/framework/CmdOptions.java b/src/main/java/org/myrobotlab/framework/CmdOptions.java index 2c357e8db6..3b3b18d7bb 100644 --- a/src/main/java/org/myrobotlab/framework/CmdOptions.java +++ b/src/main/java/org/myrobotlab/framework/CmdOptions.java @@ -39,7 +39,7 @@ static boolean contains(List l, String flag) { // launcher @Option(names = { "-c", - "--config" }, fallbackValue = "default", description = "Specify a configuration set to start. The config set is a directory which has all the necessary configuration files. It loads runtime.yml first, and subsequent service configuration files will then load. \n example: --config data/config/my-config-dir") + "--config" }, fallbackValue = "default", description = "Specify a configuration set to start. The config set is a directory which has all the necessary configuration files. It loads runtime.yml first, and subsequent service configuration files will then load. \n example: --config my-config-dir to start the configuration stored in config data/config/my-config-dir") public String config = null; @Option(names = { "-h", "-?", "--help" }, description = "shows help") diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index baa89cae49..2322a4bc8e 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -3,17 +3,16 @@ import java.io.File; import java.io.FilenameFilter; import java.io.IOException; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.TreeMap; import java.util.TreeSet; import java.util.concurrent.locks.ReentrantLock; @@ -33,6 +32,7 @@ import org.myrobotlab.opencv.OpenCVData; import org.myrobotlab.programab.PredicateEvent; import org.myrobotlab.programab.Response; +import org.myrobotlab.programab.Session; import org.myrobotlab.service.FiniteStateMachine.StateChange; import org.myrobotlab.service.Log.LogEntry; import org.myrobotlab.service.abstracts.AbstractSpeechSynthesis; @@ -47,7 +47,6 @@ import org.myrobotlab.service.interfaces.Simulator; import org.myrobotlab.service.interfaces.SpeechListener; import org.myrobotlab.service.interfaces.SpeechRecognizer; -import org.myrobotlab.service.interfaces.SpeechSynthesis; import org.myrobotlab.service.interfaces.TextListener; import org.myrobotlab.service.interfaces.TextPublisher; import org.slf4j.Logger; @@ -114,12 +113,8 @@ public Heartbeat(InMoov2 inmoov) { public final static Logger log = LoggerFactory.getLogger(InMoov2.class); - public static LinkedHashMap lpVars = new LinkedHashMap(); - private static final long serialVersionUID = 1L; - static String speechRecognizer = "WebkitSpeechRecognition"; - /** * This method will load a python file into the python interpreter. * @@ -187,8 +182,6 @@ public static void main(String[] args) { } } - protected Double batteryLevel = 100.0; - /** * number of times waited in boot state */ @@ -198,11 +191,6 @@ public static void main(String[] args) { protected List configList; - /** - * map of events or states to sounds - */ - protected Map customSoundMap = new TreeMap<>(); - protected transient SpeechRecognizer ear; protected List errors = new ArrayList<>(); @@ -213,7 +201,7 @@ public static void main(String[] args) { * there will be a direct reference to the fsm. If different state graph is * needed, then the fsm can provide that service. */ - private transient FiniteStateMachine fsm = null; + private transient FiniteStateMachine fsm; // waiting controable threaded gestures we warn user protected boolean gestureAlreadyStarted = false; @@ -223,24 +211,18 @@ public static void main(String[] args) { /** * Prevents actions or events from happening when InMoov2 is first booted */ - private boolean hasBooted = false; + protected boolean hasBooted = false; private transient final Heart heart = new Heart(); protected long heartbeatCount = 0; - protected boolean heartBeating = false; - - protected transient HtmlFilter htmlFilter; - protected transient ImageDisplay imageDisplay; protected boolean isSpeaking = false; protected String lastGestureExecuted; - protected Long lastPirActivityTime; - protected String lastState = null; /** @@ -250,8 +232,6 @@ public static void main(String[] args) { protected int maxInactivityTimeSeconds = 120; - protected transient SpeechSynthesis mouth; - protected boolean mute = false; protected transient OpenCV opencv; @@ -261,7 +241,7 @@ public static void main(String[] args) { /** * initial state - updated on any state change */ - String state = "boot"; + protected String state = "boot"; protected long stateLastIdleTime = System.currentTimeMillis(); @@ -292,6 +272,8 @@ public InMoov2Config apply(InMoov2Config c) { } else { setLocale(getSupportedLocale(Runtime.getInstance().getLocale().toString())); } + // one way sync configuration into predicates + configToPredicates(); } catch (Exception e) { error(e); @@ -567,6 +549,13 @@ public long checkInactivity() { return lastActivityTime; } + /** + * clear all errors + */ + public void clearErrors() { + errors.clear(); + } + public void closeAllImages() { // FIXME - follow this pattern ? // CON npe possible although unlikely @@ -576,6 +565,38 @@ public void closeAllImages() { imageDisplay.closeAll(); } + /** + * Updates configuration into ProgramAB predicates. + */ + public void configToPredicates() { + log.info("configToPredicates"); + if (chatBot != null) { + Class pojoClass = config.getClass(); + Field[] fields = pojoClass.getDeclaredFields(); + for (Field field : fields) { + try { + field.setAccessible(true); + Object value = field.get(config); // Requires handling + Map sessions = chatBot.getSessions(); + if (sessions != null) { + for (Session session : sessions.values()) { + if (value != null) { + session.setPredicate(field.getName(), value.toString()); + } else { + session.setPredicate(field.getName(), null); + } + + } + } + } catch (Exception e) { + error(e); + } + } + } else { + log.info("chatbot not ready for config sync"); + } + } + public void cycleGestures() { // if not loaded load - // FIXME - this needs alot of "help" :P @@ -872,10 +893,6 @@ public InMoov2Torso getTorso() { return (InMoov2Torso) getPeer("torso"); } - public InMoov2Config getTypedConfig() { - return (InMoov2Config) config; - } - public void halfSpeed() { sendToPeer("head", "setSpeed", 25.0, 25.0, 25.0, 25.0, 100.0, 25.0); sendToPeer("rightHand", "setSpeed", 30.0, 30.0, 30.0, 30.0, 30.0, 30.0); @@ -894,13 +911,6 @@ public boolean hasErrors() { return errors.size() > 0; } - /** - * clear all errors - */ - public void clearErrors() { - errors.clear(); - } - public boolean isCameraOn() { if (opencv != null) { if (opencv.isCapturing()) { @@ -914,6 +924,10 @@ public boolean isMute() { return mute; } + public boolean isSpeaking() { + return isSpeaking; + } + /** * execute python scripts in the app directory on startup of the service * @@ -1144,6 +1158,17 @@ public void onEndSpeaking(String utterance) { isSpeaking = false; } + /** + * Centralized logging system will have all logging from all services, + * including lower level logs that do not propegate as statuses + * + * @param log + * - flushed log from Log service + */ + public void onErrors(List log) { + errors.addAll(log); + } + public void onFinishedConfig(String configName) { log.info("onFinishedConfig"); // invoke("publishEvent", "configFinished"); @@ -1183,17 +1208,6 @@ public void onJoystickInput(JoystickData input) throws Exception { invoke("publishEvent", "joystick"); } - /** - * Centralized logging system will have all logging from all services, - * including lower level logs that do not propegate as statuses - * - * @param log - * - flushed log from Log service - */ - public void onErrors(List log) { - errors.addAll(log); - } - public String onNewState(String state) { log.error("onNewState {}", state); @@ -1225,20 +1239,22 @@ public void onPeak(double volume) { processMessage("onPeak", volume); } + public void onPirOff() { + log.info("onPirOff"); + setPredicate(String.format("%s.pir_off", getName()), System.currentTimeMillis()); + processMessage("onPirOff"); + } + /** * initial callback for Pir sensor Default behavior will be: send fsm event * onPirOn flash neopixel */ public void onPirOn() { log.info("onPirOn"); + setPredicate(String.format("%s.pir_on", getName()), System.currentTimeMillis()); processMessage("onPirOn"); } - public void onPirOff() { - log.info("onPirOff"); - processMessage("onPirOff"); - } - // GOOD GOOD GOOD - LOOPBACK - flexible and replacable by python // yet provides a stable default, which can be fully replaced // Works using common pub/sub rules @@ -1277,6 +1293,15 @@ public boolean onSense(boolean b) { return b; } + /** + * When a new session is started this will sync config with it + * + * @param sessionKey + */ + public void onSession(String sessionKey) { + configToPredicates(); + } + /** * runtime re-publish relay * @@ -1318,42 +1343,6 @@ public void onStartSpeaking(String utterance) { isSpeaking = true; } - /** - * publishStateChange - * - * The integration between the FiniteStateMachine (fsm) and the InMoov2 - * service and potentially other services (Python, ProgramAB) happens here. - * - * After boot all state changes get published here. - * - * Some InMoov2 service methods will be called here for "default - * implemenation" of states. If a user doesn't want to have that default - * implementation, they can change it by changing the definition of the state - * machine, and have a new state which will call a Python inmoov2 library - * callback. Overriding, appending, or completely transforming the behavior is - * all easily accomplished by managing the fsm and python inmoov2 library - * callbacks. - * - * Python inmoov2 callbacks ProgramAB topic switching - * - * Depending on config: - * - * @param stateChange - * @return - */ - public StateChange publishStateChange(StateChange stateChange) { - log.info("publishStateChange {}", stateChange); - - log.info("onStateChange {}", stateChange); - - lastState = state; - state = stateChange.state; - - processMessage("onStateChange", stateChange); - - return stateChange; - } - @Override public void onStopped(String name) { log.info("service {} has stopped"); @@ -1670,9 +1659,9 @@ public String publishPlayAudioFile(String filename) { } /** - * One of the most important publishing point. - * Processing publishing point, where everything InMoov2 wants to be processed - * is turned into a message and published. + * One of the most important publishing point. Processing publishing point, + * where everything InMoov2 wants to be processed is turned into a message and + * published. * * @param msg * @return @@ -1702,6 +1691,42 @@ public String publishSpeakingFlash(String name) { return name; } + /** + * publishStateChange + * + * The integration between the FiniteStateMachine (fsm) and the InMoov2 + * service and potentially other services (Python, ProgramAB) happens here. + * + * After boot all state changes get published here. + * + * Some InMoov2 service methods will be called here for "default + * implemenation" of states. If a user doesn't want to have that default + * implementation, they can change it by changing the definition of the state + * machine, and have a new state which will call a Python inmoov2 library + * callback. Overriding, appending, or completely transforming the behavior is + * all easily accomplished by managing the fsm and python inmoov2 library + * callbacks. + * + * Python inmoov2 callbacks ProgramAB topic switching + * + * Depending on config: + * + * @param stateChange + * @return + */ + public StateChange publishStateChange(StateChange stateChange) { + log.info("publishStateChange {}", stateChange); + + log.info("onStateChange {}", stateChange); + + lastState = state; + state = stateChange.state; + + processMessage("onStateChange", stateChange); + + return stateChange; + } + /** * stop animation event */ @@ -1788,6 +1813,12 @@ public void setAutoDisable(Boolean param) { sendToPeer("torso", "setAutoDisable", param); } + @Override + public void setConfigValue(String fieldname, Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException { + super.setConfigValue(fieldname, value); + setPredicate(fieldname, value); + } + public void setHandSpeed(String which, Double thumb, Double index, Double majeure, Double ringFinger, Double pinky) { setHandSpeed(which, thumb, index, majeure, ringFinger, pinky, null); } @@ -1902,15 +1933,6 @@ public void setNeopixelAnimation(String animation, Integer red, Integer green, I sendToPeer("neopixel", "animation", red, green, blue, speed); } - public void setOpenCV(OpenCV opencv) { - this.opencv = opencv; - } - - public boolean setPirPlaySounds(boolean b) { - getTypedConfig().pirPlaySounds = b; - return b; - } - public Object setPredicate(String key, Object data) { if (data == null) { chatBot.setPredicate(key, null); // "unknown" "null" other sillyness ? @@ -1987,24 +2009,6 @@ public void setTorsoSpeed(Integer topStom, Integer midStom, Integer lowStom) { setTorsoSpeed((double) topStom, (double) midStom, (double) lowStom); } - // ----------------------------------------------------------------------------- - // These are methods added that were in InMoov1 that we no longer had in - // InMoov2. - // From original InMoov1 so we don't loose the - - @Deprecated /* use setTorsoSpeed */ - public void setTorsoVelocity(Double topStom, Double midStom, Double lowStom) { - setTorsoSpeed(topStom, midStom, lowStom); - } - - public void setVoice(String name) { - if (mouth != null) { - mouth.setVoice(name); - voiceSelected = name; - speakBlocking(String.format("%s %s", get("SETLANG"), name)); - } - } - public void sleeping() { log.error("sleeping"); } @@ -2051,103 +2055,6 @@ public void speakBlocking(String format, Object... args) { } } - @Deprecated /* use startPeers */ - public void startAll() throws Exception { - startAll(null, null); - } - - @Deprecated /* use startPeers */ - public void startAll(String leftPort, String rightPort) throws Exception { - startChatBot(); - - // startHeadTracking(); - // startEyesTracking(); - // startOpenCV(); - startEar(); - - startServos(); - // startMouthControl(head.jaw, mouth); - - speakBlocking(get("STARTINGSEQUENCE")); - } - - @Deprecated /* i01.startPeer("chatBot") - all details should be in config */ - public void startBrain() { - startChatBot(); - } - - @Deprecated /* i01.startPeer("chatBot") - all details should be in config */ - public ProgramAB startChatBot() { - - try { - - if (locale != null) { - chatBot.setCurrentBotName(locale.getTag()); - } - - // FIXME remove get en.properties stuff - speakBlocking(get("CHATBOTACTIVATED")); - - chatBot.attachTextPublisher(ear); - - // this.attach(chatBot); FIXME - attach as a TextPublisher - then - // re-publish - // FIXME - deal with language - // speakBlocking(get("CHATBOTACTIVATED")); - chatBot.repetitionCount(10); - // chatBot.setPath(getResourceDir() + fs + "chatbot"); - // chatBot.setPath(getDataDir() + "ProgramAB"); - chatBot.startSession("default", locale.getTag()); - // reset some parameters to default... - chatBot.setPredicate("topic", "default"); - chatBot.setPredicate("questionfirstinit", ""); - chatBot.setPredicate("tmpname", ""); - chatBot.setPredicate("null", ""); - // load last user session - if (!chatBot.getPredicate("name").isEmpty()) { - if (chatBot.getPredicate("lastUsername").isEmpty() || chatBot.getPredicate("lastUsername").equals("unknown") || chatBot.getPredicate("lastUsername").equals("default")) { - chatBot.setPredicate("lastUsername", chatBot.getPredicate("name")); - } - } - chatBot.setPredicate("parameterHowDoYouDo", ""); - chatBot.savePredicates(); - htmlFilter = (HtmlFilter) startPeer("htmlFilter");// Runtime.start("htmlFilter", - // "HtmlFilter"); - chatBot.attachTextListener(htmlFilter); - htmlFilter.attachTextListener((TextListener) getPeer("mouth")); - chatBot.attachTextListener(this); - // start session based on last recognized person - // if (!chatBot.getPredicate("default", "lastUsername").isEmpty() && - // !chatBot.getPredicate("default", "lastUsername").equals("unknown")) { - // chatBot.startSession(chatBot.getPredicate("lastUsername")); - // } - if (chatBot.getPredicate("default", "firstinit").isEmpty() || chatBot.getPredicate("default", "firstinit").equals("unknown") - || chatBot.getPredicate("default", "firstinit").equals("started")) { - chatBot.startSession(chatBot.getPredicate("default", "lastUsername")); - invoke("publishEvent", "FIRST INIT"); - } else { - chatBot.startSession(chatBot.getPredicate("default", "lastUsername")); - invoke("publishEvent", "WAKE UP"); - } - } catch (Exception e) { - speak("could not load chatBot"); - error(e.getMessage()); - speak(e.getMessage()); - } - broadcastState(); - return chatBot; - } - - @Deprecated /* use startPeer */ - public SpeechRecognizer startEar() { - - ear = (SpeechRecognizer) startPeer("ear"); - ear.attachSpeechSynthesis((SpeechSynthesis) getPeer("mouth")); - ear.attachTextListener(chatBot); - broadcastState(); - return ear; - } - public void startedGesture() { startedGesture("unknown"); } diff --git a/src/main/java/org/myrobotlab/service/ProgramAB.java b/src/main/java/org/myrobotlab/service/ProgramAB.java index 6b0aad8f00..c32a0ab437 100644 --- a/src/main/java/org/myrobotlab/service/ProgramAB.java +++ b/src/main/java/org/myrobotlab/service/ProgramAB.java @@ -711,12 +711,25 @@ public Session startSession(String path, String userName, String botName, java.u } session = new Session(this, userName, botInfo); - sessions.put(getSessionKey(userName, botName), session); + String sessionKey = getSessionKey(userName, botName); + sessions.put(sessionKey, session); log.info("Started session for bot botName:{} , userName:{}", botName, userName); setCurrentSession(userName, botName); + + invoke("publishSession", sessionKey); + return session; } + + /** + * When a new session is started this event is published with the session's key + * @param sessionKey of new Session + * @return sessionKey + */ + public String publishSession(String sessionKey) { + return sessionKey; + } /** * setting the current session is equivalent to setting current user name and diff --git a/src/main/java/org/myrobotlab/service/Random.java b/src/main/java/org/myrobotlab/service/Random.java index d018df206a..fd3ce94187 100644 --- a/src/main/java/org/myrobotlab/service/Random.java +++ b/src/main/java/org/myrobotlab/service/Random.java @@ -229,11 +229,21 @@ public void run() { // and see if any random event needs processing sleep(config.rate); - for (String key : randomData.keySet()) { + // copy to avoid concurrent exceptions, avoid iterating over randomData + Map tasks = new HashMap<>(); + Set keySet = new HashSet(randomData.keySet()); + for (String k : keySet) { + RandomMessage rm = randomData.get(k); + if (rm != null) { + tasks.put(k, rm); + } + } + + for (String key : tasks.keySet()) { long now = System.currentTimeMillis(); - RandomMessage randomEntry = randomData.get(key); + RandomMessage randomEntry = tasks.get(key); if (!randomEntry.enabled) { continue; } diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index 49575f58c4..d5e7116605 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -37,7 +37,7 @@ public class InMoov2Config extends ServiceConfig { public boolean flashOnErrors = true; - public boolean flashOnPir; + public boolean flashOnPir = false; public boolean forceMicroOnIfSleeping = true; @@ -276,7 +276,8 @@ public Plan getDefault(Plan plan, String name) { } } - chatBot.listeners.add(new Listener("publishText", name + ".htmlFilter", "onText")); + chatBot.listeners.add(new Listener("publishText", getPeerName("htmlFilter"), "onText")); + chatBot.listeners.add(new Listener("publishSession", name)); Gpt3Config gpt3 = (Gpt3Config) plan.get(getPeerName("gpt3")); gpt3.listeners.add(new Listener("publishText", name + ".htmlFilter", "onText")); diff --git a/src/test/java/org/myrobotlab/service/HarryTest.java b/src/test/java/org/myrobotlab/service/HarryTest.java index 29527a0845..1d1995fc5f 100755 --- a/src/test/java/org/myrobotlab/service/HarryTest.java +++ b/src/test/java/org/myrobotlab/service/HarryTest.java @@ -228,7 +228,7 @@ public void testHarry() throws Exception { // if startInMoov: // i01.startAll(leftPort, rightPort) // else: - i01.mouth = mouth; + i01.startPeer("mouth"); solr.attachAllInboxes(); solr.attachAllOutboxes(); From 7b0bfd070c4a183cf50adbadccad272bd72bc1aa Mon Sep 17 00:00:00 2001 From: grog Date: Thu, 22 Feb 2024 07:39:37 -0800 Subject: [PATCH 087/131] updates --- .../org/myrobotlab/programab/Session.java | 9 +- .../java/org/myrobotlab/service/InMoov2.java | 52 +++-- src/main/java/org/myrobotlab/service/Log.java | 5 +- .../java/org/myrobotlab/service/Random.java | 44 ++-- .../java/org/myrobotlab/service/Runtime.java | 16 +- .../abstracts/AbstractSpeechSynthesis.java | 192 +++++++----------- .../service/config/AudioFileConfig.java | 8 +- .../service/config/InMoov2Config.java | 6 +- .../service/config/SpeechSynthesisConfig.java | 12 +- 9 files changed, 173 insertions(+), 171 deletions(-) diff --git a/src/main/java/org/myrobotlab/programab/Session.java b/src/main/java/org/myrobotlab/programab/Session.java index a234310e57..a76fb94bec 100644 --- a/src/main/java/org/myrobotlab/programab/Session.java +++ b/src/main/java/org/myrobotlab/programab/Session.java @@ -5,7 +5,9 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Date; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; @@ -122,7 +124,12 @@ public void savePredicates() { */ public Map getPredicates() { TreeMap sort = new TreeMap<>(); - sort.putAll(getChat().predicates); + // copy keys, making this sort thread safe + Set keys = new HashSet(getChat().predicates.keySet()); + for (String key: keys) { + String value = getChat().predicates.get(key); + sort.put(key, value); + } return sort; } diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index 2322a4bc8e..c496da1a61 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -98,15 +98,10 @@ public void stop() { } public static class Heartbeat { - double batteryLevel = 100; public long count = 0; - public List errors; - public String state; public long ts = System.currentTimeMillis(); public Heartbeat(InMoov2 inmoov) { - this.state = inmoov.state; - this.errors = inmoov.errors; this.count = inmoov.heartbeatCount; } } @@ -581,9 +576,9 @@ public void configToPredicates() { if (sessions != null) { for (Session session : sessions.values()) { if (value != null) { - session.setPredicate(field.getName(), value.toString()); + session.setPredicate(String.format("config.%s", field.getName()), value.toString()); } else { - session.setPredicate(field.getName(), null); + session.setPredicate(String.format("config.%s", field.getName()), null); } } @@ -640,6 +635,23 @@ public void displayFullScreen(String src) { error("could not display picture %s", src); } } + + public void enableRandomHead() { + Random random = (Random)getPeer("random"); + if (random != null) { + random.disableAll(); + random.enable(String.format("%s.setHeadSpeed", getName())); + random.enable(String.format("%s.moveHead", getName())); + random.enable(); + } + } + + public void disableRandom() { + Random random = (Random)getPeer("random"); + if (random != null) { + random.disable(); + } + } public void enable() { sendToPeer("head", "enable"); @@ -1155,6 +1167,7 @@ public void onCreated(String fullname) { @Override public void onEndSpeaking(String utterance) { + processMessage("onEndSpeaking", utterance); isSpeaking = false; } @@ -1337,9 +1350,9 @@ public void onStarted(String name) { } } - // FIXME - rebroadcast these @Override public void onStartSpeaking(String utterance) { + processMessage("onStartSpeaking", utterance); isSpeaking = true; } @@ -1402,7 +1415,7 @@ public void processMessage(String method) { * @param method * @param data */ - public void processMessage(String method, Object data) { + public void processMessage(String method, Object ... data) { // User processing should not occur until after boot has completed if (!state.equals("boot")) { // FIXME - this needs to be in config @@ -1490,7 +1503,7 @@ public Heartbeat publishHeartbeat() { if ("boot".equals(state)) { // continue booting - we don't put heartbeats in user/python space // until java-land is done booting - log.info("boot hasn't completed, will not process heartbeat"); + log.info("boot hasn't completed, will not process heartbeat - trying boot"); boot(); return heartbeat; } @@ -1721,6 +1734,9 @@ public StateChange publishStateChange(StateChange stateChange) { lastState = state; state = stateChange.state; + + setPredicate(String.format("%s.end", lastState), System.currentTimeMillis()); + setPredicate(String.format("%s.start", state), System.currentTimeMillis()); processMessage("onStateChange", stateChange); @@ -2185,15 +2201,15 @@ public void systemCheck() { // TODO change to experimental :) String version = ("unknownVersion".equals(platform.getVersion())) ? "experimental" : platform.getVersion(); - setPredicate("system_version", version); - setPredicate("system_uptime", Runtime.getUptime()); - setPredicate("system_servo_count", servoCount); - setPredicate("system_service_count", Runtime.getServices().size()); - setPredicate("system_free_memory", Runtime.getFreeMemory() / 1000000); - setPredicate("system_errors_exist", errors.size() > 0); - setPredicate("system_error_count", errors.size()); - setPredicate("system_battery_level", Runtime.getBatteryLevel()); + setPredicate("system.version", version); + setPredicate("system.uptime", Runtime.getUptime()); + setPredicate("system.servoCount", servoCount); + setPredicate("system.serviceCount", Runtime.getServices().size()); + setPredicate("system.freeMemory", Runtime.getFreeMemory() / 1000000); + setPredicate("system.errorsExist", errors.size() > 0); + setPredicate("system.errorCount", errors.size()); setPredicate("state", getState()); + setPredicate("system.batteryLevel", Runtime.getBatteryLevel().intValue()); } diff --git a/src/main/java/org/myrobotlab/service/Log.java b/src/main/java/org/myrobotlab/service/Log.java index dc20806cf2..51e388a994 100644 --- a/src/main/java/org/myrobotlab/service/Log.java +++ b/src/main/java/org/myrobotlab/service/Log.java @@ -206,7 +206,10 @@ synchronized public void flush() { List errors = new ArrayList<>(); for(int i = 0; i < buffer.size(); ++i) { - errors.add(buffer.get(i)); + LogEntry entry = buffer.get(i); + if ("ERROR".equals(entry.level)) { + errors.add(entry); + } } if (errors.size() > 0) { invoke("publishErrors", errors); diff --git a/src/main/java/org/myrobotlab/service/Random.java b/src/main/java/org/myrobotlab/service/Random.java index fd3ce94187..b419e7b8eb 100644 --- a/src/main/java/org/myrobotlab/service/Random.java +++ b/src/main/java/org/myrobotlab/service/Random.java @@ -30,7 +30,7 @@ public class Random extends Service { private static final long serialVersionUID = 1L; - public final static Logger log = LoggerFactory.getLogger(Random.class); + protected final static Logger log = LoggerFactory.getLogger(Random.class); transient private RandomProcessor processor = null; @@ -75,7 +75,7 @@ public Range(Object min, Object max) { /** * all random message data is located here */ - Map randomData = new HashMap<>(); + protected Map randomData = new HashMap<>(); /** * Java's random value generator @@ -107,7 +107,7 @@ public long getRandom(long min, long max) { public double getRandom(double min, double max) { return min + (Math.random() * (max - min)); } - + public RandomMessage getTask(String taskName) { return randomData.get(taskName); } @@ -210,7 +210,9 @@ public void addRandom(String taskName, long minIntervalMs, long maxIntervalMs, S data.data = ranges; data.enabled = true; - randomData.put(taskName, data); + synchronized (lock) { + randomData.put(taskName, data); + } log.info("add random message {} in {} to {} ms", taskName, data.minIntervalMs, data.maxIntervalMs); broadcastState(); @@ -229,16 +231,22 @@ public void run() { // and see if any random event needs processing sleep(config.rate); - // copy to avoid concurrent exceptions, avoid iterating over randomData - Map tasks = new HashMap<>(); - Set keySet = new HashSet(randomData.keySet()); - for (String k : keySet) { - RandomMessage rm = randomData.get(k); - if (rm != null) { - tasks.put(k, rm); + + Map tasks = null; + synchronized (lock) { + + // copy to avoid concurrent exceptions, avoid iterating over + // randomData + tasks = new HashMap<>(); + Set keySet = new HashSet(randomData.keySet()); + for (String k : keySet) { + RandomMessage rm = randomData.get(k); + if (rm != null) { + tasks.put(k, rm); + } } } - + for (String key : tasks.keySet()) { long now = System.currentTimeMillis(); @@ -313,7 +321,7 @@ public RandomConfig getConfig() { super.getConfig(); config.enabled = enabled; - + if (config.randomMessages == null) { config.randomMessages = new HashMap<>(); } @@ -445,15 +453,15 @@ public List methodQuery(String serviceName, String methodName) { } return MethodCache.getInstance().query(si.getClass().getCanonicalName(), methodName); } - - public Map getRandomEvents(){ + + public Map getRandomEvents() { return randomData; } - + public RandomMessage getRandomEvent(String key) { return randomData.get(key); } - + /** * disables all the individual tasks */ @@ -463,7 +471,7 @@ public void disableAll() { } broadcastState(); } - + @Override public void releaseService() { disable(); diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index d8a020dd84..e203a65b81 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -910,12 +910,14 @@ public static Runtime getInstance() { runtime.apply(c); } - if (options.services != null) { + if (options.services != null && options.services.size() != 0) { log.info("command line override for services created"); createAndStartServices(options.services); } else { log.info("processing config.registry"); - if (startYml.enable) { + if (options.config != null) { + Runtime.startConfig(options.config); + } else if (startYml.enable) { Runtime.startConfig(startYml.config); } } @@ -1544,7 +1546,7 @@ static public void install(String serviceType, Boolean blocking) { if (blocking == null) { blocking = false; } - + if (installerThread != null) { log.error("another request to install dependencies, 1st request has not completed"); return; @@ -1571,7 +1573,7 @@ public void run() { } else { installerThread.start(); } - + installerThread = null; } } @@ -4913,16 +4915,16 @@ static public void releaseConfigPath(String configPath) { RuntimeConfig config = CodecUtils.fromYaml(releaseData, RuntimeConfig.class); List registry = config.getRegistry(); Collections.reverse(Arrays.asList(registry)); - + // get starting services if any entered on the command line - // -s log Log webgui WebGui ... etc - these will be protected + // -s log Log webgui WebGui ... etc - these will be protected List startingServices = new ArrayList<>(); if (options.services.size() % 2 == 0) { for (int i = 0; i < options.services.size(); i += 2) { startingServices.add(options.services.get(i)); } } - + for (String name : registry) { if (startingServices.contains(name)) { continue; diff --git a/src/main/java/org/myrobotlab/service/abstracts/AbstractSpeechSynthesis.java b/src/main/java/org/myrobotlab/service/abstracts/AbstractSpeechSynthesis.java index f8cca2fa92..011f1f6e08 100644 --- a/src/main/java/org/myrobotlab/service/abstracts/AbstractSpeechSynthesis.java +++ b/src/main/java/org/myrobotlab/service/abstracts/AbstractSpeechSynthesis.java @@ -6,9 +6,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.TreeMap; -import java.util.concurrent.ConcurrentHashMap; import org.myrobotlab.framework.Service; import org.myrobotlab.framework.interfaces.Attachable; @@ -42,22 +40,11 @@ public abstract class AbstractSpeechSynthesis e public static final String journalFilename = "journal.txt"; - /** - * substitutions are phonetic substitutions for a specific instance of speech - * synthesis service - */ - transient protected Map substitutions = new ConcurrentHashMap(); - /** * generalized list of languages and their codes - if useful */ protected Map locales = new HashMap<>(); - /** - * mute or unmute service - */ - boolean mute = false; - /** * replaces key with replacement */ @@ -252,8 +239,6 @@ public Object getVoiceProvider() { private List voiceList = new ArrayList<>(); - protected boolean blocking = false; - // FIXME - deprecate - begin using SSML // specific effects and effect notation needs to be isolated to the // implementing service @@ -291,7 +276,7 @@ public AbstractSpeechSynthesis(String n, String id) { // should hold off creating or starting peers until the service has started // audioFile = (AudioFile) createPeer("audioFile"); -// getVoices(); + // getVoices(); } @@ -571,65 +556,65 @@ public String publishSpeechRequested(String toSpeak) { * @return - list of audio data */ public List parse(String toSpeak) { - + // we generate a list of audio data to play to support // synthesizing this speech List playList = new ArrayList(); - + try { - // TODO - not sure if we want to support this notation - // but at the moment it seems useful - // splitting on sound effects ... - // TODO - use SSML speech synthesis markup language + // TODO - not sure if we want to support this notation + // but at the moment it seems useful + // splitting on sound effects ... + // TODO - use SSML speech synthesis markup language - log.info("{} processing {}", getName(), toSpeak); + log.info("{} processing {}", getName(), toSpeak); - // broadcast the original text to be processed/parsed - invoke("publishSpeechRequested", toSpeak); + // broadcast the original text to be processed/parsed + invoke("publishSpeechRequested", toSpeak); - // normalize to lower case - toSpeak = toSpeak.toLowerCase(); + // normalize to lower case + toSpeak = toSpeak.toLowerCase(); - // process substitutions - if (substitutions != null) { - for (String substitute : substitutions.keySet()) { - toSpeak = toSpeak.replace(substitute, substitutions.get(substitute)); + // process substitutions + if (config.substitutions != null) { + for (String substitute : config.substitutions.keySet()) { + toSpeak = toSpeak.replace(substitute, config.substitutions.get(substitute)); + } } - } - List spokenParts = parseEffects(toSpeak); + List spokenParts = parseEffects(toSpeak); - toSpeak = filterText(toSpeak); + toSpeak = filterText(toSpeak); - for (String speak : spokenParts) { + for (String speak : spokenParts) { - AudioData audioData = null; - if (speak.startsWith("#") && speak.endsWith("#")) { - audioData = new AudioData( - System.getProperty("user.dir") + File.separator + "audioFile" + File.separator + "voiceEffects" + File.separator + speak.substring(1, speak.length() - 1) + ".mp3"); - } else { - audioData = new AudioData(getLocalFileName(speak)); - } + AudioData audioData = null; + if (speak.startsWith("#") && speak.endsWith("#")) { + audioData = new AudioData( + System.getProperty("user.dir") + File.separator + "audioFile" + File.separator + "voiceEffects" + File.separator + speak.substring(1, speak.length() - 1) + ".mp3"); + } else { + audioData = new AudioData(getLocalFileName(speak)); + } - if (speak.trim().length() == 0) { - continue; - } + if (speak.trim().length() == 0) { + continue; + } - if (!mute) { - process(audioData, speak, blocking); - } else { - log.info("not producing audio for {} - currently we are mute", speak); - } + if (!config.mute) { + process(audioData, speak, config.blocking); + } else { + log.info("not producing audio for {} - currently we are mute", speak); + } - // effect files are handled differently from generated audio - playList.add(audioData); - } - // FIXME - in theory "speaking" means generating audio from some text - // so starting speaking event is when the first audio is "started" - // and finished speaking is when the last audio is finished + // effect files are handled differently from generated audio + playList.add(audioData); + } + // FIXME - in theory "speaking" means generating audio from some text + // so starting speaking event is when the first audio is "started" + // and finished speaking is when the last audio is finished - } catch(Exception e) { + } catch (Exception e) { error(e); } return playList; @@ -647,12 +632,12 @@ public void addSubstitution(String key, String replacement) { */ @Override public void replaceWord(String key, String replacement) { - substitutions.put(key.toLowerCase(), replacement.toLowerCase()); + config.substitutions.put(key.toLowerCase(), replacement.toLowerCase()); } @Override public void replaceWord(WordFilter filter) { - substitutions.put(filter.word.toLowerCase(), filter.substitute.toLowerCase()); + config.substitutions.put(filter.word.toLowerCase(), filter.substitute.toLowerCase()); } public Long publishGenerationTime(Long timeMs) { @@ -706,10 +691,10 @@ public List speak(String toSpeak) { @Override public List speakBlocking(String toSpeak) { - boolean prevValue = blocking; - blocking = true; + boolean prevValue = config.blocking; + config.blocking = true; List audioData = parse(toSpeak); - blocking = prevValue; + config.blocking = prevValue; return audioData; } @@ -954,35 +939,34 @@ public boolean setLanguage(String lang) { } return false; } - @Override public boolean setVoice(String name) { - if (voices == null) { - return false; - } + if (voices == null) { + return false; + } - SpeechSynthesisConfig config = (SpeechSynthesisConfig)this.config; - voice = voices.get(name); - - if (voice == null) { - voice = voiceKeyIndex.get(name); - } - - if (voice == null) { - voice = voiceProviderIndex.get(name); - } - - if (voice == null) { - error("could not set voice %s - valid voices are %s", name, String.join(", ", getVoiceNames())); - return false; - } + SpeechSynthesisConfig config = (SpeechSynthesisConfig) this.config; + voice = voices.get(name); + + if (voice == null) { + voice = voiceKeyIndex.get(name); + } + + if (voice == null) { + voice = voiceProviderIndex.get(name); + } - config.voice = name; - broadcastState(); - return true; + if (voice == null) { + error("could not set voice %s - valid voices are %s", name, String.join(", ", getVoiceNames())); + return false; + } + + config.voice = name; + broadcastState(); + return true; } - + public boolean setVoice(Integer index) { if (index > voiceList.size() || index < 0) { error("setVoice({}) not valid pick range 0 to {}", index, voiceList.size()); @@ -1102,49 +1086,30 @@ public void unmute() { @Override public void setMute(boolean b) { - this.mute = b; + this.config.mute = b; } @Override public Boolean setBlocking(Boolean b) { - blocking = b; + config.blocking = b; return b; } public boolean isMute() { - return mute; + return config.mute; } @Override public C apply(C c) { super.apply(c); - - setMute(c.mute); - - setBlocking(c.blocking); - - if (c.substitutions != null) { - for (String n : c.substitutions.keySet()) { - replaceWord(n, c.substitutions.get(n)); - } - } + // some systems require querying set of voices getVoices(); - + if (c.voice != null) { setVoice(c.voice); } - if (c.speechRecognizers != null) { - for (String name : c.speechRecognizers) { - try { - attachSpeechListener(name); - } catch (Exception e) { - error(e); - } - } - } - return c; } @@ -1160,18 +1125,9 @@ public void attachSpeechControl(SpeechSynthesisControl control) { @Override public C getConfig() { C c = super.getConfig(); - c.mute = mute; - c.blocking = blocking; - if (substitutions != null && !substitutions.isEmpty()) { - c.substitutions = new HashMap<>(); - c.substitutions.putAll(substitutions); - } if (voice != null) { c.voice = voice.name; } - Set listeners = getAttached("publishStartSpeaking"); - c.speechRecognizers = listeners.toArray(new String[0]); - return c; } diff --git a/src/main/java/org/myrobotlab/service/config/AudioFileConfig.java b/src/main/java/org/myrobotlab/service/config/AudioFileConfig.java index 47b3dc9b91..1a91e3c096 100644 --- a/src/main/java/org/myrobotlab/service/config/AudioFileConfig.java +++ b/src/main/java/org/myrobotlab/service/config/AudioFileConfig.java @@ -12,11 +12,11 @@ public class AudioFileConfig extends ServiceConfig { public String currentPlaylist = "default"; + /** + * Named map of lists of files + */ public Map> playlists = new TreeMap<>(); - - @Deprecated /* use regular "listeners" from ServiceConfig parent */ - public String[] audioListeners; - + /** * a multiplier to scale amplitude of output waveform */ diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index d5e7116605..d9cd38d947 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -374,12 +374,12 @@ public Plan getDefault(Plan plan, String name) { fsm.transitions.add(new Transition("boot", "wake", "wake")); // setup, nor sleep should be affected by idle fsm.transitions.add(new Transition("setup", "setup_done", "idle")); - fsm.transitions.add(new Transition("idle", "random", "random")); fsm.transitions.add(new Transition("random", "idle", "idle")); fsm.transitions.add(new Transition("idle", "sleep", "sleep")); + fsm.transitions.add(new Transition("idle", "power_down", "power_down")); + fsm.transitions.add(new Transition("idle", "random", "random")); fsm.transitions.add(new Transition("sleep", "wake", "wake")); fsm.transitions.add(new Transition("sleep", "power_down", "power_down")); - fsm.transitions.add(new Transition("idle", "power_down", "power_down")); fsm.transitions.add(new Transition("wake", "setup", "setup")); fsm.transitions.add(new Transition("wake", "idle", "idle")); fsm.transitions.add(new Transition("idle", "setup", "setup")); @@ -565,7 +565,9 @@ public Plan getDefault(Plan plan, String name) { fsm.listeners.add(new Listener("publishStateChange", name, "publishStateChange")); // peer --to--> peer + mouth.listeners.add(new Listener("publishStartSpeaking", name)); mouth.listeners.add(new Listener("publishStartSpeaking", getPeerName("ear"))); + mouth.listeners.add(new Listener("publishEndSpeaking", name)); mouth.listeners.add(new Listener("publishEndSpeaking", getPeerName("ear"))); return plan; diff --git a/src/main/java/org/myrobotlab/service/config/SpeechSynthesisConfig.java b/src/main/java/org/myrobotlab/service/config/SpeechSynthesisConfig.java index c84c4dca65..fc63167ffb 100644 --- a/src/main/java/org/myrobotlab/service/config/SpeechSynthesisConfig.java +++ b/src/main/java/org/myrobotlab/service/config/SpeechSynthesisConfig.java @@ -6,11 +6,19 @@ public class SpeechSynthesisConfig extends ServiceConfig { + /** + * mute or unmute service + */ public boolean mute = false; + public boolean blocking = false; - @Deprecated /* :( ... this is already in listeners ! */ - public String[] speechRecognizers; + + /** + * substitutions are phonetic substitutions for a specific instance of speech + * synthesis service + */ public Map substitutions; + public String voice; @Override From 814de152115a67476a1e257d21af5a7892f43462 Mon Sep 17 00:00:00 2001 From: grog Date: Thu, 22 Feb 2024 07:58:59 -0800 Subject: [PATCH 088/131] fixed type --- src/main/java/org/myrobotlab/image/WebImage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/myrobotlab/image/WebImage.java b/src/main/java/org/myrobotlab/image/WebImage.java index fd4ad4e02f..4b5b41842d 100644 --- a/src/main/java/org/myrobotlab/image/WebImage.java +++ b/src/main/java/org/myrobotlab/image/WebImage.java @@ -56,7 +56,7 @@ public WebImage(final BufferedImage img, final String source, Integer frameIndex if (quality == null) { ImageIO.write(img, imgType, os); os.close(); - data = String.format("data:image/%s;base64,%s", type,CodecUtils.toBase64(os.toByteArray())); + data = String.format("data:image/%s;base64,%s", imgType,CodecUtils.toBase64(os.toByteArray())); } else { // save jpeg image with specific quality. "1f" corresponds to 100% , From db1f7d17dd48282fcfccf4626c95a6fe44544d63 Mon Sep 17 00:00:00 2001 From: grog Date: Thu, 22 Feb 2024 07:59:08 -0800 Subject: [PATCH 089/131] webgui --- src/main/java/org/myrobotlab/service/WebGui.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/myrobotlab/service/WebGui.java b/src/main/java/org/myrobotlab/service/WebGui.java index f50cdc238a..4367ae8c2a 100644 --- a/src/main/java/org/myrobotlab/service/WebGui.java +++ b/src/main/java/org/myrobotlab/service/WebGui.java @@ -1177,7 +1177,8 @@ public static void main(String[] args) { try { - Runtime.main(new String[] { "--log-level", "info", "-s", "log", "Log", "webgui", "WebGui", "intro", "Intro", "python", "Python" }); + // Runtime.main(new String[] { "--log-level", "info", "-s", "log", "Log", "webgui", "WebGui", "intro", "Intro", "python", "Python" }); + Runtime.main(new String[] { "-c", "worky"}); // Runtime.main(new String[] { "--install" }); boolean done = true; From 7470e0371698f25bac93c539aa6461d55381f755 Mon Sep 17 00:00:00 2001 From: grog Date: Thu, 22 Feb 2024 09:14:17 -0800 Subject: [PATCH 090/131] getWebImage --- .../java/org/myrobotlab/service/OpenCV.java | 131 ++++++++++-------- 1 file changed, 71 insertions(+), 60 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/OpenCV.java b/src/main/java/org/myrobotlab/service/OpenCV.java index dcd7ad08d9..474a8055d2 100644 --- a/src/main/java/org/myrobotlab/service/OpenCV.java +++ b/src/main/java/org/myrobotlab/service/OpenCV.java @@ -155,7 +155,7 @@ class VideoProcessor implements Runnable { @Override synchronized public void run() { - // create a closeable frame converter + // create a closeable frame converter CloseableFrameConverter converter = new CloseableFrameConverter(); try { @@ -308,16 +308,11 @@ public void start() { transient final static public String PART = "part"; static final String TEST_LOCAL_FACE_FILE_JPEG = "src/test/resources/OpenCV/multipleFaces.jpg"; - public final static String POSSIBLE_FILTERS[] = { "AdaptiveThreshold", "AddMask", "Affine", "And", "BlurDetector", - "BoundingBoxToFile", "Canny", "ColorTrack", "Copy", - "CreateHistogram", "Detector", "Dilate", "DL4J", "DL4JTransfer", "Erode", "FaceDetect", "FaceDetectDNN", - "FaceRecognizer", "FaceTraining", "Fauvist", "FindContours", "Flip", - "FloodFill", "FloorFinder", "FloorFinder2", "GoodFeaturesToTrack", "Gray", "HoughLines2", "Hsv", "ImageSegmenter", - "Input", "InRange", "Invert", "KinectDepth", - "KinectDepthMask", "KinectNavigate", "LKOpticalTrack", "Lloyd", "Mask", "MatchTemplate", "MiniXception", - "MotionDetect", "Mouse", "Output", "Overlay", "PyramidDown", - "PyramidUp", "ResetImageRoi", "Resize", "SampleArray", "SampleImage", "SetImageROI", "SimpleBlobDetector", - "Smooth", "Solr", "Split", "SURF", "Tesseract", "TextDetector", + public final static String POSSIBLE_FILTERS[] = { "AdaptiveThreshold", "AddMask", "Affine", "And", "BlurDetector", "BoundingBoxToFile", "Canny", "ColorTrack", "Copy", + "CreateHistogram", "Detector", "Dilate", "DL4J", "DL4JTransfer", "Erode", "FaceDetect", "FaceDetectDNN", "FaceRecognizer", "FaceTraining", "Fauvist", "FindContours", "Flip", + "FloodFill", "FloorFinder", "FloorFinder2", "GoodFeaturesToTrack", "Gray", "HoughLines2", "Hsv", "ImageSegmenter", "Input", "InRange", "Invert", "KinectDepth", + "KinectDepthMask", "KinectNavigate", "LKOpticalTrack", "Lloyd", "Mask", "MatchTemplate", "MiniXception", "MotionDetect", "Mouse", "Output", "Overlay", "PyramidDown", + "PyramidUp", "ResetImageRoi", "Resize", "SampleArray", "SampleImage", "SetImageROI", "SimpleBlobDetector", "Smooth", "Solr", "Split", "SURF", "Tesseract", "TextDetector", "Threshold", "Tracker", "Transpose", "Undistort", "Yolo" }; static final long serialVersionUID = 1L; @@ -649,7 +644,7 @@ synchronized public OpenCVFilter addFilter(OpenCVFilter filter) { * add filter by type e.g. addFilter("Canny","Canny") * * @param filterName - * - name of filter + * - name of filter * @return the filter */ public CVFilter addFilter(String filterName) { @@ -689,7 +684,7 @@ public void capture(FrameGrabber grabber) throws org.bytedeco.javacv.FrameGrabbe * capture from a camera * * @param cameraIndex - * the camera index to capture from + * the camera index to capture from */ public void capture(Integer cameraIndex) { if (cameraIndex == null) { @@ -710,7 +705,7 @@ public void capture(Integer cameraIndex) { * its the most capable of decoding different filetypes. * * @param filename - * the file to use as the input filename. + * the file to use as the input filename. * */ public void capture(String filename) { @@ -723,7 +718,7 @@ public void capture(String filename) { public void captureFromResourceFile(String filename) throws IOException { capture(filename); } - + /** * Gets valid camera indexes by iterating through 8 * @@ -761,7 +756,7 @@ public List getCameraIndexes() { return cameraIndexes; } - + public int getCameraIndex() { return this.cameraIndex; } @@ -851,7 +846,7 @@ public List getFaces(int timeout) { * get a filter by name * * @param name - * filter name to lookup + * filter name to lookup * @return the filter by name o/w null * */ @@ -881,8 +876,7 @@ public OpenCVData getGoodFeatures() { } public FrameGrabber getGrabber() - throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, - InvocationTargetException, org.bytedeco.javacv.FrameGrabber.Exception { + throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, org.bytedeco.javacv.FrameGrabber.Exception { if (grabber != null) { return grabber; @@ -907,8 +901,7 @@ public FrameGrabber getGrabber() // get and cache image file // FIXME - perhaps "test" stream to try to determine what "type" it is - // mjpeg/jpg/gif/ octet-stream :( ??? - if (grabberType == null - || (grabberType != null && (!grabberType.equals("MJpeg") && !grabberType.equals("IPCamera")))) { + if (grabberType == null || (grabberType != null && (!grabberType.equals("MJpeg") && !grabberType.equals("IPCamera")))) { inputFile = getImageFromUrl(inputFile); } } @@ -920,8 +913,7 @@ public FrameGrabber getGrabber() ext = inputFile.substring(pos + 1).toLowerCase(); } } - if (grabberType != null && (grabberType.equals("FFmpeg") || grabberType.equals("ImageFile")) - && inputSource.equals(INPUT_SOURCE_CAMERA)) { + if (grabberType != null && (grabberType.equals("FFmpeg") || grabberType.equals("ImageFile")) && inputSource.equals(INPUT_SOURCE_CAMERA)) { log.info("invalid state of ffmpeg and input source camera - setting to OpenCV frame grabber"); grabberType = "OpenCV"; } @@ -976,8 +968,7 @@ public FrameGrabber getGrabber() } String prefixPath; - if (/* "IPCamera".equals(grabberType) || */ "Pipeline".equals(grabberType) || "ImageFile".equals(grabberType) - || "Sarxos".equals(grabberType) || "MJpeg".equals(grabberType)) { + if (/* "IPCamera".equals(grabberType) || */ "Pipeline".equals(grabberType) || "ImageFile".equals(grabberType) || "Sarxos".equals(grabberType) || "MJpeg".equals(grabberType)) { prefixPath = "org.myrobotlab.opencv."; } else { prefixPath = "org.bytedeco.javacv."; @@ -1076,6 +1067,27 @@ public IplImage getImage() { return lastImage; } + /** + * "Easy" Base64 web image from display last frame + * + * @return + */ + public String getWebImage() { + try { + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + String imgType = "jpg"; + BufferedImage bi = getDisplay(); + if (bi != null) { + ImageIO.write(bi, imgType, os); + os.close(); + return String.format("data:image/%s;base64,%s", imgType, CodecUtils.toBase64(os.toByteArray())); + } + } catch (Exception e) { + error(e); + } + return null; + } + public String getInputFile() { return inputFile; } @@ -1113,11 +1125,11 @@ public OpenCVData getOpenCVData(Integer timeout) { * appropriate filter through this method. * * @param filterName - * the name of the fitler + * the name of the fitler * @param method - * the method to invoke + * the method to invoke * @param params - * the params to pass + * the params to pass */ public void invokeFilterMethod(String filterName, String method, Object... params) { OpenCVFilter filter = getFilter(filterName); @@ -1136,7 +1148,10 @@ public boolean isRecording() { return recording; } - @Deprecated /* was used in SwingGui - nice feature through .. ability to undock displays */ + @Deprecated /* + * was used in SwingGui - nice feature through .. ability to + * undock displays + */ public boolean isUndocked() { return undockDisplay; } @@ -1153,7 +1168,7 @@ synchronized public void pauseCapture() { * conversion from buffered image to base64 encoded jpg * * @param img - * the image to convert + * the image to convert * @return base64jpeg version of buffered image */ public String toBase64Jpg(BufferedImage img) { @@ -1304,7 +1319,7 @@ private void processFilterStateUpdates(OpenCVFilter filter) { * base 64 jpg frame image * * @param data - * webimage data + * webimage data * @return the web image data */ public WebImage publishWebDisplay(WebImage data) { @@ -1387,7 +1402,7 @@ public final SerializableImage publishDisplay(SerializableImage img) { * Publishing method for filters - used internally * * @param filterWrapper - * wraps a filter + * wraps a filter * * @return FilterWrapper solves the problem of multiple types being resolved * in the setFilterState(FilterWrapper data) method @@ -1400,7 +1415,7 @@ public FilterWrapper publishFilterState(FilterWrapper filterWrapper) { * Publishing method for filters - uses string parameter for remote invocation * * @param name - * name of filter to publish state for + * name of filter to publish state for * * @return FilterWrapper solves the problem of multiple types being resolved * in the setFilterState(FilterWrapper data) method @@ -1436,7 +1451,7 @@ public void publishNoRecognizedFace() { * until asked for - then its cached SMART ! :) * * @param data - * the opencv data + * the opencv data * @return cvdata * */ @@ -1469,13 +1484,13 @@ public void putText(int x, int y, String format) { * creates a new overlay of text * * @param x - * coordinate + * coordinate * @param y - * coordinate + * coordinate * @param format - * format string + * format string * @param color - * color + * color * */ public void putText(int x, int y, String format, String color) { @@ -1487,9 +1502,9 @@ public void putText(int x, int y, String format, String color) { * the "light weight" put - it does not create any new cv objects * * @param format - * format for the text + * format for the text * @param args - * args to format into the text + * args to format into the text * */ public void putText(String format, Object... args) { @@ -1550,7 +1565,7 @@ public void startStreamer() { * key- input, filter, or display * * @param data - * data + * data */ public void record(OpenCVData data) { try { @@ -1572,8 +1587,7 @@ public void record(OpenCVData data) { */ FrameRecorder recorder = null; if (!recordingFrames) { - recordingFilename = String.format(getDataDir() + File.separator + "%s-%d.flv", recordingSource, - System.currentTimeMillis()); + recordingFilename = String.format(getDataDir() + File.separator + "%s-%d.flv", recordingSource, System.currentTimeMillis()); info("recording %s", recordingFilename); recorder = new FFmpegFrameRecorder(recordingFilename, frame.imageWidth, frame.imageHeight, 0); recorder.setFormat("flv"); @@ -1639,7 +1653,7 @@ public ImageData saveImage() { /** * @param name - * remove a filter by name + * remove a filter by name */ @Override synchronized public void removeFilter(String name) { @@ -1721,7 +1735,7 @@ public void setColor(String colorStr) { * enable() and setDisplayFilter() needed filter * * @param name - * name of the filter to set active + * name of the filter to set active * */ public void setActiveFilter(String name) { @@ -1760,15 +1774,12 @@ public void setDisplayFilter(String name) { /** * @param otherFilter - * - data from remote source + * - data from remote source * - * This updates the filter with all the non-transient data in - * a - * remote copy through a reflective field update. If your - * filter has - * JNI members or pointer references it will break, mark all - * of - * these. + * This updates the filter with all the non-transient data in a + * remote copy through a reflective field update. If your filter has + * JNI members or pointer references it will break, mark all of + * these. */ public void setFilterState(FilterWrapper otherFilter) { OpenCVFilter filter = getFilter(otherFilter.name); @@ -1786,9 +1797,9 @@ public void setFilterState(FilterWrapper otherFilter) { * filter * * @param name - * name of the filter + * name of the filter * @param data - * state date to set. + * state date to set. */ public void setFilterState(String name, String data) { OpenCVFilter filter = getFilter(name); @@ -1908,8 +1919,7 @@ public void recordFrames() { private boolean isSingleFrame() { if (inputSource.equals(INPUT_SOURCE_FILE) && inputFile != null) { String testExt = inputFile.toLowerCase(); - if (testExt.endsWith(".jpg") || testExt.endsWith(".jpeg") || testExt.endsWith(".png") || testExt.endsWith(".gif") - || testExt.endsWith(".tiff") || testExt.endsWith(".tif")) { + if (testExt.endsWith(".jpg") || testExt.endsWith(".jpeg") || testExt.endsWith(".png") || testExt.endsWith(".gif") || testExt.endsWith(".tiff") || testExt.endsWith(".tif")) { return true; } } @@ -1970,11 +1980,12 @@ public void enableFilter(String name) { /** * flip the video display vertically + * * @param toFlip */ public void flip(boolean toFlip) { config.flip = toFlip; - if (config.flip) { + if (config.flip) { addFilter("Flip"); } else { removeFilter("Flip"); @@ -2076,7 +2087,7 @@ public OpenCVConfig apply(OpenCVConfig c) { // TODO: better configuration of the filter when it's added. } } - + flip(c.flip); if (c.capturing) { @@ -2101,7 +2112,7 @@ public static void main(String[] args) throws Exception { // Runtime.start("python", "Python"); OpenCV cv = (OpenCV) Runtime.start("cv", "OpenCV"); cv.capture(); - + cv.addFilter(new OpenCVFilterYolo("yolo")); sleep(1000); cv.removeFilters(); From f155d0ae357a645dffe74a7beb72c341249f853f Mon Sep 17 00:00:00 2001 From: grog Date: Thu, 22 Feb 2024 10:52:48 -0800 Subject: [PATCH 091/131] small config update --- src/main/java/org/myrobotlab/service/WebGui.java | 4 ++-- .../java/org/myrobotlab/service/config/InMoov2Config.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/myrobotlab/service/WebGui.java b/src/main/java/org/myrobotlab/service/WebGui.java index 4367ae8c2a..e6efa1f28d 100644 --- a/src/main/java/org/myrobotlab/service/WebGui.java +++ b/src/main/java/org/myrobotlab/service/WebGui.java @@ -1177,8 +1177,8 @@ public static void main(String[] args) { try { - // Runtime.main(new String[] { "--log-level", "info", "-s", "log", "Log", "webgui", "WebGui", "intro", "Intro", "python", "Python" }); - Runtime.main(new String[] { "-c", "worky"}); + Runtime.main(new String[] { "--log-level", "warn", "-s", "log", "Log", "webgui", "WebGui", "intro", "Intro", "python", "Python" }); + // Runtime.main(new String[] { "-c", "worky"}); // Runtime.main(new String[] { "--install" }); boolean done = true; diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index d9cd38d947..1ae722a633 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -516,7 +516,7 @@ public Plan getDefault(Plan plan, String name) { listeners.add(new Listener("publishConfigFinished", name)); LogConfig log = (LogConfig) plan.get(getPeerName("log")); - log.level = "WARN"; + log.level = "warn"; log.listeners.add(new Listener("publishErrors", name)); // service --to--> InMoov2 From 1cdc49376865e19275609c538905d7107ee5e088 Mon Sep 17 00:00:00 2001 From: grog Date: Fri, 23 Feb 2024 21:55:07 -0800 Subject: [PATCH 092/131] remotespeech --- .../org/myrobotlab/service/LocalSpeech.java | 85 +++++++++---------- .../org/myrobotlab/service/RemoteSpeech.java | 77 +++++++++++++++++ .../service/config/RemoteSpeechConfig.java | 21 +++++ .../service/meta/RemoteSpeechMeta.java | 38 +++++++++ .../WebGui/app/service/js/RemoteSpeechGui.js | 40 +++++++++ .../WebGui/app/service/views/IntroGui.html | 1 - .../app/service/views/RemoteSpeechGui.html | 31 +++++++ 7 files changed, 247 insertions(+), 46 deletions(-) create mode 100644 src/main/java/org/myrobotlab/service/RemoteSpeech.java create mode 100644 src/main/java/org/myrobotlab/service/config/RemoteSpeechConfig.java create mode 100644 src/main/java/org/myrobotlab/service/meta/RemoteSpeechMeta.java create mode 100644 src/main/resources/resource/WebGui/app/service/js/RemoteSpeechGui.js create mode 100644 src/main/resources/resource/WebGui/app/service/views/RemoteSpeechGui.html diff --git a/src/main/java/org/myrobotlab/service/LocalSpeech.java b/src/main/java/org/myrobotlab/service/LocalSpeech.java index 3d2194c896..cb89016c82 100644 --- a/src/main/java/org/myrobotlab/service/LocalSpeech.java +++ b/src/main/java/org/myrobotlab/service/LocalSpeech.java @@ -77,8 +77,6 @@ public LocalSpeech(String n, String id) { @Override public AudioData generateAudioData(AudioData audioData, String toSpeak) throws IOException, InterruptedException { - LocalSpeechConfig c = (LocalSpeechConfig) config; - // the actual filename on the file system String localFileName = getLocalFileName(toSpeak); @@ -96,13 +94,13 @@ public AudioData generateAudioData(AudioData audioData, String toSpeak) throws I } // filter out breaking chars - if (c.replaceChars == null) { + if (config.replaceChars == null) { // if not user defined - escape double quotes to not affect templates - c.replaceChars = new HashMap<>(); - c.replaceChars.put("\'", "\'\'"); + config.replaceChars = new HashMap<>(); + config.replaceChars.put("\'", "\'\'"); } - for (String target : c.replaceChars.keySet()) { - toSpeak = toSpeak.replace(target, c.replaceChars.get(target)); + for (String target : config.replaceChars.keySet()) { + toSpeak = toSpeak.replace(target, config.replaceChars.get(target)); } Platform platform = Runtime.getPlatform(); @@ -209,7 +207,7 @@ public void loadVoices() { // FIXME this is not right - it should be based on speechType not OS // speechType should be "set" based on OS and user preference if (platform.isWindows()) { - + try { List args = new ArrayList<>(); @@ -273,9 +271,9 @@ public void loadVoices() { } } // let apply config add and set the voices -// else if (platform.isLinux()) { -// addVoice("Linus", "male", "en-US", "festival"); -// } + // else if (platform.isLinux()) { + // addVoice("Linus", "male", "en-US", "festival"); + // } } public void removeExt(boolean b) { @@ -291,8 +289,7 @@ public boolean setEspeak() { return false; } - LocalSpeechConfig c = (LocalSpeechConfig) config; - c.speechType = "Espeak"; + config.speechType = "Espeak"; voices.clear(); addVoice("espeak", "male", "en-US", "espeak"); removeExt(false); @@ -310,10 +307,9 @@ public boolean setFestival() { return false; } - LocalSpeechConfig c = (LocalSpeechConfig) config; voices.clear(); addVoice("Linus", "male", "en-US", "festival"); - c.speechType = "Festival"; + config.speechType = "Festival"; removeExt(false); setTtsHack(false); setTtsCommand("echo \"{text}\" | text2wave -o {filename}"); @@ -330,9 +326,8 @@ public boolean setPico2Wav() { error("pico2wave only supported on Linux"); return false; } - - LocalSpeechConfig c = (LocalSpeechConfig) config; - c.speechType = "Pico2Wav"; + + config.speechType = "Pico2Wav"; removeExt(false); setTtsHack(false); @@ -343,13 +338,13 @@ public boolean setPico2Wav() { addVoice("es-ES", "female", "es-ES", "pico2wav"); addVoice("fr-FR", "female", "fr-FR", "pico2wav"); addVoice("it-IT", "female", "it-IT", "pico2wav"); - + if (voice == null) { setVoice(getLocale().getTag()); } setTtsCommand("pico2wave -l {voice_name} -w {filename} \"{text}\" "); - + broadcastState(); return true; } @@ -363,19 +358,19 @@ public boolean setPico2Wav() { * @param replace */ public void addFilter(String target, String replace) { - LocalSpeechConfig c = (LocalSpeechConfig) config; - if (c.replaceChars == null) { - c.replaceChars = new HashMap<>(); + + if (config.replaceChars == null) { + config.replaceChars = new HashMap<>(); } - c.replaceChars.put(target, replace); + config.replaceChars.put(target, replace); } /** * @return setMimic sets the Windows mimic template */ public boolean setMimic() { - LocalSpeechConfig c = (LocalSpeechConfig) config; - c.speechType = "Mimic"; + + config.speechType = "Mimic"; removeExt(false); setTtsHack(false); if (Runtime.getPlatform().isWindows()) { @@ -404,8 +399,8 @@ public String setSpeechType(String speechType) { } public String getSpeechType() { - LocalSpeechConfig c = (LocalSpeechConfig) config; - return c.speechType; + + return config.speechType; } /** @@ -418,8 +413,8 @@ public boolean setMsSpeech() { error("microsoft speech is only supported on Windows"); return false; } - LocalSpeechConfig c = (LocalSpeechConfig) config; - c.speechType = "MsSpeech"; + + config.speechType = "MsSpeech"; removeExt(false); setTtsHack(false); @@ -438,8 +433,8 @@ public boolean setMsSpeech() { * @return setSay sets the Mac say template */ public boolean setSay() { - LocalSpeechConfig c = (LocalSpeechConfig) config; - c.speechType = "Say"; + + config.speechType = "Say"; removeExt(false); setTtsHack(false); setTtsCommand("/usr/bin/say -v {voice_name} --data-format=LEF32@22050 -o {filename} \"{text}\""); @@ -455,8 +450,8 @@ public boolean setSay() { * */ public boolean setTts() { - LocalSpeechConfig c = (LocalSpeechConfig) config; - c.speechType = "Tts"; + + config.speechType = "Tts"; removeExt(false); setTtsHack(true); setTtsCommand("\"" + ttsPath + "\" -f 9 -v {voice} -o {filename} -t \"{text}\""); @@ -473,8 +468,8 @@ public boolean setTts() { * */ public void setTtsCommand(String ttsCommand) { - LocalSpeechConfig c = (LocalSpeechConfig) config; - info("LocalSpeech speechType %s template is now: %s", c.speechType, ttsCommand); + + info("LocalSpeech speechType %s template is now: %s", config.speechType, ttsCommand); this.ttsCommand = ttsCommand; } @@ -492,26 +487,26 @@ public void setTtsHack(boolean b) { public void setTtsPath(String ttsPath) { this.ttsPath = ttsPath; } - + public boolean isExecutableAvailable(String executableName) { ProcessBuilder processBuilder = new ProcessBuilder(); String command = ""; boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows"); if (isWindows) { - command = "where " + executableName; + command = "where " + executableName; } else { - command = "which " + executableName; + command = "which " + executableName; } processBuilder.command("sh", "-c", command); try { - Process process = processBuilder.start(); - process.waitFor(); - return process.exitValue() == 0; + Process process = processBuilder.start(); + process.waitFor(); + return process.exitValue() == 0; } catch (IOException | InterruptedException e) { - e.printStackTrace(); - return false; + e.printStackTrace(); + return false; } -} + } public LocalSpeechConfig apply(LocalSpeechConfig config) { super.apply(config); diff --git a/src/main/java/org/myrobotlab/service/RemoteSpeech.java b/src/main/java/org/myrobotlab/service/RemoteSpeech.java new file mode 100644 index 0000000000..6da50b45a9 --- /dev/null +++ b/src/main/java/org/myrobotlab/service/RemoteSpeech.java @@ -0,0 +1,77 @@ +package org.myrobotlab.service; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import org.myrobotlab.io.FileIO; +import org.myrobotlab.logging.Level; +import org.myrobotlab.logging.LoggerFactory; +import org.myrobotlab.logging.LoggingFactory; +import org.myrobotlab.service.abstracts.AbstractSpeechSynthesis; +import org.myrobotlab.service.config.HttpClientConfig; +import org.myrobotlab.service.config.RemoteSpeechConfig; +import org.myrobotlab.service.data.AudioData; +import org.slf4j.Logger; + +public class RemoteSpeech extends AbstractSpeechSynthesis { + + private static final long serialVersionUID = 1L; + + public final static Logger log = LoggerFactory.getLogger(RemoteSpeech.class); + + public transient HttpClient http = null; + + protected Set types = new HashSet<>(Arrays.asList("ModzillaTTS")); + + // http://localhost:5002/api/tts?text=Hello%20I%20am%20a%20speech%20synthesis%20system%20version%202 + public RemoteSpeech(String n, String id) { + super(n, id); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public void startService() { + super.startService(); + http = (HttpClient)startPeer("http"); + } + + public static void main(String[] args) { + try { + + LoggingFactory.init(Level.INFO); + + Runtime.start("webgui", "WebGui"); + Runtime.start("python", "Python"); + Runtime.start("mouth", "RemoteSpeech"); + + } catch (Exception e) { + log.error("main threw", e); + } + } + + @Override + public AudioData generateAudioData(AudioData audioData, String toSpeak) throws Exception { + + try { + // IF GET must url encode .. use replace tags like {urlEncodedText} + String localFileName = getLocalFileName(toSpeak); + // merge template with text and/or config + String url = config.url.replace("{text}", URLEncoder.encode(toSpeak, StandardCharsets.UTF_8.toString())); + byte[] bytes = http.getBytes(url); + FileIO.toFile(localFileName, bytes); + return new AudioData(localFileName); + } catch (Exception e) { + error(e); + } + + return null; + } + + @Override + public void loadVoices() throws Exception { + addVoice("default", null, null, "remote"); + } +} diff --git a/src/main/java/org/myrobotlab/service/config/RemoteSpeechConfig.java b/src/main/java/org/myrobotlab/service/config/RemoteSpeechConfig.java new file mode 100644 index 0000000000..c7b48009b1 --- /dev/null +++ b/src/main/java/org/myrobotlab/service/config/RemoteSpeechConfig.java @@ -0,0 +1,21 @@ +package org.myrobotlab.service.config; + +import org.myrobotlab.framework.Plan; + +public class RemoteSpeechConfig extends SpeechSynthesisConfig { + + public String verb = "GET"; + + public String url = "http://localhost:5002/api/tts?text={text}"; + + public String template = null; + + public String speechType = "ModzillaTTS"; + + public Plan getDefault(Plan plan, String name) { + super.getDefault(plan, name); + addDefaultPeerConfig(plan, name, "http", "HttpClient", true); + return plan; + } + +} diff --git a/src/main/java/org/myrobotlab/service/meta/RemoteSpeechMeta.java b/src/main/java/org/myrobotlab/service/meta/RemoteSpeechMeta.java new file mode 100644 index 0000000000..a2b2b7f007 --- /dev/null +++ b/src/main/java/org/myrobotlab/service/meta/RemoteSpeechMeta.java @@ -0,0 +1,38 @@ +package org.myrobotlab.service.meta; + +import org.myrobotlab.logging.LoggerFactory; +import org.myrobotlab.service.meta.abstracts.MetaData; +import org.slf4j.Logger; + +public class RemoteSpeechMeta extends MetaData { + private static final long serialVersionUID = 1L; + public final static Logger log = LoggerFactory.getLogger(RemoteSpeechMeta.class); + + /** + * This class is contains all the meta data details of a service. It's peers, + * dependencies, and all other meta data related to the service. + * + */ + public RemoteSpeechMeta() { + + // add a cool description + addDescription("used as a general template"); + + // false will prevent it being seen in the ui + setAvailable(true); + + // add dependencies if necessary + // addDependency("com.twelvemonkeys.common", "common-lang", "3.1.1"); + + setAvailable(false); + + // add it to one or many categories + addCategory("general"); + + // add a sponsor to this service + // the person who will do maintenance + // setSponsor("GroG"); + + } + +} diff --git a/src/main/resources/resource/WebGui/app/service/js/RemoteSpeechGui.js b/src/main/resources/resource/WebGui/app/service/js/RemoteSpeechGui.js new file mode 100644 index 0000000000..18ed39bca5 --- /dev/null +++ b/src/main/resources/resource/WebGui/app/service/js/RemoteSpeechGui.js @@ -0,0 +1,40 @@ +angular.module("mrlapp.service.RemoteSpeechGui", []).controller("RemoteSpeechGuiCtrl", [ + "$scope", + "mrl", + function ($scope, mrl) { + console.info("RemoteSpeechGuiCtrl") + var _self = this + var msg = this.msg + + this.updateState = function (service) { + $scope.service = service + $scope.$apply() + } + + this.onMsg = function (inMsg) { + switch (inMsg.method) { + case "onState": + _self.updateState(inMsg.data[0]) + break + default: + console.error("ERROR - unhandled method " + $scope.name + " " + inMsg.method) + break + } + } + + $scope.setType = function (type) { + msg.send("set" + type) + } + + $scope.speak = function (text) { + msg.send("speak", text) + } + + $scope.setVoice = function () { + console.log($scope.service.voice.name) + msg.send("setVoice", $scope.service.voice.name) + } + + msg.subscribe(this) + }, +]) diff --git a/src/main/resources/resource/WebGui/app/service/views/IntroGui.html b/src/main/resources/resource/WebGui/app/service/views/IntroGui.html index b85d70d473..0c9fd3d99a 100644 --- a/src/main/resources/resource/WebGui/app/service/views/IntroGui.html +++ b/src/main/resources/resource/WebGui/app/service/views/IntroGui.html @@ -104,7 +104,6 @@ - diff --git a/src/main/resources/resource/WebGui/app/service/views/RemoteSpeechGui.html b/src/main/resources/resource/WebGui/app/service/views/RemoteSpeechGui.html new file mode 100644 index 0000000000..3d8cbdae9b --- /dev/null +++ b/src/main/resources/resource/WebGui/app/service/views/RemoteSpeechGui.html @@ -0,0 +1,31 @@ +
+
+
+
+ type +
+ {{service.config.speechType}} + + +
+ Install pico2wave +
+ https://doc.ubuntu-fr.org/svoxpico +
+
sudo apt install libttspico-utils
+
+
+ voice +
+ +
+