All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.yamcs.activities.CommandStackExecution Maven / Gradle / Ivy

There is a newer version: 5.10.9
Show newest version
package org.yamcs.activities;

import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;

import org.yamcs.Processor;
import org.yamcs.YamcsServer;
import org.yamcs.cmdhistory.Attribute;
import org.yamcs.cmdhistory.CommandHistoryConsumer;
import org.yamcs.cmdhistory.CommandHistoryPublisher;
import org.yamcs.cmdhistory.CommandHistoryPublisher.AckStatus;
import org.yamcs.commanding.PreparedCommand;
import org.yamcs.mdb.MdbFactory;
import org.yamcs.protobuf.Commanding.CommandHistoryAttribute;
import org.yamcs.protobuf.Commanding.CommandId;
import org.yamcs.security.User;
import org.yamcs.yarch.Bucket;

public class CommandStackExecution extends ActivityExecution {

    private Processor processor;
    private Bucket bucket;
    private String stackName;
    private User user;

    public CommandStackExecution(
            ActivityService activityService,
            CommandStackExecutor executor,
            Activity activity,
            Processor processor,
            Bucket bucket,
            String stackName,
            User user) {
        super(activityService, executor, activity);
        this.processor = processor;
        this.bucket = bucket;
        this.stackName = stackName;
        this.user = user;
    }

    @Override
    public Void run() throws Exception {
        var yamcs = YamcsServer.getServer();
        var cmdManager = processor.getCommandingManager();
        var histManager = processor.getCommandHistoryManager();
        var mdb = MdbFactory.getInstance(processor.getInstance());
        var origin = InetAddress.getLocalHost().getHostName();
        var seq = 0;

        var bytes = bucket.getObject(stackName);
        var json = new String(bytes, StandardCharsets.UTF_8);
        var stack = CommandStack.fromJson(json, mdb);

        var pendingCommandRef = new AtomicReference();

        var histSubscription = histManager.subscribeCommandHistory(
                null, processor.getCurrentTime(), new CommandHistoryConsumer() {
                    @Override
                    public void addedCommand(PreparedCommand pc) {
                        var currentCommand = pendingCommandRef.get();
                        if (currentCommand != null && currentCommand.cmdId.equals(pc.getCommandId())) {
                            currentCommand.checkIfAcknowledged0(pc.getAttributes());
                        }
                    }

                    @Override
                    public void updatedCommand(CommandId cmdId, long time, List attrs) {
                        var currentCommand = pendingCommandRef.get();
                        if (currentCommand != null && currentCommand.cmdId.equals(cmdId)) {
                            currentCommand.checkIfAcknowledged(attrs);
                        }
                    }
                });

        try {
            for (var stackedCommand : stack.getCommands()) {
                logActivityInfo("Running command " + stackedCommand);

                var args = new LinkedHashMap();
                for (var arg : stackedCommand.getAssignments().entrySet()) {
                    args.put(arg.getKey().getName(), arg.getValue());
                }

                var preparedCommand = cmdManager.buildCommand(
                        stackedCommand.getMetaCommand(), args, origin, seq++, user);
                if (stackedCommand.getComment() != null) {
                    preparedCommand.setComment(stackedCommand.getComment());
                }

                for (var entry : stackedCommand.getExtra().entrySet()) {
                    var commandOption = yamcs.getCommandOption(entry.getKey());
                    if (commandOption == null) {
                        throw new IllegalArgumentException("Unknown command option '" + entry.getKey() + "'");
                    }
                    preparedCommand.addAttribute(CommandHistoryAttribute.newBuilder()
                            .setName(entry.getKey())
                            .setValue(commandOption.coerceValue(entry.getValue()))
                            .build());
                }

                var acknowledgment = stackedCommand.getAcknowledgment();
                if (acknowledgment == null) {
                    acknowledgment = stack.getAcknowledgment();
                }
                var pendingCommand = new PendingCommand(preparedCommand.getCommandId(), acknowledgment);
                pendingCommandRef.set(pendingCommand);

                cmdManager.sendCommand(user, preparedCommand);

                logActivityInfo("Waiting for " + acknowledgment + " acknowledgment");
                // No timeout, this should come from the verifier itself
                var ackStatus = pendingCommand.acknowledgedFuture.get();
                logActivityInfo(acknowledgment + ": " + ackStatus);

                int waitTime = stackedCommand.getWaitTime();
                if (waitTime == -1) {
                    waitTime = stack.getWaitTime();
                }
                if (waitTime > 0) {
                    logActivityInfo("Waiting for " + waitTime + " ms");
                    Thread.sleep(waitTime);
                }
            }
        } finally {
            histManager.unsubscribeCommandHistory(histSubscription.subscriptionId);
        }

        return null;
    }

    @Override
    public void stop() throws Exception {
        // NOP
    }

    private static class PendingCommand {
        final CommandId cmdId;
        final String acknowledgment;
        final CompletableFuture acknowledgedFuture = new CompletableFuture<>();

        PendingCommand(CommandId cmdId, String acknowledgment) {
            this.cmdId = cmdId;
            this.acknowledgment = acknowledgment;
        }

        void checkIfAcknowledged0(List attrs) {
            if (acknowledgedFuture.isDone()) {
                return;
            }
            var ackStatusKey = acknowledgment + CommandHistoryPublisher.SUFFIX_STATUS;
            for (var attr : attrs) {
                if (attr.getName().equals(ackStatusKey)) {
                    var ackStatus = AckStatus.valueOf(attr.getValue().getStringValue());
                    acknowledgedFuture.complete(ackStatus);
                }
            }
        }

        void checkIfAcknowledged(List attrs) {
            if (acknowledgedFuture.isDone()) {
                return;
            }
            var ackStatusKey = acknowledgment + CommandHistoryPublisher.SUFFIX_STATUS;
            for (var attr : attrs) {
                if (attr.getKey().equals(ackStatusKey)) {
                    var ackStatus = AckStatus.valueOf(attr.getValue().getStringValue());
                    acknowledgedFuture.complete(ackStatus);
                }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy