Merge pull request #374 from coreemu/coretk-enhance/wlanlink-runtime-deletion
Coretk enhance/wlanlink runtime deletion
This commit is contained in:
commit
8b544d98d8
5 changed files with 115 additions and 6 deletions
|
@ -1,7 +1,3 @@
|
||||||
"""
|
|
||||||
wlan configuration
|
|
||||||
"""
|
|
||||||
|
|
||||||
from tkinter import ttk
|
from tkinter import ttk
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
@ -16,6 +12,9 @@ if TYPE_CHECKING:
|
||||||
from core.gui.app import Application
|
from core.gui.app import Application
|
||||||
from core.gui.graph.node import CanvasNode
|
from core.gui.graph.node import CanvasNode
|
||||||
|
|
||||||
|
RANGE_COLOR = "#009933"
|
||||||
|
RANGE_WIDTH = 3
|
||||||
|
|
||||||
|
|
||||||
class WlanConfigDialog(Dialog):
|
class WlanConfigDialog(Dialog):
|
||||||
def __init__(
|
def __init__(
|
||||||
|
@ -27,15 +26,29 @@ class WlanConfigDialog(Dialog):
|
||||||
self.canvas_node = canvas_node
|
self.canvas_node = canvas_node
|
||||||
self.node = canvas_node.core_node
|
self.node = canvas_node.core_node
|
||||||
self.config_frame = None
|
self.config_frame = None
|
||||||
|
self.range_entry = None
|
||||||
self.has_error = False
|
self.has_error = False
|
||||||
|
self.canvas = app.canvas
|
||||||
|
self.ranges = {}
|
||||||
|
self.positive_int = self.app.master.register(self.validate_and_update)
|
||||||
try:
|
try:
|
||||||
self.config = self.app.core.get_wlan_config(self.node.id)
|
self.config = self.app.core.get_wlan_config(self.node.id)
|
||||||
|
self.init_draw_range()
|
||||||
self.draw()
|
self.draw()
|
||||||
except grpc.RpcError as e:
|
except grpc.RpcError as e:
|
||||||
show_grpc_error(e, self.app, self.app)
|
show_grpc_error(e, self.app, self.app)
|
||||||
self.has_error = True
|
self.has_error = True
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
|
def init_draw_range(self):
|
||||||
|
if self.canvas_node.id in self.canvas.wireless_network:
|
||||||
|
for cid in self.canvas.wireless_network[self.canvas_node.id]:
|
||||||
|
x, y = self.canvas.coords(cid)
|
||||||
|
range_id = self.canvas.create_oval(
|
||||||
|
x, y, x, y, width=RANGE_WIDTH, outline=RANGE_COLOR, tags="range"
|
||||||
|
)
|
||||||
|
self.ranges[cid] = range_id
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
self.top.columnconfigure(0, weight=1)
|
self.top.columnconfigure(0, weight=1)
|
||||||
self.top.rowconfigure(0, weight=1)
|
self.top.rowconfigure(0, weight=1)
|
||||||
|
@ -43,6 +56,7 @@ class WlanConfigDialog(Dialog):
|
||||||
self.config_frame.draw_config()
|
self.config_frame.draw_config()
|
||||||
self.config_frame.grid(sticky="nsew", pady=PADY)
|
self.config_frame.grid(sticky="nsew", pady=PADY)
|
||||||
self.draw_apply_buttons()
|
self.draw_apply_buttons()
|
||||||
|
self.top.bind("<Destroy>", self.remove_ranges)
|
||||||
|
|
||||||
def draw_apply_buttons(self):
|
def draw_apply_buttons(self):
|
||||||
"""
|
"""
|
||||||
|
@ -53,6 +67,11 @@ class WlanConfigDialog(Dialog):
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
frame.columnconfigure(i, weight=1)
|
frame.columnconfigure(i, weight=1)
|
||||||
|
|
||||||
|
self.range_entry = self.config_frame.winfo_children()[0].frame.winfo_children()[
|
||||||
|
-1
|
||||||
|
]
|
||||||
|
self.range_entry.config(validatecommand=(self.positive_int, "%P"))
|
||||||
|
|
||||||
button = ttk.Button(frame, text="Apply", command=self.click_apply)
|
button = ttk.Button(frame, text="Apply", command=self.click_apply)
|
||||||
button.grid(row=0, column=0, padx=PADX, sticky="ew")
|
button.grid(row=0, column=0, padx=PADX, sticky="ew")
|
||||||
|
|
||||||
|
@ -68,4 +87,35 @@ class WlanConfigDialog(Dialog):
|
||||||
if self.app.core.is_runtime():
|
if self.app.core.is_runtime():
|
||||||
session_id = self.app.core.session_id
|
session_id = self.app.core.session_id
|
||||||
self.app.core.client.set_wlan_config(session_id, self.node.id, config)
|
self.app.core.client.set_wlan_config(session_id, self.node.id, config)
|
||||||
|
self.remove_ranges()
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
|
def remove_ranges(self, event=None):
|
||||||
|
for cid in self.canvas.find_withtag("range"):
|
||||||
|
self.canvas.delete(cid)
|
||||||
|
self.ranges.clear()
|
||||||
|
|
||||||
|
def validate_and_update(self, s: str) -> bool:
|
||||||
|
"""
|
||||||
|
custom validation to also redraw the mdr ranges when the range value changes
|
||||||
|
"""
|
||||||
|
if len(s) == 0:
|
||||||
|
return True
|
||||||
|
try:
|
||||||
|
int_value = int(s)
|
||||||
|
if int_value >= 0:
|
||||||
|
net_range = int_value * self.canvas.ratio
|
||||||
|
if self.canvas_node.id in self.canvas.wireless_network:
|
||||||
|
for cid in self.canvas.wireless_network[self.canvas_node.id]:
|
||||||
|
x, y = self.canvas.coords(cid)
|
||||||
|
self.canvas.coords(
|
||||||
|
self.ranges[cid],
|
||||||
|
x - net_range,
|
||||||
|
y - net_range,
|
||||||
|
x + net_range,
|
||||||
|
y + net_range,
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
|
|
@ -186,6 +186,17 @@ class CanvasEdge:
|
||||||
dst_node_type = dst_node.core_node.type
|
dst_node_type = dst_node.core_node.type
|
||||||
is_src_wireless = NodeUtils.is_wireless_node(src_node_type)
|
is_src_wireless = NodeUtils.is_wireless_node(src_node_type)
|
||||||
is_dst_wireless = NodeUtils.is_wireless_node(dst_node_type)
|
is_dst_wireless = NodeUtils.is_wireless_node(dst_node_type)
|
||||||
|
|
||||||
|
# update the wlan/EMANE network
|
||||||
|
wlan_network = self.canvas.wireless_network
|
||||||
|
if is_src_wireless and not is_dst_wireless:
|
||||||
|
if self.src not in wlan_network:
|
||||||
|
wlan_network[self.src] = set()
|
||||||
|
wlan_network[self.src].add(self.dst)
|
||||||
|
elif not is_src_wireless and is_dst_wireless:
|
||||||
|
if self.dst not in wlan_network:
|
||||||
|
wlan_network[self.dst] = set()
|
||||||
|
wlan_network[self.dst].add(self.src)
|
||||||
return is_src_wireless or is_dst_wireless
|
return is_src_wireless or is_dst_wireless
|
||||||
|
|
||||||
def check_wireless(self):
|
def check_wireless(self):
|
||||||
|
|
|
@ -42,6 +42,10 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.edges = {}
|
self.edges = {}
|
||||||
self.shapes = {}
|
self.shapes = {}
|
||||||
self.wireless_edges = {}
|
self.wireless_edges = {}
|
||||||
|
|
||||||
|
# map wireless/EMANE node to the set of MDRs connected to that node
|
||||||
|
self.wireless_network = {}
|
||||||
|
|
||||||
self.drawing_edge = None
|
self.drawing_edge = None
|
||||||
self.grid = None
|
self.grid = None
|
||||||
self.shape_drawing = False
|
self.shape_drawing = False
|
||||||
|
@ -113,6 +117,7 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.edges.clear()
|
self.edges.clear()
|
||||||
self.shapes.clear()
|
self.shapes.clear()
|
||||||
self.wireless_edges.clear()
|
self.wireless_edges.clear()
|
||||||
|
self.wireless_network.clear()
|
||||||
self.drawing_edge = None
|
self.drawing_edge = None
|
||||||
self.draw_session(session)
|
self.draw_session(session)
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ from core.gui.errors import show_grpc_error
|
||||||
from core.gui.graph import tags
|
from core.gui.graph import tags
|
||||||
from core.gui.graph.tooltip import CanvasTooltip
|
from core.gui.graph.tooltip import CanvasTooltip
|
||||||
from core.gui.images import ImageEnum, Images
|
from core.gui.images import ImageEnum, Images
|
||||||
from core.gui.nodeutils import ANTENNA_SIZE, NodeUtils
|
from core.gui.nodeutils import ANTENNA_SIZE, EdgeUtils, NodeUtils
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.gui.app import Application
|
from core.gui.app import Application
|
||||||
|
@ -66,9 +66,48 @@ class CanvasNode:
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
logging.debug("Delete canvas node for %s", self.core_node)
|
logging.debug("Delete canvas node for %s", self.core_node)
|
||||||
|
|
||||||
|
# if node is wlan, EMANE type, remove any existing wireless links between nodes connetect to this node
|
||||||
|
if NodeUtils.is_wireless_node(self.core_node.type):
|
||||||
|
nodes = []
|
||||||
|
for edge in self.edges:
|
||||||
|
token = edge.token
|
||||||
|
if self.id == token[0]:
|
||||||
|
nodes.append(token[1])
|
||||||
|
else:
|
||||||
|
nodes.append(token[0])
|
||||||
|
for i in range(len(nodes)):
|
||||||
|
for j in range(i + 1, len(nodes)):
|
||||||
|
token = EdgeUtils.get_token(nodes[i], nodes[j])
|
||||||
|
wireless_edge = self.canvas.wireless_edges.pop(token, None)
|
||||||
|
if wireless_edge:
|
||||||
|
|
||||||
|
self.canvas.nodes[nodes[i]].wireless_edges.remove(wireless_edge)
|
||||||
|
self.canvas.nodes[nodes[j]].wireless_edges.remove(wireless_edge)
|
||||||
|
self.canvas.delete(wireless_edge.id)
|
||||||
|
else:
|
||||||
|
logging.debug("%s is not a wireless edge", token)
|
||||||
|
# if node is MDR, remove wireless links to other MDRs
|
||||||
|
elif NodeUtils.is_mdr_node(self.core_node.type, self.core_node.model):
|
||||||
|
for wireless_edge in self.wireless_edges:
|
||||||
|
token = wireless_edge.token
|
||||||
|
other = token[0]
|
||||||
|
if other == self.id:
|
||||||
|
other = token[1]
|
||||||
|
self.canvas.nodes[other].wireless_edges.discard(wireless_edge)
|
||||||
|
try:
|
||||||
|
wlan_edge = self.canvas.wireless_edges.pop(token)
|
||||||
|
self.canvas.delete(wlan_edge.id)
|
||||||
|
except KeyError:
|
||||||
|
logging.error(
|
||||||
|
"wireless link not found, potentially multiple wireless link issue"
|
||||||
|
)
|
||||||
|
self.delete_antennas()
|
||||||
|
|
||||||
|
self.wireless_edges.clear()
|
||||||
|
|
||||||
self.canvas.delete(self.id)
|
self.canvas.delete(self.id)
|
||||||
self.canvas.delete(self.text_id)
|
self.canvas.delete(self.text_id)
|
||||||
self.delete_antennas()
|
|
||||||
|
|
||||||
def add_antenna(self):
|
def add_antenna(self):
|
||||||
x, y = self.canvas.coords(self.id)
|
x, y = self.canvas.coords(self.id)
|
||||||
|
|
|
@ -90,6 +90,10 @@ class NodeUtils:
|
||||||
def is_rj45_node(cls, node_type: NodeType) -> bool:
|
def is_rj45_node(cls, node_type: NodeType) -> bool:
|
||||||
return node_type in cls.RJ45_NODES
|
return node_type in cls.RJ45_NODES
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_mdr_node(cls, node_type: NodeType, model: str) -> bool:
|
||||||
|
return cls.is_container_node(node_type) and model == "mdr"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def node_icon(
|
def node_icon(
|
||||||
cls,
|
cls,
|
||||||
|
|
Loading…
Reference in a new issue