update node creation and storage to leverage protobufs directly

This commit is contained in:
bharnden 2019-11-15 10:22:30 -08:00
parent fa76bbf01b
commit 6d38058887
10 changed files with 216 additions and 516 deletions

View file

@ -36,8 +36,6 @@ class CanvasAction:
self.node_to_show_config = None self.node_to_show_config = None
def display_wlan_configuration(self, canvas_node): def display_wlan_configuration(self, canvas_node):
# print(self.canvas.grpc_manager.wlanconfig_management.configurations)
wlan_config = self.master.core.wlanconfig_management.configurations[ wlan_config = self.master.core.wlanconfig_management.configurations[
canvas_node.core_id canvas_node.core_id
] ]

View file

@ -5,7 +5,6 @@ import logging
import os import os
from core.api.grpc import client, core_pb2 from core.api.grpc import client, core_pb2
from coretk.coretocanvas import CoreToCanvasMapping
from coretk.dialogs.sessions import SessionsDialog from coretk.dialogs.sessions import SessionsDialog
from coretk.emaneodelnodeconfig import EmaneModelNodeConfig from coretk.emaneodelnodeconfig import EmaneModelNodeConfig
from coretk.images import NODE_WIDTH, Images 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: class Edge:
def __init__(self, session_id, node_id_1, node_type_1, node_id_2, node_type_2): 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() self.read_config()
# data for managing the current session # data for managing the current session
self.canvas_nodes = {}
self.interface_to_edge = {}
self.state = None self.state = None
self.nodes = {}
self.edges = {} self.edges = {}
self.hooks = {} self.hooks = {}
self.id = 1 self.id = 1
self.reusable = [] self.reusable = []
self.preexisting = set() self.preexisting = set()
self.interfaces_manager = InterfaceManager() self.interfaces_manager = InterfaceManager()
self.core_mapping = CoreToCanvasMapping()
self.wlanconfig_management = WlanNodeConfig() self.wlanconfig_management = WlanNodeConfig()
self.mobilityconfig_management = MobilityNodeConfig() self.mobilityconfig_management = MobilityNodeConfig()
self.emaneconfig_management = EmaneModelNodeConfig(app) self.emaneconfig_management = EmaneModelNodeConfig(app)
@ -179,7 +156,7 @@ class CoreClient:
# clear session data # clear session data
self.reusable.clear() self.reusable.clear()
self.preexisting.clear() self.preexisting.clear()
self.nodes.clear() self.canvas_nodes.clear()
self.edges.clear() self.edges.clear()
self.hooks.clear() self.hooks.clear()
self.wlanconfig_management.configurations.clear() self.wlanconfig_management.configurations.clear()
@ -203,14 +180,14 @@ class CoreClient:
for node in session.nodes: for node in session.nodes:
if node.type == core_pb2.NodeType.WIRELESS_LAN: if node.type == core_pb2.NodeType.WIRELESS_LAN:
response = self.client.get_wlan_config(self.session_id, node.id) 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 node_config = response.config
config = {x: node_config[x].value for x in node_config} config = {x: node_config[x].value for x in node_config}
self.wlanconfig_management.configurations[node.id] = config self.wlanconfig_management.configurations[node.id] = config
# get mobility configs # get mobility configs
response = self.client.get_mobility_configs(self.session_id) 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: for node_id in response.configs:
node_config = response.configs[node_id].config node_config = response.configs[node_id].config
config = {x: node_config[x].value for x in node_config} config = {x: node_config[x].value for x in node_config}
@ -218,7 +195,7 @@ class CoreClient:
# get emane config # get emane config
response = self.client.get_emane_config(self.session_id) 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 self.emane_config = response.config
# get emane model config # get emane model config
@ -339,7 +316,7 @@ class CoreClient:
logging.info("delete links %s", response) logging.info("delete links %s", response)
def start_session(self): 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() links = self.get_links_proto()
wlan_configs = self.get_wlan_configs_proto() wlan_configs = self.get_wlan_configs_proto()
mobility_configs = self.get_mobility_configs_proto() mobility_configs = self.get_mobility_configs_proto()
@ -411,7 +388,7 @@ class CoreClient:
logging.debug("set node service %s", response) logging.debug("set node service %s", response)
def create_nodes_and_links(self): 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() link_protos = self.get_links_proto()
self.client.set_session_state(self.session_id, core_pb2.SessionState.DEFINITION) self.client.set_session_state(self.session_id, core_pb2.SessionState.DEFINITION)
for node_proto in node_protos: for node_proto in node_protos:
@ -437,17 +414,6 @@ class CoreClient:
logging.debug("Close grpc") logging.debug("Close grpc")
self.client.close() 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): def get_id(self):
""" """
Get the next node id as well as update id status and reusable ids 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): def is_model_node(self, name):
return name in DEFAULT_NODES or name in self.custom_nodes 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 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 x: x coord
:param int y: y 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 :return: nothing
""" """
node_type = None node_id = self.get_id()
node_model = None position = core_pb2.Position(x=x, y=y)
if name in NETWORK_NODES: node = core_pb2.Node(
if name == "switch": id=node_id,
node_type = core_pb2.NodeType.SWITCH type=node_type,
elif name == "hub": name=f"n{node_id}",
node_type = core_pb2.NodeType.HUB model=model,
elif name == "wlan": position=position,
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)
# set default configuration for wireless node # set default configuration for wireless node
self.wlanconfig_management.set_default_config(node_type, nid) self.wlanconfig_management.set_default_config(node_type, node_id)
self.mobilityconfig_management.set_default_configuration(node_type, nid) self.mobilityconfig_management.set_default_configuration(node_type, node_id)
# set default emane configuration for emane node # set default emane configuration for emane node
if node_type == core_pb2.NodeType.EMANE: 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 # set default service configurations
if node_type == core_pb2.NodeType.DEFAULT: if node_type == core_pb2.NodeType.DEFAULT:
self.serviceconfig_manager.node_default_services_configuration( 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( logging.debug(
"Adding node to core.. session id: %s, coords: (%s, %s), name: %s", "adding node to core session: %s, coords: (%s, %s), name: %s",
session_id, self.session_id,
x, x,
y, 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 remove the nodes selected by the user and anything related to that node
such as link, configurations, interfaces 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 :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 # delete the nodes
for i in canvas_ids: for node_id in node_ids:
try: try:
n = self.nodes.pop(i) del self.canvas_nodes[node_id]
self.reusable.append(n.node_id) self.reusable.append(node_id)
except KeyError: except KeyError:
logging.error("coreclient.py INVALID NODE CANVAS ID") logging.error("invalid canvas id: %s", node_id)
self.reusable.sort() self.reusable.sort()
# delete the edges and interfaces # delete the edges and interfaces
for i in tokens: node_interface_pairs = []
for i in edge_tokens:
try: try:
e = self.edges.pop(i) e = self.edges.pop(i)
if e.interface_1 is not None: if e.interface_1 is not None:
node_interface_pairs.append(tuple([e.id1, e.interface_1.id])) node_interface_pairs.append(tuple([e.id1, e.interface_1.id]))
if e.interface_2 is not None: if e.interface_2 is not None:
node_interface_pairs.append(tuple([e.id2, e.interface_2.id])) node_interface_pairs.append(tuple([e.id2, e.interface_2.id]))
except KeyError: except KeyError:
logging.error("coreclient.py invalid edge token ") logging.error("coreclient.py invalid edge token ")
# delete global emane config if there no longer exist any emane cloud # 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 self.emane_config = None
# delete any mobility configuration, wlan configuration # delete any mobility configuration, wlan configuration
for i in core_node_ids: for i in node_ids:
if i in self.mobilityconfig_management.configurations: if i in self.mobilityconfig_management.configurations:
self.mobilityconfig_management.configurations.pop(i) self.mobilityconfig_management.configurations.pop(i)
if i in self.wlanconfig_management.configurations: if i in self.wlanconfig_management.configurations:
@ -574,69 +521,16 @@ class CoreClient:
for i in node_interface_pairs: for i in node_interface_pairs:
if i in self.emaneconfig_management.configurations: if i in self.emaneconfig_management.configurations:
self.emaneconfig_management.configurations.pop(i) 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: if tuple([i, None]) in self.emaneconfig_management.configurations:
self.emaneconfig_management.configurations.pop(tuple([i, None])) 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): def create_interface(self, node_type, gui_interface):
""" """
create a protobuf interface given the interface object stored by the programmer create a protobuf interface given the interface object stored by the programmer
:param core_bp2.NodeType type: node type :param core_bp2.NodeType node_type: node type
:param coretk.interface.Interface gui_interface: the programmer's interface object :param coretk.interface.Interface gui_interface: the programmer's interface
:rtype: core_bp2.Interface :rtype: core_bp2.Interface
:return: protobuf interface object :return: protobuf interface object
""" """
@ -653,120 +547,71 @@ class CoreClient:
logging.debug("create interface: %s", interface) logging.debug("create interface: %s", interface)
return interface return interface
def create_edge_interface(self, edge, src_canvas_id, dst_canvas_id): def create_edge_interface(self, canvas_node):
""" interface = None
Create the interface for the two end of an edge, add a copy to node's interfaces core_node = canvas_node.core_node
if self.is_model_node(core_node.model):
:param coretk.coreclient.Edge edge: edge to add interfaces to ifid = len(canvas_node.interfaces)
:param int src_canvas_id: canvas id for the source node name = f"eth{ifid}"
:param int dst_canvas_id: canvas id for the destination node interface = Interface(
: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(
name=name, ifid=ifid, ipv4=str(self.interfaces_manager.get_address()) 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( logging.debug(
"Create source interface 1... IP: %s, name: %s", "create node(%s) interface IP: %s, name: %s",
src_interface.ipv4, core_node.name,
src_interface.name, interface.ipv4,
interface.name,
) )
return interface
dst_node = self.nodes[dst_canvas_id] def create_edge(self, token, canvas_node_one, canvas_node_two):
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):
""" """
Add an edge to grpc manager 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 tuple(int, int) token: edge's identification in the canvas
:param int canvas_id_1: canvas id of source node :param canvas_node_one: canvas node one
:param int canvas_id_2: canvas_id of destination node :param canvas_node_two: canvas node two
:return: nothing :return: nothing
""" """
node_one = self.nodes[canvas_id_1] node_one = canvas_node_one.core_node
node_two = self.nodes[canvas_id_2] node_two = canvas_node_two.core_node
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
# provide a way to get an edge from a core node and an interface id # create interfaces
if src_interface is not None: self.interfaces_manager.new_subnet()
self.core_mapping.map_node_and_interface_to_canvas_edge( interface_one = self.create_edge_interface(canvas_node_one)
node_one_id, src_interface.id, token 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: edge = Edge(
self.core_mapping.map_node_and_interface_to_canvas_edge( self.session_id, node_one.id, node_one.type, node_two.id, node_two.type
node_two_id, dst_interface.id, token )
) edge.interface_1 = interface_one
edge.interface_2 = interface_two
if ( self.edges[token] = edge
node_one.type == core_pb2.NodeType.EMANE return edge
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
def get_links_proto(self): def get_links_proto(self):
links = [] links = []

View file

@ -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

View file

@ -21,7 +21,7 @@ class NodeConfigDialog(Dialog):
self.image = canvas_node.image self.image = canvas_node.image
self.image_button = None self.image_button = None
self.name = tk.StringVar(value=canvas_node.name) 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.server = tk.StringVar()
self.draw() self.draw()

View file

@ -39,7 +39,8 @@ class CanvasGraph(tk.Canvas):
super().__init__(master, cnf, **kwargs) super().__init__(master, cnf, **kwargs)
self.mode = GraphMode.SELECT self.mode = GraphMode.SELECT
self.draw_node_image = None self.draw_node_image = None
self.draw_node_name = None self.draw_node_type = None
self.draw_node_model = None
self.selected = None self.selected = None
self.node_context = None self.node_context = None
self.nodes = {} self.nodes = {}
@ -97,13 +98,14 @@ class CanvasGraph(tk.Canvas):
# set the private variables to default value # set the private variables to default value
self.mode = GraphMode.SELECT self.mode = GraphMode.SELECT
self.draw_node_image = None self.draw_node_image = None
self.draw_node_name = None self.draw_node_type = None
self.draw_node_model = None
self.selected = None self.selected = None
self.node_context = None self.node_context = None
self.nodes.clear() self.nodes.clear()
self.edges.clear() self.edges.clear()
self.drawing_edge = None self.drawing_edge = None
self.draw_existing_component(session) self.draw_session(session)
def setup_bindings(self): def setup_bindings(self):
""" """
@ -143,61 +145,46 @@ class CanvasGraph(tk.Canvas):
self.tag_lower("gridline") self.tag_lower("gridline")
self.tag_lower(self.grid) 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 :return: nothing
""" """
core_id_to_canvas_id = {} # draw existing nodes
# redraw existing nodes for core_node in session.nodes:
for node in session.nodes:
# peer to peer node is not drawn on the GUI # peer to peer node is not drawn on the GUI
if node.type != core_pb2.NodeType.PEER_TO_PEER: if core_node.type == core_pb2.NodeType.PEER_TO_PEER:
# draw nodes on the canvas continue
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
# store the node in grpc manager # draw nodes on the canvas
self.core.add_preexisting_node(n, session.id, node, name) 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 # draw existing links
for link in session.links: for link in session.links:
n1 = self.nodes[core_id_to_canvas_id[link.node_one_id]] canvas_node_one = self.core.canvas_nodes[link.node_one_id]
n2 = self.nodes[core_id_to_canvas_id[link.node_two_id]] canvas_node_two = self.core.canvas_nodes[link.node_two_id]
if link.type == core_pb2.LinkType.WIRED: is_wired = link.type == core_pb2.LinkType.WIRED
e = CanvasEdge( edge = CanvasEdge(
n1.x_coord, canvas_node_one.x_coord,
n1.y_coord, canvas_node_one.y_coord,
n2.x_coord, canvas_node_two.x_coord,
n2.y_coord, canvas_node_two.y_coord,
n1.id, canvas_node_one.id,
self, self,
is_wired=True, is_wired=is_wired,
) )
elif link.type == core_pb2.LinkType.WIRELESS: edge.token = tuple(sorted((canvas_node_one.id, canvas_node_two.id)))
e = CanvasEdge( edge.dst = canvas_node_two.id
n1.x_coord, canvas_node_one.edges.add(edge)
n1.y_coord, canvas_node_two.edges.add(edge)
n2.x_coord, self.edges[edge.token] = edge
n2.y_coord, self.core.create_edge(edge.token, canvas_node_one, canvas_node_two)
n1.id, self.helper.redraw_antenna(link, canvas_node_one, canvas_node_two)
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)
# TODO add back the link info to grpc manager also redraw # TODO add back the link info to grpc manager also redraw
grpc_if1 = link.interface_one grpc_if1 = link.interface_one
@ -212,9 +199,9 @@ class CanvasGraph(tk.Canvas):
if grpc_if2 is not None: if grpc_if2 is not None:
ip4_dst = grpc_if2.ip4 ip4_dst = grpc_if2.ip4
ip6_dst = grpc_if2.ip6 ip6_dst = grpc_if2.ip6
e.link_info = LinkInfo( edge.link_info = LinkInfo(
canvas=self, canvas=self,
edge=e, edge=edge,
ip4_src=ip4_src, ip4_src=ip4_src,
ip6_src=ip6_src, ip6_src=ip6_src,
ip4_dst=ip4_dst, ip4_dst=ip4_dst,
@ -224,14 +211,10 @@ class CanvasGraph(tk.Canvas):
# TODO will include throughput and ipv6 in the future # TODO will include throughput and ipv6 in the future
if1 = Interface(grpc_if1.name, grpc_if1.ip4, ifid=grpc_if1.id) if1 = Interface(grpc_if1.name, grpc_if1.ip4, ifid=grpc_if1.id)
if2 = Interface(grpc_if2.name, grpc_if2.ip4, ifid=grpc_if2.id) if2 = Interface(grpc_if2.name, grpc_if2.ip4, ifid=grpc_if2.id)
self.core.edges[e.token].interface_1 = if1 self.core.edges[edge.token].interface_1 = if1
self.core.edges[e.token].interface_2 = if2 self.core.edges[edge.token].interface_2 = if2
self.core.nodes[core_id_to_canvas_id[link.node_one_id]].interfaces.append( canvas_node_one.interfaces.append(if1)
if1 canvas_node_two.interfaces.append(if2)
)
self.core.nodes[core_id_to_canvas_id[link.node_two_id]].interfaces.append(
if2
)
# raise the nodes so they on top of the links # raise the nodes so they on top of the links
self.tag_raise("node") self.tag_raise("node")
@ -290,7 +273,13 @@ class CanvasGraph(tk.Canvas):
self.handle_edge_release(event) self.handle_edge_release(event)
elif self.mode == GraphMode.NODE: elif self.mode == GraphMode.NODE:
x, y = self.canvas_xy(event) 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: elif self.mode == GraphMode.PICKNODE:
self.mode = GraphMode.NODE self.mode = GraphMode.NODE
@ -313,6 +302,7 @@ class CanvasGraph(tk.Canvas):
# edge dst is same as src, delete edge # edge dst is same as src, delete edge
if edge.src == self.selected: if edge.src == self.selected:
edge.delete() edge.delete()
return
# set dst node and snap edge to center # set dst node and snap edge to center
x, y = self.coords(self.selected) x, y = self.coords(self.selected)
@ -326,14 +316,11 @@ class CanvasGraph(tk.Canvas):
node_src.edges.add(edge) node_src.edges.add(edge)
node_dst = self.nodes[edge.dst] node_dst = self.nodes[edge.dst]
node_dst.edges.add(edge) node_dst.edges.add(edge)
core_edge = self.core.create_edge(edge.token, node_src, node_dst)
self.core.add_edge(
self.core.session_id, edge.token, node_src.id, node_dst.id
)
# draw link info on the edge # draw link info on the edge
if1 = self.core.edges[edge.token].interface_1 if1 = core_edge.interface_1
if2 = self.core.edges[edge.token].interface_2 if2 = core_edge.interface_2
ip4_and_prefix_1 = None ip4_and_prefix_1 = None
ip4_and_prefix_2 = None ip4_and_prefix_2 = None
if if1 is not None: if if1 is not None:
@ -404,8 +391,10 @@ class CanvasGraph(tk.Canvas):
) )
# delete nodes and link info stored in CanvasGraph object # delete nodes and link info stored in CanvasGraph object
node_ids = []
for nid in to_delete_nodes: 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: for token in to_delete_edge_tokens:
self.edges.pop(token) self.edges.pop(token)
@ -419,15 +408,16 @@ class CanvasGraph(tk.Canvas):
self.nodes[nid].edges.remove(edge) self.nodes[nid].edges.remove(edge)
# delete the related data from core # 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] plot_id = self.find_all()[0]
logging.info("add node event: %s - %s", plot_id, self.selected) logging.info("add node event: %s - %s", plot_id, self.selected)
if self.selected == plot_id: 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.nodes[node.id] = node
self.core.add_graph_node(self.core.session_id, node.id, x, y, node_name)
return node return node
def width_and_height(self): def width_and_height(self):
@ -494,7 +484,6 @@ class CanvasGraph(tk.Canvas):
""" """
scale image based on canvas dimension scale image based on canvas dimension
:param Image img: image object
:return: nothing :return: nothing
""" """
canvas_w, canvas_h = self.width_and_height() canvas_w, canvas_h = self.width_and_height()
@ -614,18 +603,17 @@ class CanvasEdge:
class CanvasNode: 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.image = image
self.node_type = node_type
self.app = app self.app = app
self.canvas = app.canvas self.canvas = app.canvas
self.id = self.canvas.create_image( self.id = self.canvas.create_image(
x, y, anchor=tk.CENTER, image=self.image, tags="node" 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.x_coord = x
self.y_coord = y self.y_coord = y
self.name = f"N{self.core_id}"
self.text_id = self.canvas.create_text( self.text_id = self.canvas.create_text(
x, y + 20, text=self.name, tags="nodename" x, y + 20, text=self.name, tags="nodename"
) )
@ -641,6 +629,7 @@ class CanvasNode:
self.canvas.tag_bind(self.id, "<Leave>", self.on_leave) self.canvas.tag_bind(self.id, "<Leave>", self.on_leave)
self.edges = set() self.edges = set()
self.interfaces = []
self.wlans = [] self.wlans = []
self.moving = None self.moving = None
@ -648,7 +637,7 @@ class CanvasNode:
if self.app.core.is_runtime() and self.app.core.observer: if self.app.core.is_runtime() and self.app.core.observer:
self.tooltip.text.set("waiting...") self.tooltip.text.set("waiting...")
self.tooltip.on_enter(event) 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) self.tooltip.text.set(output)
def on_leave(self, event): def on_leave(self, event):
@ -658,15 +647,15 @@ class CanvasNode:
print("click") print("click")
def double_click(self, event): def double_click(self, event):
node_id = self.canvas.core.nodes[self.id].node_id if self.app.core.is_runtime():
state = self.canvas.core.get_session_state() self.canvas.core.launch_terminal(self.core_node.id)
if state == core_pb2.SessionState.RUNTIME:
self.canvas.core.launch_terminal(node_id)
else: else:
self.canvas.canvas_action.display_configuration(self) self.canvas.canvas_action.display_configuration(self)
def update_coords(self): def update_coords(self):
self.x_coord, self.y_coord = self.canvas.coords(self.id) 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): def click_press(self, event):
logging.debug(f"node click press {self.name}: {event}") logging.debug(f"node click press {self.name}: {event}")
@ -677,7 +666,6 @@ class CanvasNode:
def click_release(self, event): def click_release(self, event):
logging.debug(f"node click release {self.name}: {event}") logging.debug(f"node click release {self.name}: {event}")
self.update_coords() self.update_coords()
self.canvas.core.update_node_location(self.id, self.x_coord, self.y_coord)
self.moving = None self.moving = None
def motion(self, event): def motion(self, event):
@ -697,7 +685,7 @@ class CanvasNode:
new_x, new_y = self.canvas.coords(self.id) new_x, new_y = self.canvas.coords(self.id)
if self.canvas.core.get_session_state() == core_pb2.SessionState.RUNTIME: 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: for edge in self.edges:
x1, y1, x2, y2 = self.canvas.coords(edge.id) x1, y1, x2, y2 = self.canvas.coords(edge.id)

View file

@ -29,29 +29,31 @@ class GraphHelper:
self.canvas.delete(i) self.canvas.delete(i)
def draw_wireless_case(self, src_id, dst_id, edge): def draw_wireless_case(self, src_id, dst_id, edge):
src_node_name = self.canvas.nodes[src_id].node_type src_node_type = self.canvas.nodes[src_id].core_node.type
dst_node_name = self.canvas.nodes[dst_id].node_type dst_node_type = self.canvas.nodes[dst_id].core_node.type
is_src_wlan = src_node_type == core_pb2.NodeType.WIRELESS_LAN
if src_node_name == "wlan" or dst_node_name == "wlan": 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) self.canvas.itemconfig(edge.id, state=tk.HIDDEN)
edge.wired = False edge.wired = False
if edge.token not in self.canvas.edges: 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() 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() self.canvas.nodes[dst_id].antenna_draw.add_antenna()
else: else:
self.canvas.nodes[src_id].antenna_draw.add_antenna() self.canvas.nodes[src_id].antenna_draw.add_antenna()
edge.wired = True edge.wired = True
def redraw_antenna(self, link, node_one, node_two): 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 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() 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() 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() node_one.antenna_draw.add_antenna()
else: else:
logging.error( logging.error(
@ -122,91 +124,3 @@ class WlanAntennaManager:
""" """
for i in self.antennas: for i in self.antennas:
self.canvas.delete(i) 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)

View file

@ -31,7 +31,7 @@ class Images:
return cls.create(file_path, width, height) return cls.create(file_path, width, height)
@classmethod @classmethod
def get_custom(cls, name, width, height): def get_custom(cls, name, width, height=None):
file_path = cls.images[name] file_path = cls.images[name]
return cls.create(file_path, width, height) return cls.create(file_path, width, height)
@ -41,52 +41,38 @@ class Images:
Retrieve image based on type and model Retrieve image based on type and model
:param core_pb2.NodeType node_type: core node type :param core_pb2.NodeType node_type: core node type
:param string node_model: the node model :param string node_model: the node model
:return: core node icon
:rtype: tuple(PhotoImage, str) :rtype: PhotoImage
:return: the matching image and its name
""" """
image_enum = ImageEnum.ROUTER image_enum = ImageEnum.ROUTER
name = "unknown"
if node_type == core_pb2.NodeType.SWITCH: if node_type == core_pb2.NodeType.SWITCH:
image_enum = ImageEnum.SWITCH image_enum = ImageEnum.SWITCH
name = "switch"
elif node_type == core_pb2.NodeType.HUB: elif node_type == core_pb2.NodeType.HUB:
image_enum = ImageEnum.HUB image_enum = ImageEnum.HUB
name = "hub"
elif node_type == core_pb2.NodeType.WIRELESS_LAN: elif node_type == core_pb2.NodeType.WIRELESS_LAN:
image_enum = ImageEnum.WLAN image_enum = ImageEnum.WLAN
name = "wlan"
elif node_type == core_pb2.NodeType.EMANE: elif node_type == core_pb2.NodeType.EMANE:
image_enum = ImageEnum.EMANE image_enum = ImageEnum.EMANE
name = "emane"
elif node_type == core_pb2.NodeType.RJ45: elif node_type == core_pb2.NodeType.RJ45:
image_enum = ImageEnum.RJ45 image_enum = ImageEnum.RJ45
name = "rj45"
elif node_type == core_pb2.NodeType.TUNNEL: elif node_type == core_pb2.NodeType.TUNNEL:
image_enum = ImageEnum.TUNNEL image_enum = ImageEnum.TUNNEL
name = "tunnel"
elif node_type == core_pb2.NodeType.DEFAULT: elif node_type == core_pb2.NodeType.DEFAULT:
if node_model == "router": if node_model == "router":
image_enum = ImageEnum.ROUTER image_enum = ImageEnum.ROUTER
name = "router"
elif node_model == "host": elif node_model == "host":
image_enum = ImageEnum.HOST image_enum = ImageEnum.HOST
name = "host"
elif node_model == "PC": elif node_model == "PC":
image_enum = ImageEnum.PC image_enum = ImageEnum.PC
name = "PC"
elif node_model == "mdr": elif node_model == "mdr":
image_enum = ImageEnum.MDR image_enum = ImageEnum.MDR
name = "mdr"
elif node_model == "prouter": elif node_model == "prouter":
image_enum = ImageEnum.PROUTER image_enum = ImageEnum.PROUTER
name = "prouter"
else: else:
logging.error("invalid node model: %s", node_model) logging.error("invalid node model: %s", node_model)
else: else:
logging.error("invalid node type: %s", node_type) logging.error("invalid node type: %s", node_type)
return Images.get(image_enum, NODE_WIDTH)
return Images.get(image_enum, NODE_WIDTH), name
class ImageEnum(Enum): class ImageEnum(Enum):

View file

@ -129,8 +129,7 @@ class Throughput:
nid = t.node_id nid = t.node_id
iid = t.interface_id iid = t.interface_id
tp = t.throughput tp = t.throughput
# token = self.grpc_manager.node_id_and_interface_to_edge_token[nid, iid] token = self.core.interface_to_edge[(nid, iid)]
token = self.core.core_mapping.get_token_from_node_and_interface(nid, iid)
print(token) print(token)
edge_id = self.canvas.edges[token].id edge_id = self.canvas.edges[token].id

View file

@ -3,6 +3,7 @@ import tkinter as tk
from functools import partial from functools import partial
from tkinter import ttk from tkinter import ttk
from core.api.grpc import core_pb2
from coretk.dialogs.customnodes import CustomNodesDialog from coretk.dialogs.customnodes import CustomNodesDialog
from coretk.graph import GraphMode from coretk.graph import GraphMode
from coretk.images import ImageEnum, Images from coretk.images import ImageEnum, Images
@ -136,10 +137,16 @@ class Toolbar(ttk.Frame):
(ImageEnum.PROUTER, "prouter"), (ImageEnum.PROUTER, "prouter"),
] ]
# draw default nodes # draw default nodes
for image_enum, tooltip in nodes: for image_enum, model in nodes:
image = icon(image_enum) image = icon(image_enum)
func = partial(self.update_button, self.node_button, image, tooltip) func = partial(
self.create_picker_button(image, func, self.node_picker, tooltip) 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 # draw custom nodes
for name in sorted(self.app.core.custom_nodes): for name in sorted(self.app.core.custom_nodes):
custom_node = self.app.core.custom_nodes[name] custom_node = self.app.core.custom_nodes[name]
@ -216,14 +223,15 @@ class Toolbar(ttk.Frame):
dialog = CustomNodesDialog(self.app, self.app) dialog = CustomNodesDialog(self.app, self.app)
dialog.show() dialog.show()
def update_button(self, button, image, name): def update_button(self, button, image, node_type, model=None):
logging.info("update button(%s): %s", button, name) logging.info("update button(%s): %s", button, node_type)
self.hide_pickers() self.hide_pickers()
button.configure(image=image) button.configure(image=image)
button.image = image button.image = image
self.app.canvas.mode = GraphMode.NODE self.app.canvas.mode = GraphMode.NODE
self.app.canvas.draw_node_image = image 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): def hide_pickers(self):
logging.info("hiding pickers") logging.info("hiding pickers")
@ -260,18 +268,18 @@ class Toolbar(ttk.Frame):
self.hide_pickers() self.hide_pickers()
self.network_picker = ttk.Frame(self.master) self.network_picker = ttk.Frame(self.master)
nodes = [ nodes = [
(ImageEnum.HUB, "hub", "ethernet hub"), (ImageEnum.HUB, core_pb2.NodeType.HUB, "ethernet hub"),
(ImageEnum.SWITCH, "switch", "ethernet switch"), (ImageEnum.SWITCH, core_pb2.NodeType.SWITCH, "ethernet switch"),
(ImageEnum.WLAN, "wlan", "wireless LAN"), (ImageEnum.WLAN, core_pb2.NodeType.WIRELESS_LAN, "wireless LAN"),
(ImageEnum.EMANE, "emane", "EMANE"), (ImageEnum.EMANE, core_pb2.NodeType.EMANE, "EMANE"),
(ImageEnum.RJ45, "rj45", "rj45 physical interface tool"), (ImageEnum.RJ45, core_pb2.NodeType.RJ45, "rj45 physical interface tool"),
(ImageEnum.TUNNEL, "tunnel", "tunnel 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) image = icon(image_enum)
self.create_picker_button( self.create_picker_button(
image, image,
partial(self.update_button, self.network_button, image, name), partial(self.update_button, self.network_button, image, node_type),
self.network_picker, self.network_picker,
tooltip, tooltip,
) )

View file

@ -7,35 +7,31 @@ from core.api.grpc import core_pb2
class WirelessConnection: class WirelessConnection:
def __init__(self, canvas, core): def __init__(self, canvas, core):
self.canvas = canvas 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 # map a (node_one_id, node_two_id) to a wlan canvas id
self.map = {} self.map = {}
def add_wlan_connection(self, node_one_id, node_two_id): 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_node_one = self.core.canvas_nodes[node_one_id]
canvas_id_two = self.core_mapping.get_canvas_id_from_core_id(node_two_id) canvas_node_two = self.core.canvas_nodes[node_two_id]
key = tuple(sorted((node_one_id, node_two_id))) key = tuple(sorted((node_one_id, node_two_id)))
if key not in self.map: if key not in self.map:
x1, y1 = self.canvas.coords(canvas_id_one) x1, y1 = self.canvas.coords(canvas_node_one.id)
x2, y2 = self.canvas.coords(canvas_id_two) x2, y2 = self.canvas.coords(canvas_node_two.id)
wlan_canvas_id = self.canvas.create_line( wlan_canvas_id = self.canvas.create_line(
x1, y1, x2, y2, fill="#009933", tags="wlan", width=1.5 x1, y1, x2, y2, fill="#009933", tags="wlan", width=1.5
) )
self.map[key] = wlan_canvas_id self.map[key] = wlan_canvas_id
self.canvas.nodes[canvas_id_one].wlans.append(wlan_canvas_id) canvas_node_one.wlans.append(wlan_canvas_id)
self.canvas.nodes[canvas_id_two].wlans.append(wlan_canvas_id) canvas_node_two.wlans.append(wlan_canvas_id)
def delete_wlan_connection(self, node_one_id, node_two_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_node_one = self.core.canvas_nodes[node_one_id]
canvas_id_two = self.core_mapping.get_canvas_id_from_core_id(node_two_id) canvas_node_two = self.core.canvas_nodes[node_two_id]
key = tuple(sorted((node_one_id, node_two_id))) key = tuple(sorted((node_one_id, node_two_id)))
wlan_canvas_id = self.map[key] wlan_canvas_id = self.map[key]
canvas_node_one.wlans.remove(wlan_canvas_id)
self.canvas.nodes[canvas_id_one].wlans.remove(wlan_canvas_id) canvas_node_two.wlans.remove(wlan_canvas_id)
self.canvas.nodes[canvas_id_two].wlans.remove(wlan_canvas_id)
self.canvas.delete(wlan_canvas_id) self.canvas.delete(wlan_canvas_id)
self.map.pop(key, None) self.map.pop(key, None)