diff --git a/coretk/coretk/canvasaction.py b/coretk/coretk/canvasaction.py index decf43f3..8f217833 100644 --- a/coretk/coretk/canvasaction.py +++ b/coretk/coretk/canvasaction.py @@ -36,8 +36,6 @@ class CanvasAction: self.node_to_show_config = None def display_wlan_configuration(self, canvas_node): - - # print(self.canvas.grpc_manager.wlanconfig_management.configurations) wlan_config = self.master.core.wlanconfig_management.configurations[ canvas_node.core_id ] diff --git a/coretk/coretk/coreclient.py b/coretk/coretk/coreclient.py index 2bf047d7..d80f6e5c 100644 --- a/coretk/coretk/coreclient.py +++ b/coretk/coretk/coreclient.py @@ -5,7 +5,6 @@ import logging import os from core.api.grpc import client, core_pb2 -from coretk.coretocanvas import CoreToCanvasMapping from coretk.dialogs.sessions import SessionsDialog from coretk.emaneodelnodeconfig import EmaneModelNodeConfig from coretk.images import NODE_WIDTH, Images @@ -29,28 +28,6 @@ OBSERVERS = { } -class Node: - def __init__(self, session_id, node_id, node_type, model, x, y, name): - """ - Create an instance of a node - - :param int session_id: session id - :param int node_id: node id - :param core_pb2.NodeType node_type: node type - :param int x: x coordinate - :param int y: coordinate - :param str name: node name - """ - self.session_id = session_id - self.node_id = node_id - self.type = node_type - self.x = x - self.y = y - self.model = model - self.name = name - self.interfaces = [] - - class Edge: def __init__(self, session_id, node_id_1, node_type_1, node_id_2, node_type_2): """ @@ -112,15 +89,15 @@ class CoreClient: self.read_config() # data for managing the current session + self.canvas_nodes = {} + self.interface_to_edge = {} self.state = None - self.nodes = {} self.edges = {} self.hooks = {} self.id = 1 self.reusable = [] self.preexisting = set() self.interfaces_manager = InterfaceManager() - self.core_mapping = CoreToCanvasMapping() self.wlanconfig_management = WlanNodeConfig() self.mobilityconfig_management = MobilityNodeConfig() self.emaneconfig_management = EmaneModelNodeConfig(app) @@ -179,7 +156,7 @@ class CoreClient: # clear session data self.reusable.clear() self.preexisting.clear() - self.nodes.clear() + self.canvas_nodes.clear() self.edges.clear() self.hooks.clear() self.wlanconfig_management.configurations.clear() @@ -203,14 +180,14 @@ class CoreClient: for node in session.nodes: if node.type == core_pb2.NodeType.WIRELESS_LAN: response = self.client.get_wlan_config(self.session_id, node.id) - logging.info("wlan config(%s): %s", node.id, response) + logging.debug("wlan config(%s): %s", node.id, response) node_config = response.config config = {x: node_config[x].value for x in node_config} self.wlanconfig_management.configurations[node.id] = config # get mobility configs response = self.client.get_mobility_configs(self.session_id) - logging.info("mobility configs: %s", response) + logging.debug("mobility configs: %s", response) for node_id in response.configs: node_config = response.configs[node_id].config config = {x: node_config[x].value for x in node_config} @@ -218,7 +195,7 @@ class CoreClient: # get emane config response = self.client.get_emane_config(self.session_id) - logging.info("emane config: %s", response) + logging.debug("emane config: %s", response) self.emane_config = response.config # get emane model config @@ -339,7 +316,7 @@ class CoreClient: logging.info("delete links %s", response) def start_session(self): - nodes = self.get_nodes_proto() + nodes = [x.core_node for x in self.canvas_nodes.values()] links = self.get_links_proto() wlan_configs = self.get_wlan_configs_proto() mobility_configs = self.get_mobility_configs_proto() @@ -411,7 +388,7 @@ class CoreClient: logging.debug("set node service %s", response) def create_nodes_and_links(self): - node_protos = self.get_nodes_proto() + node_protos = [x.core_node for x in self.canvas_nodes.values()] link_protos = self.get_links_proto() self.client.set_session_state(self.session_id, core_pb2.SessionState.DEFINITION) for node_proto in node_protos: @@ -437,17 +414,6 @@ class CoreClient: logging.debug("Close grpc") self.client.close() - def peek_id(self): - """ - Peek the next id to be used - - :return: nothing - """ - if len(self.reusable) == 0: - return self.id - else: - return self.reusable[0] - def get_id(self): """ Get the next node id as well as update id status and reusable ids @@ -465,106 +431,87 @@ class CoreClient: def is_model_node(self, name): return name in DEFAULT_NODES or name in self.custom_nodes - def add_graph_node(self, session_id, canvas_id, x, y, name): + def create_node(self, x, y, node_type, model): """ Add node, with information filled in, to grpc manager - :param int session_id: session id - :param int canvas_id: node's canvas id :param int x: x coord :param int y: y coord - :param str name: node type + :param core_pb2.NodeType node_type: node type + :param str model: node model :return: nothing """ - node_type = None - node_model = None - if name in NETWORK_NODES: - if name == "switch": - node_type = core_pb2.NodeType.SWITCH - elif name == "hub": - node_type = core_pb2.NodeType.HUB - elif name == "wlan": - node_type = core_pb2.NodeType.WIRELESS_LAN - elif name == "rj45": - node_type = core_pb2.NodeType.RJ45 - elif name == "emane": - node_type = core_pb2.NodeType.EMANE - elif name == "tunnel": - node_type = core_pb2.NodeType.TUNNEL - elif name == "emane": - node_type = core_pb2.NodeType.EMANE - elif self.is_model_node(name): - node_type = core_pb2.NodeType.DEFAULT - node_model = name - else: - logging.error("invalid node name: %s", name) - nid = self.get_id() - create_node = Node(session_id, nid, node_type, node_model, x, y, name) + node_id = self.get_id() + position = core_pb2.Position(x=x, y=y) + node = core_pb2.Node( + id=node_id, + type=node_type, + name=f"n{node_id}", + model=model, + position=position, + ) # set default configuration for wireless node - self.wlanconfig_management.set_default_config(node_type, nid) - self.mobilityconfig_management.set_default_configuration(node_type, nid) + self.wlanconfig_management.set_default_config(node_type, node_id) + self.mobilityconfig_management.set_default_configuration(node_type, node_id) # set default emane configuration for emane node if node_type == core_pb2.NodeType.EMANE: - self.emaneconfig_management.set_default_config(nid) + self.emaneconfig_management.set_default_config(node_id) # set default service configurations if node_type == core_pb2.NodeType.DEFAULT: self.serviceconfig_manager.node_default_services_configuration( - node_id=nid, node_model=node_model + node_id=node_id, node_model=model ) - self.nodes[canvas_id] = create_node - self.core_mapping.map_core_id_to_canvas_id(nid, canvas_id) logging.debug( - "Adding node to core.. session id: %s, coords: (%s, %s), name: %s", - session_id, + "adding node to core session: %s, coords: (%s, %s), name: %s", + self.session_id, x, y, - name, + node.name, ) + return node - def delete_wanted_graph_nodes(self, canvas_ids, tokens): + def delete_wanted_graph_nodes(self, node_ids, edge_tokens): """ remove the nodes selected by the user and anything related to that node such as link, configurations, interfaces - :param list(int) canvas_ids: list of canvas node ids + :param list[int] node_ids: list of nodes to delete + :param list edge_tokens: list of edges to delete :return: nothing """ - # keep reference to the core ids - core_node_ids = [self.nodes[x].node_id for x in canvas_ids] - node_interface_pairs = [] - # delete the nodes - for i in canvas_ids: + for node_id in node_ids: try: - n = self.nodes.pop(i) - self.reusable.append(n.node_id) + del self.canvas_nodes[node_id] + self.reusable.append(node_id) except KeyError: - logging.error("coreclient.py INVALID NODE CANVAS ID") - + logging.error("invalid canvas id: %s", node_id) self.reusable.sort() # delete the edges and interfaces - for i in tokens: + node_interface_pairs = [] + for i in edge_tokens: try: e = self.edges.pop(i) if e.interface_1 is not None: node_interface_pairs.append(tuple([e.id1, e.interface_1.id])) if e.interface_2 is not None: node_interface_pairs.append(tuple([e.id2, e.interface_2.id])) - except KeyError: logging.error("coreclient.py invalid edge token ") # delete global emane config if there no longer exist any emane cloud - if core_pb2.NodeType.EMANE not in [x.type for x in self.nodes.values()]: + # TODO: should not need to worry about this + node_types = [x.core_node.type for x in self.canvas_nodes.values()] + if core_pb2.NodeType.EMANE not in node_types: self.emane_config = None # delete any mobility configuration, wlan configuration - for i in core_node_ids: + for i in node_ids: if i in self.mobilityconfig_management.configurations: self.mobilityconfig_management.configurations.pop(i) if i in self.wlanconfig_management.configurations: @@ -574,69 +521,16 @@ class CoreClient: for i in node_interface_pairs: if i in self.emaneconfig_management.configurations: self.emaneconfig_management.configurations.pop(i) - for i in core_node_ids: + for i in node_ids: if tuple([i, None]) in self.emaneconfig_management.configurations: self.emaneconfig_management.configurations.pop(tuple([i, None])) - def add_preexisting_node(self, canvas_node, session_id, core_node, name): - """ - Add preexisting nodes to grpc manager - - :param str name: node_type - :param core_pb2.Node core_node: core node grpc message - :param coretk.graph.CanvasNode canvas_node: canvas node - :param int session_id: session id - :return: nothing - """ - - # update the next available id - core_id = core_node.id - if self.id is None or core_id >= self.id: - self.id = core_id + 1 - self.preexisting.add(core_id) - n = Node( - session_id, - core_id, - core_node.type, - core_node.model, - canvas_node.x_coord, - canvas_node.y_coord, - name, - ) - self.nodes[canvas_node.id] = n - - def update_node_location(self, canvas_id, new_x, new_y): - """ - update node - - :param int canvas_id: canvas id of that node - :param int new_x: new x coord - :param int new_y: new y coord - :return: nothing - """ - self.nodes[canvas_id].x = new_x - self.nodes[canvas_id].y = new_y - - def update_reusable_id(self): - """ - Update available id for reuse - - :return: nothing - """ - if len(self.preexisting) > 0: - for i in range(1, self.id): - if i not in self.preexisting: - self.reusable.append(i) - - self.preexisting.clear() - logging.debug("Next id: %s, Reusable: %s", self.id, self.reusable) - def create_interface(self, node_type, gui_interface): """ create a protobuf interface given the interface object stored by the programmer - :param core_bp2.NodeType type: node type - :param coretk.interface.Interface gui_interface: the programmer's interface object + :param core_bp2.NodeType node_type: node type + :param coretk.interface.Interface gui_interface: the programmer's interface :rtype: core_bp2.Interface :return: protobuf interface object """ @@ -653,120 +547,71 @@ class CoreClient: logging.debug("create interface: %s", interface) return interface - def create_edge_interface(self, edge, src_canvas_id, dst_canvas_id): - """ - Create the interface for the two end of an edge, add a copy to node's interfaces - - :param coretk.coreclient.Edge edge: edge to add interfaces to - :param int src_canvas_id: canvas id for the source node - :param int dst_canvas_id: canvas id for the destination node - :return: nothing - """ - src_interface = None - dst_interface = None - print("create interface") - self.interfaces_manager.new_subnet() - - src_node = self.nodes[src_canvas_id] - if self.is_model_node(src_node.model): - ifid = len(src_node.interfaces) - name = "eth" + str(ifid) - src_interface = Interface( + def create_edge_interface(self, canvas_node): + interface = None + core_node = canvas_node.core_node + if self.is_model_node(core_node.model): + ifid = len(canvas_node.interfaces) + name = f"eth{ifid}" + interface = Interface( name=name, ifid=ifid, ipv4=str(self.interfaces_manager.get_address()) ) - self.nodes[src_canvas_id].interfaces.append(src_interface) + canvas_node.interfaces.append(interface) logging.debug( - "Create source interface 1... IP: %s, name: %s", - src_interface.ipv4, - src_interface.name, + "create node(%s) interface IP: %s, name: %s", + core_node.name, + interface.ipv4, + interface.name, ) + return interface - dst_node = self.nodes[dst_canvas_id] - if self.is_model_node(dst_node.model): - ifid = len(dst_node.interfaces) - name = "eth" + str(ifid) - dst_interface = Interface( - name=name, ifid=ifid, ipv4=str(self.interfaces_manager.get_address()) - ) - self.nodes[dst_canvas_id].interfaces.append(dst_interface) - logging.debug( - "Create destination interface... IP: %s, name: %s", - dst_interface.ipv4, - dst_interface.name, - ) - - edge.interface_1 = src_interface - edge.interface_2 = dst_interface - return src_interface, dst_interface - - def add_edge(self, session_id, token, canvas_id_1, canvas_id_2): + def create_edge(self, token, canvas_node_one, canvas_node_two): """ Add an edge to grpc manager - :param int session_id: core session id :param tuple(int, int) token: edge's identification in the canvas - :param int canvas_id_1: canvas id of source node - :param int canvas_id_2: canvas_id of destination node + :param canvas_node_one: canvas node one + :param canvas_node_two: canvas node two :return: nothing """ - node_one = self.nodes[canvas_id_1] - node_two = self.nodes[canvas_id_2] - if canvas_id_1 in self.nodes and canvas_id_2 in self.nodes: - edge = Edge( - session_id, - node_one.node_id, - node_one.type, - node_two.node_id, - node_two.type, - ) - self.edges[token] = edge - src_interface, dst_interface = self.create_edge_interface( - edge, canvas_id_1, canvas_id_2 - ) - node_one_id = node_one.node_id - node_two_id = node_two.node_id + node_one = canvas_node_one.core_node + node_two = canvas_node_two.core_node - # provide a way to get an edge from a core node and an interface id - if src_interface is not None: - self.core_mapping.map_node_and_interface_to_canvas_edge( - node_one_id, src_interface.id, token + # create interfaces + self.interfaces_manager.new_subnet() + interface_one = self.create_edge_interface(canvas_node_one) + if interface_one is not None: + self.interface_to_edge[(node_one.id, interface_one.id)] = token + interface_two = self.create_edge_interface(canvas_node_two) + if interface_two is not None: + self.interface_to_edge[(node_two.id, interface_two.id)] = token + + # emane setup + if ( + node_one.type == core_pb2.NodeType.EMANE + and node_two.type == core_pb2.NodeType.DEFAULT + ): + if node_two.model == "mdr": + self.emaneconfig_management.set_default_for_mdr( + node_one.node_id, node_two.node_id, interface_two.id + ) + elif ( + node_two.type == core_pb2.NodeType.EMANE + and node_one.type == core_pb2.NodeType.DEFAULT + ): + if node_one.model == "mdr": + self.emaneconfig_management.set_default_for_mdr( + node_two.node_id, node_one.node_id, interface_one.id ) - if dst_interface is not None: - self.core_mapping.map_node_and_interface_to_canvas_edge( - node_two_id, dst_interface.id, token - ) - - if ( - node_one.type == core_pb2.NodeType.EMANE - and node_two.type == core_pb2.NodeType.DEFAULT - ): - if node_two.model == "mdr": - self.emaneconfig_management.set_default_for_mdr( - node_one.node_id, node_two.node_id, dst_interface.id - ) - elif ( - node_two.type == core_pb2.NodeType.EMANE - and node_one.type == core_pb2.NodeType.DEFAULT - ): - if node_one.model == "mdr": - self.emaneconfig_management.set_default_for_mdr( - node_two.node_id, node_one.node_id, src_interface.id - ) - - else: - logging.error("grpcmanagement.py INVALID CANVAS NODE ID") - - def get_nodes_proto(self): - nodes = [] - for node in self.nodes.values(): - pos = core_pb2.Position(x=int(node.x), y=int(node.y)) - proto_node = core_pb2.Node( - id=node.node_id, type=node.type, position=pos, model=node.model - ) - nodes.append(proto_node) - return nodes + edge = Edge( + self.session_id, node_one.id, node_one.type, node_two.id, node_two.type + ) + edge.interface_1 = interface_one + edge.interface_2 = interface_two + self.edges[token] = edge + return edge def get_links_proto(self): links = [] diff --git a/coretk/coretk/coretocanvas.py b/coretk/coretk/coretocanvas.py deleted file mode 100644 index 6e767db3..00000000 --- a/coretk/coretk/coretocanvas.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -provide mapping from core to canvas -""" -import logging - - -class CoreToCanvasMapping: - def __init__(self): - self.core_id_to_canvas_id = {} - self.core_node_and_interface_to_canvas_edge = {} - - def map_node_and_interface_to_canvas_edge(self, nid, iid, edge_token): - self.core_node_and_interface_to_canvas_edge[tuple([nid, iid])] = edge_token - - def get_token_from_node_and_interface(self, nid, iid): - key = tuple([nid, iid]) - if key in self.core_node_and_interface_to_canvas_edge: - return self.core_node_and_interface_to_canvas_edge[key] - else: - logging.error("invalid key") - return None - - def map_core_id_to_canvas_id(self, core_nid, canvas_nid): - if core_nid not in self.core_id_to_canvas_id: - self.core_id_to_canvas_id[core_nid] = canvas_nid - else: - logging.debug("key already existed") - - def get_canvas_id_from_core_id(self, core_id): - if core_id in self.core_id_to_canvas_id: - return self.core_id_to_canvas_id[core_id] - else: - logging.debug("invalid key") - return None diff --git a/coretk/coretk/dialogs/nodeconfig.py b/coretk/coretk/dialogs/nodeconfig.py index 48233762..14e9de03 100644 --- a/coretk/coretk/dialogs/nodeconfig.py +++ b/coretk/coretk/dialogs/nodeconfig.py @@ -21,7 +21,7 @@ class NodeConfigDialog(Dialog): self.image = canvas_node.image self.image_button = None self.name = tk.StringVar(value=canvas_node.name) - self.type = tk.StringVar(value=canvas_node.node_type) + self.type = tk.StringVar(value=canvas_node.core_node.model) self.server = tk.StringVar() self.draw() diff --git a/coretk/coretk/graph.py b/coretk/coretk/graph.py index f7c45e63..1fcafac1 100644 --- a/coretk/coretk/graph.py +++ b/coretk/coretk/graph.py @@ -39,7 +39,8 @@ class CanvasGraph(tk.Canvas): super().__init__(master, cnf, **kwargs) self.mode = GraphMode.SELECT self.draw_node_image = None - self.draw_node_name = None + self.draw_node_type = None + self.draw_node_model = None self.selected = None self.node_context = None self.nodes = {} @@ -97,13 +98,14 @@ class CanvasGraph(tk.Canvas): # set the private variables to default value self.mode = GraphMode.SELECT self.draw_node_image = None - self.draw_node_name = None + self.draw_node_type = None + self.draw_node_model = None self.selected = None self.node_context = None self.nodes.clear() self.edges.clear() self.drawing_edge = None - self.draw_existing_component(session) + self.draw_session(session) def setup_bindings(self): """ @@ -143,61 +145,46 @@ class CanvasGraph(tk.Canvas): self.tag_lower("gridline") self.tag_lower(self.grid) - def draw_existing_component(self, session): + def draw_session(self, session): """ - Draw existing node and update the information in grpc manager to match + Draw existing session. :return: nothing """ - core_id_to_canvas_id = {} - # redraw existing nodes - for node in session.nodes: + # draw existing nodes + for core_node in session.nodes: # peer to peer node is not drawn on the GUI - if node.type != core_pb2.NodeType.PEER_TO_PEER: - # draw nodes on the canvas - image, name = Images.node_icon(node.type, node.model) - n = CanvasNode( - node.position.x, node.position.y, image, name, self.master, node.id - ) - self.nodes[n.id] = n - core_id_to_canvas_id[node.id] = n.id + if core_node.type == core_pb2.NodeType.PEER_TO_PEER: + continue - # store the node in grpc manager - self.core.add_preexisting_node(n, session.id, node, name) + # draw nodes on the canvas + image = Images.node_icon(core_node.type, core_node.model) + position = core_node.position + node = CanvasNode(position.x, position.y, image, self.master, core_node) + self.nodes[node.id] = node + self.core.canvas_nodes[core_node.id] = node # draw existing links for link in session.links: - n1 = self.nodes[core_id_to_canvas_id[link.node_one_id]] - n2 = self.nodes[core_id_to_canvas_id[link.node_two_id]] - if link.type == core_pb2.LinkType.WIRED: - e = CanvasEdge( - n1.x_coord, - n1.y_coord, - n2.x_coord, - n2.y_coord, - n1.id, - self, - is_wired=True, - ) - elif link.type == core_pb2.LinkType.WIRELESS: - e = CanvasEdge( - n1.x_coord, - n1.y_coord, - n2.x_coord, - n2.y_coord, - n1.id, - self, - is_wired=False, - ) - edge_token = tuple(sorted((n1.id, n2.id))) - e.token = edge_token - e.dst = n2.id - n1.edges.add(e) - n2.edges.add(e) - self.edges[e.token] = e - self.core.add_edge(session.id, e.token, n1.id, n2.id) - - self.helper.redraw_antenna(link, n1, n2) + canvas_node_one = self.core.canvas_nodes[link.node_one_id] + canvas_node_two = self.core.canvas_nodes[link.node_two_id] + is_wired = link.type == core_pb2.LinkType.WIRED + edge = CanvasEdge( + canvas_node_one.x_coord, + canvas_node_one.y_coord, + canvas_node_two.x_coord, + canvas_node_two.y_coord, + canvas_node_one.id, + self, + is_wired=is_wired, + ) + edge.token = tuple(sorted((canvas_node_one.id, canvas_node_two.id))) + edge.dst = canvas_node_two.id + canvas_node_one.edges.add(edge) + canvas_node_two.edges.add(edge) + self.edges[edge.token] = edge + self.core.create_edge(edge.token, canvas_node_one, canvas_node_two) + self.helper.redraw_antenna(link, canvas_node_one, canvas_node_two) # TODO add back the link info to grpc manager also redraw grpc_if1 = link.interface_one @@ -212,9 +199,9 @@ class CanvasGraph(tk.Canvas): if grpc_if2 is not None: ip4_dst = grpc_if2.ip4 ip6_dst = grpc_if2.ip6 - e.link_info = LinkInfo( + edge.link_info = LinkInfo( canvas=self, - edge=e, + edge=edge, ip4_src=ip4_src, ip6_src=ip6_src, ip4_dst=ip4_dst, @@ -224,14 +211,10 @@ class CanvasGraph(tk.Canvas): # TODO will include throughput and ipv6 in the future if1 = Interface(grpc_if1.name, grpc_if1.ip4, ifid=grpc_if1.id) if2 = Interface(grpc_if2.name, grpc_if2.ip4, ifid=grpc_if2.id) - self.core.edges[e.token].interface_1 = if1 - self.core.edges[e.token].interface_2 = if2 - self.core.nodes[core_id_to_canvas_id[link.node_one_id]].interfaces.append( - if1 - ) - self.core.nodes[core_id_to_canvas_id[link.node_two_id]].interfaces.append( - if2 - ) + self.core.edges[edge.token].interface_1 = if1 + self.core.edges[edge.token].interface_2 = if2 + canvas_node_one.interfaces.append(if1) + canvas_node_two.interfaces.append(if2) # raise the nodes so they on top of the links self.tag_raise("node") @@ -290,7 +273,13 @@ class CanvasGraph(tk.Canvas): self.handle_edge_release(event) elif self.mode == GraphMode.NODE: x, y = self.canvas_xy(event) - self.add_node(x, y, self.draw_node_image, self.draw_node_name) + self.add_node( + x, + y, + self.draw_node_image, + self.draw_node_type, + self.draw_node_model, + ) elif self.mode == GraphMode.PICKNODE: self.mode = GraphMode.NODE @@ -313,6 +302,7 @@ class CanvasGraph(tk.Canvas): # edge dst is same as src, delete edge if edge.src == self.selected: edge.delete() + return # set dst node and snap edge to center x, y = self.coords(self.selected) @@ -326,14 +316,11 @@ class CanvasGraph(tk.Canvas): node_src.edges.add(edge) node_dst = self.nodes[edge.dst] node_dst.edges.add(edge) - - self.core.add_edge( - self.core.session_id, edge.token, node_src.id, node_dst.id - ) + core_edge = self.core.create_edge(edge.token, node_src, node_dst) # draw link info on the edge - if1 = self.core.edges[edge.token].interface_1 - if2 = self.core.edges[edge.token].interface_2 + if1 = core_edge.interface_1 + if2 = core_edge.interface_2 ip4_and_prefix_1 = None ip4_and_prefix_2 = None if if1 is not None: @@ -404,8 +391,10 @@ class CanvasGraph(tk.Canvas): ) # delete nodes and link info stored in CanvasGraph object + node_ids = [] for nid in to_delete_nodes: - self.nodes.pop(nid) + canvas_node = self.nodes.pop(nid) + node_ids.append(canvas_node.core_node.id) for token in to_delete_edge_tokens: self.edges.pop(token) @@ -419,15 +408,16 @@ class CanvasGraph(tk.Canvas): self.nodes[nid].edges.remove(edge) # delete the related data from core - self.core.delete_wanted_graph_nodes(to_delete_nodes, to_delete_edge_tokens) + self.core.delete_wanted_graph_nodes(node_ids, to_delete_edge_tokens) - def add_node(self, x, y, image, node_name): + def add_node(self, x, y, image, node_type, model): plot_id = self.find_all()[0] logging.info("add node event: %s - %s", plot_id, self.selected) if self.selected == plot_id: - node = CanvasNode(x, y, image, node_name, self.master, self.core.peek_id()) + core_node = self.core.create_node(int(x), int(y), node_type, model) + node = CanvasNode(x, y, image, self.master, core_node) + self.core.canvas_nodes[core_node.id] = node self.nodes[node.id] = node - self.core.add_graph_node(self.core.session_id, node.id, x, y, node_name) return node def width_and_height(self): @@ -494,7 +484,6 @@ class CanvasGraph(tk.Canvas): """ scale image based on canvas dimension - :param Image img: image object :return: nothing """ canvas_w, canvas_h = self.width_and_height() @@ -614,18 +603,17 @@ class CanvasEdge: class CanvasNode: - def __init__(self, x, y, image, node_type, app, core_id): + def __init__(self, x, y, image, app, core_node): self.image = image - self.node_type = node_type self.app = app self.canvas = app.canvas self.id = self.canvas.create_image( x, y, anchor=tk.CENTER, image=self.image, tags="node" ) - self.core_id = core_id + self.core_node = core_node + self.name = core_node.name self.x_coord = x self.y_coord = y - self.name = f"N{self.core_id}" self.text_id = self.canvas.create_text( x, y + 20, text=self.name, tags="nodename" ) @@ -641,6 +629,7 @@ class CanvasNode: self.canvas.tag_bind(self.id, "", self.on_leave) self.edges = set() + self.interfaces = [] self.wlans = [] self.moving = None @@ -648,7 +637,7 @@ class CanvasNode: if self.app.core.is_runtime() and self.app.core.observer: self.tooltip.text.set("waiting...") self.tooltip.on_enter(event) - output = self.app.core.run(self.core_id) + output = self.app.core.run(self.core_node.id) self.tooltip.text.set(output) def on_leave(self, event): @@ -658,15 +647,15 @@ class CanvasNode: print("click") def double_click(self, event): - node_id = self.canvas.core.nodes[self.id].node_id - state = self.canvas.core.get_session_state() - if state == core_pb2.SessionState.RUNTIME: - self.canvas.core.launch_terminal(node_id) + if self.app.core.is_runtime(): + self.canvas.core.launch_terminal(self.core_node.id) else: self.canvas.canvas_action.display_configuration(self) def update_coords(self): self.x_coord, self.y_coord = self.canvas.coords(self.id) + self.core_node.position.x = int(self.x_coord) + self.core_node.position.y = int(self.y_coord) def click_press(self, event): logging.debug(f"node click press {self.name}: {event}") @@ -677,7 +666,6 @@ class CanvasNode: def click_release(self, event): logging.debug(f"node click release {self.name}: {event}") self.update_coords() - self.canvas.core.update_node_location(self.id, self.x_coord, self.y_coord) self.moving = None def motion(self, event): @@ -697,7 +685,7 @@ class CanvasNode: new_x, new_y = self.canvas.coords(self.id) if self.canvas.core.get_session_state() == core_pb2.SessionState.RUNTIME: - self.canvas.core.edit_node(self.core_id, int(new_x), int(new_y)) + self.canvas.core.edit_node(self.core_node.id, int(new_x), int(new_y)) for edge in self.edges: x1, y1, x2, y2 = self.canvas.coords(edge.id) diff --git a/coretk/coretk/graph_helper.py b/coretk/coretk/graph_helper.py index c1f59815..476c0182 100644 --- a/coretk/coretk/graph_helper.py +++ b/coretk/coretk/graph_helper.py @@ -29,29 +29,31 @@ class GraphHelper: self.canvas.delete(i) def draw_wireless_case(self, src_id, dst_id, edge): - src_node_name = self.canvas.nodes[src_id].node_type - dst_node_name = self.canvas.nodes[dst_id].node_type - - if src_node_name == "wlan" or dst_node_name == "wlan": + src_node_type = self.canvas.nodes[src_id].core_node.type + dst_node_type = self.canvas.nodes[dst_id].core_node.type + is_src_wlan = src_node_type == core_pb2.NodeType.WIRELESS_LAN + is_dst_wlan = dst_node_type == core_pb2.NodeType.WIRELESS_LAN + if is_src_wlan or is_dst_wlan: self.canvas.itemconfig(edge.id, state=tk.HIDDEN) edge.wired = False if edge.token not in self.canvas.edges: - if src_node_name == "wlan" and dst_node_name == "wlan": + if is_src_wlan and is_dst_wlan: self.canvas.nodes[src_id].antenna_draw.add_antenna() - elif src_node_name == "wlan": + elif is_src_wlan: self.canvas.nodes[dst_id].antenna_draw.add_antenna() else: self.canvas.nodes[src_id].antenna_draw.add_antenna() - edge.wired = True def redraw_antenna(self, link, node_one, node_two): + is_node_one_wlan = node_one.core_node.type == core_pb2.NodeType.WIRELESS_LAN + is_node_two_wlan = node_two.core_node.type == core_pb2.NodeType.WIRELESS_LAN if link.type == core_pb2.LinkType.WIRELESS: - if node_one.node_type == "wlan" and node_two.node_type == "wlan": + if is_node_one_wlan and is_node_two_wlan: node_one.antenna_draw.add_antenna() - elif node_one.node_type == "wlan" and node_two.node_type != "wlan": + elif is_node_one_wlan and not is_node_two_wlan: node_two.antenna_draw.add_antenna() - elif node_one.node_type != "wlan" and node_two.node_type == "wlan": + elif not is_node_one_wlan and is_node_two_wlan: node_one.antenna_draw.add_antenna() else: logging.error( @@ -122,91 +124,3 @@ class WlanAntennaManager: """ for i in self.antennas: self.canvas.delete(i) - - -# class WlanConnection: -# def __init__(self, canvas, grpc): -# """ -# create in -# :param canvas: -# """ -# self.canvas = canvas -# self.core_grpc = grpc -# self.throughput_on = False -# self.map_node_link = {} -# self.links = [] -# -# def wireless_nodes(self): -# """ -# retrieve all the wireless clouds in the canvas -# -# :return: list(coretk.graph.CanvasNode) -# """ -# wireless_nodes = [] -# for n in self.canvas.nodes.values(): -# if n.node_type == "wlan": -# wireless_nodes.append(n) -# return wireless_nodes -# -# def draw_wireless_link(self, src, dst): -# """ -# draw a line between 2 nodes that are connected to the same wireless cloud -# -# :param coretk.graph.CanvasNode src: source node -# :param coretk.graph.CanvasNode dst: destination node -# :return: nothing -# """ -# cid = self.canvas.create_line(src.x_coord, src.y_coord, dst.x_coord, dst.y_coord, tags="wlanconnection") -# if src.id not in self.map_node_link: -# self.map_node_link[src.id] = [] -# if dst.id not in self.map_node_link: -# self.map_node_link[dst.id] = [] -# self.map_node_link[src.id].append(cid) -# self.map_node_link[dst.id].append(cid) -# self.links.append(cid) -# -# def subnet_wireless_connection(self, wlan_node): -# """ -# retrieve all the non-wireless nodes connected to wireless_node and create line (represent wireless connection) between each pair of nodes -# :param coretk.grpah.CanvasNode wlan_node: wireless node -# -# :return: nothing -# """ -# non_wlan_nodes = [] -# for e in wlan_node.edges: -# src = self.canvas.nodes[e.src] -# dst = self.canvas.nodes[e.dst] -# if src.node_type == "wlan" and dst.node_type != "wlan": -# non_wlan_nodes.append(dst) -# elif src.node_type != "wlan" and dst.node_type == "wlan": -# non_wlan_nodes.append(src) -# -# size = len(non_wlan_nodes) -# for i in range(size): -# for j in range(i+1, size): -# self.draw_wireless_link(non_wlan_nodes[i], non_wlan_nodes[j]) -# -# def session_wireless_connection(self): -# """ -# draw all the wireless connection in the canvas -# -# :return: nothing -# """ -# wlan_nodes = self.wireless_nodes() -# for n in wlan_nodes: -# self.subnet_wireless_connection(n) -# -# def show_links(self): -# """ -# show all the links -# """ -# for l in self.links: -# self.canvas.itemconfig(l, state=tk.NORMAL) -# -# def hide_links(self): -# """ -# hide all the links -# :return: -# """ -# for l in self.links: -# self.canvas.itemconfig(l, state=tk.HIDDEN) diff --git a/coretk/coretk/images.py b/coretk/coretk/images.py index 7335e14e..6ce4732f 100644 --- a/coretk/coretk/images.py +++ b/coretk/coretk/images.py @@ -31,7 +31,7 @@ class Images: return cls.create(file_path, width, height) @classmethod - def get_custom(cls, name, width, height): + def get_custom(cls, name, width, height=None): file_path = cls.images[name] return cls.create(file_path, width, height) @@ -41,52 +41,38 @@ class Images: Retrieve image based on type and model :param core_pb2.NodeType node_type: core node type :param string node_model: the node model - - :rtype: tuple(PhotoImage, str) - :return: the matching image and its name + :return: core node icon + :rtype: PhotoImage """ image_enum = ImageEnum.ROUTER - name = "unknown" if node_type == core_pb2.NodeType.SWITCH: image_enum = ImageEnum.SWITCH - name = "switch" elif node_type == core_pb2.NodeType.HUB: image_enum = ImageEnum.HUB - name = "hub" elif node_type == core_pb2.NodeType.WIRELESS_LAN: image_enum = ImageEnum.WLAN - name = "wlan" elif node_type == core_pb2.NodeType.EMANE: image_enum = ImageEnum.EMANE - name = "emane" elif node_type == core_pb2.NodeType.RJ45: image_enum = ImageEnum.RJ45 - name = "rj45" elif node_type == core_pb2.NodeType.TUNNEL: image_enum = ImageEnum.TUNNEL - name = "tunnel" elif node_type == core_pb2.NodeType.DEFAULT: if node_model == "router": image_enum = ImageEnum.ROUTER - name = "router" elif node_model == "host": image_enum = ImageEnum.HOST - name = "host" elif node_model == "PC": image_enum = ImageEnum.PC - name = "PC" elif node_model == "mdr": image_enum = ImageEnum.MDR - name = "mdr" elif node_model == "prouter": image_enum = ImageEnum.PROUTER - name = "prouter" else: logging.error("invalid node model: %s", node_model) else: logging.error("invalid node type: %s", node_type) - - return Images.get(image_enum, NODE_WIDTH), name + return Images.get(image_enum, NODE_WIDTH) class ImageEnum(Enum): diff --git a/coretk/coretk/linkinfo.py b/coretk/coretk/linkinfo.py index 916e8dfb..29430deb 100644 --- a/coretk/coretk/linkinfo.py +++ b/coretk/coretk/linkinfo.py @@ -129,8 +129,7 @@ class Throughput: nid = t.node_id iid = t.interface_id tp = t.throughput - # token = self.grpc_manager.node_id_and_interface_to_edge_token[nid, iid] - token = self.core.core_mapping.get_token_from_node_and_interface(nid, iid) + token = self.core.interface_to_edge[(nid, iid)] print(token) edge_id = self.canvas.edges[token].id diff --git a/coretk/coretk/toolbar.py b/coretk/coretk/toolbar.py index 89393c3e..a049c321 100644 --- a/coretk/coretk/toolbar.py +++ b/coretk/coretk/toolbar.py @@ -3,6 +3,7 @@ import tkinter as tk from functools import partial from tkinter import ttk +from core.api.grpc import core_pb2 from coretk.dialogs.customnodes import CustomNodesDialog from coretk.graph import GraphMode from coretk.images import ImageEnum, Images @@ -136,10 +137,16 @@ class Toolbar(ttk.Frame): (ImageEnum.PROUTER, "prouter"), ] # draw default nodes - for image_enum, tooltip in nodes: + for image_enum, model in nodes: image = icon(image_enum) - func = partial(self.update_button, self.node_button, image, tooltip) - self.create_picker_button(image, func, self.node_picker, tooltip) + func = partial( + self.update_button, + self.node_button, + image, + core_pb2.NodeType.DEFAULT, + model, + ) + self.create_picker_button(image, func, self.node_picker, model) # draw custom nodes for name in sorted(self.app.core.custom_nodes): custom_node = self.app.core.custom_nodes[name] @@ -216,14 +223,15 @@ class Toolbar(ttk.Frame): dialog = CustomNodesDialog(self.app, self.app) dialog.show() - def update_button(self, button, image, name): - logging.info("update button(%s): %s", button, name) + def update_button(self, button, image, node_type, model=None): + logging.info("update button(%s): %s", button, node_type) self.hide_pickers() button.configure(image=image) button.image = image self.app.canvas.mode = GraphMode.NODE self.app.canvas.draw_node_image = image - self.app.canvas.draw_node_name = name + self.app.canvas.draw_node_type = node_type + self.app.canvas.draw_node_model = model def hide_pickers(self): logging.info("hiding pickers") @@ -260,18 +268,18 @@ class Toolbar(ttk.Frame): self.hide_pickers() self.network_picker = ttk.Frame(self.master) nodes = [ - (ImageEnum.HUB, "hub", "ethernet hub"), - (ImageEnum.SWITCH, "switch", "ethernet switch"), - (ImageEnum.WLAN, "wlan", "wireless LAN"), - (ImageEnum.EMANE, "emane", "EMANE"), - (ImageEnum.RJ45, "rj45", "rj45 physical interface tool"), - (ImageEnum.TUNNEL, "tunnel", "tunnel tool"), + (ImageEnum.HUB, core_pb2.NodeType.HUB, "ethernet hub"), + (ImageEnum.SWITCH, core_pb2.NodeType.SWITCH, "ethernet switch"), + (ImageEnum.WLAN, core_pb2.NodeType.WIRELESS_LAN, "wireless LAN"), + (ImageEnum.EMANE, core_pb2.NodeType.EMANE, "EMANE"), + (ImageEnum.RJ45, core_pb2.NodeType.RJ45, "rj45 physical interface tool"), + (ImageEnum.TUNNEL, core_pb2.NodeType.TUNNEL, "tunnel tool"), ] - for image_enum, name, tooltip in nodes: + for image_enum, node_type, tooltip in nodes: image = icon(image_enum) self.create_picker_button( image, - partial(self.update_button, self.network_button, image, name), + partial(self.update_button, self.network_button, image, node_type), self.network_picker, tooltip, ) diff --git a/coretk/coretk/wirelessconnection.py b/coretk/coretk/wirelessconnection.py index d1e17bc5..b864ce38 100644 --- a/coretk/coretk/wirelessconnection.py +++ b/coretk/coretk/wirelessconnection.py @@ -7,35 +7,31 @@ from core.api.grpc import core_pb2 class WirelessConnection: def __init__(self, canvas, core): self.canvas = canvas - self.core_mapping = core.core_mapping + self.core = core # map a (node_one_id, node_two_id) to a wlan canvas id self.map = {} def add_wlan_connection(self, node_one_id, node_two_id): - canvas_id_one = self.core_mapping.get_canvas_id_from_core_id(node_one_id) - canvas_id_two = self.core_mapping.get_canvas_id_from_core_id(node_two_id) + canvas_node_one = self.core.canvas_nodes[node_one_id] + canvas_node_two = self.core.canvas_nodes[node_two_id] key = tuple(sorted((node_one_id, node_two_id))) - if key not in self.map: - x1, y1 = self.canvas.coords(canvas_id_one) - x2, y2 = self.canvas.coords(canvas_id_two) + x1, y1 = self.canvas.coords(canvas_node_one.id) + x2, y2 = self.canvas.coords(canvas_node_two.id) wlan_canvas_id = self.canvas.create_line( x1, y1, x2, y2, fill="#009933", tags="wlan", width=1.5 ) self.map[key] = wlan_canvas_id - self.canvas.nodes[canvas_id_one].wlans.append(wlan_canvas_id) - self.canvas.nodes[canvas_id_two].wlans.append(wlan_canvas_id) + canvas_node_one.wlans.append(wlan_canvas_id) + canvas_node_two.wlans.append(wlan_canvas_id) def delete_wlan_connection(self, node_one_id, node_two_id): - canvas_id_one = self.core_mapping.get_canvas_id_from_core_id(node_one_id) - canvas_id_two = self.core_mapping.get_canvas_id_from_core_id(node_two_id) - + canvas_node_one = self.core.canvas_nodes[node_one_id] + canvas_node_two = self.core.canvas_nodes[node_two_id] key = tuple(sorted((node_one_id, node_two_id))) wlan_canvas_id = self.map[key] - - self.canvas.nodes[canvas_id_one].wlans.remove(wlan_canvas_id) - self.canvas.nodes[canvas_id_two].wlans.remove(wlan_canvas_id) - + canvas_node_one.wlans.remove(wlan_canvas_id) + canvas_node_two.wlans.remove(wlan_canvas_id) self.canvas.delete(wlan_canvas_id) self.map.pop(key, None)