Skip to content

Commit

Permalink
Merge branch 'develop' of github.com-myrobotlab:MyRobotLab/myrobotlab…
Browse files Browse the repository at this point in the history
… into inmoov-and-statemachine-1
  • Loading branch information
supertick committed Oct 24, 2023
2 parents 2380e7b + 1dc0085 commit 6f0372e
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 30 deletions.
14 changes: 12 additions & 2 deletions src/main/java/org/myrobotlab/codec/CodecUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidObjectException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
Expand Down Expand Up @@ -1481,6 +1482,10 @@ public static boolean isLocal(String name, String id) {
return name.substring(name.indexOf("@") + 1).equals(id);
}

public static ServiceConfig readServiceConfig(String filename) throws IOException {
return readServiceConfig(filename, new StaticType<>() {});
}

/**
* Read a YAML file given by the filename and convert it into a ServiceConfig
* object by deserialization.
Expand All @@ -1491,10 +1496,15 @@ public static boolean isLocal(String name, String id) {
* @throws IOException
* if reading the file fails
*/
public static ServiceConfig readServiceConfig(String filename) throws IOException {
public static <C extends ServiceConfig> C readServiceConfig(String filename, StaticType<C> type) throws IOException {
String data = Files.readString(Paths.get(filename));
Yaml yaml = new Yaml();
return yaml.load(data);
C parsed = yaml.load(data);
if (type.asClass().isAssignableFrom(parsed.getClass())) {
return parsed;
} else {
throw new InvalidObjectException("Deserialized type was " + parsed.getClass() + ", expected " + type + ". Deserialized object: " + parsed);
}
}

/**
Expand Down
25 changes: 17 additions & 8 deletions src/main/java/org/myrobotlab/framework/Service.java
Original file line number Diff line number Diff line change
Expand Up @@ -1403,23 +1403,28 @@ public T getConfig() {
* i01."opencv"
* @return
*/
public ServiceConfig getPeerConfig(String peerKey) {
public <P extends ServiceConfig> P getPeerConfig(String peerKey, StaticType<P> type) {
String peerName = getPeerName(peerKey);
if (peerName == null) {
error("peer name not found for peer key %s", peerKey);
return null;
}

ServiceInterface si = Runtime.getService(peerName);
// Java generics don't let us create a new StaticType using
// P here because the type variable is erased, so we have to cast anyway for now
ConfigurableService<P> si = (ConfigurableService<P>) Runtime.getService(peerName);
if (si != null) {
// peer is currently running - get its config
return si.getConfig();
P c = si.getConfig();
if (type.asClass().isAssignableFrom(c.getClass())) {
return c;
}
}

// peer is not currently running attempt to read from config
Runtime runtime = Runtime.getInstance();
// read current service config for this peer service
ServiceConfig sc = runtime.readServiceConfig(peerName);
P sc = runtime.readServiceConfig(peerName, type);
if (sc == null) {
error("peer service %s is defined, but %s.yml not available on filesystem", peerKey, peerName);
return null;
Expand All @@ -1428,7 +1433,7 @@ public ServiceConfig getPeerConfig(String peerKey) {
}

public void setPeerConfigValue(String peerKey, String fieldname, Object value) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
ServiceConfig sc = getPeerConfig(peerKey);
ServiceConfig sc = getPeerConfig(peerKey, new StaticType<>() {});
if (sc == null) {
error("invalid config for peer key %s field name %s", peerKey, fieldname);
return;
Expand All @@ -1437,7 +1442,7 @@ public void setPeerConfigValue(String peerKey, String fieldname, Object value) t
field.set(sc, value);
savePeerConfig(peerKey, sc);
String peerName = getPeerName(peerKey);
ConfigurableService cs = (ConfigurableService) Runtime.getService(peerName);
var cs = Runtime.getConfigurableService(peerName, new StaticType<Service<ServiceConfig>>() {});
if (cs != null) {
cs.apply(sc); // TODO - look for applies if its read from the file system
// it needs to update Runtime.plan
Expand Down Expand Up @@ -2846,20 +2851,24 @@ public void apply() {
apply((T) sc);
}

public void applyPeerConfig(String peerKey, ServiceConfig config) {
applyPeerConfig(peerKey, config, new StaticType<>() {});
}

/**
* Apply the config to a peer, regardless if the peer is currently running or
* not
*
* @param peerKey
* @param config
*/
public void applyPeerConfig(String peerKey, ServiceConfig config) {
public <P extends ServiceConfig> void applyPeerConfig(String peerKey, P config, StaticType<Service<P>> configServiceType) {
String peerName = getPeerName(peerKey);

Runtime.getPlan().put(peerName, config);

// meh - templating is not very helpful here
ConfigurableService si = (ConfigurableService) Runtime.getService(peerName);
ConfigurableService<P> si = Runtime.getService(peerName, configServiceType);
if (si != null) {
si.apply(config);
}
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/org/myrobotlab/framework/StaticType.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,27 @@ public Type getType() {
return storedType;
}

/**
* Get the stored type as a Class object
* that can be used for checking cast
* compatibility. Note that the resulting
* Class object will not check for generic
* compatibility. If the stored type
* is not a Class type, then this method
* throws {@link IllegalStateException}.
*
* @return The internal stored type cast to a Class object
* @throws IllegalStateException if the stored type is not a Class.
*/
@SuppressWarnings("unchecked")
public Class<T> asClass() {
if (storedType instanceof Class) {
return (Class<T>) storedType;
} else {
throw new IllegalStateException("Stored type " + storedType + " is not a Class.");
}
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand All @@ -96,6 +117,11 @@ public int hashCode() {
return storedType != null ? storedType.hashCode() : 0;
}


@Override
public String toString() {
return storedType.toString();
}
/**
* Function to recursively validate type parameters
* to ensure they are all concrete so no type variables sneak in.
Expand Down
52 changes: 39 additions & 13 deletions src/main/java/org/myrobotlab/service/InMoov2.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
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;
Expand Down Expand Up @@ -98,22 +99,13 @@ public static boolean loadFile(String file) {
return true;
}

public static void main(String[] args) {
try {

LoggingFactory.init(Level.ERROR);
// identical to command line start
// Runtime.startConfig("inmoov2");
Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", "WebGui", "intro", "Intro", "python", "Python" });
} catch (Exception e) {
log.error("main threw", e);
}
}

/**
* the config that was processed before booting, if there was one.
*/
String bootedConfig = null;
protected String bootedConfig = null;

protected LedDisplayData led = new LedDisplayData();

protected transient ProgramAB chatBot;

Expand Down Expand Up @@ -1548,7 +1540,17 @@ public void publishInactivity() {
log.info("publishInactivity");
fsm.fire("inactvity");
}


/**
* used to configure a flashing event - could use configuration to signal
* different colors and states
*
* @return
*/
public LedDisplayData publishFlash() {
return led;
}

/**
* A more extensible interface point than publishEvent FIXME - create
* interface for this
Expand Down Expand Up @@ -2099,6 +2101,19 @@ public void startService() {

// get service start and release life cycle events
runtime.attachServiceLifeCycleListener(getName());

List<ServiceInterface> services = Runtime.getServices();
for (ServiceInterface si : services) {
if ("Servo".equals(si.getSimpleName())) {
send(si.getFullName(), "setAutoDisable", true);
}
}

// get events of new services and shutdown
subscribe("runtime", "shutdown");
// power up loopback subscription
addListener(getName(), "powerUp");

subscribe("runtime", "publishConfigList");

// subscribe to config processing events
Expand Down Expand Up @@ -2364,5 +2379,16 @@ public void wake() {
}
}

public static void main(String[] args) {
try {

LoggingFactory.init(Level.ERROR);
// identical to command line start
// Runtime.startConfig("inmoov2");
Runtime.main(new String[] { "--log-level", "info", "-s", "webgui", "WebGui", "intro", "Intro", "python", "Python" });
} catch (Exception e) {
log.error("main threw", e);
}
}

}
3 changes: 3 additions & 0 deletions src/main/java/org/myrobotlab/service/Python.java
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,9 @@ public PythonConfig apply(PythonConfig c) {
*/
public List<String> getScriptList() throws IOException {
List<String> sorted = new ArrayList<>();
if (config.scriptRootDir == null) {
config.scriptRootDir = new File(getDataInstanceDir()).getAbsolutePath();
}
List<File> files = FileIO.getFileList(config.scriptRootDir, true);
for (File file : files) {
if (file.toString().endsWith(".py")) {
Expand Down
38 changes: 33 additions & 5 deletions src/main/java/org/myrobotlab/service/Runtime.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import org.myrobotlab.framework.Registration;
import org.myrobotlab.framework.Service;
import org.myrobotlab.framework.ServiceReservation;
import org.myrobotlab.framework.StaticType;
import org.myrobotlab.framework.Status;
import org.myrobotlab.framework.interfaces.ConfigurableService;
import org.myrobotlab.framework.interfaces.MessageListener;
Expand Down Expand Up @@ -440,7 +441,11 @@ synchronized private static Map<String, ServiceInterface> createServicesFromPlan
// 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);
Expand Down Expand Up @@ -1150,6 +1155,14 @@ public static Map<String, ServiceInterface> getRegistry() {
return registry;// FIXME should return copy
}

public static ServiceInterface getService(String inName) {
return getService(inName, new StaticType<>() {});
}

public static <C extends ServiceConfig, S extends ServiceInterface & ConfigurableService<C>> S getConfigurableService(String inName, StaticType<S> serviceType) {
return getService(inName, serviceType);
}

/**
* Gets a running service with the specified name. If the name is null or
* there's no such service with the specified name, returns null instead.
Expand All @@ -1158,7 +1171,8 @@ public static Map<String, ServiceInterface> getRegistry() {
* The name of the service
* @return The service if it exists, or null
*/
public static ServiceInterface getService(String inName) {
@SuppressWarnings("unchecked")
public static <S extends ServiceInterface> S getService(String inName, StaticType<S> serviceType) {
if (inName == null) {
return null;
}
Expand All @@ -1168,7 +1182,7 @@ public static ServiceInterface getService(String inName) {
if (!registry.containsKey(name)) {
return null;
} else {
return registry.get(name);
return (S) registry.get(name);
}
}

Expand Down Expand Up @@ -4769,6 +4783,20 @@ synchronized private Plan loadService(Plan plan, String name, String type, boole
public ServiceConfig readServiceConfig(String name) {
return readServiceConfig(null, name);
}

/**
* read a service's configuration, in the context
* of current config set name or default
* @param name
* @return
*/
public <C extends ServiceConfig> C readServiceConfig(String name, StaticType<C> configType) {
return readServiceConfig(null, name, configType);
}

public ServiceConfig readServiceConfig(String configName, String name) {
return readServiceConfig(configName, name, new StaticType<>() {});
}

/**
*
Expand All @@ -4778,7 +4806,7 @@ public ServiceConfig readServiceConfig(String name) {
* - name of config file within that dir e.g. {name}.yml
* @return
*/
public ServiceConfig readServiceConfig(String configName, String name) {
public <C extends ServiceConfig> C readServiceConfig(String configName, String name, StaticType<C> configType) {
// if config path set and yaml file exists - it takes precedence

if (configName == null) {
Expand All @@ -4792,10 +4820,10 @@ public ServiceConfig readServiceConfig(String configName, String name) {

String filename = CONFIG_ROOT + fs + configName + fs + name + ".yml";
File check = new File(filename);
ServiceConfig sc = null;
C sc = null;
if (check.exists()) {
try {
sc = CodecUtils.readServiceConfig(filename);
sc = CodecUtils.readServiceConfig(filename, configType);
} catch (ConstructorException e) {
error("%s invalid %s %s. Please remove it from the file.", name, filename, e.getCause().getMessage());
} catch (IOException e) {
Expand Down
5 changes: 3 additions & 2 deletions src/test/java/org/myrobotlab/service/InMoov2Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.junit.Assert.assertTrue;

import org.junit.Test;
import org.myrobotlab.framework.StaticType;
import org.myrobotlab.service.config.OpenCVConfig;

public class InMoov2Test {
Expand All @@ -14,11 +15,11 @@ public void testCvFilters() throws NoSuchFieldException, SecurityException, Ille

// flip
i01.setPeerConfigValue("opencv", "flip", true);
OpenCVConfig cvconfig = (OpenCVConfig)i01.getPeerConfig("opencv");
OpenCVConfig cvconfig = i01.getPeerConfig("opencv", new StaticType<>() {});
assertTrue(cvconfig.flip);

i01.setPeerConfigValue("opencv", "flip", false);
cvconfig = (OpenCVConfig)i01.getPeerConfig("opencv");
cvconfig = i01.getPeerConfig("opencv", new StaticType<>() {});
assertFalse(cvconfig.flip);

}
Expand Down

0 comments on commit 6f0372e

Please sign in to comment.