package org.yamcs.web.websocket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.yamcs.ProcessorException; import org.yamcs.Processor; import org.yamcs.cmdhistory.CommandHistoryConsumer; import org.yamcs.cmdhistory.CommandHistoryFilter; import org.yamcs.cmdhistory.CommandHistoryRequestManager; import org.yamcs.commanding.PreparedCommand; import org.yamcs.parameter.Value; import org.yamcs.protobuf.Commanding.CommandHistoryAttribute; import org.yamcs.protobuf.Commanding.CommandHistoryEntry; import org.yamcs.protobuf.Commanding.CommandId; import org.yamcs.protobuf.SchemaCommanding; import org.yamcs.protobuf.Web.WebSocketServerMessage.WebSocketReplyData; import org.yamcs.protobuf.Yamcs.ProtoDataType; import org.yamcs.utils.ValueUtility; /** * Provides realtime command history subscription via web. */ public class CommandHistoryResource extends AbstractWebSocketResource implements CommandHistoryConsumer { private static final Logger log = LoggerFactory.getLogger(CommandHistoryResource.class); public static final String RESOURCE_NAME = "cmdhistory"; private int subscriptionId = -1; public CommandHistoryResource(WebSocketProcessorClient client) { super(client); } @Override public WebSocketReplyData processRequest(WebSocketDecodeContext ctx, WebSocketDecoder decoder) throws WebSocketException { switch (ctx.getOperation()) { case "subscribe": return subscribe(ctx.getRequestId()); default: throw new WebSocketException(ctx.getRequestId(), "Unsupported operation '"+ctx.getOperation()+"'"); } } private WebSocketReplyData subscribe(int requestId) { CommandHistoryRequestManager chrm = processor.getCommandHistoryManager(); if (chrm != null) { subscriptionId = chrm.subscribeCommandHistory(null, 0, this); } return toAckReply(requestId); } /** * called when the socket is closed */ @Override public void quit() { if(subscriptionId == -1) { return; } CommandHistoryRequestManager chrm = processor.getCommandHistoryManager(); if (chrm != null) { chrm.unsubscribeCommandHistory(subscriptionId); } } @Override public void switchProcessor(Processor oldProcessor, Processor newProcessor) throws ProcessorException { if(subscriptionId == -1) { return; } CommandHistoryRequestManager chrm = processor.getCommandHistoryManager(); CommandHistoryFilter filter = null; if (chrm != null) { filter = chrm.unsubscribeCommandHistory(subscriptionId); } super.switchProcessor(oldProcessor, newProcessor); if (processor.hasCommanding()) { chrm = processor.getCommandHistoryManager(); if (filter != null) { chrm.addSubscription(filter, this); } else { chrm.subscribeCommandHistory(null, 0, this); } } } @Override public void addedCommand(PreparedCommand pc) { CommandHistoryEntry entry = CommandHistoryEntry.newBuilder().setCommandId(pc.getCommandId()).addAllAttr(pc.getAttributes()).build(); doSend(entry); } @Override public void updatedCommand(CommandId cmdId, long changeDate, String key, Value value) { CommandHistoryAttribute cha = CommandHistoryAttribute.newBuilder().setName(key).setValue(ValueUtility.toGbp(value)).build(); CommandHistoryEntry entry = CommandHistoryEntry.newBuilder().setCommandId(cmdId).addAttr(cha).build(); doSend(entry); } private void doSend(CommandHistoryEntry entry) { try { wsHandler.sendData(ProtoDataType.CMD_HISTORY, entry, SchemaCommanding.CommandHistoryEntry.WRITE); } catch (Exception e) { log.warn("got error when sending command history updates, quitting", e); quit(); } } }