changes to support mobility from rest and configuring mobility from a wlan context menu
This commit is contained in:
parent
dd9ad5644d
commit
f2f83f247d
12 changed files with 379 additions and 15 deletions
|
@ -71,6 +71,7 @@ public class Controller implements Initializable {
|
|||
private NodeWlanDialog nodeWlanDialog = new NodeWlanDialog(this);
|
||||
private ConfigDialog configDialog = new ConfigDialog(this);
|
||||
private HooksDialog hooksDialog = new HooksDialog(this);
|
||||
private MobilityDialog mobilityDialog = new MobilityDialog(this);
|
||||
|
||||
public Controller() {
|
||||
// load configuration
|
||||
|
@ -108,6 +109,7 @@ public class Controller implements Initializable {
|
|||
nodeWlanDialog.setOwner(window);
|
||||
nodeEmaneDialog.setOwner(window);
|
||||
configDialog.setOwner(window);
|
||||
mobilityDialog.setOwner(window);
|
||||
}
|
||||
|
||||
@FXML
|
||||
|
|
|
@ -39,6 +39,7 @@ public class CoreClient {
|
|||
logger.info("joining core session({}) state({}): {}", sessionId, sessionState, session);
|
||||
for (CoreNode node : session.getNodes()) {
|
||||
if (node.getModel() == null) {
|
||||
logger.info("skipping joined session node: {}", node.getName());
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -220,4 +221,16 @@ public class CoreClient {
|
|||
public String getTerminalCommand(CoreNode node) throws IOException {
|
||||
return coreApi.getTerminalCommand(sessionId, node);
|
||||
}
|
||||
|
||||
public boolean setMobilityConfig(CoreNode node, MobilityConfig config) throws IOException {
|
||||
return coreApi.setMobilityConfig(sessionId, node, config);
|
||||
}
|
||||
|
||||
public MobilityConfig getMobilityConfig(CoreNode node) throws IOException {
|
||||
return coreApi.getMobilityConfig(sessionId, node);
|
||||
}
|
||||
|
||||
public boolean mobilityAction(CoreNode node, String action) throws IOException {
|
||||
return coreApi.mobilityAction(sessionId, node, action);
|
||||
}
|
||||
}
|
||||
|
|
20
corefx/src/main/java/com/core/data/MobilityConfig.java
Normal file
20
corefx/src/main/java/com/core/data/MobilityConfig.java
Normal file
|
@ -0,0 +1,20 @@
|
|||
package com.core.data;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class MobilityConfig {
|
||||
private String file;
|
||||
@JsonProperty("refresh_ms")
|
||||
private Integer refresh;
|
||||
private String loop;
|
||||
private String autostart;
|
||||
private String map;
|
||||
@JsonProperty("script_start")
|
||||
private String startScript;
|
||||
@JsonProperty("script_pause")
|
||||
private String pauseScript;
|
||||
@JsonProperty("script_stop")
|
||||
private String stopScript;
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package com.core.data;
|
||||
|
||||
import lombok.Data;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
@ -8,6 +10,7 @@ import java.util.Map;
|
|||
|
||||
@Data
|
||||
public class NodeType {
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
public static final int DEFAULT = 0;
|
||||
public static final int SWITCH = 4;
|
||||
public static final int HUB = 5;
|
||||
|
@ -36,7 +39,7 @@ public class NodeType {
|
|||
addNodeType(new NodeType(DEFAULT, "mdr", "MDR", "/icons/router-100.png"));
|
||||
addNodeType(new NodeType(SWITCH, "Switch", "/icons/switch-100.png"));
|
||||
addNodeType(new NodeType(HUB, "Hub", "/icons/hub-100.png"));
|
||||
addNodeType(new NodeType(WLAN, "WLAN", "/icons/wlan-100.png"));
|
||||
addNodeType(new NodeType(WLAN, "wlan", "WLAN", "/icons/wlan-100.png"));
|
||||
addNodeType(new NodeType(EMANE, "EMANE", "/icons/emane-100.png"));
|
||||
|
||||
DISPLAY_MAP.put(HUB, "Hub");
|
||||
|
|
|
@ -82,6 +82,8 @@ public class CorePopupGraphMousePlugin<V, E> extends EditingPopupGraphMousePlugi
|
|||
case NodeType.WLAN:
|
||||
menuItems.add(createMenuItem("WLAN Settings",
|
||||
event -> controller.getNodeWlanDialog().showDialog(node)));
|
||||
menuItems.add(createMenuItem("Mobility",
|
||||
event -> controller.getMobilityDialog().showDialog(node)));
|
||||
menuItems.add(createMenuItem("Link MDRs",
|
||||
event -> networkGraph.linkMdrs(node)));
|
||||
break;
|
||||
|
|
|
@ -271,6 +271,19 @@ public class NetworkGraph {
|
|||
nodeMap.put(node.getId(), node);
|
||||
}
|
||||
|
||||
public void setNodeLocation(CoreNode nodeData) {
|
||||
// update actual graph node
|
||||
CoreNode node = nodeMap.get(nodeData.getId());
|
||||
node.getPosition().setX(nodeData.getPosition().getX());
|
||||
node.getPosition().setY(nodeData.getPosition().getY());
|
||||
|
||||
// set graph node location
|
||||
Double x = Math.abs(node.getPosition().getX());
|
||||
Double y = Math.abs(node.getPosition().getY());
|
||||
graphLayout.setLocation(node, x, y);
|
||||
graphViewer.repaint();
|
||||
}
|
||||
|
||||
public void removeNode(CoreNode node) {
|
||||
try {
|
||||
controller.getCoreClient().deleteNode(node);
|
||||
|
|
|
@ -170,6 +170,22 @@ public class CoreApi {
|
|||
return WebUtils.putJson(url, jsonData);
|
||||
}
|
||||
|
||||
public boolean setMobilityConfig(Integer session, CoreNode node, MobilityConfig config) throws IOException {
|
||||
String url = getUrl(String.format("sessions/%s/nodes/%s/mobility", session, node.getId()));
|
||||
String data = JsonUtils.toString(config);
|
||||
return WebUtils.postJson(url, data);
|
||||
}
|
||||
|
||||
public MobilityConfig getMobilityConfig(Integer session, CoreNode node) throws IOException {
|
||||
String url = getUrl(String.format("sessions/%s/nodes/%s/mobility", session, node.getId()));
|
||||
return WebUtils.getJson(url, MobilityConfig.class);
|
||||
}
|
||||
|
||||
public boolean mobilityAction(Integer session, CoreNode node, String action) throws IOException {
|
||||
String url = getUrl(String.format("sessions/%s/nodes/%s/mobility/%s", session, node.getId(), action));
|
||||
return WebUtils.putJson(url, null);
|
||||
}
|
||||
|
||||
public String getTerminalCommand(Integer session, CoreNode node) throws IOException {
|
||||
String url = getUrl(String.format("sessions/%s/nodes/%s/terminal", session, node.getId()));
|
||||
return WebUtils.getJson(url, String.class);
|
||||
|
|
117
corefx/src/main/java/com/core/ui/MobilityDialog.java
Normal file
117
corefx/src/main/java/com/core/ui/MobilityDialog.java
Normal file
|
@ -0,0 +1,117 @@
|
|||
package com.core.ui;
|
||||
|
||||
import com.core.Controller;
|
||||
import com.core.data.CoreNode;
|
||||
import com.core.data.MobilityConfig;
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import com.jfoenix.controls.JFXTextField;
|
||||
import com.jfoenix.controls.JFXToggleButton;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.stage.FileChooser;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class MobilityDialog extends StageDialog {
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
|
||||
@FXML
|
||||
private JFXTextField fileTextField;
|
||||
|
||||
@FXML
|
||||
private JFXTextField refreshTextField;
|
||||
|
||||
@FXML
|
||||
private JFXToggleButton loopToggleButton;
|
||||
|
||||
@FXML
|
||||
private JFXTextField nodeMappingTextField;
|
||||
|
||||
@FXML
|
||||
private JFXTextField autoStartTextField;
|
||||
|
||||
@FXML
|
||||
private JFXTextField startTextField;
|
||||
|
||||
@FXML
|
||||
private JFXTextField pauseTextField;
|
||||
|
||||
@FXML
|
||||
private JFXTextField stopTextField;
|
||||
|
||||
private CoreNode node;
|
||||
|
||||
public MobilityDialog(Controller controller) {
|
||||
super(controller, "/fxml/mobility_dialog.fxml");
|
||||
|
||||
setTitle("Mobility Script");
|
||||
|
||||
JFXButton saveButton = createButton("Save");
|
||||
saveButton.setOnAction(event -> {
|
||||
MobilityConfig mobilityConfig = new MobilityConfig();
|
||||
mobilityConfig.setFile(fileTextField.getText());
|
||||
mobilityConfig.setAutostart(autoStartTextField.getText());
|
||||
String loop = loopToggleButton.isSelected() ? "1" : "";
|
||||
mobilityConfig.setLoop(loop);
|
||||
mobilityConfig.setRefresh(Integer.parseInt(refreshTextField.getText()));
|
||||
mobilityConfig.setMap(nodeMappingTextField.getText());
|
||||
mobilityConfig.setStartScript(startTextField.getText());
|
||||
mobilityConfig.setPauseScript(pauseTextField.getText());
|
||||
mobilityConfig.setStopScript(stopTextField.getText());
|
||||
|
||||
try {
|
||||
controller.getCoreClient().setMobilityConfig(node, mobilityConfig);
|
||||
} catch (IOException ex) {
|
||||
logger.error("error setting mobility configuration", ex);
|
||||
Toast.error("error setting mobility configuration");
|
||||
}
|
||||
|
||||
close();
|
||||
});
|
||||
addCancelButton();
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void onSelectAction(ActionEvent event) {
|
||||
JFXButton button = (JFXButton) event.getSource();
|
||||
GridPane gridPane = (GridPane) button.getParent();
|
||||
JFXTextField textField = (JFXTextField) gridPane.getChildren().get(0);
|
||||
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle("Select File");
|
||||
fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Mobility",
|
||||
"*.mobility"));
|
||||
File file = fileChooser.showOpenDialog(getController().getWindow());
|
||||
if (file != null) {
|
||||
logger.info("opening session xml: {}", file.getPath());
|
||||
textField.setText(file.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
public void showDialog(CoreNode node) {
|
||||
this.node = node;
|
||||
|
||||
try {
|
||||
MobilityConfig mobilityConfig = getController().getCoreClient().getMobilityConfig(this.node);
|
||||
fileTextField.setText(mobilityConfig.getFile());
|
||||
autoStartTextField.setText(mobilityConfig.getAutostart());
|
||||
boolean loop = "1".equals(mobilityConfig.getLoop());
|
||||
loopToggleButton.setSelected(loop);
|
||||
refreshTextField.setText(mobilityConfig.getRefresh().toString());
|
||||
nodeMappingTextField.setText(mobilityConfig.getMap());
|
||||
startTextField.setText(mobilityConfig.getStartScript());
|
||||
pauseTextField.setText(mobilityConfig.getPauseScript());
|
||||
stopTextField.setText(mobilityConfig.getStopScript());
|
||||
} catch (IOException ex) {
|
||||
logger.error("error getting mobility config", ex);
|
||||
Toast.error("error getting mobility config");
|
||||
}
|
||||
|
||||
show();
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package com.core.websocket;
|
|||
|
||||
import com.core.Controller;
|
||||
import com.core.data.CoreEvent;
|
||||
import com.core.data.CoreNode;
|
||||
import com.core.data.SessionState;
|
||||
import com.core.utils.JsonUtils;
|
||||
import io.socket.client.IO;
|
||||
|
@ -26,6 +27,17 @@ public class CoreWebSocket {
|
|||
socket.on(Socket.EVENT_CONNECT, args -> {
|
||||
logger.info("connected to web socket");
|
||||
});
|
||||
socket.on("node", args -> {
|
||||
for (Object arg : args) {
|
||||
try {
|
||||
CoreNode node = JsonUtils.read(arg.toString(), CoreNode.class);
|
||||
logger.info("core node update: {}", node);
|
||||
controller.getNetworkGraph().setNodeLocation(node);
|
||||
} catch (IOException ex) {
|
||||
logger.error("error getting core node", ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
socket.on("event", args -> {
|
||||
for (Object arg : args) {
|
||||
try {
|
||||
|
|
96
corefx/src/main/resources/fxml/mobility_dialog.fxml
Normal file
96
corefx/src/main/resources/fxml/mobility_dialog.fxml
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import com.jfoenix.controls.JFXButton?>
|
||||
<?import com.jfoenix.controls.JFXTextField?>
|
||||
<?import com.jfoenix.controls.JFXToggleButton?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
|
||||
<GridPane hgap="10.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" vgap="10.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="40.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER" />
|
||||
</rowConstraints>
|
||||
<padding>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
|
||||
</padding>
|
||||
<children>
|
||||
<Label text="File" />
|
||||
<Label text="Refresh Rate (ms)" GridPane.rowIndex="1" />
|
||||
<Label text="Auto-Start (0.0 for runtime)" GridPane.rowIndex="3" />
|
||||
<Label text="Node Mapping (optional, e.g. 0:1,1:2,etc)" GridPane.rowIndex="4" />
|
||||
<Label text="Start Script" GridPane.rowIndex="5" />
|
||||
<Label text="Pause Script" GridPane.rowIndex="6" />
|
||||
<Label text="Stop Script" GridPane.rowIndex="7" />
|
||||
<JFXTextField fx:id="refreshTextField" GridPane.columnIndex="1" GridPane.rowIndex="1" />
|
||||
<JFXTextField fx:id="autoStartTextField" GridPane.columnIndex="1" GridPane.rowIndex="3" />
|
||||
<JFXTextField fx:id="nodeMappingTextField" GridPane.columnIndex="1" GridPane.rowIndex="4" />
|
||||
<JFXToggleButton fx:id="loopToggleButton" contentDisplay="GRAPHIC_ONLY" maxWidth="1.7976931348623157E308" text="Loop?" GridPane.columnIndex="1" GridPane.columnSpan="2147483647" GridPane.halignment="CENTER" GridPane.rowIndex="2" />
|
||||
<Label text="Loop?" GridPane.rowIndex="2" />
|
||||
<GridPane hgap="5.0" GridPane.columnIndex="1">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="80.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<JFXTextField fx:id="fileTextField" />
|
||||
<JFXButton maxWidth="1.7976931348623157E308" onAction="#onSelectAction" styleClass="core-button" text="Select" GridPane.columnIndex="1" />
|
||||
</children>
|
||||
</GridPane>
|
||||
<GridPane hgap="5.0" GridPane.columnIndex="1" GridPane.rowIndex="6">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="80.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<JFXTextField fx:id="pauseTextField" />
|
||||
<JFXButton maxWidth="1.7976931348623157E308" onAction="#onSelectAction" styleClass="core-button" text="Select" GridPane.columnIndex="1" />
|
||||
</children>
|
||||
</GridPane>
|
||||
<GridPane hgap="5.0" GridPane.columnIndex="1" GridPane.rowIndex="7">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="80.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<JFXTextField fx:id="stopTextField" />
|
||||
<JFXButton maxWidth="1.7976931348623157E308" onAction="#onSelectAction" styleClass="core-button" text="Select" GridPane.columnIndex="1" />
|
||||
</children>
|
||||
</GridPane>
|
||||
<GridPane hgap="5.0" GridPane.columnIndex="1" GridPane.rowIndex="5">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="80.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<JFXTextField fx:id="startTextField" />
|
||||
<JFXButton maxWidth="1.7976931348623157E308" onAction="#onSelectAction" styleClass="core-button" text="Select" GridPane.columnIndex="1" />
|
||||
</children>
|
||||
</GridPane>
|
||||
</children>
|
||||
</GridPane>
|
|
@ -11,6 +11,7 @@ from flask import send_file
|
|||
from flask_socketio import SocketIO
|
||||
from flask_socketio import emit
|
||||
|
||||
import mobility_routes
|
||||
from core import logger
|
||||
from core.emulator.coreemu import CoreEmu
|
||||
from core.emulator.emudata import InterfaceData
|
||||
|
@ -25,12 +26,14 @@ from core.mobility import BasicRangeModel
|
|||
from core.service import ServiceManager
|
||||
|
||||
CORE_LOCK = Lock()
|
||||
coreemu = CoreEmu()
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config["SECRET_KEY"] = "core"
|
||||
socketio = SocketIO(app)
|
||||
app.config["SECRET_KEY"] = "core"
|
||||
|
||||
coreemu = CoreEmu()
|
||||
mobility_routes.coreemu = coreemu
|
||||
app.register_blueprint(mobility_routes.mobility_api, url_prefix="/sessions/<int:session_id>")
|
||||
|
||||
|
||||
def synchronized(function):
|
||||
|
@ -120,19 +123,22 @@ def broadcast_event(event):
|
|||
})
|
||||
|
||||
|
||||
def broadcast_node(node):
|
||||
socketio.emit("node", {
|
||||
"id": node.id,
|
||||
"name": node.name,
|
||||
"model": node.model,
|
||||
"position": {
|
||||
"x": node.x_position,
|
||||
"y": node.y_position,
|
||||
},
|
||||
"services": node.services.split("|"),
|
||||
})
|
||||
|
||||
|
||||
@socketio.on("connect")
|
||||
def websocket_connect():
|
||||
emit("info", {"message": "You are connected!"})
|
||||
socketio.emit("node", {
|
||||
"id": 1,
|
||||
"x": 100,
|
||||
"y": 101
|
||||
})
|
||||
socketio.emit("node", {
|
||||
"id": 1,
|
||||
"x": 100,
|
||||
"y": 150
|
||||
})
|
||||
|
||||
|
||||
@socketio.on("disconnect")
|
||||
|
@ -142,7 +148,7 @@ def websocket_disconnect():
|
|||
|
||||
@app.route("/")
|
||||
def home():
|
||||
return render_template('index.html')
|
||||
return render_template("index.html")
|
||||
|
||||
|
||||
@app.route("/ips", methods=["POST"])
|
||||
|
@ -233,6 +239,7 @@ def create_session():
|
|||
|
||||
# add handlers
|
||||
session.event_handlers.append(broadcast_event)
|
||||
session.node_handlers.append(broadcast_node)
|
||||
|
||||
response_data = jsonify(
|
||||
id=session.session_id,
|
||||
|
|
63
webapp/mobility_routes.py
Normal file
63
webapp/mobility_routes.py
Normal file
|
@ -0,0 +1,63 @@
|
|||
from flask import Blueprint
|
||||
from flask import jsonify
|
||||
from flask import request
|
||||
|
||||
from core.mobility import Ns2ScriptedMobility
|
||||
|
||||
mobility_api = Blueprint("mobility_api", __name__)
|
||||
|
||||
coreemu = None
|
||||
|
||||
|
||||
@mobility_api.route("/nodes/<node_id>/mobility", methods=["POST"])
|
||||
def set_mobility_config(session_id, node_id):
|
||||
session = coreemu.sessions.get(session_id)
|
||||
if not session:
|
||||
return jsonify(error="session does not exist"), 404
|
||||
|
||||
if node_id.isdigit():
|
||||
node_id = int(node_id)
|
||||
|
||||
data = request.get_json() or {}
|
||||
|
||||
session.mobility.set_model_config(node_id, Ns2ScriptedMobility.name, data)
|
||||
|
||||
return jsonify()
|
||||
|
||||
|
||||
@mobility_api.route("/nodes/<node_id>/mobility")
|
||||
def get_mobility_config(session_id, node_id):
|
||||
session = coreemu.sessions.get(session_id)
|
||||
if not session:
|
||||
return jsonify(error="session does not exist"), 404
|
||||
|
||||
if node_id.isdigit():
|
||||
node_id = int(node_id)
|
||||
|
||||
config = session.mobility.get_model_config(node_id, Ns2ScriptedMobility.name)
|
||||
|
||||
return jsonify(config)
|
||||
|
||||
|
||||
@mobility_api.route("/nodes/<node_id>/mobility/<action>", methods=["PUT"])
|
||||
def mobility_action(session_id, node_id, action):
|
||||
session = coreemu.sessions.get(session_id)
|
||||
if not session:
|
||||
return jsonify(error="session does not exist"), 404
|
||||
|
||||
if node_id.isdigit():
|
||||
node_id = int(node_id)
|
||||
node = session.objects.get(node_id)
|
||||
if not node:
|
||||
return jsonify(error="node does not exist"), 404
|
||||
|
||||
if action == "start":
|
||||
node.mobility.start()
|
||||
elif action == "pause":
|
||||
node.mobility.pause()
|
||||
elif action == "stop":
|
||||
node.mobility.stop(move_initial=True)
|
||||
else:
|
||||
return jsonify(error="invalid mobility action: %s" % action), 404
|
||||
|
||||
return jsonify()
|
Loading…
Reference in a new issue