use of me.retrodaredevil.action.Action in project solarthing by wildmountainfarms.
the class CommandController method runCommand.
/**
* Runs the given action. A response is not returned until the action is done running
*
* @param apiKey The api key
* @param commandName The name of the command, which corresponds to an action
* @return
*/
@GetMapping(path = "/run", produces = "application/json")
public CommandRequestResponse runCommand(String apiKey, String commandName) {
// Also consider using this way instead of exceptions: https://stackoverflow.com/a/60079942
if (apiKey == null) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "apiKey is required!");
}
if (commandName == null) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "commandName is required!");
}
if (!commandHandler.isAuthorized(apiKey)) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "You are not authorized with the given api key!");
}
ActionNode actionNode = commandHandler.getActionNode(commandName);
if (actionNode == null) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "No corresponding command with commandName: " + commandName);
}
InjectEnvironment injectEnvironment = commandHandler.createInjectEnvironment(commandName);
// We don't know or care what thread this is running on, so we won't have a shared global variable environment.
// We could make a shared global environment a feature of this down the line, but for now let's keep this simple
ActionEnvironment actionEnvironment = new ActionEnvironment(new VariableEnvironment(), new VariableEnvironment(), injectEnvironment);
Action action = actionNode.createAction(actionEnvironment);
while (!action.isDone()) {
action.update();
try {
// This is here to make sure our CPU doesn't go to 100% for no reason
Thread.sleep(5);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOGGER.error("Interrupted while action was being performed.", e);
action.end();
return new CommandRequestResponse(false);
}
}
action.end();
return new CommandRequestResponse(true);
}
use of me.retrodaredevil.action.Action in project solarthing by wildmountainfarms.
the class ActionNodeTest method testDeclaration.
@Test
void testDeclaration() throws JsonProcessingException {
String json = "{\n" + " \"type\": \"race\",\n" + " \"racers\": [\n" + " [{ \"type\": \"waitms\", \"wait\": 500}, { \"type\": \"log\", \"message\": \"500ms finished first!\"}],\n" + " [{ \"type\": \"waitms\", \"wait\": 200}, { \"type\": \"log\", \"message\": \"200ms finished first!\"}],\n" + " [{ \"type\": \"waitms\", \"wait\": 1000}, { \"type\": \"log\", \"message\": \"1000ms finished first!\"}]\n" + " ]\n" + "}";
ActionNode actionNode = MAPPER.readValue(json, ActionNode.class);
Action action = actionNode.createAction(createEnvironment());
do {
action.update();
} while (!action.isDone());
action.end();
}
use of me.retrodaredevil.action.Action in project solarthing by wildmountainfarms.
the class ActionNodeDataReceiver method receiveData.
private void receiveData(OpenSource source, String commandName) {
ActionNode requested = actionNodeMap.get(commandName);
if (requested != null) {
InjectEnvironment.Builder injectEnvironmentBuilder = new InjectEnvironment.Builder();
environmentUpdater.updateInjectEnvironment(source, injectEnvironmentBuilder);
Action action = requested.createAction(new ActionEnvironment(variableEnvironment, new VariableEnvironment(), injectEnvironmentBuilder.build()));
// Now that action has been created, add it to the action multiplexer. (Adding is thread safe).
// The action has not been used by this thread, so when a different thread starts executing it, there will be no problems.
actionMultiplexer.add(action);
LOGGER.info(SolarThingConstants.SUMMARY_MARKER, source.getSender() + " has requested command sequence: " + commandName);
} else {
LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Sender: " + source.getSender() + " has requested unknown command: " + commandName);
}
}
use of me.retrodaredevil.action.Action in project solarthing by wildmountainfarms.
the class SlackChatBotActionNode method createAction.
@Override
public Action createAction(ActionEnvironment actionEnvironment) {
LatestFragmentedPacketGroupEnvironment latestPacketGroupEnvironment = actionEnvironment.getInjectEnvironment().get(LatestFragmentedPacketGroupEnvironment.class);
AlterPacketsEnvironment alterPacketsEnvironment = actionEnvironment.getInjectEnvironment().get(AlterPacketsEnvironment.class);
SolarThingDatabaseEnvironment solarThingDatabaseEnvironment = actionEnvironment.getInjectEnvironment().get(SolarThingDatabaseEnvironment.class);
SourceIdEnvironment sourceIdEnvironment = actionEnvironment.getInjectEnvironment().get(SourceIdEnvironment.class);
TimeZoneEnvironment timeZoneEnvironment = actionEnvironment.getInjectEnvironment().get(TimeZoneEnvironment.class);
EventDatabaseCacheEnvironment eventDatabaseCacheEnvironment = actionEnvironment.getInjectEnvironment().get(EventDatabaseCacheEnvironment.class);
// Note that all objects listed here must be thread safe, as data will be accessed from them on a separate thread
FragmentedPacketGroupProvider packetGroupProvider = latestPacketGroupEnvironment.getFragmentedPacketGroupProvider();
AlterPacketsProvider alterPacketsProvider = alterPacketsEnvironment.getAlterPacketsProvider();
SolarThingDatabase database = solarThingDatabaseEnvironment.getSolarThingDatabase();
String sourceId = sourceIdEnvironment.getSourceId();
ZoneId zoneId = timeZoneEnvironment.getZoneId();
ResourceManager<? extends DatabaseCache> eventDatabaseCacheManager = eventDatabaseCacheEnvironment.getEventDatabaseCacheManager();
Slack slack = Slack.getInstance(new SlackConfig(), new SlackHttpClient(new OkHttpClient.Builder().callTimeout(Duration.ofSeconds(10)).connectTimeout(Duration.ofSeconds(4)).build()));
ChatBotCommandHelper commandHelper = new ChatBotCommandHelper(permissionMap, packetGroupProvider, new CommandManager(keyDirectory, sender));
return new SlackChatBotAction(appToken, new SlackMessageSender(authToken, channelId, slack), slack, new HelpChatBotHandler(new ChatBotHandlerMultiplexer(Arrays.asList(// note: this isn't applied to "help" commands
new StaleMessageHandler(), new ScheduleCommandChatBotHandler(commandHelper, database, sourceId, zoneId), new CancelCommandChatBotHandler(commandHelper, database, sourceId, zoneId, alterPacketsProvider), new FlagCommandChatBotHandler(commandHelper, database, sourceId, zoneId, alterPacketsProvider), new CommandChatBotHandler(commandHelper, database, sourceId, zoneId), new StatusChatBotHandler(packetGroupProvider, alterPacketsProvider), new HeartbeatCommandChatBotHandler(eventDatabaseCacheManager), (message, messageSender) -> {
messageSender.sendMessage("Unknown command!");
return true;
}))));
}
use of me.retrodaredevil.action.Action in project solarthing by wildmountainfarms.
the class DeserializeTest method testRunAlertGeneratorOffWhileAuxOn.
@Test
void testRunAlertGeneratorOffWhileAuxOn() throws IOException, ParsePacketAsciiDecimalDigitException, CheckSumException {
File file = new File(ACTION_CONFIG_DIRECTORY, "alert_generator_off_while_aux_on.json");
ActionNode actionNode = MAPPER.readValue(file, ActionNode.class);
// We need to simulate an automation program environment to run this action
Duration[] timeReference = new Duration[] { Duration.ZERO };
FragmentedPacketGroup[] packetGroupReference = new FragmentedPacketGroup[] { null };
FragmentedPacketGroupProvider fragmentedPacketGroupProvider = () -> requireNonNull(packetGroupReference[0]);
InjectEnvironment injectEnvironment = new InjectEnvironment.Builder().add(new NanoTimeProviderEnvironment(() -> timeReference[0].toNanos())).add(new LatestPacketGroupEnvironment(fragmentedPacketGroupProvider)).add(new LatestFragmentedPacketGroupEnvironment(fragmentedPacketGroupProvider)).build();
FXStatusPacket auxOnNoAC = FXStatusPackets.createFromChars("\n1,00,00,02,123,123,00,10,000,00,252,136,000,999\r".toCharArray(), IgnoreCheckSum.IGNORE);
FXStatusPacket auxOffNoAC = FXStatusPackets.createFromChars("\n1,00,00,02,123,123,00,10,000,00,252,008,000,999\r".toCharArray(), IgnoreCheckSum.IGNORE);
FXStatusPacket auxOnACUse = FXStatusPackets.createFromChars("\n1,00,00,02,123,123,00,10,000,02,252,136,000,999\r".toCharArray(), IgnoreCheckSum.IGNORE);
FXStatusPacket auxOffACUse = FXStatusPackets.createFromChars("\n1,00,00,02,123,123,00,10,000,02,252,008,000,999\r".toCharArray(), IgnoreCheckSum.IGNORE);
for (FXStatusPacket packet : new FXStatusPacket[] { auxOffNoAC, auxOnACUse, auxOffACUse }) {
// for these three cases, the action should end immediately
packetGroupReference[0] = PacketGroups.createInstancePacketGroup(Collections.singleton(packet), 0L, "my_source_id", 999);
Action action = actionNode.createAction(new ActionEnvironment(new VariableEnvironment(), new VariableEnvironment(), injectEnvironment));
action.update();
assertTrue(action.isDone());
}
{
// Test that no alert is sent unless the aux is on, and it's in No AC for 30 seconds
packetGroupReference[0] = PacketGroups.createInstancePacketGroup(Collections.singleton(auxOnNoAC), 0L, "my_source_id", 999);
Action action = actionNode.createAction(new ActionEnvironment(new VariableEnvironment(), new VariableEnvironment(), injectEnvironment));
action.update();
assertFalse(action.isDone());
timeReference[0] = timeReference[0].plus(Duration.ofSeconds(29));
action.update();
assertFalse(action.isDone());
packetGroupReference[0] = PacketGroups.createInstancePacketGroup(Collections.singleton(auxOnACUse), 0L, "my_source_id", 999);
action.update();
// No alert has been sent, since it started to AC Use before the 30 second period completed.
assertTrue(action.isDone());
}
{
// Test that the alert gets sent and the action doesn't end until the 300-second timeout completes
packetGroupReference[0] = PacketGroups.createInstancePacketGroup(Collections.singleton(auxOnNoAC), 0L, "my_source_id", 999);
Action action = actionNode.createAction(new ActionEnvironment(new VariableEnvironment(), new VariableEnvironment(), injectEnvironment));
action.update();
assertFalse(action.isDone());
timeReference[0] = timeReference[0].plus(Duration.ofSeconds(30));
action.update();
assertFalse(action.isDone());
packetGroupReference[0] = PacketGroups.createInstancePacketGroup(Collections.singleton(auxOnACUse), 0L, "my_source_id", 999);
action.update();
// Alert has been sent, so the action isn't going to end
assertFalse(action.isDone());
timeReference[0] = timeReference[0].plus(Duration.ofSeconds(299));
action.update();
assertFalse(action.isDone());
timeReference[0] = timeReference[0].plus(Duration.ofSeconds(1));
action.update();
// the 300-second timeout has completed, so the action will end
assertTrue(action.isDone());
}
}
Aggregations