pygui updated node service configurations to be self contained and copyable
This commit is contained in:
parent
85b4a81f8a
commit
d7ebb90329
6 changed files with 57 additions and 77 deletions
|
@ -91,9 +91,7 @@ class CoreClient:
|
||||||
self.links = {}
|
self.links = {}
|
||||||
self.hooks = {}
|
self.hooks = {}
|
||||||
self.emane_config = None
|
self.emane_config = None
|
||||||
self.service_configs = {}
|
|
||||||
self.config_service_configs = {}
|
self.config_service_configs = {}
|
||||||
self.file_configs = {}
|
|
||||||
self.mobility_players = {}
|
self.mobility_players = {}
|
||||||
self.handling_throughputs = None
|
self.handling_throughputs = None
|
||||||
self.handling_events = None
|
self.handling_events = None
|
||||||
|
@ -126,8 +124,6 @@ class CoreClient:
|
||||||
self.links.clear()
|
self.links.clear()
|
||||||
self.hooks.clear()
|
self.hooks.clear()
|
||||||
self.emane_config = None
|
self.emane_config = None
|
||||||
self.service_configs.clear()
|
|
||||||
self.file_configs.clear()
|
|
||||||
self.modified_service_nodes.clear()
|
self.modified_service_nodes.clear()
|
||||||
for mobility_player in self.mobility_players.values():
|
for mobility_player in self.mobility_players.values():
|
||||||
mobility_player.handle_close()
|
mobility_player.handle_close()
|
||||||
|
@ -332,13 +328,14 @@ class CoreClient:
|
||||||
# get service configurations
|
# get service configurations
|
||||||
response = self.client.get_node_service_configs(self.session_id)
|
response = self.client.get_node_service_configs(self.session_id)
|
||||||
for config in response.configs:
|
for config in response.configs:
|
||||||
service_configs = self.service_configs.setdefault(config.node_id, {})
|
canvas_node = self.canvas_nodes[config.node_id]
|
||||||
service_configs[config.service] = config.data
|
canvas_node.service_configs[config.service] = config.data
|
||||||
logging.debug("service file configs: %s", config.files)
|
logging.debug("service file configs: %s", config.files)
|
||||||
for file_name in config.files:
|
for file_name in config.files:
|
||||||
file_configs = self.file_configs.setdefault(config.node_id, {})
|
|
||||||
files = file_configs.setdefault(config.service, {})
|
|
||||||
data = config.files[file_name]
|
data = config.files[file_name]
|
||||||
|
files = canvas_node.service_file_configs.setdefault(
|
||||||
|
config.service, {}
|
||||||
|
)
|
||||||
files[file_name] = data
|
files[file_name] = data
|
||||||
|
|
||||||
# get config service configurations
|
# get config service configurations
|
||||||
|
@ -953,8 +950,13 @@ class CoreClient:
|
||||||
|
|
||||||
def get_service_configs_proto(self) -> List[ServiceConfig]:
|
def get_service_configs_proto(self) -> List[ServiceConfig]:
|
||||||
configs = []
|
configs = []
|
||||||
for node_id, services in self.service_configs.items():
|
for canvas_node in self.canvas_nodes.values():
|
||||||
for name, config in services.items():
|
if not NodeUtils.is_container_node(canvas_node.core_node.type):
|
||||||
|
continue
|
||||||
|
if not canvas_node.service_configs:
|
||||||
|
continue
|
||||||
|
node_id = canvas_node.core_node.id
|
||||||
|
for name, config in canvas_node.service_configs.items():
|
||||||
config_proto = ServiceConfig(
|
config_proto = ServiceConfig(
|
||||||
node_id=node_id,
|
node_id=node_id,
|
||||||
service=name,
|
service=name,
|
||||||
|
@ -969,9 +971,14 @@ class CoreClient:
|
||||||
|
|
||||||
def get_service_file_configs_proto(self) -> List[ServiceFileConfig]:
|
def get_service_file_configs_proto(self) -> List[ServiceFileConfig]:
|
||||||
configs = []
|
configs = []
|
||||||
for (node_id, file_configs) in self.file_configs.items():
|
for canvas_node in self.canvas_nodes.values():
|
||||||
for service, file_config in file_configs.items():
|
if not NodeUtils.is_container_node(canvas_node.core_node.type):
|
||||||
for file, data in file_config.items():
|
continue
|
||||||
|
if not canvas_node.service_file_configs:
|
||||||
|
continue
|
||||||
|
node_id = canvas_node.core_node.id
|
||||||
|
for service, file_configs in canvas_node.service_file_configs.items():
|
||||||
|
for file, data in file_configs.items():
|
||||||
config_proto = ServiceFileConfig(
|
config_proto = ServiceFileConfig(
|
||||||
node_id=node_id, service=service, file=file, data=data
|
node_id=node_id, service=service, file=file, data=data
|
||||||
)
|
)
|
||||||
|
@ -1036,27 +1043,6 @@ class CoreClient:
|
||||||
)
|
)
|
||||||
return dict(config)
|
return dict(config)
|
||||||
|
|
||||||
def copy_node_service(self, _from: int, _to: int):
|
|
||||||
services = self.canvas_nodes[_from].core_node.services
|
|
||||||
self.canvas_nodes[_to].core_node.services[:] = services
|
|
||||||
logging.debug("copying node %s service to node %s", _from, _to)
|
|
||||||
|
|
||||||
def copy_node_config(self, src_node: core_pb2.Node, dst_id: int):
|
|
||||||
node_type = src_node.type
|
|
||||||
if node_type == core_pb2.NodeType.DEFAULT:
|
|
||||||
services = src_node.services
|
|
||||||
dst_node = self.canvas_nodes[dst_id]
|
|
||||||
dst_node.core_node.services[:] = services
|
|
||||||
config = self.service_configs.get(src_node.id)
|
|
||||||
if config:
|
|
||||||
self.service_configs[dst_id] = config
|
|
||||||
file_configs = self.file_configs.get(src_node.id)
|
|
||||||
if file_configs:
|
|
||||||
for key, value in file_configs.items():
|
|
||||||
if dst_id not in self.file_configs:
|
|
||||||
self.file_configs[dst_id] = {}
|
|
||||||
self.file_configs[dst_id][key] = value
|
|
||||||
|
|
||||||
def service_been_modified(self, node_id: int) -> bool:
|
def service_been_modified(self, node_id: int) -> bool:
|
||||||
return node_id in self.modified_service_nodes
|
return node_id in self.modified_service_nodes
|
||||||
|
|
||||||
|
|
|
@ -135,10 +135,11 @@ class NodeServiceDialog(Dialog):
|
||||||
current_selection = self.current.listbox.curselection()
|
current_selection = self.current.listbox.curselection()
|
||||||
if len(current_selection):
|
if len(current_selection):
|
||||||
dialog = ServiceConfigDialog(
|
dialog = ServiceConfigDialog(
|
||||||
master=self,
|
self,
|
||||||
app=self.app,
|
self.app,
|
||||||
service_name=self.current.listbox.get(current_selection[0]),
|
self.current.listbox.get(current_selection[0]),
|
||||||
node_id=self.node_id,
|
self.canvas_node,
|
||||||
|
self.node_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
# if error occurred when creating ServiceConfigDialog, don't show the dialog
|
# if error occurred when creating ServiceConfigDialog, don't show the dialog
|
||||||
|
@ -182,14 +183,6 @@ class NodeServiceDialog(Dialog):
|
||||||
return
|
return
|
||||||
|
|
||||||
def is_custom_service(self, service: str) -> bool:
|
def is_custom_service(self, service: str) -> bool:
|
||||||
service_configs = self.app.core.service_configs
|
has_service_config = service in self.canvas_node.service_configs
|
||||||
file_configs = self.app.core.file_configs
|
has_file_config = service in self.canvas_node.service_file_configs
|
||||||
if self.node_id in service_configs and service in service_configs[self.node_id]:
|
return has_service_config or has_file_config
|
||||||
return True
|
|
||||||
if (
|
|
||||||
self.node_id in file_configs
|
|
||||||
and service in file_configs[self.node_id]
|
|
||||||
and file_configs[self.node_id][service]
|
|
||||||
):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
|
@ -16,22 +16,26 @@ from core.gui.widgets import CodeText, ListboxScroll
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.gui.app import Application
|
from core.gui.app import Application
|
||||||
|
from core.gui.graph.node import CanvasNode
|
||||||
|
|
||||||
|
|
||||||
class ServiceConfigDialog(Dialog):
|
class ServiceConfigDialog(Dialog):
|
||||||
def __init__(
|
def __init__(
|
||||||
self, master: Any, app: "Application", service_name: str, node_id: int
|
self,
|
||||||
|
master: Any,
|
||||||
|
app: "Application",
|
||||||
|
service_name: str,
|
||||||
|
canvas_node: "CanvasNode",
|
||||||
|
node_id: int,
|
||||||
):
|
):
|
||||||
title = f"{service_name} Service"
|
title = f"{service_name} Service"
|
||||||
super().__init__(master, app, title, modal=True)
|
super().__init__(master, app, title, modal=True)
|
||||||
self.master = master
|
self.master = master
|
||||||
self.app = app
|
self.app = app
|
||||||
self.core = app.core
|
self.core = app.core
|
||||||
|
self.canvas_node = canvas_node
|
||||||
self.node_id = node_id
|
self.node_id = node_id
|
||||||
self.service_name = service_name
|
self.service_name = service_name
|
||||||
self.service_configs = app.core.service_configs
|
|
||||||
self.file_configs = app.core.file_configs
|
|
||||||
|
|
||||||
self.radiovar = tk.IntVar()
|
self.radiovar = tk.IntVar()
|
||||||
self.radiovar.set(2)
|
self.radiovar.set(2)
|
||||||
self.metadata = ""
|
self.metadata = ""
|
||||||
|
@ -54,7 +58,6 @@ class ServiceConfigDialog(Dialog):
|
||||||
ImageEnum.DOCUMENTNEW, int(16 * app.app_scale)
|
ImageEnum.DOCUMENTNEW, int(16 * app.app_scale)
|
||||||
)
|
)
|
||||||
self.editdelete_img = Images.get(ImageEnum.EDITDELETE, int(16 * app.app_scale))
|
self.editdelete_img = Images.get(ImageEnum.EDITDELETE, int(16 * app.app_scale))
|
||||||
|
|
||||||
self.notebook = None
|
self.notebook = None
|
||||||
self.metadata_entry = None
|
self.metadata_entry = None
|
||||||
self.filename_combobox = None
|
self.filename_combobox = None
|
||||||
|
@ -70,9 +73,7 @@ class ServiceConfigDialog(Dialog):
|
||||||
self.default_config = None
|
self.default_config = None
|
||||||
self.temp_service_files = {}
|
self.temp_service_files = {}
|
||||||
self.modified_files = set()
|
self.modified_files = set()
|
||||||
|
|
||||||
self.has_error = False
|
self.has_error = False
|
||||||
|
|
||||||
self.load()
|
self.load()
|
||||||
if not self.has_error:
|
if not self.has_error:
|
||||||
self.draw()
|
self.draw()
|
||||||
|
@ -87,8 +88,8 @@ class ServiceConfigDialog(Dialog):
|
||||||
self.default_validate = default_config.validate[:]
|
self.default_validate = default_config.validate[:]
|
||||||
self.default_shutdown = default_config.shutdown[:]
|
self.default_shutdown = default_config.shutdown[:]
|
||||||
self.default_directories = default_config.dirs[:]
|
self.default_directories = default_config.dirs[:]
|
||||||
custom_service_config = self.service_configs.get(self.node_id, {}).get(
|
custom_service_config = self.canvas_node.service_configs.get(
|
||||||
self.service_name, None
|
self.service_name
|
||||||
)
|
)
|
||||||
self.default_config = default_config
|
self.default_config = default_config
|
||||||
service_config = (
|
service_config = (
|
||||||
|
@ -111,10 +112,11 @@ class ServiceConfigDialog(Dialog):
|
||||||
for x in default_config.configs
|
for x in default_config.configs
|
||||||
}
|
}
|
||||||
self.temp_service_files = dict(self.original_service_files)
|
self.temp_service_files = dict(self.original_service_files)
|
||||||
file_config = self.file_configs.get(self.node_id, {}).get(
|
|
||||||
|
file_configs = self.canvas_node.service_file_configs.get(
|
||||||
self.service_name, {}
|
self.service_name, {}
|
||||||
)
|
)
|
||||||
for file, data in file_config.items():
|
for file, data in file_configs.items():
|
||||||
self.temp_service_files[file] = data
|
self.temp_service_files[file] = data
|
||||||
except grpc.RpcError as e:
|
except grpc.RpcError as e:
|
||||||
self.has_error = True
|
self.has_error = True
|
||||||
|
@ -449,7 +451,7 @@ class ServiceConfigDialog(Dialog):
|
||||||
and not self.has_new_files()
|
and not self.has_new_files()
|
||||||
and not self.is_custom_directory()
|
and not self.is_custom_directory()
|
||||||
):
|
):
|
||||||
self.service_configs.get(self.node_id, {}).pop(self.service_name, None)
|
self.canvas_node.service_configs.pop(self.service_name, None)
|
||||||
self.current_service_color("")
|
self.current_service_color("")
|
||||||
self.destroy()
|
self.destroy()
|
||||||
return
|
return
|
||||||
|
@ -470,17 +472,13 @@ class ServiceConfigDialog(Dialog):
|
||||||
validations=validate,
|
validations=validate,
|
||||||
shutdowns=shutdown,
|
shutdowns=shutdown,
|
||||||
)
|
)
|
||||||
if self.node_id not in self.service_configs:
|
self.canvas_node.service_configs[self.service_name] = config
|
||||||
self.service_configs[self.node_id] = {}
|
|
||||||
self.service_configs[self.node_id][self.service_name] = config
|
|
||||||
for file in self.modified_files:
|
for file in self.modified_files:
|
||||||
if self.node_id not in self.file_configs:
|
file_configs = self.canvas_node.service_file_configs.setdefault(
|
||||||
self.file_configs[self.node_id] = {}
|
self.service_name, {}
|
||||||
if self.service_name not in self.file_configs[self.node_id]:
|
)
|
||||||
self.file_configs[self.node_id][self.service_name] = {}
|
file_configs[file] = self.temp_service_files[file]
|
||||||
self.file_configs[self.node_id][self.service_name][
|
# TODO: check if this is really needed
|
||||||
file
|
|
||||||
] = self.temp_service_files[file]
|
|
||||||
self.app.core.set_node_service_file(
|
self.app.core.set_node_service_file(
|
||||||
self.node_id, self.service_name, file, self.temp_service_files[file]
|
self.node_id, self.service_name, file, self.temp_service_files[file]
|
||||||
)
|
)
|
||||||
|
@ -526,8 +524,9 @@ class ServiceConfigDialog(Dialog):
|
||||||
clears out any custom configuration permanently
|
clears out any custom configuration permanently
|
||||||
"""
|
"""
|
||||||
# clear coreclient data
|
# clear coreclient data
|
||||||
self.service_configs.get(self.node_id, {}).pop(self.service_name, None)
|
self.canvas_node.service_configs.pop(self.service_name, None)
|
||||||
self.file_configs.get(self.node_id, {}).pop(self.service_name, None)
|
file_configs = self.canvas_node.service_file_configs.pop(self.service_name, {})
|
||||||
|
file_configs.pop(self.service_name, None)
|
||||||
self.temp_service_files = dict(self.original_service_files)
|
self.temp_service_files = dict(self.original_service_files)
|
||||||
self.modified_files.clear()
|
self.modified_files.clear()
|
||||||
|
|
||||||
|
|
|
@ -352,7 +352,6 @@ class CanvasGraph(tk.Canvas):
|
||||||
"""
|
"""
|
||||||
Convert window coordinate to canvas coordinate
|
Convert window coordinate to canvas coordinate
|
||||||
"""
|
"""
|
||||||
logging.info("event type: %s", type(event))
|
|
||||||
x = self.canvasx(event.x)
|
x = self.canvasx(event.x)
|
||||||
y = self.canvasy(event.y)
|
y = self.canvasy(event.y)
|
||||||
return x, y
|
return x, y
|
||||||
|
@ -924,10 +923,13 @@ class CanvasGraph(tk.Canvas):
|
||||||
)
|
)
|
||||||
node = CanvasNode(self.master, scaled_x, scaled_y, copy, canvas_node.image)
|
node = CanvasNode(self.master, scaled_x, scaled_y, copy, canvas_node.image)
|
||||||
|
|
||||||
# copy configurations
|
# copy configurations and services
|
||||||
|
node.core_node.services[:] = canvas_node.core_node.services
|
||||||
node.emane_model_configs = deepcopy(canvas_node.emane_model_configs)
|
node.emane_model_configs = deepcopy(canvas_node.emane_model_configs)
|
||||||
node.wlan_config = deepcopy(canvas_node.wlan_config)
|
node.wlan_config = deepcopy(canvas_node.wlan_config)
|
||||||
node.mobility_config = deepcopy(canvas_node.mobility_config)
|
node.mobility_config = deepcopy(canvas_node.mobility_config)
|
||||||
|
node.service_configs = deepcopy(canvas_node.service_configs)
|
||||||
|
node.service_file_configs = deepcopy(canvas_node.service_file_configs)
|
||||||
|
|
||||||
# add new node to modified_service_nodes set if that set contains the
|
# add new node to modified_service_nodes set if that set contains the
|
||||||
# to_copy node
|
# to_copy node
|
||||||
|
@ -937,7 +939,6 @@ class CanvasGraph(tk.Canvas):
|
||||||
copy_map[canvas_node.id] = node.id
|
copy_map[canvas_node.id] = node.id
|
||||||
self.core.canvas_nodes[copy.id] = node
|
self.core.canvas_nodes[copy.id] = node
|
||||||
self.nodes[node.id] = node
|
self.nodes[node.id] = node
|
||||||
self.core.copy_node_config(core_node, copy.id)
|
|
||||||
for edge in canvas_node.edges:
|
for edge in canvas_node.edges:
|
||||||
if edge.src not in self.to_copy or edge.dst not in self.to_copy:
|
if edge.src not in self.to_copy or edge.dst not in self.to_copy:
|
||||||
if canvas_node.id == edge.src:
|
if canvas_node.id == edge.src:
|
||||||
|
|
|
@ -62,6 +62,8 @@ class CanvasNode:
|
||||||
self.emane_model_configs = {}
|
self.emane_model_configs = {}
|
||||||
self.wlan_config = {}
|
self.wlan_config = {}
|
||||||
self.mobility_config = {}
|
self.mobility_config = {}
|
||||||
|
self.service_configs = {}
|
||||||
|
self.service_file_configs = {}
|
||||||
self.setup_bindings()
|
self.setup_bindings()
|
||||||
|
|
||||||
def setup_bindings(self):
|
def setup_bindings(self):
|
||||||
|
|
|
@ -347,7 +347,6 @@ class Menubar(tk.Menu):
|
||||||
for i in range(self.edit_menu.index(tk.END) + 1):
|
for i in range(self.edit_menu.index(tk.END) + 1):
|
||||||
try:
|
try:
|
||||||
label = self.edit_menu.entrycget(i, "label")
|
label = self.edit_menu.entrycget(i, "label")
|
||||||
logging.info("menu label: %s", label)
|
|
||||||
if label not in labels:
|
if label not in labels:
|
||||||
continue
|
continue
|
||||||
state = tk.DISABLED if is_runtime else tk.NORMAL
|
state = tk.DISABLED if is_runtime else tk.NORMAL
|
||||||
|
|
Loading…
Add table
Reference in a new issue