package org.yamcs.web.websocket;
import java.io.IOException;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yamcs.Processor;
import org.yamcs.management.ManagementGpbHelper;
import org.yamcs.management.ManagementListener;
import org.yamcs.management.ManagementService;
import org.yamcs.protobuf.SchemaYamcsManagement;
import org.yamcs.protobuf.Web.WebSocketServerMessage.WebSocketReplyData;
import org.yamcs.protobuf.Yamcs.ProtoDataType;
import org.yamcs.protobuf.YamcsManagement.ClientInfo;
import org.yamcs.protobuf.YamcsManagement.ClientInfo.ClientState;
import org.yamcs.protobuf.YamcsManagement.ProcessorInfo;
import org.yamcs.protobuf.YamcsManagement.Statistics;
/**
* Provides access to any Processor/Client info over web socket
*/
public class ManagementResource extends AbstractWebSocketResource implements ManagementListener {
private static final Logger log = LoggerFactory.getLogger(ManagementResource.class);
public static final String RESOURCE_NAME = "management";
public static final String OP_getProcessorInfo = "getProcessorInfo";
public static final String OP_getClientInfo = "getClientInfo";
public static final String OP_subscribe = "subscribe";
private int clientId;
public ManagementResource(WebSocketProcessorClient client) {
super(client);
clientId = client.getClientId();
}
@Override
public WebSocketReplyData processRequest(WebSocketDecodeContext ctx, WebSocketDecoder decoder) throws WebSocketException {
switch (ctx.getOperation()) {
case OP_getProcessorInfo:
return processGetProcessorInfoRequest(ctx, decoder);
case OP_getClientInfo:
return processGetClientInfoRequest(ctx, decoder);
case OP_subscribe:
return processSubscribeRequest(ctx, decoder);
default:
throw new WebSocketException(ctx.getRequestId(), "Unsupported operation '" + ctx.getOperation() + "'");
}
}
private WebSocketReplyData processGetProcessorInfoRequest(WebSocketDecodeContext ctx, WebSocketDecoder decoder) {
int requestId = ctx.getRequestId();
ProcessorInfo pinfo = ManagementGpbHelper.toProcessorInfo(processor);
try {
wsHandler.sendReply(toAckReply(requestId));
wsHandler.sendData(ProtoDataType.PROCESSOR_INFO, pinfo, SchemaYamcsManagement.ProcessorInfo.WRITE);
} catch (IOException e) {
log.warn("Exception when sending data", e);
return null;
}
return null;
}
//return client info of this client
private WebSocketReplyData processGetClientInfoRequest(WebSocketDecodeContext ctx, WebSocketDecoder decoder) {
int requestId = ctx.getRequestId();
ClientInfo cinfo = ManagementService.getInstance().getClientInfo(clientId);
cinfo = ClientInfo.newBuilder(cinfo).setState(ClientState.CONNECTED).setCurrentClient(true).build();
try {
wsHandler.sendReply(toAckReply(requestId));
wsHandler.sendData(ProtoDataType.CLIENT_INFO, cinfo, SchemaYamcsManagement.ClientInfo.WRITE);
} catch (IOException e) {
log.error("Exception when sending data", e);
return null;
}
return null;
}
/**
* Registers for updates on any processor or client. Sends the current set
* of processor, and clients (in that order) to the requester.
* <p>
* Calling this multiple times, will cause the current set of data to be
* sent again. Further updates will still arrive one-time only.
*/
private WebSocketReplyData processSubscribeRequest(WebSocketDecodeContext ctx, WebSocketDecoder decoder) {
try {
wsHandler.sendReply(toAckReply(ctx.getRequestId()));
// Send current set of processors
for (Processor processor : Processor.getProcessors()) {
ProcessorInfo pinfo = ManagementGpbHelper.toProcessorInfo(processor);
wsHandler.sendData(ProtoDataType.PROCESSOR_INFO, pinfo, SchemaYamcsManagement.ProcessorInfo.WRITE);
}
// Send current set of clients
Set<ClientInfo> clients = ManagementService.getInstance().getClientInfo();
for (ClientInfo client : clients) {
ClientInfo cinfo = ClientInfo.newBuilder(client)
.setState(ClientState.CONNECTED).setCurrentClient(client.getId() == clientId).build();
wsHandler.sendData(ProtoDataType.CLIENT_INFO, cinfo, SchemaYamcsManagement.ClientInfo.WRITE);
}
} catch (IOException e) {
log.error("Exception when sending data", e);
return null;
}
ManagementService.getInstance().addManagementListener(this);
return null;
}
@Override
public void quit() {
ManagementService.getInstance().removeManagementListener(this);
}
@Override
public void processorAdded(ProcessorInfo processorInfo) {
try {
wsHandler.sendData(ProtoDataType.PROCESSOR_INFO, processorInfo, SchemaYamcsManagement.ProcessorInfo.WRITE);
} catch (IOException e) {
log.error("Exception when sending data", e);
}
}
@Override
public void processorStateChanged(ProcessorInfo processorInfo) {
try {
wsHandler.sendData(ProtoDataType.PROCESSOR_INFO, processorInfo, SchemaYamcsManagement.ProcessorInfo.WRITE);
} catch (IOException e) {
log.error("Exception when sending data", e);
}
}
@Override
public void processorClosed(ProcessorInfo processorInfo) {
try {
wsHandler.sendData(ProtoDataType.PROCESSOR_INFO, processorInfo, SchemaYamcsManagement.ProcessorInfo.WRITE);
} catch (IOException e) {
log.error("Exception when sending data", e);
}
}
@Override
public void clientRegistered(ClientInfo ci) {
ClientInfo cinfo = ClientInfo.newBuilder(ci).setState(ClientState.CONNECTED).setCurrentClient(ci.getId() == clientId).build();
try {
wsHandler.sendData(ProtoDataType.CLIENT_INFO, cinfo, SchemaYamcsManagement.ClientInfo.WRITE);
} catch (IOException e) {
log.error("Exception when sending data", e);
}
}
@Override
public void clientInfoChanged(ClientInfo ci) {
ClientInfo cinfo = ClientInfo.newBuilder(ci).setState(ClientState.CONNECTED).setCurrentClient(ci.getId() == clientId).build();
try {
wsHandler.sendData(ProtoDataType.CLIENT_INFO, cinfo, SchemaYamcsManagement.ClientInfo.WRITE);
} catch (IOException e) {
log.error("Exception when sending data", e);
}
}
@Override
public void clientUnregistered(ClientInfo ci) {
if (ci.getId() == clientId) {
return;
}
ClientInfo cinfo = ClientInfo.newBuilder(ci).setState(ClientState.DISCONNECTED).setCurrentClient(false).build();
try {
wsHandler.sendData(ProtoDataType.CLIENT_INFO, cinfo, SchemaYamcsManagement.ClientInfo.WRITE);
} catch (IOException e) {
log.error("Exception when sending data", e);
}
}
@Override
public void statisticsUpdated(Processor processor, Statistics stats) {
try {
wsHandler.sendData(ProtoDataType.PROCESSING_STATISTICS, stats, SchemaYamcsManagement.Statistics.WRITE);
} catch (IOException e) {
log.error("Exception when sending data", e);
}
}
}