updated so that throughputs will update link color/width based on threshold

This commit is contained in:
Blake Harnden 2019-12-27 00:32:10 -08:00
parent 5dd08c283a
commit 2be0713ed1
7 changed files with 75 additions and 167 deletions

View file

@ -212,9 +212,7 @@ class CoreClient:
) )
return return
logging.info("handling throughputs event: %s", event) logging.info("handling throughputs event: %s", event)
self.app.canvas.throughput_draw.process_grpc_throughput_event( self.app.canvas.set_throughputs(event)
event.interface_throughputs
)
def handle_exception_event(self, event): def handle_exception_event(self, event):
logging.info("exception event: %s", event) logging.info("exception event: %s", event)
@ -511,6 +509,7 @@ class CoreClient:
start = time.perf_counter() start = time.perf_counter()
try: try:
response = self.client.stop_session(session_id) response = self.client.stop_session(session_id)
self.app.canvas.stopped_session()
logging.debug( logging.debug(
"stopped session(%s), result: %s", session_id, response.result "stopped session(%s), result: %s", session_id, response.result
) )

View file

@ -8,6 +8,8 @@ from core.gui.graph import tags
from core.gui.nodeutils import NodeUtils from core.gui.nodeutils import NodeUtils
TEXT_DISTANCE = 0.30 TEXT_DISTANCE = 0.30
EDGE_WIDTH = 3
EDGE_COLOR = "#ff0000"
class CanvasWirelessEdge: class CanvasWirelessEdge:
@ -29,8 +31,6 @@ class CanvasEdge:
Canvas edge class Canvas edge class
""" """
width = 3
def __init__(self, x1, y1, x2, y2, src, canvas): def __init__(self, x1, y1, x2, y2, src, canvas):
""" """
Create an instance of canvas edge object Create an instance of canvas edge object
@ -47,10 +47,11 @@ class CanvasEdge:
self.dst_interface = None self.dst_interface = None
self.canvas = canvas self.canvas = canvas
self.id = self.canvas.create_line( self.id = self.canvas.create_line(
x1, y1, x2, y2, tags=tags.EDGE, width=self.width, fill="#ff0000" x1, y1, x2, y2, tags=tags.EDGE, width=EDGE_WIDTH, fill=EDGE_COLOR
) )
self.text_src = None self.text_src = None
self.text_dst = None self.text_dst = None
self.text_middle = None
self.token = None self.token = None
self.font = Font(size=8) self.font = Font(size=8)
self.link = None self.link = None
@ -77,6 +78,12 @@ class CanvasEdge:
y2 = y2 - uy y2 = y2 - uy
return x1, y1, x2, y2 return x1, y1, x2, y2
def get_midpoint(self):
x1, y1, x2, y2 = self.canvas.coords(self.id)
x = (x1 + x2) / 2
y = (y1 + y2) / 2
return x, y
def draw_labels(self): def draw_labels(self):
x1, y1, x2, y2 = self.get_coordinates() x1, y1, x2, y2 = self.get_coordinates()
label_one = None label_one = None
@ -117,6 +124,28 @@ class CanvasEdge:
x1, y1, x2, y2 = self.get_coordinates() x1, y1, x2, y2 = self.get_coordinates()
self.canvas.coords(self.text_src, x1, y1) self.canvas.coords(self.text_src, x1, y1)
self.canvas.coords(self.text_dst, x2, y2) self.canvas.coords(self.text_dst, x2, y2)
if self.text_middle is not None:
x, y = self.get_midpoint()
self.canvas.coords(self.text_middle, x, y)
def set_throughput(self, throughput):
throughput = 0.001 * throughput
value = f"{throughput:.3f} kbps"
if self.text_middle is None:
x, y = self.get_midpoint()
self.text_middle = self.canvas.create_text(
x, y, tags=tags.THROUGHPUT, font=self.font, text=value
)
else:
self.canvas.itemconfig(self.text_middle, text=value)
if throughput > self.canvas.throughput_threshold:
color = self.canvas.throughput_color
width = self.canvas.throughput_width
else:
color = EDGE_COLOR
width = EDGE_WIDTH
self.canvas.itemconfig(self.id, fill=color, width=width)
def complete(self, dst): def complete(self, dst):
self.dst = dst self.dst = dst
@ -128,14 +157,17 @@ class CanvasEdge:
self.canvas.tag_raise(self.src) self.canvas.tag_raise(self.src)
self.canvas.tag_raise(self.dst) self.canvas.tag_raise(self.dst)
def check_wireless(self): def is_wireless(self):
src_node = self.canvas.nodes[self.src] src_node = self.canvas.nodes[self.src]
dst_node = self.canvas.nodes[self.dst] dst_node = self.canvas.nodes[self.dst]
src_node_type = src_node.core_node.type src_node_type = src_node.core_node.type
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)
if is_src_wireless or is_dst_wireless: return is_src_wireless or is_dst_wireless
def check_wireless(self):
if self.is_wireless():
self.canvas.itemconfig(self.id, state=tk.HIDDEN) self.canvas.itemconfig(self.id, state=tk.HIDDEN)
self._check_antenna() self._check_antenna()
@ -160,6 +192,12 @@ class CanvasEdge:
if self.link: if self.link:
self.canvas.delete(self.text_src) self.canvas.delete(self.text_src)
self.canvas.delete(self.text_dst) self.canvas.delete(self.text_dst)
self.canvas.delete(self.text_middle)
def reset(self):
self.canvas.delete(self.text_middle)
self.text_middle = None
self.canvas.itemconfig(self.id, fill=EDGE_COLOR, width=EDGE_WIDTH)
def create_context(self, event): def create_context(self, event):
logging.debug("create link context") logging.debug("create link context")

View file

@ -9,7 +9,6 @@ from core.gui.dialogs.shapemod import ShapeDialog
from core.gui.graph import tags from core.gui.graph import tags
from core.gui.graph.edges import CanvasEdge, CanvasWirelessEdge from core.gui.graph.edges import CanvasEdge, CanvasWirelessEdge
from core.gui.graph.enums import GraphMode, ScaleOption from core.gui.graph.enums import GraphMode, ScaleOption
from core.gui.graph.linkinfo import Throughput
from core.gui.graph.node import CanvasNode from core.gui.graph.node import CanvasNode
from core.gui.graph.shape import Shape from core.gui.graph.shape import Shape
from core.gui.graph.shapeutils import ShapeType, is_draw_shape, is_marker from core.gui.graph.shapeutils import ShapeType, is_draw_shape, is_marker
@ -38,7 +37,6 @@ class CanvasGraph(tk.Canvas):
self.wireless_edges = {} self.wireless_edges = {}
self.drawing_edge = None self.drawing_edge = None
self.grid = None self.grid = None
self.throughput_draw = Throughput(self, core)
self.shape_drawing = False self.shape_drawing = False
self.default_dimensions = (width, height) self.default_dimensions = (width, height)
self.current_dimensions = self.default_dimensions self.current_dimensions = self.default_dimensions
@ -158,6 +156,21 @@ class CanvasGraph(tk.Canvas):
valid_bottomright = self.inside_canvas(x2, y2) valid_bottomright = self.inside_canvas(x2, y2)
return valid_topleft and valid_bottomright return valid_topleft and valid_bottomright
def set_throughputs(self, throughputs_event):
for interface_throughput in throughputs_event.interface_throughputs:
node_id = interface_throughput.node_id
interface_id = interface_throughput.interface_id
throughput = interface_throughput.throughput
interface_to_edge_id = (node_id, interface_id)
token = self.core.interface_to_edge.get(interface_to_edge_id)
if not token:
continue
edge = self.edges.get(token)
if edge:
edge.set_throughput(throughput)
else:
del self.core.interface_to_edge[interface_to_edge_id]
def draw_grid(self): def draw_grid(self):
""" """
Create grid. Create grid.
@ -269,6 +282,20 @@ class CanvasGraph(tk.Canvas):
# raise the nodes so they on top of the links # raise the nodes so they on top of the links
self.tag_raise(tags.NODE) self.tag_raise(tags.NODE)
def stopped_session(self):
# clear wireless edges
for edge in self.wireless_edges.values():
edge.delete()
src_node = self.nodes[edge.src]
src_node.wireless_edges.remove(edge)
dst_node = self.nodes[edge.dst]
dst_node.wireless_edges.remove(edge)
self.wireless_edges.clear()
# clear all middle edge labels
for edge in self.edges.values():
edge.reset()
def canvas_xy(self, event): def canvas_xy(self, event):
""" """
Convert window coordinate to canvas coordinate Convert window coordinate to canvas coordinate
@ -446,9 +473,7 @@ class CanvasGraph(tk.Canvas):
if edge in edges: if edge in edges:
continue continue
edges.add(edge) edges.add(edge)
self.throughput_draw.delete(edge)
self.edges.pop(edge.token, None) self.edges.pop(edge.token, None)
# del self.edges[edge.token]
edge.delete() edge.delete()
# update node connected to edge being deleted # update node connected to edge being deleted

View file

@ -1,152 +0,0 @@
"""
Link information, such as IPv4, IPv6 and throughput drawn in the canvas
"""
from core.api.grpc import core_pb2
class Throughput:
def __init__(self, canvas, core):
self.canvas = canvas
self.core = core
# edge canvas id mapped to throughput value
self.tracker = {}
# map an edge canvas id to a throughput canvas id
self.map = {}
# map edge canvas id to token
self.edge_id_to_token = {}
def load_throughput_info(self, interface_throughputs):
"""
load all interface throughouts from an event
:param repeated core_bp2.InterfaceThroughputinterface_throughputs: interface
throughputs
:return: nothing
"""
for throughput in interface_throughputs:
nid = throughput.node_id
iid = throughput.interface_id
tp = throughput.throughput
token = self.core.interface_to_edge.get((nid, iid))
if token:
edge = self.canvas.edges.get(token)
if edge:
edge_id = edge.id
self.edge_id_to_token[edge_id] = token
if edge_id not in self.tracker:
self.tracker[edge_id] = tp
else:
temp = self.tracker[edge_id]
self.tracker[edge_id] = (temp + tp) / 2
else:
self.core.interface_to_edge.pop((nid, iid), None)
def edge_is_wired(self, token):
"""
determine whether link is a WIRED link
:param token:
:return:
"""
canvas_edge = self.canvas.edges[token]
canvas_src_id = canvas_edge.src
canvas_dst_id = canvas_edge.dst
src = self.canvas.nodes[canvas_src_id].core_node
dst = self.canvas.nodes[canvas_dst_id].core_node
return not (
src.type == core_pb2.NodeType.WIRELESS_LAN
and dst.model == "mdr"
or src.model == "mdr"
and dst.type == core_pb2.NodeType.WIRELESS_LAN
)
def draw_wired_throughput(self, edge_id):
x0, y0, x1, y1 = self.canvas.coords(edge_id)
x = (x0 + x1) / 2
y = (y0 + y1) / 2
if edge_id not in self.map:
tpid = self.canvas.create_text(
x,
y,
tags="throughput",
font=("Arial", 8),
text="{0:.3f} kbps".format(0.001 * self.tracker[edge_id]),
)
self.map[edge_id] = tpid
else:
tpid = self.map[edge_id]
self.canvas.coords(tpid, x, y)
self.canvas.itemconfig(
tpid, text="{0:.3f} kbps".format(0.001 * self.tracker[edge_id])
)
def draw_wireless_throughput(self, edge_id):
token = self.edge_id_to_token[edge_id]
canvas_edge = self.canvas.edges[token]
canvas_src_id = canvas_edge.src
canvas_dst_id = canvas_edge.dst
src_node = self.canvas.nodes[canvas_src_id]
dst_node = self.canvas.nodes[canvas_dst_id]
not_wlan = (
dst_node
if src_node.core_node.type == core_pb2.NodeType.WIRELESS_LAN
else src_node
)
x, y = self.canvas.coords(not_wlan.id)
if edge_id not in self.map:
tp_id = self.canvas.create_text(
x + 50,
y + 25,
font=("Arial", 8),
tags="throughput",
text="{0:.3f} kbps".format(0.001 * self.tracker[edge_id]),
)
self.map[edge_id] = tp_id
# redraw throughput
else:
self.canvas.itemconfig(
self.map[edge_id],
text="{0:.3f} kbps".format(0.001 * self.tracker[edge_id]),
)
def draw_throughputs(self):
for edge_id in self.tracker:
if self.edge_is_wired(self.edge_id_to_token[edge_id]):
self.draw_wired_throughput(edge_id)
else:
self.draw_wireless_throughput(edge_id)
def process_grpc_throughput_event(self, interface_throughputs):
self.load_throughput_info(interface_throughputs)
self.draw_throughputs()
def move(self, edge):
tpid = self.map.get(edge.id)
if tpid:
if self.edge_is_wired(edge.token):
x0, y0, x1, y1 = self.canvas.coords(edge.id)
self.canvas.coords(tpid, (x0 + x1) / 2, (y0 + y1) / 2)
else:
if (
self.canvas.nodes[edge.src].core_node.type
== core_pb2.NodeType.WIRELESS_LAN
):
x, y = self.canvas.coords(edge.dst)
self.canvas.coords(tpid, x + 50, y + 20)
else:
x, y = self.canvas.coords(edge.src)
self.canvas.coords(tpid, x + 50, y + 25)
def delete(self, edge):
tpid = self.map.get(edge.id)
if tpid:
eid = edge.id
self.canvas.delete(tpid)
self.tracker.pop(eid)
self.map.pop(eid)
self.edge_id_to_token.pop(eid)

View file

@ -128,7 +128,6 @@ class CanvasNode:
self.canvas.coords(edge.id, x, y, x2, y2) self.canvas.coords(edge.id, x, y, x2, y2)
else: else:
self.canvas.coords(edge.id, x1, y1, x, y) self.canvas.coords(edge.id, x1, y1, x, y)
self.canvas.throughput_draw.move(edge)
edge.update_labels() edge.update_labels()
for edge in self.wireless_edges: for edge in self.wireless_edges:

View file

@ -9,6 +9,7 @@ NODE_NAME = "nodename"
NODE = "node" NODE = "node"
WALLPAPER = "wallpaper" WALLPAPER = "wallpaper"
SELECTION = "selectednodes" SELECTION = "selectednodes"
THROUGHPUT = "throughput"
ABOVE_WALLPAPER_TAGS = [ ABOVE_WALLPAPER_TAGS = [
GRIDLINE, GRIDLINE,
SHAPE, SHAPE,

View file

@ -7,7 +7,6 @@ from tkinter.font import Font
from core.gui.dialogs.customnodes import CustomNodesDialog from core.gui.dialogs.customnodes import CustomNodesDialog
from core.gui.dialogs.marker import MarkerDialog from core.gui.dialogs.marker import MarkerDialog
from core.gui.graph import tags
from core.gui.graph.enums import GraphMode from core.gui.graph.enums import GraphMode
from core.gui.graph.shapeutils import ShapeType, is_marker from core.gui.graph.shapeutils import ShapeType, is_marker
from core.gui.images import ImageEnum, Images from core.gui.images import ImageEnum, Images
@ -404,7 +403,6 @@ class Toolbar(ttk.Frame):
self.app.statusbar.progress_bar.start(5) self.app.statusbar.progress_bar.start(5)
thread = threading.Thread(target=self.app.core.stop_session) thread = threading.Thread(target=self.app.core.stop_session)
thread.start() thread.start()
self.app.canvas.delete(tags.WIRELESS_EDGE)
self.design_frame.tkraise() self.design_frame.tkraise()
self.click_selection() self.click_selection()