diff --git a/coretk/coretk/coreclient.py b/coretk/coretk/coreclient.py index 8738c4f7..ad85b689 100644 --- a/coretk/coretk/coreclient.py +++ b/coretk/coretk/coreclient.py @@ -70,8 +70,6 @@ class CoreClient: # helpers self.interface_to_edge = {} self.interfaces_manager = InterfaceManager(self.app) - self.created_nodes = set() - self.created_links = set() # session data self.state = None @@ -90,8 +88,6 @@ class CoreClient: def reset(self): # helpers - self.created_nodes.clear() - self.created_links.clear() self.interfaces_manager.reset() self.interface_to_edge.clear() # session data @@ -181,7 +177,6 @@ class CoreClient: canvas_node.move(x, y, update=False) def handle_throughputs(self, event): - # print(event.interface_throughputs) if self.throughput: self.app.canvas.throughput_draw.process_grpc_throughput_event( event.interface_throughputs @@ -243,8 +238,6 @@ class CoreClient: # save and retrieve data, needed for session nodes for node in session.nodes: # get node service config and file config - self.created_nodes.add(node.id) - # get wlan configs for wlan nodes if node.type == core_pb2.NodeType.WIRELESS_LAN: response = self.client.get_wlan_config(self.session_id, node.id) @@ -435,8 +428,6 @@ class CoreClient: hooks = list(self.hooks.values()) service_configs = self.get_service_config_proto() file_configs = self.get_service_file_config_proto() - self.created_links.clear() - self.created_nodes.clear() if self.emane_config: emane_config = {x: self.emane_config[x].value for x in self.emane_config} else: @@ -585,31 +576,20 @@ class CoreClient: self.session_id, core_pb2.SessionState.DEFINITION ) - # temp self.client.set_session_state(self.session_id, core_pb2.SessionState.DEFINITION) for node_proto in node_protos: - if node_proto.id not in self.created_nodes or True: - response = self.client.add_node(self.session_id, node_proto) - logging.debug("create node: %s", response) - self.created_nodes.add(node_proto.id) + response = self.client.add_node(self.session_id, node_proto) + logging.debug("create node: %s", response) for link_proto in link_protos: - if ( - tuple([link_proto.node_one_id, link_proto.node_two_id]) - not in self.created_links - or True - ): - response = self.client.add_link( - self.session_id, - link_proto.node_one_id, - link_proto.node_two_id, - link_proto.interface_one, - link_proto.interface_two, - link_proto.options, - ) - logging.debug("create link: %s", response) - self.created_links.add( - tuple([link_proto.node_one_id, link_proto.node_two_id]) - ) + response = self.client.add_link( + self.session_id, + link_proto.node_one_id, + link_proto.node_two_id, + link_proto.interface_one, + link_proto.interface_two, + link_proto.options, + ) + logging.debug("create link: %s", response) def close(self): """ diff --git a/coretk/coretk/dialogs/canvassizeandscale.py b/coretk/coretk/dialogs/canvassizeandscale.py index 624e4246..f2bf4fc3 100644 --- a/coretk/coretk/dialogs/canvassizeandscale.py +++ b/coretk/coretk/dialogs/canvassizeandscale.py @@ -66,7 +66,7 @@ class SizeAndScaleDialog(Dialog): validate="key", validatecommand=(self.validation.positive_int, "%P"), ) - entry.bind("", self.validation.focus_out) + entry.bind("", lambda event: self.validation.focus_out(event, "0")) entry.grid(row=0, column=1, sticky="ew", padx=PAD) label = ttk.Label(frame, text="x Height") label.grid(row=0, column=2, sticky="w", padx=PAD) @@ -76,7 +76,7 @@ class SizeAndScaleDialog(Dialog): validate="key", validatecommand=(self.validation.positive_int, "%P"), ) - entry.bind("", self.validation.focus_out) + entry.bind("", lambda event: self.validation.focus_out(event, "0")) entry.grid(row=0, column=3, sticky="ew", padx=PAD) label = ttk.Label(frame, text="Pixels") label.grid(row=0, column=4, sticky="w") @@ -94,7 +94,7 @@ class SizeAndScaleDialog(Dialog): validate="key", validatecommand=(self.validation.positive_float, "%P"), ) - entry.bind("", self.validation.focus_out) + entry.bind("", lambda event: self.validation.focus_out(event, "0")) entry.grid(row=0, column=1, sticky="ew", padx=PAD) label = ttk.Label(frame, text="x Height") label.grid(row=0, column=2, sticky="w", padx=PAD) @@ -104,7 +104,7 @@ class SizeAndScaleDialog(Dialog): validate="key", validatecommand=(self.validation.positive_float, "%P"), ) - entry.bind("", self.validation.focus_out) + entry.bind("", lambda event: self.validation.focus_out(event, "0")) entry.grid(row=0, column=3, sticky="ew", padx=PAD) label = ttk.Label(frame, text="Meters") label.grid(row=0, column=4, sticky="w") @@ -125,7 +125,7 @@ class SizeAndScaleDialog(Dialog): validate="key", validatecommand=(self.validation.positive_float, "%P"), ) - entry.bind("", self.validation.focus_out) + entry.bind("", lambda event: self.validation.focus_out(event, "0")) entry.grid(row=0, column=1, sticky="ew", padx=PAD) label = ttk.Label(frame, text="Meters") label.grid(row=0, column=2, sticky="w") @@ -153,7 +153,7 @@ class SizeAndScaleDialog(Dialog): validate="key", validatecommand=(self.validation.positive_float, "%P"), ) - entry.bind("", self.validation.focus_out) + entry.bind("", lambda event: self.validation.focus_out(event, "0")) entry.grid(row=0, column=1, sticky="ew", padx=PAD) label = ttk.Label(frame, text="Y") @@ -164,7 +164,7 @@ class SizeAndScaleDialog(Dialog): validate="key", validatecommand=(self.validation.positive_float, "%P"), ) - entry.bind("", self.validation.focus_out) + entry.bind("", lambda event: self.validation.focus_out(event, "0")) entry.grid(row=0, column=3, sticky="ew", padx=PAD) label = ttk.Label(label_frame, text="Translates To") @@ -184,7 +184,7 @@ class SizeAndScaleDialog(Dialog): validate="key", validatecommand=(self.validation.positive_float, "%P"), ) - entry.bind("", self.validation.focus_out) + entry.bind("", lambda event: self.validation.focus_out(event, "0")) entry.grid(row=0, column=1, sticky="ew", padx=PAD) label = ttk.Label(frame, text="Lon") @@ -195,7 +195,7 @@ class SizeAndScaleDialog(Dialog): validate="key", validatecommand=(self.validation.positive_float, "%P"), ) - entry.bind("", self.validation.focus_out) + entry.bind("", lambda event: self.validation.focus_out(event, "0")) entry.grid(row=0, column=3, sticky="ew", padx=PAD) label = ttk.Label(frame, text="Alt") @@ -206,7 +206,7 @@ class SizeAndScaleDialog(Dialog): validate="key", validatecommand=(self.validation.positive_float, "%P"), ) - entry.bind("", self.validation.focus_out) + entry.bind("", lambda event: self.validation.focus_out(event, "0")) entry.grid(row=0, column=5, sticky="ew") def draw_save_as_default(self): diff --git a/coretk/coretk/dialogs/nodeconfig.py b/coretk/coretk/dialogs/nodeconfig.py index 9f7c4d6c..8853e908 100644 --- a/coretk/coretk/dialogs/nodeconfig.py +++ b/coretk/coretk/dialogs/nodeconfig.py @@ -75,7 +75,9 @@ class NodeConfigDialog(Dialog): validate="key", validatecommand=(self.app.validation.name, "%P"), ) - entry.bind("", self.app.validation.name_focus_out) + entry.bind( + "", lambda event: self.app.validation.focus_out(event, "noname") + ) entry.grid(row=row, column=1, sticky="ew") row += 1 @@ -165,12 +167,14 @@ class NodeConfigDialog(Dialog): label.grid(row=1, column=0, padx=PAD, pady=PAD) ip4 = tk.StringVar(value=f"{interface.ip4}/{interface.ip4mask}") entry = ttk.Entry(frame, textvariable=ip4) + entry.bind("", self.app.validation.ip_focus_out) entry.grid(row=1, column=1, columnspan=2, sticky="ew") label = ttk.Label(frame, text="IPv6") label.grid(row=2, column=0, padx=PAD, pady=PAD) ip6 = tk.StringVar(value=f"{interface.ip6}/{interface.ip6mask}") entry = ttk.Entry(frame, textvariable=ip6) + entry.bind("", self.app.validation.ip_focus_out) entry.grid(row=2, column=1, columnspan=2, sticky="ew") self.interfaces[interface.id] = InterfaceData(is_auto, mac, ip4, ip6) diff --git a/coretk/coretk/dialogs/servers.py b/coretk/coretk/dialogs/servers.py index 10a6e79e..9df7bf55 100644 --- a/coretk/coretk/dialogs/servers.py +++ b/coretk/coretk/dialogs/servers.py @@ -72,7 +72,15 @@ class ServersDialog(Dialog): label = ttk.Label(frame, text="Port") label.grid(row=0, column=4, sticky="w") - entry = ttk.Entry(frame, textvariable=self.port) + entry = ttk.Entry( + frame, + textvariable=self.port, + validate="key", + validatecommand=(self.app.validation.positive_int, "%P"), + ) + entry.bind( + "", lambda event: self.app.validation.focus_out(event, "50051") + ) entry.grid(row=0, column=5, sticky="ew") def draw_servers_buttons(self): diff --git a/coretk/coretk/dialogs/serviceconfiguration.py b/coretk/coretk/dialogs/serviceconfiguration.py index 354937e5..01610eb1 100644 --- a/coretk/coretk/dialogs/serviceconfiguration.py +++ b/coretk/coretk/dialogs/serviceconfiguration.py @@ -51,7 +51,6 @@ class ServiceConfiguration(Dialog): def load(self): try: - # create nodes and links in definition state for getting and setting service file self.app.core.create_nodes_and_links() service_configs = self.app.core.service_configs if ( diff --git a/coretk/coretk/graph/node.py b/coretk/coretk/graph/node.py index ede26440..bfc11cbf 100644 --- a/coretk/coretk/graph/node.py +++ b/coretk/coretk/graph/node.py @@ -8,6 +8,7 @@ from core.api.grpc.core_pb2 import NodeType from coretk.dialogs.emaneconfig import EmaneConfigDialog from coretk.dialogs.mobilityconfig import MobilityConfigDialog from coretk.dialogs.nodeconfig import NodeConfigDialog +from coretk.dialogs.nodeservice import NodeService from coretk.dialogs.wlanconfig import WlanConfigDialog from coretk.errors import show_grpc_error from coretk.graph import tags @@ -217,7 +218,7 @@ class CanvasNode: else: context.add_command(label="Configure", command=self.show_config) if NodeUtils.is_container_node(self.core_node.type): - context.add_command(label="Services", state=tk.DISABLED) + context.add_command(label="Services", command=self.show_services) if is_emane: context.add_command( label="EMANE Config", command=self.show_emane_config @@ -268,3 +269,8 @@ class CanvasNode: self.canvas.context = None dialog = EmaneConfigDialog(self.app, self.app, self) dialog.show() + + def show_services(self): + self.canvas.context = None + dialog = NodeService(self.app.master, self.app, self) + dialog.show() diff --git a/coretk/coretk/validation.py b/coretk/coretk/validation.py index a580c712..403e073d 100644 --- a/coretk/coretk/validation.py +++ b/coretk/coretk/validation.py @@ -4,6 +4,9 @@ input validation import logging import tkinter as tk +import netaddr +from netaddr import IPNetwork + class InputValidation: def __init__(self, app): @@ -18,16 +21,18 @@ class InputValidation: self.positive_float = self.master.register(self.check_positive_float) self.name = self.master.register(self.check_node_name) - def focus_out(self, event): + def ip_focus_out(self, event): value = event.widget.get() - if value == "": - event.widget.insert(tk.END, 0) + try: + IPNetwork(value) + except netaddr.core.AddrFormatError: + event.widget.delete(0, tk.END) + event.widget.insert(tk.END, "invalid") - def name_focus_out(self, event): - logging.debug("name focus out") + def focus_out(self, event, default): value = event.widget.get() if value == "": - event.widget.insert(tk.END, "empty") + event.widget.insert(tk.END, default) def check_positive_int(self, s): logging.debug("int validation...") diff --git a/coretk/coretk/widgets.py b/coretk/coretk/widgets.py index 7d908476..68983210 100644 --- a/coretk/coretk/widgets.py +++ b/coretk/coretk/widgets.py @@ -127,7 +127,10 @@ class ConfigFrame(FrameScroll): validate="key", validatecommand=(self.app.validation.positive_int, "%P"), ) - entry.bind("", self.app.validation.focus_out) + entry.bind( + "", + lambda event: self.app.validation.focus_out(event, "0"), + ) entry.grid(row=index, column=1, sticky="ew", pady=pady) elif option.type == core_pb2.ConfigOptionType.FLOAT: value.set(option.value) @@ -137,7 +140,10 @@ class ConfigFrame(FrameScroll): validate="key", validatecommand=(self.app.validation.positive_float, "%P"), ) - entry.bind("", self.app.validation.focus_out) + entry.bind( + "", + lambda event: self.app.validation.focus_out(event, "0"), + ) entry.grid(row=index, column=1, sticky="ew", pady=pady) else: logging.error("unhandled config option type: %s", option.type)