Search in sources :

Example 1 with ActionNode

use of me.retrodaredevil.action.node.ActionNode in project solarthing by wildmountainfarms.

the class PacketHandlerInit method initHandlers.

public static <T extends PacketHandlingOption & CommandOption> Result initHandlers(T options, Supplier<? extends EnvironmentUpdater> environmentUpdaterSupplier, Collection<? extends PacketHandler> additionalPacketHandlers) throws IOException {
    List<DatabaseConfig> databaseConfigs = ConfigUtil.getDatabaseConfigs(options);
    PacketHandlerBundle packetHandlerBundle = PacketHandlerInit.getPacketHandlerBundle(databaseConfigs, SolarThingConstants.STATUS_DATABASE, SolarThingConstants.EVENT_DATABASE, options.getSourceId(), options.getFragmentId());
    List<PacketHandler> statusPacketHandlers = new ArrayList<>();
    final Runnable updateCommandActions;
    if (options.hasCommands()) {
        LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Command are enabled!");
        // this is used to determine the state of the system when a command is requested
        LatestPacketHandler latestPacketHandler = new LatestPacketHandler();
        statusPacketHandlers.add(latestPacketHandler);
        Map<String, ActionNode> actionNodeMap = ActionUtil.getActionNodeMap(CONFIG_MAPPER, options);
        ActionNodeDataReceiver commandReceiver = new ActionNodeDataReceiver(actionNodeMap, (source, injectEnvironmentBuilder) -> {
            injectEnvironmentBuilder.add(new NanoTimeProviderEnvironment(NanoTimeProvider.SYSTEM_NANO_TIME)).add(new TimeZoneEnvironment(options.getZoneId())).add(new LatestPacketGroupEnvironment(latestPacketHandler::getLatestPacketCollection)).add(new SourceEnvironment(source)).add(new EventReceiverEnvironment(PacketListReceiverHandlerBundle.createEventPacketListReceiverHandler(SolarMain.getSourceAndFragmentUpdater(options), options.getZoneId(), packetHandlerBundle)));
            EnvironmentUpdater environmentUpdater = environmentUpdaterSupplier.get();
            if (environmentUpdater == null) {
                throw new NullPointerException("The EnvironmentUpdater supplier gave a null value! (Fatal)");
            }
            environmentUpdater.updateInjectEnvironment(source, injectEnvironmentBuilder);
        });
        PacketGroupReceiver mainPacketGroupReceiver = new PacketGroupReceiverMultiplexer(Arrays.asList(commandReceiver, new RequestHeartbeatReceiver(PacketListReceiverHandlerBundle.createEventPacketListReceiverHandler(SolarMain.getSourceAndFragmentUpdater(options), options.getZoneId(), packetHandlerBundle))));
        statusPacketHandlers.add((packetCollection) -> commandReceiver.getActionUpdater().update());
        List<PacketHandler> commandPacketHandlers = CommandUtil.getCommandRequesterHandlerList(databaseConfigs, mainPacketGroupReceiver, options);
        statusPacketHandlers.add(new PacketHandlerMultiplexer(commandPacketHandlers));
        updateCommandActions = () -> commandReceiver.getActionUpdater().update();
    } else {
        LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Commands are disabled");
        updateCommandActions = () -> {
        };
    }
    statusPacketHandlers.addAll(additionalPacketHandlers);
    statusPacketHandlers.addAll(packetHandlerBundle.getStatusPacketHandlers());
    PacketListReceiverHandlerBundle bundle = PacketListReceiverHandlerBundle.createFrom(options, packetHandlerBundle, statusPacketHandlers);
    return new Result(bundle, updateCommandActions);
}
Also used : TimeZoneEnvironment(me.retrodaredevil.solarthing.actions.environment.TimeZoneEnvironment) EventReceiverEnvironment(me.retrodaredevil.solarthing.actions.environment.EventReceiverEnvironment) NanoTimeProviderEnvironment(me.retrodaredevil.action.node.environment.NanoTimeProviderEnvironment) LatestPacketGroupEnvironment(me.retrodaredevil.solarthing.actions.environment.LatestPacketGroupEnvironment) PacketGroupReceiver(me.retrodaredevil.solarthing.PacketGroupReceiver) ArrayList(java.util.ArrayList) ActionNode(me.retrodaredevil.action.node.ActionNode) RequestHeartbeatReceiver(me.retrodaredevil.solarthing.program.receiver.RequestHeartbeatReceiver) PacketGroupReceiverMultiplexer(me.retrodaredevil.solarthing.PacketGroupReceiverMultiplexer) EnvironmentUpdater(me.retrodaredevil.solarthing.actions.command.EnvironmentUpdater) SourceEnvironment(me.retrodaredevil.solarthing.actions.environment.SourceEnvironment) FileWritePacketHandler(me.retrodaredevil.solarthing.packets.handling.implementations.FileWritePacketHandler) PostPacketHandler(me.retrodaredevil.solarthing.packets.handling.implementations.PostPacketHandler) JacksonStringPacketHandler(me.retrodaredevil.solarthing.packets.handling.implementations.JacksonStringPacketHandler) ActionNodeDataReceiver(me.retrodaredevil.solarthing.program.receiver.ActionNodeDataReceiver)

Example 2 with ActionNode

use of me.retrodaredevil.action.node.ActionNode 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);
}
Also used : ActionEnvironment(me.retrodaredevil.action.node.environment.ActionEnvironment) Action(me.retrodaredevil.action.Action) ActionNode(me.retrodaredevil.action.node.ActionNode) VariableEnvironment(me.retrodaredevil.action.node.environment.VariableEnvironment) ResponseStatusException(org.springframework.web.server.ResponseStatusException) InjectEnvironment(me.retrodaredevil.action.node.environment.InjectEnvironment) GetMapping(org.springframework.web.bind.annotation.GetMapping)

Example 3 with ActionNode

use of me.retrodaredevil.action.node.ActionNode 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();
}
Also used : Action(me.retrodaredevil.action.Action) ActionNode(me.retrodaredevil.action.node.ActionNode) CallActionNode(me.retrodaredevil.action.node.CallActionNode) Test(org.junit.jupiter.api.Test)

Example 4 with ActionNode

use of me.retrodaredevil.action.node.ActionNode 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);
    }
}
Also used : ActionEnvironment(me.retrodaredevil.action.node.environment.ActionEnvironment) Action(me.retrodaredevil.action.Action) ActionNode(me.retrodaredevil.action.node.ActionNode) VariableEnvironment(me.retrodaredevil.action.node.environment.VariableEnvironment) InjectEnvironment(me.retrodaredevil.action.node.environment.InjectEnvironment)

Example 5 with ActionNode

use of me.retrodaredevil.action.node.ActionNode in project solarthing by wildmountainfarms.

the class AutomationMain method startAutomation.

public static int startAutomation(List<ActionNode> actionNodes, DatabaseTimeZoneOptionBase options, long periodMillis) {
    LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Starting automation program.");
    final CouchDbDatabaseSettings couchSettings;
    try {
        couchSettings = ConfigUtil.expectCouchDbDatabaseSettings(options);
    } catch (IllegalArgumentException ex) {
        LOGGER.error("(Fatal)", ex);
        return SolarThingConstants.EXIT_CODE_INVALID_CONFIG;
    }
    SolarThingDatabase database = CouchDbSolarThingDatabase.create(CouchDbUtil.createInstance(couchSettings.getCouchProperties(), couchSettings.getOkHttpProperties()));
    VariableEnvironment variableEnvironment = new VariableEnvironment();
    // Use atomic reference so that access is thread safe
    AtomicReference<FragmentedPacketGroup> latestPacketGroupReference = new AtomicReference<>(null);
    // Use atomic reference so that access is thread safe
    AtomicReference<List<VersionedPacket<StoredAlterPacket>>> alterPacketsReference = new AtomicReference<>(null);
    // note this may return null, and that's OK // This is thread safe if needed
    FragmentedPacketGroupProvider fragmentedPacketGroupProvider = latestPacketGroupReference::get;
    Clock clock = Clock.systemUTC();
    SimpleDatabaseCache statusDatabaseCache = SimpleDatabaseCache.createDefault(clock);
    // not thread safe
    ResourceManager<SimpleDatabaseCache> statusDatabaseCacheManager = new BasicResourceManager<>(statusDatabaseCache);
    SimpleDatabaseCache eventDatabaseCache = SimpleDatabaseCache.createDefault(clock);
    ResourceManager<SimpleDatabaseCache> eventDatabaseCacheManager = new ReadWriteResourceManager<>(eventDatabaseCache);
    SimpleDatabaseCache openDatabaseCache = new SimpleDatabaseCache(Duration.ofMinutes(60), Duration.ofMinutes(40), Duration.ofMinutes(20), Duration.ofMinutes(15), clock);
    // not thread safe
    ResourceManager<SimpleDatabaseCache> openDatabaseCacheManager = new BasicResourceManager<>(openDatabaseCache);
    SimplePacketCache<AuthorizationPacket> authorizationPacketCache = new SimplePacketCache<>(Duration.ofSeconds(20), DatabaseDocumentKeyMap.createPacketSourceFromDatabase(database), false);
    String sourceId = options.getSourceId();
    InjectEnvironment injectEnvironment = new InjectEnvironment.Builder().add(new NanoTimeProviderEnvironment(NanoTimeProvider.SYSTEM_NANO_TIME)).add(new SourceIdEnvironment(sourceId)).add(// most of the time, it's better to use SolarThingDatabaseEnvironment instead, but this option is here in case it's needed
    new CouchDbEnvironment(couchSettings)).add(new SolarThingDatabaseEnvironment(CouchDbSolarThingDatabase.create(CouchDbUtil.createInstance(couchSettings.getCouchProperties(), couchSettings.getOkHttpProperties())))).add(new TimeZoneEnvironment(options.getZoneId())).add(// access is thread safe if needed
    new LatestPacketGroupEnvironment(fragmentedPacketGroupProvider)).add(// access is thread safe if needed
    new LatestFragmentedPacketGroupEnvironment(fragmentedPacketGroupProvider)).add(new EventDatabaseCacheEnvironment(eventDatabaseCacheManager)).add(new OpenDatabaseCacheEnvironment(openDatabaseCache)).add(// access is thread safe if needed
    new AlterPacketsEnvironment(alterPacketsReference::get)).add(new AuthorizationEnvironment(new DatabaseDocumentKeyMap(authorizationPacketCache))).build();
    ActionMultiplexer multiplexer = new Actions.ActionMultiplexerBuilder().build();
    while (!Thread.currentThread().isInterrupted()) {
        queryAndFeed(database.getStatusDatabase(), statusDatabaseCacheManager, true);
        queryAndFeed(database.getEventDatabase(), eventDatabaseCacheManager, true);
        queryAndFeed(database.getOpenDatabase(), openDatabaseCacheManager, false);
        {
            // Never cache alter packets, because it's always important that we have up-to-date data, or no data at all.
            List<VersionedPacket<StoredAlterPacket>> alterPackets = null;
            try {
                alterPackets = database.getAlterDatabase().queryAll(sourceId);
                LOGGER.debug("Got " + alterPackets.size() + " alter packets");
            } catch (SolarThingDatabaseException e) {
                LOGGER.error("Could not get alter packets", e);
            }
            alterPacketsReference.set(alterPackets);
        }
        // we have auto update turned off, so we have to call this
        authorizationPacketCache.updateIfNeeded();
        List<FragmentedPacketGroup> statusPacketGroups = PacketUtil.getPacketGroups(options.getSourceId(), options.getDefaultInstanceOptions(), statusDatabaseCache.getAllCachedPackets());
        if (statusPacketGroups != null) {
            FragmentedPacketGroup statusPacketGroup = statusPacketGroups.get(statusPacketGroups.size() - 1);
            latestPacketGroupReference.set(statusPacketGroup);
        }
        for (ActionNode actionNode : actionNodes) {
            multiplexer.add(actionNode.createAction(new ActionEnvironment(variableEnvironment, new VariableEnvironment(), injectEnvironment)));
        }
        multiplexer.update();
        LOGGER.debug("There are " + multiplexer.getActiveActions().size() + " active actions");
        try {
            Thread.sleep(periodMillis);
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
            throw new RuntimeException(ex);
        }
    }
    return 0;
}
Also used : ActionEnvironment(me.retrodaredevil.action.node.environment.ActionEnvironment) NanoTimeProviderEnvironment(me.retrodaredevil.action.node.environment.NanoTimeProviderEnvironment) ActionNode(me.retrodaredevil.action.node.ActionNode) BasicResourceManager(me.retrodaredevil.solarthing.util.sync.BasicResourceManager) Clock(java.time.Clock) FragmentedPacketGroupProvider(me.retrodaredevil.solarthing.FragmentedPacketGroupProvider) InjectEnvironment(me.retrodaredevil.action.node.environment.InjectEnvironment) AuthorizationPacket(me.retrodaredevil.solarthing.type.closed.authorization.AuthorizationPacket) SimpleDatabaseCache(me.retrodaredevil.solarthing.database.cache.SimpleDatabaseCache) SimplePacketCache(me.retrodaredevil.solarthing.database.cache.SimplePacketCache) ArrayList(java.util.ArrayList) List(java.util.List) ActionMultiplexer(me.retrodaredevil.action.ActionMultiplexer) CouchDbSolarThingDatabase(me.retrodaredevil.solarthing.database.couchdb.CouchDbSolarThingDatabase) ReadWriteResourceManager(me.retrodaredevil.solarthing.util.sync.ReadWriteResourceManager) FragmentedPacketGroup(me.retrodaredevil.solarthing.packets.collection.FragmentedPacketGroup) StoredAlterPacket(me.retrodaredevil.solarthing.type.alter.StoredAlterPacket) Actions(me.retrodaredevil.action.Actions) AtomicReference(java.util.concurrent.atomic.AtomicReference) SolarThingDatabaseException(me.retrodaredevil.solarthing.database.exception.SolarThingDatabaseException) CouchDbDatabaseSettings(me.retrodaredevil.solarthing.config.databases.implementations.CouchDbDatabaseSettings) VariableEnvironment(me.retrodaredevil.action.node.environment.VariableEnvironment)

Aggregations

ActionNode (me.retrodaredevil.action.node.ActionNode)7 Action (me.retrodaredevil.action.Action)4 ActionEnvironment (me.retrodaredevil.action.node.environment.ActionEnvironment)4 InjectEnvironment (me.retrodaredevil.action.node.environment.InjectEnvironment)4 VariableEnvironment (me.retrodaredevil.action.node.environment.VariableEnvironment)4 NanoTimeProviderEnvironment (me.retrodaredevil.action.node.environment.NanoTimeProviderEnvironment)3 File (java.io.File)2 ArrayList (java.util.ArrayList)2 FragmentedPacketGroupProvider (me.retrodaredevil.solarthing.FragmentedPacketGroupProvider)2 LatestPacketGroupEnvironment (me.retrodaredevil.solarthing.actions.environment.LatestPacketGroupEnvironment)2 FragmentedPacketGroup (me.retrodaredevil.solarthing.packets.collection.FragmentedPacketGroup)2 Test (org.junit.jupiter.api.Test)2 Clock (java.time.Clock)1 Duration (java.time.Duration)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Map (java.util.Map)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1 ActionMultiplexer (me.retrodaredevil.action.ActionMultiplexer)1 Actions (me.retrodaredevil.action.Actions)1