updates to implement working observer widgets
This commit is contained in:
parent
18c9904d58
commit
aa718817d0
5 changed files with 74 additions and 63 deletions
|
@ -18,25 +18,14 @@ class CanvasTooltip:
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
canvas,
|
||||
tag_or_id,
|
||||
*,
|
||||
bg="#FFFFEA",
|
||||
pad=(5, 3, 5, 3),
|
||||
text="canvas info",
|
||||
waittime=400,
|
||||
wraplength=250
|
||||
self, canvas, *, bg="#FFFFEA", pad=(5, 3, 5, 3), waittime=400, wraplength=600
|
||||
):
|
||||
# in miliseconds, originally 500
|
||||
self.waittime = waittime
|
||||
# in pixels, originally 180
|
||||
self.wraplength = wraplength
|
||||
self.canvas = canvas
|
||||
self.text = text
|
||||
self.canvas.tag_bind(tag_or_id, "<Enter>", self.on_enter)
|
||||
self.canvas.tag_bind(tag_or_id, "<Leave>", self.on_leave)
|
||||
self.canvas.tag_bind(tag_or_id, "<ButtonPress>", self.on_leave)
|
||||
self.text = tk.StringVar()
|
||||
self.bg = bg
|
||||
self.pad = pad
|
||||
self.id = None
|
||||
|
@ -61,18 +50,13 @@ class CanvasTooltip:
|
|||
|
||||
def show(self, event=None):
|
||||
def tip_pos_calculator(canvas, label, *, tip_delta=(10, 5), pad=(5, 3, 5, 3)):
|
||||
|
||||
c = canvas
|
||||
|
||||
s_width, s_height = c.winfo_screenwidth(), c.winfo_screenheight()
|
||||
|
||||
width, height = (
|
||||
pad[0] + label.winfo_reqwidth() + pad[2],
|
||||
pad[1] + label.winfo_reqheight() + pad[3],
|
||||
)
|
||||
|
||||
mouse_x, mouse_y = c.winfo_pointerxy()
|
||||
|
||||
x1, y1 = mouse_x + tip_delta[0], mouse_y + tip_delta[1]
|
||||
x2, y2 = x1 + width, y1 + height
|
||||
|
||||
|
@ -84,20 +68,14 @@ class CanvasTooltip:
|
|||
y_delta = 0
|
||||
|
||||
offscreen = (x_delta, y_delta) != (0, 0)
|
||||
|
||||
if offscreen:
|
||||
|
||||
if x_delta:
|
||||
x1 = mouse_x - tip_delta[0] - width
|
||||
|
||||
if y_delta:
|
||||
y1 = mouse_y - tip_delta[1] - height
|
||||
|
||||
offscreen_again = y1 < 0 # out on the top
|
||||
|
||||
if offscreen_again:
|
||||
y1 = 0
|
||||
|
||||
return x1, y1
|
||||
|
||||
bg = self.bg
|
||||
|
@ -111,21 +89,18 @@ class CanvasTooltip:
|
|||
self.tw.wm_overrideredirect(True)
|
||||
|
||||
win = tk.Frame(self.tw, background=bg, borderwidth=0)
|
||||
win.grid()
|
||||
label = ttk.Label(
|
||||
win,
|
||||
text=self.text,
|
||||
textvariable=self.text,
|
||||
justify=tk.LEFT,
|
||||
background=bg,
|
||||
relief=tk.SOLID,
|
||||
borderwidth=0,
|
||||
wraplength=self.wraplength,
|
||||
)
|
||||
|
||||
label.grid(padx=(pad[0], pad[2]), pady=(pad[1], pad[3]), sticky=tk.NSEW)
|
||||
win.grid()
|
||||
|
||||
x, y = tip_pos_calculator(canvas, label)
|
||||
|
||||
self.tw.wm_geometry("+%d+%d" % (x, y))
|
||||
|
||||
def hide(self):
|
||||
|
|
|
@ -15,6 +15,17 @@ from coretk.wlannodeconfig import WlanNodeConfig
|
|||
|
||||
NETWORK_NODES = {"switch", "hub", "wlan", "rj45", "tunnel", "emane"}
|
||||
DEFAULT_NODES = {"router", "host", "PC", "mdr", "prouter"}
|
||||
OBSERVER_WIDGETS = {
|
||||
"processes": "ps",
|
||||
"ifconfig": "ifconfig",
|
||||
"IPV4 Routes": "ip -4 ro",
|
||||
"IPV6 Routes": "ip -6 ro",
|
||||
"Listening sockets": "netstat -tuwnl",
|
||||
"IPv4 MFC entries": "ip -4 mroute show",
|
||||
"IPv6 MFC entries": "ip -6 mroute show",
|
||||
"firewall rules": "iptables -L",
|
||||
"IPSec policies": "setkey -DP",
|
||||
}
|
||||
|
||||
|
||||
class Node:
|
||||
|
@ -85,6 +96,7 @@ class CoreClient:
|
|||
self.master = app.master
|
||||
self.interface_helper = None
|
||||
self.services = {}
|
||||
self.observer = None
|
||||
|
||||
# loaded configuration data
|
||||
self.servers = {}
|
||||
|
@ -92,6 +104,7 @@ class CoreClient:
|
|||
self.read_config()
|
||||
|
||||
# data for managing the current session
|
||||
self.state = None
|
||||
self.nodes = {}
|
||||
self.edges = {}
|
||||
self.hooks = {}
|
||||
|
@ -105,6 +118,9 @@ class CoreClient:
|
|||
self.emaneconfig_management = EmaneModelNodeConfig(app)
|
||||
self.emane_config = None
|
||||
|
||||
def set_observer(self, value):
|
||||
self.observer = value
|
||||
|
||||
def read_config(self):
|
||||
# read distributed server
|
||||
for server_config in self.app.config["servers"]:
|
||||
|
@ -124,8 +140,11 @@ class CoreClient:
|
|||
|
||||
def handle_events(self, event):
|
||||
logging.info("event: %s", event)
|
||||
if event.link_event is not None:
|
||||
if event.HasField("link_event"):
|
||||
self.app.canvas.wireless_draw.hangle_link_event(event.link_event)
|
||||
elif event.HasField("session_event"):
|
||||
if event.session_event.event <= core_pb2.SessionState.SHUTDOWN:
|
||||
self.state = event.session_event.event
|
||||
|
||||
def handle_throughputs(self, event):
|
||||
interface_throughputs = event.interface_throughputs
|
||||
|
@ -159,7 +178,7 @@ class CoreClient:
|
|||
response = self.client.get_session(self.session_id)
|
||||
logging.info("joining session(%s): %s", self.session_id, response)
|
||||
session = response.session
|
||||
session_state = session.state
|
||||
self.state = session.state
|
||||
self.client.events(self.session_id, self.handle_events)
|
||||
|
||||
# get hooks
|
||||
|
@ -207,11 +226,14 @@ class CoreClient:
|
|||
self.app.canvas.canvas_reset_and_redraw(session)
|
||||
|
||||
# draw tool bar appropritate with session state
|
||||
if session_state == core_pb2.SessionState.RUNTIME:
|
||||
if self.is_runtime():
|
||||
self.app.toolbar.runtime_frame.tkraise()
|
||||
else:
|
||||
self.app.toolbar.design_frame.tkraise()
|
||||
|
||||
def is_runtime(self):
|
||||
return self.state == core_pb2.SessionState.RUNTIME
|
||||
|
||||
def create_new_session(self):
|
||||
"""
|
||||
Create a new session
|
||||
|
@ -754,3 +776,7 @@ class CoreClient:
|
|||
)
|
||||
configs.append(config_proto)
|
||||
return configs
|
||||
|
||||
def run(self, node_id):
|
||||
logging.info("running node(%s) cmd: %s", node_id, self.observer)
|
||||
return self.client.node_command(self.session_id, node_id, self.observer).output
|
||||
|
|
|
@ -150,7 +150,7 @@ class CanvasGraph(tk.Canvas):
|
|||
node.type, node.model
|
||||
)
|
||||
n = CanvasNode(
|
||||
node.position.x, node.position.y, image, name, self, node.id
|
||||
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
|
||||
|
@ -419,14 +419,7 @@ class CanvasGraph(tk.Canvas):
|
|||
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=x,
|
||||
y=y,
|
||||
image=image,
|
||||
node_type=node_name,
|
||||
canvas=self,
|
||||
core_id=self.core.peek_id(),
|
||||
)
|
||||
node = CanvasNode(x, y, image, node_name, self.master, self.core.peek_id())
|
||||
self.nodes[node.id] = node
|
||||
self.core.add_graph_node(self.core.session_id, node.id, x, y, node_name)
|
||||
return node
|
||||
|
@ -491,10 +484,11 @@ class CanvasEdge:
|
|||
|
||||
|
||||
class CanvasNode:
|
||||
def __init__(self, x, y, image, node_type, canvas, core_id):
|
||||
def __init__(self, x, y, image, node_type, app, core_id):
|
||||
self.image = image
|
||||
self.node_type = node_type
|
||||
self.canvas = canvas
|
||||
self.app = app
|
||||
self.canvas = app.canvas
|
||||
self.id = self.canvas.create_image(
|
||||
x, y, anchor=tk.CENTER, image=self.image, tags="node"
|
||||
)
|
||||
|
@ -506,19 +500,30 @@ class CanvasNode:
|
|||
x, y + 20, text=self.name, tags="nodename"
|
||||
)
|
||||
self.antenna_draw = WlanAntennaManager(self.canvas, self.id)
|
||||
|
||||
self.tooltip = CanvasTooltip(self.canvas)
|
||||
self.canvas.tag_bind(self.id, "<ButtonPress-1>", self.click_press)
|
||||
self.canvas.tag_bind(self.id, "<ButtonRelease-1>", self.click_release)
|
||||
self.canvas.tag_bind(self.id, "<B1-Motion>", self.motion)
|
||||
self.canvas.tag_bind(self.id, "<Button-3>", self.context)
|
||||
self.canvas.tag_bind(self.id, "<Double-Button-1>", self.double_click)
|
||||
self.canvas.tag_bind(self.id, "<Control-1>", self.select_multiple)
|
||||
self.tooltip = CanvasTooltip(self.canvas, self.id, text=self.name)
|
||||
self.canvas.tag_bind(self.id, "<Enter>", self.on_enter)
|
||||
self.canvas.tag_bind(self.id, "<Leave>", self.on_leave)
|
||||
|
||||
self.edges = set()
|
||||
self.wlans = []
|
||||
self.moving = None
|
||||
|
||||
def on_enter(self, event):
|
||||
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)
|
||||
self.tooltip.text.set(output)
|
||||
|
||||
def on_leave(self, event):
|
||||
self.tooltip.on_leave(event)
|
||||
|
||||
def click(self, event):
|
||||
print("click")
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import tkinter as tk
|
||||
from functools import partial
|
||||
|
||||
import coretk.menuaction as action
|
||||
from coretk.coreclient import OBSERVER_WIDGETS
|
||||
|
||||
|
||||
class Menubar(tk.Menu):
|
||||
|
@ -364,23 +366,26 @@ class Menubar(tk.Menu):
|
|||
:param tkinter.Menu widget_menu: widget_menu
|
||||
:return: nothing
|
||||
"""
|
||||
var = tk.StringVar(value="none")
|
||||
menu = tk.Menu(widget_menu)
|
||||
menu.add_command(label="None", state=tk.DISABLED)
|
||||
menu.add_command(label="processes", state=tk.DISABLED)
|
||||
menu.add_command(label="ifconfig", state=tk.DISABLED)
|
||||
menu.add_command(label="IPv4 routes", state=tk.DISABLED)
|
||||
menu.add_command(label="IPv6 routes", state=tk.DISABLED)
|
||||
menu.add_command(label="OSPFv2 neighbors", state=tk.DISABLED)
|
||||
menu.add_command(label="OSPFv3 neighbors", state=tk.DISABLED)
|
||||
menu.add_command(label="Listening sockets", state=tk.DISABLED)
|
||||
menu.add_command(label="IPv4 MFC entries", state=tk.DISABLED)
|
||||
menu.add_command(label="IPv6 MFC entries", state=tk.DISABLED)
|
||||
menu.add_command(label="firewall rules", state=tk.DISABLED)
|
||||
menu.add_command(label="IPsec policies", state=tk.DISABLED)
|
||||
menu.add_command(label="docker logs", state=tk.DISABLED)
|
||||
menu.add_command(label="OSPFv3 MDR level", state=tk.DISABLED)
|
||||
menu.add_command(label="PIM neighbors", state=tk.DISABLED)
|
||||
menu.add_command(label="Edit...", command=self.menuaction.edit_observer_widgets)
|
||||
menu.var = var
|
||||
menu.add_radiobutton(
|
||||
label="None",
|
||||
variable=var,
|
||||
value="none",
|
||||
command=lambda: self.app.core.set_observer(None),
|
||||
)
|
||||
for name in sorted(OBSERVER_WIDGETS):
|
||||
cmd = OBSERVER_WIDGETS[name]
|
||||
menu.add_radiobutton(
|
||||
label=name,
|
||||
variable=var,
|
||||
value=name,
|
||||
command=partial(self.app.core.set_observer, cmd),
|
||||
)
|
||||
menu.add_radiobutton(
|
||||
label="Edit...", command=self.menuaction.edit_observer_widgets
|
||||
)
|
||||
widget_menu.add_cascade(label="Observer Widgets", menu=menu)
|
||||
|
||||
def create_adjacency_menu(self, widget_menu):
|
||||
|
|
|
@ -184,9 +184,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
|
|||
logging.debug("stop session: %s", request)
|
||||
session = self.get_session(request.session_id, context)
|
||||
session.data_collect()
|
||||
session.set_state(EventTypes.DATACOLLECT_STATE)
|
||||
session.set_state(EventTypes.DATACOLLECT_STATE, send_event=True)
|
||||
session.clear()
|
||||
session.set_state(EventTypes.SHUTDOWN_STATE)
|
||||
session.set_state(EventTypes.SHUTDOWN_STATE, send_event=True)
|
||||
return core_pb2.StopSessionResponse(result=True)
|
||||
|
||||
def CreateSession(self, request, context):
|
||||
|
|
Loading…
Reference in a new issue