corefx - initial work to add option to display throughputs received from core rest
This commit is contained in:
parent
6bbc47d61a
commit
5382ab2d30
10 changed files with 144 additions and 1 deletions
|
@ -14,10 +14,12 @@ import com.jfoenix.controls.JFXDecorator;
|
||||||
import com.jfoenix.controls.JFXProgressBar;
|
import com.jfoenix.controls.JFXProgressBar;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.concurrent.Task;
|
||||||
import javafx.embed.swing.SwingNode;
|
import javafx.embed.swing.SwingNode;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.scene.control.CheckMenuItem;
|
||||||
import javafx.scene.control.MenuItem;
|
import javafx.scene.control.MenuItem;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
|
@ -48,7 +50,9 @@ public class Controller implements Initializable {
|
||||||
@FXML private SwingNode swingNode;
|
@FXML private SwingNode swingNode;
|
||||||
@FXML private MenuItem saveXmlMenuItem;
|
@FXML private MenuItem saveXmlMenuItem;
|
||||||
@FXML private JFXProgressBar progressBar;
|
@FXML private JFXProgressBar progressBar;
|
||||||
|
@FXML private CheckMenuItem throughputMenuItem;
|
||||||
|
|
||||||
|
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||||
private final Map<Integer, MobilityConfig> mobilityScripts = new HashMap<>();
|
private final Map<Integer, MobilityConfig> mobilityScripts = new HashMap<>();
|
||||||
private final Map<Integer, MobilityPlayerDialog> mobilityPlayerDialogs = new HashMap<>();
|
private final Map<Integer, MobilityPlayerDialog> mobilityPlayerDialogs = new HashMap<>();
|
||||||
private Application application;
|
private Application application;
|
||||||
|
@ -228,6 +232,27 @@ public class Controller implements Initializable {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handleThroughputs(Throughputs throughputs) {
|
||||||
|
for (InterfaceThroughput interfaceThroughput : throughputs.getInterfaces()) {
|
||||||
|
int nodeId = interfaceThroughput.getNode();
|
||||||
|
CoreNode node = networkGraph.getVertex(nodeId);
|
||||||
|
Collection<CoreLink> links = networkGraph.getGraph().getIncidentEdges(node);
|
||||||
|
int interfaceId = interfaceThroughput.getNodeInterface();
|
||||||
|
for (CoreLink link : links) {
|
||||||
|
if (nodeId == link.getNodeOne()) {
|
||||||
|
if (interfaceId == link.getInterfaceOne().getId()) {
|
||||||
|
link.setThroughput(interfaceThroughput.getThroughput());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (interfaceId == link.getInterfaceTwo().getId()) {
|
||||||
|
link.setThroughput(interfaceThroughput.getThroughput());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
networkGraph.getGraphViewer().repaint();
|
||||||
|
}
|
||||||
|
|
||||||
private void setCoreDefaultServices() {
|
private void setCoreDefaultServices() {
|
||||||
try {
|
try {
|
||||||
coreClient.setDefaultServices(defaultServices);
|
coreClient.setDefaultServices(defaultServices);
|
||||||
|
@ -453,6 +478,9 @@ public class Controller implements Initializable {
|
||||||
// setup snackbar
|
// setup snackbar
|
||||||
Toast.setSnackbarRoot(stackPane);
|
Toast.setSnackbarRoot(stackPane);
|
||||||
|
|
||||||
|
// setup throughput menu item
|
||||||
|
throughputMenuItem.setOnAction(event -> executorService.submit(new ChangeThroughputTask()));
|
||||||
|
|
||||||
// node details
|
// node details
|
||||||
networkGraph.getGraphViewer().getPickedVertexState().addItemListener(event -> {
|
networkGraph.getGraphViewer().getPickedVertexState().addItemListener(event -> {
|
||||||
CoreNode node = (CoreNode) event.getItem();
|
CoreNode node = (CoreNode) event.getItem();
|
||||||
|
@ -481,4 +509,35 @@ public class Controller implements Initializable {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ChangeThroughputTask extends Task<Boolean> {
|
||||||
|
@Override
|
||||||
|
protected Boolean call() throws Exception {
|
||||||
|
if (throughputMenuItem.isSelected()) {
|
||||||
|
return coreClient.startThroughput();
|
||||||
|
} else {
|
||||||
|
return coreClient.stopThroughput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void succeeded() {
|
||||||
|
if (getValue()) {
|
||||||
|
if (throughputMenuItem.isSelected()) {
|
||||||
|
networkGraph.setShowThroughput(true);
|
||||||
|
} else {
|
||||||
|
networkGraph.setShowThroughput(false);
|
||||||
|
networkGraph.getGraph().getEdges().forEach(edge -> edge.setThroughput(0));
|
||||||
|
networkGraph.getGraphViewer().repaint();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Toast.error("Failure changing throughput");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void failed() {
|
||||||
|
Toast.error("Error changing throughput", new RuntimeException(getException()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,10 @@ public interface ICoreClient {
|
||||||
|
|
||||||
Integer currentSession();
|
Integer currentSession();
|
||||||
|
|
||||||
|
boolean startThroughput() throws IOException;
|
||||||
|
|
||||||
|
boolean stopThroughput() throws IOException;
|
||||||
|
|
||||||
void updateSession(Integer sessionId);
|
void updateSession(Integer sessionId);
|
||||||
|
|
||||||
void updateState(SessionState state);
|
void updateState(SessionState state);
|
||||||
|
|
|
@ -144,6 +144,18 @@ public class CoreRestClient implements ICoreClient {
|
||||||
return WebUtils.postFile(url, file);
|
return WebUtils.postFile(url, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean startThroughput() throws IOException {
|
||||||
|
String url = getUrl("throughput/start");
|
||||||
|
return WebUtils.putJson(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean stopThroughput() throws IOException {
|
||||||
|
String url = getUrl("throughput/stop");
|
||||||
|
return WebUtils.putJson(url);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, List<String>> getDefaultServices() throws IOException {
|
public Map<String, List<String>> getDefaultServices() throws IOException {
|
||||||
String url = getUrl(String.format("sessions/%s/services/default", sessionId));
|
String url = getUrl(String.format("sessions/%s/services/default", sessionId));
|
||||||
|
|
9
corefx/src/main/java/com/core/data/BridgeThroughput.java
Normal file
9
corefx/src/main/java/com/core/data/BridgeThroughput.java
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package com.core.data;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class BridgeThroughput {
|
||||||
|
private int node;
|
||||||
|
private Double throughput;
|
||||||
|
}
|
|
@ -12,12 +12,16 @@ import lombok.NoArgsConstructor;
|
||||||
public class CoreLink {
|
public class CoreLink {
|
||||||
@EqualsAndHashCode.Include
|
@EqualsAndHashCode.Include
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private Float weight = 1.0f;
|
private Float weight = 1.0f;
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private boolean loaded = true;
|
private boolean loaded = true;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
private double throughput;
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private boolean visible = true;
|
private boolean visible = true;
|
||||||
|
|
||||||
|
|
12
corefx/src/main/java/com/core/data/InterfaceThroughput.java
Normal file
12
corefx/src/main/java/com/core/data/InterfaceThroughput.java
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package com.core.data;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class InterfaceThroughput {
|
||||||
|
private int node;
|
||||||
|
@JsonProperty("interface")
|
||||||
|
private int nodeInterface;
|
||||||
|
private double throughput;
|
||||||
|
}
|
12
corefx/src/main/java/com/core/data/Throughputs.java
Normal file
12
corefx/src/main/java/com/core/data/Throughputs.java
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package com.core.data;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class Throughputs {
|
||||||
|
private List<InterfaceThroughput> interfaces = new ArrayList<>();
|
||||||
|
private List<BridgeThroughput> bridges = new ArrayList<>();
|
||||||
|
}
|
|
@ -41,6 +41,7 @@ import java.util.stream.Collectors;
|
||||||
@Data
|
@Data
|
||||||
public class NetworkGraph {
|
public class NetworkGraph {
|
||||||
private static final Logger logger = LogManager.getLogger();
|
private static final Logger logger = LogManager.getLogger();
|
||||||
|
private static final int EDGE_LABEL_OFFSET = -5;
|
||||||
private Controller controller;
|
private Controller controller;
|
||||||
private ObservableGraph<CoreNode, CoreLink> graph;
|
private ObservableGraph<CoreNode, CoreLink> graph;
|
||||||
private StaticLayout<CoreNode, CoreLink> graphLayout;
|
private StaticLayout<CoreNode, CoreLink> graphLayout;
|
||||||
|
@ -61,6 +62,9 @@ public class NetworkGraph {
|
||||||
private BackgroundPaintable<CoreNode, CoreLink> backgroundPaintable;
|
private BackgroundPaintable<CoreNode, CoreLink> backgroundPaintable;
|
||||||
private CoreVertexLabelRenderer nodeLabelRenderer = new CoreVertexLabelRenderer();
|
private CoreVertexLabelRenderer nodeLabelRenderer = new CoreVertexLabelRenderer();
|
||||||
|
|
||||||
|
// display options
|
||||||
|
private boolean showThroughput = false;
|
||||||
|
|
||||||
public NetworkGraph(Controller controller) {
|
public NetworkGraph(Controller controller) {
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
graph = new CoreObservableGraph<>(new UndirectedSimpleGraph<>());
|
graph = new CoreObservableGraph<>(new UndirectedSimpleGraph<>());
|
||||||
|
@ -86,6 +90,14 @@ public class NetworkGraph {
|
||||||
});
|
});
|
||||||
|
|
||||||
// link render properties
|
// link render properties
|
||||||
|
renderContext.setEdgeLabelTransformer(link -> {
|
||||||
|
if (!showThroughput || link == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
double kbps = link.getThroughput() / 1000.0;
|
||||||
|
return String.format("%.2f kbps", kbps);
|
||||||
|
});
|
||||||
|
renderContext.setLabelOffset(EDGE_LABEL_OFFSET);
|
||||||
renderContext.setEdgeStrokeTransformer(edge -> {
|
renderContext.setEdgeStrokeTransformer(edge -> {
|
||||||
LinkTypes linkType = LinkTypes.get(edge.getType());
|
LinkTypes linkType = LinkTypes.get(edge.getType());
|
||||||
if (LinkTypes.WIRELESS == linkType) {
|
if (LinkTypes.WIRELESS == linkType) {
|
||||||
|
|
|
@ -2,7 +2,6 @@ package com.core.websocket;
|
||||||
|
|
||||||
import com.core.Controller;
|
import com.core.Controller;
|
||||||
import com.core.data.*;
|
import com.core.data.*;
|
||||||
import com.core.ui.dialogs.MobilityDialog;
|
|
||||||
import com.core.ui.dialogs.MobilityPlayerDialog;
|
import com.core.ui.dialogs.MobilityPlayerDialog;
|
||||||
import com.core.utils.JsonUtils;
|
import com.core.utils.JsonUtils;
|
||||||
import io.socket.client.IO;
|
import io.socket.client.IO;
|
||||||
|
@ -30,6 +29,7 @@ public class CoreWebSocket {
|
||||||
socket.on("event", this::handleEvents);
|
socket.on("event", this::handleEvents);
|
||||||
socket.on("config", this::handleConfigs);
|
socket.on("config", this::handleConfigs);
|
||||||
socket.on("link", this::handleLinks);
|
socket.on("link", this::handleLinks);
|
||||||
|
socket.on("throughput", this::handleThroughputs);
|
||||||
socket.on(Socket.EVENT_DISCONNECT, args -> logger.info("disconnected from web socket"));
|
socket.on(Socket.EVENT_DISCONNECT, args -> logger.info("disconnected from web socket"));
|
||||||
|
|
||||||
logger.info("attempting to connect to web socket!");
|
logger.info("attempting to connect to web socket!");
|
||||||
|
@ -45,6 +45,18 @@ public class CoreWebSocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleThroughputs(Object... args) {
|
||||||
|
for (Object arg : args) {
|
||||||
|
logger.info("throughput update: {}", arg);
|
||||||
|
try {
|
||||||
|
Throughputs throughputs = JsonUtils.read(arg.toString(), Throughputs.class);
|
||||||
|
controller.handleThroughputs(throughputs);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.error("error getting throughputs", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void handleNodes(Object... args) {
|
private void handleNodes(Object... args) {
|
||||||
for (Object arg : args) {
|
for (Object arg : args) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
<?import com.jfoenix.controls.JFXProgressBar?>
|
<?import com.jfoenix.controls.JFXProgressBar?>
|
||||||
<?import javafx.embed.swing.SwingNode?>
|
<?import javafx.embed.swing.SwingNode?>
|
||||||
|
<?import javafx.scene.control.CheckMenuItem?>
|
||||||
<?import javafx.scene.control.Menu?>
|
<?import javafx.scene.control.Menu?>
|
||||||
<?import javafx.scene.control.MenuBar?>
|
<?import javafx.scene.control.MenuBar?>
|
||||||
<?import javafx.scene.control.MenuItem?>
|
<?import javafx.scene.control.MenuItem?>
|
||||||
|
@ -40,6 +41,12 @@
|
||||||
<MenuItem mnemonicParsing="false" onAction="#onOptionsMenuBackground" text="Background" />
|
<MenuItem mnemonicParsing="false" onAction="#onOptionsMenuBackground" text="Background" />
|
||||||
<MenuItem mnemonicParsing="false" onAction="#onSessionOptionsMenu" text="Options" />
|
<MenuItem mnemonicParsing="false" onAction="#onSessionOptionsMenu" text="Options" />
|
||||||
</items>
|
</items>
|
||||||
|
</Menu>
|
||||||
|
<Menu mnemonicParsing="false" text="Widgets">
|
||||||
|
<items>
|
||||||
|
<CheckMenuItem fx:id="throughputMenuItem" mnemonicParsing="false" text="Throughput" />
|
||||||
|
<MenuItem mnemonicParsing="false" text="Throughput Config" />
|
||||||
|
</items>
|
||||||
</Menu>
|
</Menu>
|
||||||
<Menu mnemonicParsing="false" text="Help">
|
<Menu mnemonicParsing="false" text="Help">
|
||||||
<items>
|
<items>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue