pygui: replaced hook with wrapped hook class, fixed hook dialog edit
This commit is contained in:
parent
ba3a247495
commit
154fa8b77d
3 changed files with 159 additions and 17 deletions
|
@ -19,7 +19,6 @@ from core.api.grpc.core_pb2 import (
|
||||||
CpuUsageEvent,
|
CpuUsageEvent,
|
||||||
Event,
|
Event,
|
||||||
ExceptionEvent,
|
ExceptionEvent,
|
||||||
Hook,
|
|
||||||
Interface,
|
Interface,
|
||||||
Link,
|
Link,
|
||||||
LinkEvent,
|
LinkEvent,
|
||||||
|
@ -51,6 +50,7 @@ from core.gui.graph.shape import AnnotationData, Shape
|
||||||
from core.gui.graph.shapeutils import ShapeType
|
from core.gui.graph.shapeutils import ShapeType
|
||||||
from core.gui.interface import InterfaceManager
|
from core.gui.interface import InterfaceManager
|
||||||
from core.gui.nodeutils import NodeDraw, NodeUtils
|
from core.gui.nodeutils import NodeDraw, NodeUtils
|
||||||
|
from core.gui.wrappers import Hook
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.gui.app import Application
|
from core.gui.app import Application
|
||||||
|
@ -332,7 +332,8 @@ class CoreClient:
|
||||||
|
|
||||||
# get hooks
|
# get hooks
|
||||||
response = self.client.get_hooks(self.session_id)
|
response = self.client.get_hooks(self.session_id)
|
||||||
for hook in response.hooks:
|
for hook_proto in response.hooks:
|
||||||
|
hook = Hook.from_proto(hook_proto)
|
||||||
self.hooks[hook.file] = hook
|
self.hooks[hook.file] = hook
|
||||||
|
|
||||||
# get emane config
|
# get emane config
|
||||||
|
@ -570,7 +571,7 @@ class CoreClient:
|
||||||
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()
|
||||||
emane_model_configs = self.get_emane_model_configs_proto()
|
emane_model_configs = self.get_emane_model_configs_proto()
|
||||||
hooks = list(self.hooks.values())
|
hooks = [x.to_proto() for x in self.hooks.values()]
|
||||||
service_configs = self.get_service_configs_proto()
|
service_configs = self.get_service_configs_proto()
|
||||||
file_configs = self.get_service_file_configs_proto()
|
file_configs = self.get_service_file_configs_proto()
|
||||||
asymmetric_links = [
|
asymmetric_links = [
|
||||||
|
@ -823,7 +824,9 @@ class CoreClient:
|
||||||
config_proto.data,
|
config_proto.data,
|
||||||
)
|
)
|
||||||
for hook in self.hooks.values():
|
for hook in self.hooks.values():
|
||||||
self.client.add_hook(self.session_id, hook.state, hook.file, hook.data)
|
self.client.add_hook(
|
||||||
|
self.session_id, hook.state.value, hook.file, hook.data
|
||||||
|
)
|
||||||
for config_proto in self.get_emane_model_configs_proto():
|
for config_proto in self.get_emane_model_configs_proto():
|
||||||
self.client.set_emane_model_config(
|
self.client.set_emane_model_config(
|
||||||
self.session_id,
|
self.session_id,
|
||||||
|
|
|
@ -2,10 +2,10 @@ import tkinter as tk
|
||||||
from tkinter import ttk
|
from tkinter import ttk
|
||||||
from typing import TYPE_CHECKING, Optional
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from core.api.grpc import core_pb2
|
|
||||||
from core.gui.dialogs.dialog import Dialog
|
from core.gui.dialogs.dialog import Dialog
|
||||||
from core.gui.themes import PADX, PADY
|
from core.gui.themes import PADX, PADY
|
||||||
from core.gui.widgets import CodeText, ListboxScroll
|
from core.gui.widgets import CodeText, ListboxScroll
|
||||||
|
from core.gui.wrappers import Hook, SessionState
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.gui.app import Application
|
from core.gui.app import Application
|
||||||
|
@ -16,8 +16,9 @@ class HookDialog(Dialog):
|
||||||
super().__init__(app, "Hook", master=master)
|
super().__init__(app, "Hook", master=master)
|
||||||
self.name: tk.StringVar = tk.StringVar()
|
self.name: tk.StringVar = tk.StringVar()
|
||||||
self.codetext: Optional[CodeText] = None
|
self.codetext: Optional[CodeText] = None
|
||||||
self.hook: core_pb2.Hook = core_pb2.Hook()
|
self.hook: Optional[Hook] = None
|
||||||
self.state: tk.StringVar = tk.StringVar()
|
self.state: tk.StringVar = tk.StringVar()
|
||||||
|
self.editing: bool = False
|
||||||
self.draw()
|
self.draw()
|
||||||
|
|
||||||
def draw(self) -> None:
|
def draw(self) -> None:
|
||||||
|
@ -34,8 +35,8 @@ class HookDialog(Dialog):
|
||||||
label.grid(row=0, column=0, sticky="ew", padx=PADX)
|
label.grid(row=0, column=0, sticky="ew", padx=PADX)
|
||||||
entry = ttk.Entry(frame, textvariable=self.name)
|
entry = ttk.Entry(frame, textvariable=self.name)
|
||||||
entry.grid(row=0, column=1, sticky="ew", padx=PADX)
|
entry.grid(row=0, column=1, sticky="ew", padx=PADX)
|
||||||
values = tuple(x for x in core_pb2.SessionState.Enum.keys() if x != "NONE")
|
values = tuple(x.name for x in SessionState)
|
||||||
initial_state = core_pb2.SessionState.Enum.Name(core_pb2.SessionState.RUNTIME)
|
initial_state = SessionState.RUNTIME.name
|
||||||
self.state.set(initial_state)
|
self.state.set(initial_state)
|
||||||
self.name.set(f"{initial_state.lower()}_hook.sh")
|
self.name.set(f"{initial_state.lower()}_hook.sh")
|
||||||
combobox = ttk.Combobox(
|
combobox = ttk.Combobox(
|
||||||
|
@ -67,23 +68,30 @@ class HookDialog(Dialog):
|
||||||
button.grid(row=0, column=1, sticky="ew")
|
button.grid(row=0, column=1, sticky="ew")
|
||||||
|
|
||||||
def state_change(self, event: tk.Event) -> None:
|
def state_change(self, event: tk.Event) -> None:
|
||||||
|
if self.editing:
|
||||||
|
return
|
||||||
state_name = self.state.get()
|
state_name = self.state.get()
|
||||||
self.name.set(f"{state_name.lower()}_hook.sh")
|
self.name.set(f"{state_name.lower()}_hook.sh")
|
||||||
|
|
||||||
def set(self, hook: core_pb2.Hook) -> None:
|
def set(self, hook: Hook) -> None:
|
||||||
|
self.editing = True
|
||||||
self.hook = hook
|
self.hook = hook
|
||||||
self.name.set(hook.file)
|
self.name.set(hook.file)
|
||||||
self.codetext.text.delete(1.0, tk.END)
|
self.codetext.text.delete(1.0, tk.END)
|
||||||
self.codetext.text.insert(tk.END, hook.data)
|
self.codetext.text.insert(tk.END, hook.data)
|
||||||
state_name = core_pb2.SessionState.Enum.Name(hook.state)
|
state_name = hook.state.name
|
||||||
self.state.set(state_name)
|
self.state.set(state_name)
|
||||||
|
|
||||||
def save(self) -> None:
|
def save(self) -> None:
|
||||||
data = self.codetext.text.get("1.0", tk.END).strip()
|
data = self.codetext.text.get("1.0", tk.END).strip()
|
||||||
state_value = core_pb2.SessionState.Enum.Value(self.state.get())
|
state = SessionState[self.state.get()]
|
||||||
self.hook.file = self.name.get()
|
file_name = self.name.get()
|
||||||
self.hook.data = data
|
if self.editing:
|
||||||
self.hook.state = state_value
|
self.hook.state = state
|
||||||
|
self.hook.file = file_name
|
||||||
|
self.hook.data = data
|
||||||
|
else:
|
||||||
|
self.hook = Hook(state=state, file=file_name, data=data)
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,6 +102,7 @@ class HooksDialog(Dialog):
|
||||||
self.edit_button: Optional[ttk.Button] = None
|
self.edit_button: Optional[ttk.Button] = None
|
||||||
self.delete_button: Optional[ttk.Button] = None
|
self.delete_button: Optional[ttk.Button] = None
|
||||||
self.selected: Optional[str] = None
|
self.selected: Optional[str] = None
|
||||||
|
self.selected_index: Optional[int] = None
|
||||||
self.draw()
|
self.draw()
|
||||||
|
|
||||||
def draw(self) -> None:
|
def draw(self) -> None:
|
||||||
|
@ -133,10 +142,13 @@ class HooksDialog(Dialog):
|
||||||
self.listbox.insert(tk.END, hook.file)
|
self.listbox.insert(tk.END, hook.file)
|
||||||
|
|
||||||
def click_edit(self) -> None:
|
def click_edit(self) -> None:
|
||||||
hook = self.app.core.hooks[self.selected]
|
hook = self.app.core.hooks.pop(self.selected)
|
||||||
dialog = HookDialog(self, self.app)
|
dialog = HookDialog(self, self.app)
|
||||||
dialog.set(hook)
|
dialog.set(hook)
|
||||||
dialog.show()
|
dialog.show()
|
||||||
|
self.app.core.hooks[hook.file] = hook
|
||||||
|
self.listbox.delete(self.selected_index)
|
||||||
|
self.listbox.insert(self.selected_index, hook.file)
|
||||||
|
|
||||||
def click_delete(self) -> None:
|
def click_delete(self) -> None:
|
||||||
del self.app.core.hooks[self.selected]
|
del self.app.core.hooks[self.selected]
|
||||||
|
@ -146,11 +158,12 @@ class HooksDialog(Dialog):
|
||||||
|
|
||||||
def select(self, event: tk.Event) -> None:
|
def select(self, event: tk.Event) -> None:
|
||||||
if self.listbox.curselection():
|
if self.listbox.curselection():
|
||||||
index = self.listbox.curselection()[0]
|
self.selected_index = self.listbox.curselection()[0]
|
||||||
self.selected = self.listbox.get(index)
|
self.selected = self.listbox.get(self.selected_index)
|
||||||
self.edit_button.config(state=tk.NORMAL)
|
self.edit_button.config(state=tk.NORMAL)
|
||||||
self.delete_button.config(state=tk.NORMAL)
|
self.delete_button.config(state=tk.NORMAL)
|
||||||
else:
|
else:
|
||||||
self.selected = None
|
self.selected = None
|
||||||
|
self.selected_index = None
|
||||||
self.edit_button.config(state=tk.DISABLED)
|
self.edit_button.config(state=tk.DISABLED)
|
||||||
self.delete_button.config(state=tk.DISABLED)
|
self.delete_button.config(state=tk.DISABLED)
|
||||||
|
|
126
daemon/core/gui/wrappers.py
Normal file
126
daemon/core/gui/wrappers.py
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from enum import Enum
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from core.api.grpc import core_pb2
|
||||||
|
|
||||||
|
|
||||||
|
class SessionState(Enum):
|
||||||
|
DEFINITION = 1
|
||||||
|
CONFIGURATION = 2
|
||||||
|
INSTANTIATION = 3
|
||||||
|
RUNTIME = 4
|
||||||
|
DATACOLLECT = 5
|
||||||
|
SHUTDOWN = 6
|
||||||
|
|
||||||
|
|
||||||
|
class NodeType(Enum):
|
||||||
|
DEFAULT = 0
|
||||||
|
PHYSICAL = 1
|
||||||
|
SWITCH = 4
|
||||||
|
HUB = 5
|
||||||
|
WIRELESS_LAN = 6
|
||||||
|
RJ45 = 7
|
||||||
|
TUNNEL = 8
|
||||||
|
EMANE = 10
|
||||||
|
TAP_BRIDGE = 11
|
||||||
|
PEER_TO_PEER = 12
|
||||||
|
CONTROL_NET = 13
|
||||||
|
DOCKER = 15
|
||||||
|
LXC = 16
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Hook:
|
||||||
|
state: SessionState
|
||||||
|
file: str
|
||||||
|
data: str
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_proto(cls, hook: core_pb2.Hook) -> "Hook":
|
||||||
|
return Hook(state=SessionState(hook.state), file=hook.file, data=hook.data)
|
||||||
|
|
||||||
|
def to_proto(self) -> core_pb2.Hook:
|
||||||
|
return core_pb2.Hook(state=self.state.value, file=self.file, data=self.data)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Position:
|
||||||
|
x: float
|
||||||
|
y: float
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_proto(cls, position: core_pb2.Position) -> "Position":
|
||||||
|
return Position(x=position.x, y=position.y)
|
||||||
|
|
||||||
|
def to_proto(self) -> core_pb2.Position:
|
||||||
|
return core_pb2.Position(x=self.x, y=self.y)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Geo:
|
||||||
|
lat: float = None
|
||||||
|
lon: float = None
|
||||||
|
alt: float = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_proto(cls, geo: core_pb2.Geo) -> "Geo":
|
||||||
|
return Geo(lat=geo.lat, lon=geo.lon, alt=geo.alt)
|
||||||
|
|
||||||
|
def to_proto(self) -> core_pb2.Geo:
|
||||||
|
return core_pb2.Geo(lat=self.lat, lon=self.lon, alt=self.alt)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Node:
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
type: NodeType
|
||||||
|
model: str = None
|
||||||
|
position: Position = None
|
||||||
|
services: List[str] = None
|
||||||
|
config_services: List[str] = None
|
||||||
|
emane: str = None
|
||||||
|
icon: str = None
|
||||||
|
image: str = None
|
||||||
|
server: str = None
|
||||||
|
geo: Geo = None
|
||||||
|
dir: str = None
|
||||||
|
channel: str = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_proto(cls, node: core_pb2.Node) -> "Node":
|
||||||
|
return Node(
|
||||||
|
id=node.id,
|
||||||
|
name=node.name,
|
||||||
|
type=NodeType(node.type),
|
||||||
|
model=node.model,
|
||||||
|
position=Position.from_proto(node.position),
|
||||||
|
services=list(node.services),
|
||||||
|
config_services=list(node.config_services),
|
||||||
|
emane=node.emane,
|
||||||
|
icon=node.icon,
|
||||||
|
image=node.image,
|
||||||
|
server=node.server,
|
||||||
|
geo=Geo.from_proto(node.geo),
|
||||||
|
dir=node.dir,
|
||||||
|
channel=node.channel,
|
||||||
|
)
|
||||||
|
|
||||||
|
def to_proto(self) -> core_pb2.Node:
|
||||||
|
return core_pb2.Node(
|
||||||
|
id=self.id,
|
||||||
|
name=self.name,
|
||||||
|
type=self.type.value,
|
||||||
|
model=self.model,
|
||||||
|
position=self.position.to_proto(),
|
||||||
|
services=self.services,
|
||||||
|
config_services=self.config_services,
|
||||||
|
emane=self.emane,
|
||||||
|
icon=self.icon,
|
||||||
|
image=self.image,
|
||||||
|
server=self.server,
|
||||||
|
geo=self.geo.to_proto(),
|
||||||
|
dir=self.dir,
|
||||||
|
channel=self.channel,
|
||||||
|
)
|
Loading…
Add table
Reference in a new issue