pygui updated node service configurations to be self contained and copyable

This commit is contained in:
Blake Harnden 2020-04-21 10:31:20 -07:00
parent 85b4a81f8a
commit d7ebb90329
6 changed files with 57 additions and 77 deletions

View file

@ -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

View file

@ -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

View file

@ -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()

View file

@ -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:

View file

@ -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):

View file

@ -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