pygui: changes to make use of wrapped session object and wrapped nodes to maintain and retrieving configurations information
This commit is contained in:
		
							parent
							
								
									3bdd6292cd
								
							
						
					
					
						commit
						588afaad13
					
				
					 21 changed files with 284 additions and 455 deletions
				
			
		|  | @ -580,6 +580,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): | |||
|         service_configs = grpcutils.get_node_service_configs(session) | ||||
|         config_service_configs = grpcutils.get_node_config_service_configs(session) | ||||
|         session_proto = core_pb2.Session( | ||||
|             id=session.id, | ||||
|             state=session.state.value, | ||||
|             nodes=nodes, | ||||
|             links=links, | ||||
|  |  | |||
|  | @ -37,7 +37,6 @@ from core.gui.wrappers import ( | |||
|     ConfigOption, | ||||
|     ConfigService, | ||||
|     ExceptionEvent, | ||||
|     Hook, | ||||
|     Interface, | ||||
|     Link, | ||||
|     LinkEvent, | ||||
|  | @ -61,6 +60,10 @@ GUI_SOURCE = "gui" | |||
| CPU_USAGE_DELAY = 3 | ||||
| 
 | ||||
| 
 | ||||
| def to_dict(config: Dict[str, ConfigOption]) -> Dict[str, str]: | ||||
|     return {x: y.value for x, y in config.items()} | ||||
| 
 | ||||
| 
 | ||||
| class CoreClient: | ||||
|     def __init__(self, app: "Application", proxy: bool) -> None: | ||||
|         """ | ||||
|  | @ -69,14 +72,13 @@ class CoreClient: | |||
|         self.app: "Application" = app | ||||
|         self.master: tk.Tk = app.master | ||||
|         self._client: client.CoreGrpcClient = client.CoreGrpcClient(proxy=proxy) | ||||
|         self.session_id: Optional[int] = None | ||||
|         self.session: Optional[Session] = None | ||||
|         self.user = getpass.getuser() | ||||
| 
 | ||||
|         # global service settings | ||||
|         self.services: Dict[str, Set[str]] = {} | ||||
|         self.config_services_groups: Dict[str, Set[str]] = {} | ||||
|         self.config_services: Dict[str, ConfigService] = {} | ||||
|         self.default_services: Dict[NodeType, Set[str]] = {} | ||||
|         self.emane_models: List[str] = [] | ||||
|         self.observer: Optional[str] = None | ||||
|         self.user = getpass.getuser() | ||||
| 
 | ||||
|         # loaded configuration data | ||||
|         self.servers: Dict[str, CoreServer] = {} | ||||
|  | @ -87,15 +89,12 @@ class CoreClient: | |||
|         # helpers | ||||
|         self.iface_to_edge: Dict[Tuple[int, ...], Tuple[int, ...]] = {} | ||||
|         self.ifaces_manager: InterfaceManager = InterfaceManager(self.app) | ||||
|         self.observer: Optional[str] = None | ||||
| 
 | ||||
|         # session data | ||||
|         self.state: Optional[SessionState] = None | ||||
|         self.canvas_nodes: Dict[int, CanvasNode] = {} | ||||
|         self.location: Optional[SessionLocation] = None | ||||
|         self.links: Dict[Tuple[int, int], CanvasEdge] = {} | ||||
|         self.hooks: Dict[str, Hook] = {} | ||||
|         self.emane_config: Dict[str, ConfigOption] = {} | ||||
|         self.mobility_players: Dict[int, MobilityPlayer] = {} | ||||
|         self.canvas_nodes: Dict[int, CanvasNode] = {} | ||||
|         self.links: Dict[Tuple[int, int], CanvasEdge] = {} | ||||
|         self.handling_throughputs: Optional[grpc.Future] = None | ||||
|         self.handling_cpu_usage: Optional[grpc.Future] = None | ||||
|         self.handling_events: Optional[grpc.Future] = None | ||||
|  | @ -104,15 +103,15 @@ class CoreClient: | |||
| 
 | ||||
|     @property | ||||
|     def client(self) -> client.CoreGrpcClient: | ||||
|         if self.session_id: | ||||
|             response = self._client.check_session(self.session_id) | ||||
|         if self.session: | ||||
|             response = self._client.check_session(self.session.id) | ||||
|             if not response.result: | ||||
|                 throughputs_enabled = self.handling_throughputs is not None | ||||
|                 self.cancel_throughputs() | ||||
|                 self.cancel_events() | ||||
|                 self._client.create_session(self.session_id) | ||||
|                 self._client.create_session(self.session.id) | ||||
|                 self.handling_events = self._client.events( | ||||
|                     self.session_id, self.handle_events | ||||
|                     self.session.id, self.handle_events | ||||
|                 ) | ||||
|                 if throughputs_enabled: | ||||
|                     self.enable_throughputs() | ||||
|  | @ -126,8 +125,6 @@ class CoreClient: | |||
|         # session data | ||||
|         self.canvas_nodes.clear() | ||||
|         self.links.clear() | ||||
|         self.hooks.clear() | ||||
|         self.emane_config = None | ||||
|         self.close_mobility_players() | ||||
|         self.mobility_players.clear() | ||||
|         # clear streams | ||||
|  | @ -145,12 +142,10 @@ class CoreClient: | |||
|         # read distributed servers | ||||
|         for server in self.app.guiconfig.servers: | ||||
|             self.servers[server.name] = server | ||||
| 
 | ||||
|         # read custom nodes | ||||
|         for custom_node in self.app.guiconfig.nodes: | ||||
|             node_draw = NodeDraw.from_custom(custom_node) | ||||
|             self.custom_nodes[custom_node.name] = node_draw | ||||
| 
 | ||||
|         # read observers | ||||
|         for observer in self.app.guiconfig.observers: | ||||
|             self.custom_observers[observer.name] = observer | ||||
|  | @ -158,11 +153,11 @@ class CoreClient: | |||
|     def handle_events(self, event: core_pb2.Event) -> None: | ||||
|         if event.source == GUI_SOURCE: | ||||
|             return | ||||
|         if event.session_id != self.session_id: | ||||
|         if event.session_id != self.session.id: | ||||
|             logging.warning( | ||||
|                 "ignoring event session(%s) current(%s)", | ||||
|                 event.session_id, | ||||
|                 self.session_id, | ||||
|                 self.session.id, | ||||
|             ) | ||||
|             return | ||||
| 
 | ||||
|  | @ -173,7 +168,7 @@ class CoreClient: | |||
|             logging.info("session event: %s", event) | ||||
|             session_event = event.session_event | ||||
|             if session_event.event <= SessionState.SHUTDOWN.value: | ||||
|                 self.state = SessionState(session_event.event) | ||||
|                 self.session.state = SessionState(session_event.event) | ||||
|             elif session_event.event in {7, 8, 9}: | ||||
|                 node_id = session_event.node_id | ||||
|                 dialog = self.mobility_players.get(node_id) | ||||
|  | @ -253,7 +248,7 @@ class CoreClient: | |||
| 
 | ||||
|     def enable_throughputs(self) -> None: | ||||
|         self.handling_throughputs = self.client.throughputs( | ||||
|             self.session_id, self.handle_throughputs | ||||
|             self.session.id, self.handle_throughputs | ||||
|         ) | ||||
| 
 | ||||
|     def cancel_throughputs(self) -> None: | ||||
|  | @ -283,11 +278,11 @@ class CoreClient: | |||
| 
 | ||||
|     def handle_throughputs(self, event: core_pb2.ThroughputsEvent) -> None: | ||||
|         event = ThroughputsEvent.from_proto(event) | ||||
|         if event.session_id != self.session_id: | ||||
|         if event.session_id != self.session.id: | ||||
|             logging.warning( | ||||
|                 "ignoring throughput event session(%s) current(%s)", | ||||
|                 event.session_id, | ||||
|                 self.session_id, | ||||
|                 self.session.id, | ||||
|             ) | ||||
|             return | ||||
|         logging.debug("handling throughputs event: %s", event) | ||||
|  | @ -300,126 +295,33 @@ class CoreClient: | |||
|         logging.info("exception event: %s", event) | ||||
|         self.app.statusbar.add_alert(event) | ||||
| 
 | ||||
|     def join_session(self, session_id: int, query_location: bool = True) -> None: | ||||
|         logging.info("join session(%s)", session_id) | ||||
|         # update session and title | ||||
|         self.session_id = session_id | ||||
|         self.master.title(f"CORE Session({self.session_id})") | ||||
| 
 | ||||
|         # clear session data | ||||
|     def join_session(self, session_id: int) -> None: | ||||
|         logging.info("joining session(%s)", session_id) | ||||
|         self.reset() | ||||
| 
 | ||||
|         # get session data | ||||
|         try: | ||||
|             response = self.client.get_session(self.session_id) | ||||
|             session = Session.from_proto(response.session) | ||||
|             self.state = session.state | ||||
|             response = self.client.get_session(session_id) | ||||
|             self.session = Session.from_proto(response.session) | ||||
|             self.client.set_session_user(self.session.id, self.user) | ||||
|             self.master.title(f"CORE Session({self.session.id})") | ||||
|             self.handling_events = self.client.events( | ||||
|                 self.session_id, self.handle_events | ||||
|                 self.session.id, self.handle_events | ||||
|             ) | ||||
| 
 | ||||
|             # set session user | ||||
|             self.client.set_session_user(self.session_id, self.user) | ||||
| 
 | ||||
|             # get session service defaults | ||||
|             response = self.client.get_service_defaults(self.session_id) | ||||
|             self.default_services = { | ||||
|                 x.node_type: set(x.services) for x in response.defaults | ||||
|             } | ||||
| 
 | ||||
|             # get location | ||||
|             if query_location: | ||||
|                 response = self.client.get_session_location(self.session_id) | ||||
|                 self.location = SessionLocation.from_proto(response.location) | ||||
| 
 | ||||
|             # get emane models | ||||
|             response = self.client.get_emane_models(self.session_id) | ||||
|             self.emane_models = response.models | ||||
| 
 | ||||
|             # get hooks | ||||
|             response = self.client.get_hooks(self.session_id) | ||||
|             for hook_proto in response.hooks: | ||||
|                 hook = Hook.from_proto(hook_proto) | ||||
|                 self.hooks[hook.file] = hook | ||||
| 
 | ||||
|             # get emane config | ||||
|             response = self.client.get_emane_config(self.session_id) | ||||
|             self.emane_config = ConfigOption.from_dict(response.config) | ||||
| 
 | ||||
|             # update interface manager | ||||
|             self.ifaces_manager.joined(session.links) | ||||
| 
 | ||||
|             # draw session | ||||
|             self.app.canvas.reset_and_redraw(session) | ||||
| 
 | ||||
|             # get mobility configs | ||||
|             response = self.client.get_mobility_configs(self.session_id) | ||||
|             for node_id in response.configs: | ||||
|                 config = response.configs[node_id].config | ||||
|                 canvas_node = self.canvas_nodes[node_id] | ||||
|                 canvas_node.mobility_config = ConfigOption.from_dict(config) | ||||
| 
 | ||||
|             # get emane model config | ||||
|             response = self.client.get_emane_model_configs(self.session_id) | ||||
|             for config in response.configs: | ||||
|                 iface_id = None | ||||
|                 if config.iface_id != -1: | ||||
|                     iface_id = config.iface_id | ||||
|                 canvas_node = self.canvas_nodes[config.node_id] | ||||
|                 canvas_node.emane_model_configs[ | ||||
|                     (config.model, iface_id) | ||||
|                 ] = ConfigOption.from_dict(config.config) | ||||
| 
 | ||||
|             # get wlan configurations | ||||
|             response = self.client.get_wlan_configs(self.session_id) | ||||
|             for _id in response.configs: | ||||
|                 mapped_config = response.configs[_id] | ||||
|                 canvas_node = self.canvas_nodes[_id] | ||||
|                 canvas_node.wlan_config = ConfigOption.from_dict(mapped_config.config) | ||||
| 
 | ||||
|             # get service configurations | ||||
|             response = self.client.get_node_service_configs(self.session_id) | ||||
|             for config in response.configs: | ||||
|                 canvas_node = self.canvas_nodes[config.node_id] | ||||
|                 canvas_node.service_configs[config.service] = config.data | ||||
|                 logging.debug("service file configs: %s", config.files) | ||||
|                 for file_name in config.files: | ||||
|                     data = config.files[file_name] | ||||
|                     files = canvas_node.service_file_configs.setdefault( | ||||
|                         config.service, {} | ||||
|                     ) | ||||
|                     files[file_name] = data | ||||
| 
 | ||||
|             # get config service configurations | ||||
|             response = self.client.get_node_config_service_configs(self.session_id) | ||||
|             for config in response.configs: | ||||
|                 canvas_node = self.canvas_nodes[config.node_id] | ||||
|                 service_config = canvas_node.config_service_configs.setdefault( | ||||
|                     config.name, {} | ||||
|                 ) | ||||
|                 if config.templates: | ||||
|                     service_config["templates"] = config.templates | ||||
|                 if config.config: | ||||
|                     service_config["config"] = config.config | ||||
| 
 | ||||
|             # get metadata | ||||
|             response = self.client.get_session_metadata(self.session_id) | ||||
|             self.parse_metadata(response.config) | ||||
|             self.ifaces_manager.joined(self.session.links) | ||||
|             self.app.canvas.reset_and_redraw(self.session) | ||||
|             self.parse_metadata() | ||||
|             self.app.canvas.organize() | ||||
|             if self.is_runtime(): | ||||
|                 self.show_mobility_players() | ||||
|             self.app.after(0, self.app.joined_session_update) | ||||
|         except grpc.RpcError as e: | ||||
|             self.app.show_grpc_exception("Join Session Error", e) | ||||
| 
 | ||||
|         # organize canvas | ||||
|         self.app.canvas.organize() | ||||
|         if self.is_runtime(): | ||||
|             self.show_mobility_players() | ||||
|         # update ui to represent current state | ||||
|         self.app.after(0, self.app.joined_session_update) | ||||
| 
 | ||||
|     def is_runtime(self) -> bool: | ||||
|         return self.state == SessionState.RUNTIME | ||||
|         return self.session and self.session.state == SessionState.RUNTIME | ||||
| 
 | ||||
|     def parse_metadata(self, config: Dict[str, str]) -> None: | ||||
|     def parse_metadata(self) -> None: | ||||
|         # canvas setting | ||||
|         config = self.session.metadata | ||||
|         canvas_config = config.get("canvas") | ||||
|         logging.debug("canvas metadata: %s", canvas_config) | ||||
|         if canvas_config: | ||||
|  | @ -447,7 +349,7 @@ class CoreClient: | |||
|         if shapes_config: | ||||
|             shapes_config = json.loads(shapes_config) | ||||
|             for shape_config in shapes_config: | ||||
|                 logging.info("loading shape: %s", shape_config) | ||||
|                 logging.debug("loading shape: %s", shape_config) | ||||
|                 shape_type = shape_config["type"] | ||||
|                 try: | ||||
|                     shape_type = ShapeType(shape_type) | ||||
|  | @ -478,8 +380,9 @@ class CoreClient: | |||
|         try: | ||||
|             response = self.client.create_session() | ||||
|             logging.info("created session: %s", response) | ||||
|             self.join_session(response.session_id) | ||||
|             location_config = self.app.guiconfig.location | ||||
|             self.location = SessionLocation( | ||||
|             self.session.location = SessionLocation( | ||||
|                 x=location_config.x, | ||||
|                 y=location_config.y, | ||||
|                 z=location_config.z, | ||||
|  | @ -488,13 +391,12 @@ class CoreClient: | |||
|                 alt=location_config.alt, | ||||
|                 scale=location_config.scale, | ||||
|             ) | ||||
|             self.join_session(response.session_id, query_location=False) | ||||
|         except grpc.RpcError as e: | ||||
|             self.app.show_grpc_exception("New Session Error", e) | ||||
| 
 | ||||
|     def delete_session(self, session_id: int = None) -> None: | ||||
|         if session_id is None: | ||||
|             session_id = self.session_id | ||||
|             session_id = self.session.id | ||||
|         try: | ||||
|             response = self.client.delete_session(session_id) | ||||
|             logging.info("deleted session(%s), Result: %s", session_id, response) | ||||
|  | @ -507,13 +409,11 @@ class CoreClient: | |||
|         """ | ||||
|         try: | ||||
|             self.client.connect() | ||||
| 
 | ||||
|             # get service information | ||||
|             # get all available services | ||||
|             response = self.client.get_services() | ||||
|             for service in response.services: | ||||
|                 group_services = self.services.setdefault(service.group, set()) | ||||
|                 group_services.add(service.name) | ||||
| 
 | ||||
|             # get config service informations | ||||
|             response = self.client.get_config_services() | ||||
|             for service in response.services: | ||||
|  | @ -522,7 +422,6 @@ class CoreClient: | |||
|                     service.group, set() | ||||
|                 ) | ||||
|                 group_services.add(service.name) | ||||
| 
 | ||||
|             # join provided session, create new session, or show dialog to select an | ||||
|             # existing session | ||||
|             response = self.client.get_sessions() | ||||
|  | @ -553,14 +452,14 @@ class CoreClient: | |||
|         try: | ||||
|             position = core_node.position.to_proto() | ||||
|             self.client.edit_node( | ||||
|                 self.session_id, core_node.id, position, source=GUI_SOURCE | ||||
|                 self.session.id, core_node.id, position, source=GUI_SOURCE | ||||
|             ) | ||||
|         except grpc.RpcError as e: | ||||
|             self.app.show_grpc_exception("Edit Node Error", e) | ||||
| 
 | ||||
|     def send_servers(self) -> None: | ||||
|         for server in self.servers.values(): | ||||
|             self.client.add_session_server(self.session_id, server.name, server.address) | ||||
|             self.client.add_session_server(self.session.id, server.name, server.address) | ||||
| 
 | ||||
|     def start_session(self) -> Tuple[bool, List[str]]: | ||||
|         self.ifaces_manager.reset_mac() | ||||
|  | @ -576,26 +475,23 @@ class CoreClient: | |||
|         wlan_configs = self.get_wlan_configs_proto() | ||||
|         mobility_configs = self.get_mobility_configs_proto() | ||||
|         emane_model_configs = self.get_emane_model_configs_proto() | ||||
|         hooks = [x.to_proto() for x in self.hooks.values()] | ||||
|         hooks = [x.to_proto() for x in self.session.hooks.values()] | ||||
|         service_configs = self.get_service_configs_proto() | ||||
|         file_configs = self.get_service_file_configs_proto() | ||||
|         asymmetric_links = [ | ||||
|             x.asymmetric_link for x in self.links.values() if x.asymmetric_link | ||||
|         ] | ||||
|         config_service_configs = self.get_config_service_configs_proto() | ||||
|         if self.emane_config: | ||||
|             emane_config = {x: self.emane_config[x].value for x in self.emane_config} | ||||
|         else: | ||||
|             emane_config = None | ||||
|         emane_config = to_dict(self.session.emane_config) | ||||
|         result = False | ||||
|         exceptions = [] | ||||
|         try: | ||||
|             self.send_servers() | ||||
|             response = self.client.start_session( | ||||
|                 self.session_id, | ||||
|                 self.session.id, | ||||
|                 nodes, | ||||
|                 links, | ||||
|                 self.location.to_proto(), | ||||
|                 self.session.location.to_proto(), | ||||
|                 hooks, | ||||
|                 emane_config, | ||||
|                 emane_model_configs, | ||||
|  | @ -607,7 +503,7 @@ class CoreClient: | |||
|                 config_service_configs, | ||||
|             ) | ||||
|             logging.info( | ||||
|                 "start session(%s), result: %s", self.session_id, response.result | ||||
|                 "start session(%s), result: %s", self.session.id, response.result | ||||
|             ) | ||||
|             if response.result: | ||||
|                 self.set_metadata() | ||||
|  | @ -619,7 +515,7 @@ class CoreClient: | |||
| 
 | ||||
|     def stop_session(self, session_id: int = None) -> bool: | ||||
|         if not session_id: | ||||
|             session_id = self.session_id | ||||
|             session_id = self.session.id | ||||
|         result = False | ||||
|         try: | ||||
|             response = self.client.stop_session(session_id) | ||||
|  | @ -630,15 +526,12 @@ class CoreClient: | |||
|         return result | ||||
| 
 | ||||
|     def show_mobility_players(self) -> None: | ||||
|         for canvas_node in self.canvas_nodes.values(): | ||||
|             if canvas_node.core_node.type != NodeType.WIRELESS_LAN: | ||||
|         for node in self.session.nodes.values(): | ||||
|             if node.type != NodeType.WIRELESS_LAN: | ||||
|                 continue | ||||
|             if canvas_node.mobility_config: | ||||
|                 mobility_player = MobilityPlayer( | ||||
|                     self.app, canvas_node, canvas_node.mobility_config | ||||
|                 ) | ||||
|                 node_id = canvas_node.core_node.id | ||||
|                 self.mobility_players[node_id] = mobility_player | ||||
|             if node.mobility_config: | ||||
|                 mobility_player = MobilityPlayer(self.app, node) | ||||
|                 self.mobility_players[node.id] = mobility_player | ||||
|                 mobility_player.show() | ||||
| 
 | ||||
|     def set_metadata(self) -> None: | ||||
|  | @ -662,8 +555,8 @@ class CoreClient: | |||
|         shapes = json.dumps(shapes) | ||||
| 
 | ||||
|         metadata = {"canvas": canvas_config, "shapes": shapes} | ||||
|         response = self.client.set_session_metadata(self.session_id, metadata) | ||||
|         logging.info("set session metadata %s, result: %s", metadata, response) | ||||
|         response = self.client.set_session_metadata(self.session.id, metadata) | ||||
|         logging.debug("set session metadata %s, result: %s", metadata, response) | ||||
| 
 | ||||
|     def launch_terminal(self, node_id: int) -> None: | ||||
|         try: | ||||
|  | @ -675,7 +568,7 @@ class CoreClient: | |||
|                     parent=self.app, | ||||
|                 ) | ||||
|                 return | ||||
|             response = self.client.get_node_terminal(self.session_id, node_id) | ||||
|             response = self.client.get_node_terminal(self.session.id, node_id) | ||||
|             cmd = f"{terminal} {response.terminal} &" | ||||
|             logging.info("launching terminal %s", cmd) | ||||
|             os.system(cmd) | ||||
|  | @ -687,10 +580,10 @@ class CoreClient: | |||
|         Save core session as to an xml file | ||||
|         """ | ||||
|         try: | ||||
|             if self.state != SessionState.RUNTIME: | ||||
|             if not self.is_runtime(): | ||||
|                 logging.debug("Send session data to the daemon") | ||||
|                 self.send_data() | ||||
|             response = self.client.save_xml(self.session_id, file_path) | ||||
|             response = self.client.save_xml(self.session.id, file_path) | ||||
|             logging.info("saved xml file %s, result: %s", file_path, response) | ||||
|         except grpc.RpcError as e: | ||||
|             self.app.show_grpc_exception("Save XML Error", e) | ||||
|  | @ -707,7 +600,7 @@ class CoreClient: | |||
|             self.app.show_grpc_exception("Open XML Error", e) | ||||
| 
 | ||||
|     def get_node_service(self, node_id: int, service_name: str) -> NodeServiceData: | ||||
|         response = self.client.get_node_service(self.session_id, node_id, service_name) | ||||
|         response = self.client.get_node_service(self.session.id, node_id, service_name) | ||||
|         logging.debug( | ||||
|             "get node(%s) %s service, response: %s", node_id, service_name, response | ||||
|         ) | ||||
|  | @ -724,7 +617,7 @@ class CoreClient: | |||
|         shutdowns: List[str], | ||||
|     ) -> NodeServiceData: | ||||
|         response = self.client.set_node_service( | ||||
|             self.session_id, | ||||
|             self.session.id, | ||||
|             node_id, | ||||
|             service_name, | ||||
|             directories=dirs, | ||||
|  | @ -744,14 +637,14 @@ class CoreClient: | |||
|             shutdowns, | ||||
|             response, | ||||
|         ) | ||||
|         response = self.client.get_node_service(self.session_id, node_id, service_name) | ||||
|         response = self.client.get_node_service(self.session.id, node_id, service_name) | ||||
|         return NodeServiceData.from_proto(response.service) | ||||
| 
 | ||||
|     def get_node_service_file( | ||||
|         self, node_id: int, service_name: str, file_name: str | ||||
|     ) -> str: | ||||
|         response = self.client.get_node_service_file( | ||||
|             self.session_id, node_id, service_name, file_name | ||||
|             self.session.id, node_id, service_name, file_name | ||||
|         ) | ||||
|         logging.debug( | ||||
|             "get service file for node(%s), service: %s, file: %s, result: %s", | ||||
|  | @ -766,7 +659,7 @@ class CoreClient: | |||
|         self, node_id: int, service_name: str, file_name: str, data: str | ||||
|     ) -> None: | ||||
|         response = self.client.set_node_service_file( | ||||
|             self.session_id, node_id, service_name, file_name, data | ||||
|             self.session.id, node_id, service_name, file_name, data | ||||
|         ) | ||||
|         logging.info( | ||||
|             "set node(%s) service file, service: %s, file: %s, data: %s, result: %s", | ||||
|  | @ -783,13 +676,13 @@ class CoreClient: | |||
|         """ | ||||
|         node_protos = [x.core_node.to_proto() for x in self.canvas_nodes.values()] | ||||
|         link_protos = [x.link.to_proto() for x in self.links.values()] | ||||
|         self.client.set_session_state(self.session_id, SessionState.DEFINITION.value) | ||||
|         self.client.set_session_state(self.session.id, SessionState.DEFINITION.value) | ||||
|         for node_proto in node_protos: | ||||
|             response = self.client.add_node(self.session_id, node_proto) | ||||
|             response = self.client.add_node(self.session.id, node_proto) | ||||
|             logging.debug("create node: %s", response) | ||||
|         for link_proto in link_protos: | ||||
|             response = self.client.add_link( | ||||
|                 self.session_id, | ||||
|                 self.session.id, | ||||
|                 link_proto.node1_id, | ||||
|                 link_proto.node2_id, | ||||
|                 link_proto.iface1, | ||||
|  | @ -806,15 +699,15 @@ class CoreClient: | |||
|         self.create_nodes_and_links() | ||||
|         for config_proto in self.get_wlan_configs_proto(): | ||||
|             self.client.set_wlan_config( | ||||
|                 self.session_id, config_proto.node_id, config_proto.config | ||||
|                 self.session.id, config_proto.node_id, config_proto.config | ||||
|             ) | ||||
|         for config_proto in self.get_mobility_configs_proto(): | ||||
|             self.client.set_mobility_config( | ||||
|                 self.session_id, config_proto.node_id, config_proto.config | ||||
|                 self.session.id, config_proto.node_id, config_proto.config | ||||
|             ) | ||||
|         for config_proto in self.get_service_configs_proto(): | ||||
|             self.client.set_node_service( | ||||
|                 self.session_id, | ||||
|                 self.session.id, | ||||
|                 config_proto.node_id, | ||||
|                 config_proto.service, | ||||
|                 startup=config_proto.startup, | ||||
|  | @ -823,38 +716,37 @@ class CoreClient: | |||
|             ) | ||||
|         for config_proto in self.get_service_file_configs_proto(): | ||||
|             self.client.set_node_service_file( | ||||
|                 self.session_id, | ||||
|                 self.session.id, | ||||
|                 config_proto.node_id, | ||||
|                 config_proto.service, | ||||
|                 config_proto.file, | ||||
|                 config_proto.data, | ||||
|             ) | ||||
|         for hook in self.hooks.values(): | ||||
|         for hook in self.session.hooks.values(): | ||||
|             self.client.add_hook( | ||||
|                 self.session_id, hook.state.value, hook.file, hook.data | ||||
|                 self.session.id, hook.state.value, hook.file, hook.data | ||||
|             ) | ||||
|         for config_proto in self.get_emane_model_configs_proto(): | ||||
|             self.client.set_emane_model_config( | ||||
|                 self.session_id, | ||||
|                 self.session.id, | ||||
|                 config_proto.node_id, | ||||
|                 config_proto.model, | ||||
|                 config_proto.config, | ||||
|                 config_proto.iface_id, | ||||
|             ) | ||||
|         if self.emane_config: | ||||
|             config = {x: self.emane_config[x].value for x in self.emane_config} | ||||
|             self.client.set_emane_config(self.session_id, config) | ||||
|         if self.location: | ||||
|             self.client.set_session_location( | ||||
|                 self.session_id, | ||||
|                 self.location.x, | ||||
|                 self.location.y, | ||||
|                 self.location.z, | ||||
|                 self.location.lat, | ||||
|                 self.location.lon, | ||||
|                 self.location.alt, | ||||
|                 self.location.scale, | ||||
|             ) | ||||
|         config = to_dict(self.session.emane_config) | ||||
|         self.client.set_emane_config(self.session.id, config) | ||||
|         location = self.session.location | ||||
|         self.client.set_session_location( | ||||
|             self.session.id, | ||||
|             location.x, | ||||
|             location.y, | ||||
|             location.z, | ||||
|             location.lat, | ||||
|             location.lon, | ||||
|             location.alt, | ||||
|             location.scale, | ||||
|         ) | ||||
|         self.set_metadata() | ||||
| 
 | ||||
|     def close(self) -> None: | ||||
|  | @ -888,16 +780,16 @@ class CoreClient: | |||
|             image = "ubuntu:latest" | ||||
|         emane = None | ||||
|         if node_type == NodeType.EMANE: | ||||
|             if not self.emane_models: | ||||
|             if not self.session.emane_models: | ||||
|                 dialog = EmaneInstallDialog(self.app) | ||||
|                 dialog.show() | ||||
|                 return | ||||
|             emane = self.emane_models[0] | ||||
|             name = f"EMANE{node_id}" | ||||
|             emane = self.session.emane_models[0] | ||||
|             name = f"emane{node_id}" | ||||
|         elif node_type == NodeType.WIRELESS_LAN: | ||||
|             name = f"WLAN{node_id}" | ||||
|             name = f"wlan{node_id}" | ||||
|         elif node_type in [NodeType.RJ45, NodeType.TUNNEL]: | ||||
|             name = "UNASSIGNED" | ||||
|             name = "unassigned" | ||||
|         else: | ||||
|             name = f"n{node_id}" | ||||
|         node = Node( | ||||
|  | @ -914,13 +806,13 @@ class CoreClient: | |||
|             node.services[:] = services | ||||
|         # assign default services to CORE node | ||||
|         else: | ||||
|             services = self.default_services.get(model) | ||||
|             services = self.session.default_services.get(model) | ||||
|             if services: | ||||
|                 node.services[:] = services | ||||
|                 node.services = services.copy() | ||||
|         logging.info( | ||||
|             "add node(%s) to session(%s), coordinates(%s, %s)", | ||||
|             node.name, | ||||
|             self.session_id, | ||||
|             self.session.id, | ||||
|             x, | ||||
|             y, | ||||
|         ) | ||||
|  | @ -1005,60 +897,56 @@ class CoreClient: | |||
| 
 | ||||
|     def get_wlan_configs_proto(self) -> List[wlan_pb2.WlanConfig]: | ||||
|         configs = [] | ||||
|         for canvas_node in self.canvas_nodes.values(): | ||||
|             if canvas_node.core_node.type != NodeType.WIRELESS_LAN: | ||||
|         for node in self.session.nodes.values(): | ||||
|             if node.type != NodeType.WIRELESS_LAN: | ||||
|                 continue | ||||
|             if not canvas_node.wlan_config: | ||||
|             if not node.wlan_config: | ||||
|                 continue | ||||
|             config = ConfigOption.to_dict(canvas_node.wlan_config) | ||||
|             node_id = canvas_node.core_node.id | ||||
|             wlan_config = wlan_pb2.WlanConfig(node_id=node_id, config=config) | ||||
|             config = ConfigOption.to_dict(node.wlan_config) | ||||
|             wlan_config = wlan_pb2.WlanConfig(node_id=node.id, config=config) | ||||
|             configs.append(wlan_config) | ||||
|         return configs | ||||
| 
 | ||||
|     def get_mobility_configs_proto(self) -> List[mobility_pb2.MobilityConfig]: | ||||
|         configs = [] | ||||
|         for canvas_node in self.canvas_nodes.values(): | ||||
|             if canvas_node.core_node.type != NodeType.WIRELESS_LAN: | ||||
|         for node in self.session.nodes.values(): | ||||
|             if node.type != NodeType.WIRELESS_LAN: | ||||
|                 continue | ||||
|             if not canvas_node.mobility_config: | ||||
|             if not node.mobility_config: | ||||
|                 continue | ||||
|             config = ConfigOption.to_dict(canvas_node.mobility_config) | ||||
|             node_id = canvas_node.core_node.id | ||||
|             config = ConfigOption.to_dict(node.mobility_config) | ||||
|             mobility_config = mobility_pb2.MobilityConfig( | ||||
|                 node_id=node_id, config=config | ||||
|                 node_id=node.id, config=config | ||||
|             ) | ||||
|             configs.append(mobility_config) | ||||
|         return configs | ||||
| 
 | ||||
|     def get_emane_model_configs_proto(self) -> List[emane_pb2.EmaneModelConfig]: | ||||
|         configs = [] | ||||
|         for canvas_node in self.canvas_nodes.values(): | ||||
|             if canvas_node.core_node.type != NodeType.EMANE: | ||||
|         for node in self.session.nodes.values(): | ||||
|             if node.type != NodeType.EMANE: | ||||
|                 continue | ||||
|             node_id = canvas_node.core_node.id | ||||
|             for key, config in canvas_node.emane_model_configs.items(): | ||||
|             for key, config in node.emane_model_configs.items(): | ||||
|                 model, iface_id = key | ||||
|                 config = ConfigOption.to_dict(config) | ||||
|                 if iface_id is None: | ||||
|                     iface_id = -1 | ||||
|                 config_proto = emane_pb2.EmaneModelConfig( | ||||
|                     node_id=node_id, iface_id=iface_id, model=model, config=config | ||||
|                     node_id=node.id, iface_id=iface_id, model=model, config=config | ||||
|                 ) | ||||
|                 configs.append(config_proto) | ||||
|         return configs | ||||
| 
 | ||||
|     def get_service_configs_proto(self) -> List[services_pb2.ServiceConfig]: | ||||
|         configs = [] | ||||
|         for canvas_node in self.canvas_nodes.values(): | ||||
|             if not NodeUtils.is_container_node(canvas_node.core_node.type): | ||||
|         for node in self.session.nodes.values(): | ||||
|             if not NodeUtils.is_container_node(node.type): | ||||
|                 continue | ||||
|             if not canvas_node.service_configs: | ||||
|             if not node.service_configs: | ||||
|                 continue | ||||
|             node_id = canvas_node.core_node.id | ||||
|             for name, config in canvas_node.service_configs.items(): | ||||
|             for name, config in node.service_configs.items(): | ||||
|                 config_proto = services_pb2.ServiceConfig( | ||||
|                     node_id=node_id, | ||||
|                     node_id=node.id, | ||||
|                     service=name, | ||||
|                     directories=config.dirs, | ||||
|                     files=config.configs, | ||||
|  | @ -1071,16 +959,15 @@ class CoreClient: | |||
| 
 | ||||
|     def get_service_file_configs_proto(self) -> List[services_pb2.ServiceFileConfig]: | ||||
|         configs = [] | ||||
|         for canvas_node in self.canvas_nodes.values(): | ||||
|             if not NodeUtils.is_container_node(canvas_node.core_node.type): | ||||
|         for node in self.session.nodes.values(): | ||||
|             if not NodeUtils.is_container_node(node.type): | ||||
|                 continue | ||||
|             if not canvas_node.service_file_configs: | ||||
|             if not node.service_file_configs: | ||||
|                 continue | ||||
|             node_id = canvas_node.core_node.id | ||||
|             for service, file_configs in canvas_node.service_file_configs.items(): | ||||
|             for service, file_configs in node.service_file_configs.items(): | ||||
|                 for file, data in file_configs.items(): | ||||
|                     config_proto = services_pb2.ServiceFileConfig( | ||||
|                         node_id=node_id, service=service, file=file, data=data | ||||
|                         node_id=node.id, service=service, file=file, data=data | ||||
|                     ) | ||||
|                     configs.append(config_proto) | ||||
|         return configs | ||||
|  | @ -1089,29 +976,27 @@ class CoreClient: | |||
|         self | ||||
|     ) -> List[configservices_pb2.ConfigServiceConfig]: | ||||
|         config_service_protos = [] | ||||
|         for canvas_node in self.canvas_nodes.values(): | ||||
|             if not NodeUtils.is_container_node(canvas_node.core_node.type): | ||||
|         for node in self.session.nodes.values(): | ||||
|             if not NodeUtils.is_container_node(node.type): | ||||
|                 continue | ||||
|             if not canvas_node.config_service_configs: | ||||
|             if not node.config_service_configs: | ||||
|                 continue | ||||
|             node_id = canvas_node.core_node.id | ||||
|             for name, service_config in canvas_node.config_service_configs.items(): | ||||
|                 config = service_config.get("config", {}) | ||||
|             for name, service_config in node.config_service_configs.items(): | ||||
|                 config_proto = configservices_pb2.ConfigServiceConfig( | ||||
|                     node_id=node_id, | ||||
|                     node_id=node.id, | ||||
|                     name=name, | ||||
|                     templates=service_config["templates"], | ||||
|                     config=config, | ||||
|                     templates=service_config.templates, | ||||
|                     config=service_config.config, | ||||
|                 ) | ||||
|                 config_service_protos.append(config_proto) | ||||
|         return config_service_protos | ||||
| 
 | ||||
|     def run(self, node_id: int) -> str: | ||||
|         logging.info("running node(%s) cmd: %s", node_id, self.observer) | ||||
|         return self.client.node_command(self.session_id, node_id, self.observer).output | ||||
|         return self.client.node_command(self.session.id, node_id, self.observer).output | ||||
| 
 | ||||
|     def get_wlan_config(self, node_id: int) -> Dict[str, ConfigOption]: | ||||
|         response = self.client.get_wlan_config(self.session_id, node_id) | ||||
|         response = self.client.get_wlan_config(self.session.id, node_id) | ||||
|         config = response.config | ||||
|         logging.debug( | ||||
|             "get wlan configuration from node %s, result configuration: %s", | ||||
|  | @ -1121,7 +1006,7 @@ class CoreClient: | |||
|         return ConfigOption.from_dict(config) | ||||
| 
 | ||||
|     def get_mobility_config(self, node_id: int) -> Dict[str, ConfigOption]: | ||||
|         response = self.client.get_mobility_config(self.session_id, node_id) | ||||
|         response = self.client.get_mobility_config(self.session.id, node_id) | ||||
|         config = response.config | ||||
|         logging.debug( | ||||
|             "get mobility config from node %s, result configuration: %s", | ||||
|  | @ -1136,7 +1021,7 @@ class CoreClient: | |||
|         if iface_id is None: | ||||
|             iface_id = -1 | ||||
|         response = self.client.get_emane_model_config( | ||||
|             self.session_id, node_id, model, iface_id | ||||
|             self.session.id, node_id, model, iface_id | ||||
|         ) | ||||
|         config = response.config | ||||
|         logging.debug( | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ class SizeAndScaleDialog(Dialog): | |||
|         width, height = self.canvas.current_dimensions | ||||
|         self.pixel_width: tk.IntVar = tk.IntVar(value=width) | ||||
|         self.pixel_height: tk.IntVar = tk.IntVar(value=height) | ||||
|         location = self.app.core.location | ||||
|         location = self.app.core.session.location | ||||
|         self.x: tk.DoubleVar = tk.DoubleVar(value=location.x) | ||||
|         self.y: tk.DoubleVar = tk.DoubleVar(value=location.y) | ||||
|         self.lat: tk.DoubleVar = tk.DoubleVar(value=location.lat) | ||||
|  | @ -192,7 +192,7 @@ class SizeAndScaleDialog(Dialog): | |||
|         self.canvas.redraw_canvas((width, height)) | ||||
|         if self.canvas.wallpaper: | ||||
|             self.canvas.redraw_wallpaper() | ||||
|         location = self.app.core.location | ||||
|         location = self.app.core.session.location | ||||
|         location.x = self.x.get() | ||||
|         location.y = self.y.get() | ||||
|         location.lat = self.lat.get() | ||||
|  |  | |||
|  | @ -11,28 +11,26 @@ import grpc | |||
| from core.gui.dialogs.dialog import Dialog | ||||
| from core.gui.themes import FRAME_PAD, PADX, PADY | ||||
| from core.gui.widgets import CodeText, ConfigFrame, ListboxScroll | ||||
| from core.gui.wrappers import ConfigOption, ServiceValidationMode | ||||
| from core.gui.wrappers import ( | ||||
|     ConfigOption, | ||||
|     ConfigServiceData, | ||||
|     Node, | ||||
|     ServiceValidationMode, | ||||
| ) | ||||
| 
 | ||||
| if TYPE_CHECKING: | ||||
|     from core.gui.app import Application | ||||
|     from core.gui.graph.node import CanvasNode | ||||
|     from core.gui.coreclient import CoreClient | ||||
| 
 | ||||
| 
 | ||||
| class ConfigServiceConfigDialog(Dialog): | ||||
|     def __init__( | ||||
|         self, | ||||
|         master: tk.BaseWidget, | ||||
|         app: "Application", | ||||
|         service_name: str, | ||||
|         canvas_node: "CanvasNode", | ||||
|         node_id: int, | ||||
|         self, master: tk.BaseWidget, app: "Application", service_name: str, node: Node | ||||
|     ) -> None: | ||||
|         title = f"{service_name} Config Service" | ||||
|         super().__init__(app, title, master=master) | ||||
|         self.core: "CoreClient" = app.core | ||||
|         self.canvas_node: "CanvasNode" = canvas_node | ||||
|         self.node_id: int = node_id | ||||
|         self.node: Node = node | ||||
|         self.service_name: str = service_name | ||||
|         self.radiovar: tk.IntVar = tk.IntVar() | ||||
|         self.radiovar.set(2) | ||||
|  | @ -50,7 +48,7 @@ class ConfigServiceConfigDialog(Dialog): | |||
|         self.validation_time: Optional[int] = None | ||||
|         self.validation_period: tk.StringVar = tk.StringVar() | ||||
|         self.modes: List[str] = [] | ||||
|         self.mode_configs: Dict[str, str] = {} | ||||
|         self.mode_configs: Dict[str, Dict[str, str]] = {} | ||||
| 
 | ||||
|         self.notebook: Optional[ttk.Notebook] = None | ||||
|         self.templates_combobox: Optional[ttk.Combobox] = None | ||||
|  | @ -91,25 +89,18 @@ class ConfigServiceConfigDialog(Dialog): | |||
|             response = self.core.client.get_config_service_defaults(self.service_name) | ||||
|             self.original_service_files = response.templates | ||||
|             self.temp_service_files = dict(self.original_service_files) | ||||
| 
 | ||||
|             self.modes = sorted(x.name for x in response.modes) | ||||
|             self.mode_configs = {x.name: x.config for x in response.modes} | ||||
| 
 | ||||
|             service_config = self.canvas_node.config_service_configs.get( | ||||
|                 self.service_name, {} | ||||
|             ) | ||||
|             self.config = ConfigOption.from_dict(response.config) | ||||
|             self.default_config = {x.name: x.value for x in self.config.values()} | ||||
|             custom_config = service_config.get("config") | ||||
|             if custom_config: | ||||
|                 for key, value in custom_config.items(): | ||||
|             service_config = self.node.config_service_configs.get(self.service_name) | ||||
|             if service_config: | ||||
|                 for key, value in service_config.config.items(): | ||||
|                     self.config[key].value = value | ||||
|             logging.info("default config: %s", self.default_config) | ||||
| 
 | ||||
|             custom_templates = service_config.get("templates", {}) | ||||
|             for file, data in custom_templates.items(): | ||||
|                 self.modified_files.add(file) | ||||
|                 self.temp_service_files[file] = data | ||||
|                 logging.info("default config: %s", self.default_config) | ||||
|                 for file, data in service_config.templates.items(): | ||||
|                     self.modified_files.add(file) | ||||
|                     self.temp_service_files[file] = data | ||||
|         except grpc.RpcError as e: | ||||
|             self.app.show_grpc_exception("Get Config Service Error", e) | ||||
|             self.has_error = True | ||||
|  | @ -313,20 +304,18 @@ class ConfigServiceConfigDialog(Dialog): | |||
|     def click_apply(self) -> None: | ||||
|         current_listbox = self.master.current.listbox | ||||
|         if not self.is_custom(): | ||||
|             self.canvas_node.config_service_configs.pop(self.service_name, None) | ||||
|             self.node.config_service_configs.pop(self.service_name, None) | ||||
|             current_listbox.itemconfig(current_listbox.curselection()[0], bg="") | ||||
|             self.destroy() | ||||
|             return | ||||
| 
 | ||||
|         service_config = self.canvas_node.config_service_configs.setdefault( | ||||
|             self.service_name, {} | ||||
|         ) | ||||
|         service_config = self.node.config_service_configs.get(self.service_name) | ||||
|         if not service_config: | ||||
|             service_config = ConfigServiceData() | ||||
|         if self.config_frame: | ||||
|             self.config_frame.parse_config() | ||||
|             service_config["config"] = {x.name: x.value for x in self.config.values()} | ||||
|         templates_config = service_config.setdefault("templates", {}) | ||||
|             service_config.config = {x.name: x.value for x in self.config.values()} | ||||
|         for file in self.modified_files: | ||||
|             templates_config[file] = self.temp_service_files[file] | ||||
|             service_config.templates[file] = self.temp_service_files[file] | ||||
|         all_current = current_listbox.get(0, tk.END) | ||||
|         current_listbox.itemconfig(all_current.index(self.service_name), bg="green") | ||||
|         self.destroy() | ||||
|  | @ -360,9 +349,9 @@ class ConfigServiceConfigDialog(Dialog): | |||
|         return has_custom_templates or has_custom_config | ||||
| 
 | ||||
|     def click_defaults(self) -> None: | ||||
|         self.canvas_node.config_service_configs.pop(self.service_name, None) | ||||
|         self.node.config_service_configs.pop(self.service_name, None) | ||||
|         logging.info( | ||||
|             "cleared config service config: %s", self.canvas_node.config_service_configs | ||||
|             "cleared config service config: %s", self.node.config_service_configs | ||||
|         ) | ||||
|         self.temp_service_files = dict(self.original_service_files) | ||||
|         filename = self.templates_combobox.get() | ||||
|  |  | |||
|  | @ -43,16 +43,15 @@ class CopyServiceConfigDialog(Dialog): | |||
|         listbox_scroll = ListboxScroll(self.top) | ||||
|         listbox_scroll.grid(sticky="nsew", pady=PADY) | ||||
|         self.listbox = listbox_scroll.listbox | ||||
|         for canvas_node in self.app.canvas.nodes.values(): | ||||
|             file_configs = canvas_node.service_file_configs.get(self.service) | ||||
|         for node in self.app.core.session.nodes.values(): | ||||
|             file_configs = node.service_file_configs.get(self.service) | ||||
|             if not file_configs: | ||||
|                 continue | ||||
|             data = file_configs.get(self.file_name) | ||||
|             if not data: | ||||
|                 continue | ||||
|             name = canvas_node.core_node.name | ||||
|             self.nodes[name] = canvas_node.id | ||||
|             self.listbox.insert(tk.END, name) | ||||
|             self.nodes[node.name] = node.id | ||||
|             self.listbox.insert(tk.END, node.name) | ||||
| 
 | ||||
|         frame = ttk.Frame(self.top) | ||||
|         frame.grid(sticky="ew") | ||||
|  | @ -70,9 +69,9 @@ class CopyServiceConfigDialog(Dialog): | |||
|         if not selection: | ||||
|             return | ||||
|         name = self.listbox.get(selection) | ||||
|         canvas_node_id = self.nodes[name] | ||||
|         canvas_node = self.app.canvas.nodes[canvas_node_id] | ||||
|         data = canvas_node.service_file_configs[self.service][self.file_name] | ||||
|         node_id = self.nodes[name] | ||||
|         node = self.app.core.session.nodes[node_id] | ||||
|         data = node.service_file_configs[self.service][self.file_name] | ||||
|         self.dialog.temp_service_files[self.file_name] = data | ||||
|         self.dialog.modified_files.add(self.file_name) | ||||
|         self.dialog.service_file_data.text.delete(1.0, tk.END) | ||||
|  | @ -84,9 +83,9 @@ class CopyServiceConfigDialog(Dialog): | |||
|         if not selection: | ||||
|             return | ||||
|         name = self.listbox.get(selection) | ||||
|         canvas_node_id = self.nodes[name] | ||||
|         canvas_node = self.app.canvas.nodes[canvas_node_id] | ||||
|         data = canvas_node.service_file_configs[self.service][self.file_name] | ||||
|         node_id = self.nodes[name] | ||||
|         node = self.app.core.session.nodes[node_id] | ||||
|         data = node.service_file_configs[self.service][self.file_name] | ||||
|         dialog = ViewConfigDialog( | ||||
|             self.app, self, name, self.service, self.file_name, data | ||||
|         ) | ||||
|  |  | |||
|  | @ -16,7 +16,6 @@ from core.gui.wrappers import ConfigOption, Node | |||
| 
 | ||||
| if TYPE_CHECKING: | ||||
|     from core.gui.app import Application | ||||
|     from core.gui.graph.node import CanvasNode | ||||
| 
 | ||||
| 
 | ||||
| class GlobalEmaneDialog(Dialog): | ||||
|  | @ -29,8 +28,9 @@ class GlobalEmaneDialog(Dialog): | |||
|     def draw(self) -> None: | ||||
|         self.top.columnconfigure(0, weight=1) | ||||
|         self.top.rowconfigure(0, weight=1) | ||||
|         session = self.app.core.session | ||||
|         self.config_frame = ConfigFrame( | ||||
|             self.top, self.app, self.app.core.emane_config, self.enabled | ||||
|             self.top, self.app, session.emane_config, self.enabled | ||||
|         ) | ||||
|         self.config_frame.draw_config() | ||||
|         self.config_frame.grid(sticky="nsew", pady=PADY) | ||||
|  | @ -58,24 +58,19 @@ class EmaneModelDialog(Dialog): | |||
|         self, | ||||
|         master: tk.BaseWidget, | ||||
|         app: "Application", | ||||
|         canvas_node: "CanvasNode", | ||||
|         node: Node, | ||||
|         model: str, | ||||
|         iface_id: int = None, | ||||
|     ) -> None: | ||||
|         super().__init__( | ||||
|             app, f"{canvas_node.core_node.name} {model} Configuration", master=master | ||||
|         ) | ||||
|         self.canvas_node: "CanvasNode" = canvas_node | ||||
|         self.node: Node = canvas_node.core_node | ||||
|         super().__init__(app, f"{node.name} {model} Configuration", master=master) | ||||
|         self.node: Node = node | ||||
|         self.model: str = f"emane_{model}" | ||||
|         self.iface_id: int = iface_id | ||||
|         self.config_frame: Optional[ConfigFrame] = None | ||||
|         self.enabled: bool = not self.app.core.is_runtime() | ||||
|         self.has_error: bool = False | ||||
|         try: | ||||
|             config = self.canvas_node.emane_model_configs.get( | ||||
|                 (self.model, self.iface_id) | ||||
|             ) | ||||
|             config = self.node.emane_model_configs.get((self.model, self.iface_id)) | ||||
|             if not config: | ||||
|                 config = self.app.core.get_emane_model_config( | ||||
|                     self.node.id, self.model, self.iface_id | ||||
|  | @ -110,19 +105,18 @@ class EmaneModelDialog(Dialog): | |||
|     def click_apply(self) -> None: | ||||
|         self.config_frame.parse_config() | ||||
|         key = (self.model, self.iface_id) | ||||
|         self.canvas_node.emane_model_configs[key] = self.config | ||||
|         self.node.emane_model_configs[key] = self.config | ||||
|         self.destroy() | ||||
| 
 | ||||
| 
 | ||||
| class EmaneConfigDialog(Dialog): | ||||
|     def __init__(self, app: "Application", canvas_node: "CanvasNode") -> None: | ||||
|         super().__init__(app, f"{canvas_node.core_node.name} EMANE Configuration") | ||||
|         self.canvas_node: "CanvasNode" = canvas_node | ||||
|         self.node: Node = canvas_node.core_node | ||||
|     def __init__(self, app: "Application", node: Node) -> None: | ||||
|         super().__init__(app, f"{node.name} EMANE Configuration") | ||||
|         self.node: Node = node | ||||
|         self.radiovar: tk.IntVar = tk.IntVar() | ||||
|         self.radiovar.set(1) | ||||
|         self.emane_models: List[str] = [ | ||||
|             x.split("_")[1] for x in self.app.core.emane_models | ||||
|             x.split("_")[1] for x in self.app.core.session.emane_models | ||||
|         ] | ||||
|         model = self.node.emane.split("_")[1] | ||||
|         self.emane_model: tk.StringVar = tk.StringVar(value=model) | ||||
|  | @ -231,7 +225,7 @@ class EmaneConfigDialog(Dialog): | |||
|         draw emane model configuration | ||||
|         """ | ||||
|         model_name = self.emane_model.get() | ||||
|         dialog = EmaneModelDialog(self, self.app, self.canvas_node, model_name) | ||||
|         dialog = EmaneModelDialog(self, self.app, self.node, model_name) | ||||
|         if not dialog.has_error: | ||||
|             dialog.show() | ||||
| 
 | ||||
|  |  | |||
|  | @ -113,8 +113,9 @@ class HooksDialog(Dialog): | |||
|         listbox_scroll.grid(sticky="nsew", pady=PADY) | ||||
|         self.listbox = listbox_scroll.listbox | ||||
|         self.listbox.bind("<<ListboxSelect>>", self.select) | ||||
|         for hook_file in self.app.core.hooks: | ||||
|             self.listbox.insert(tk.END, hook_file) | ||||
|         session = self.app.core.session | ||||
|         for file in session.hooks: | ||||
|             self.listbox.insert(tk.END, file) | ||||
| 
 | ||||
|         frame = ttk.Frame(self.top) | ||||
|         frame.grid(sticky="ew") | ||||
|  | @ -138,20 +139,22 @@ class HooksDialog(Dialog): | |||
|         dialog.show() | ||||
|         hook = dialog.hook | ||||
|         if hook: | ||||
|             self.app.core.hooks[hook.file] = hook | ||||
|             self.app.core.session.hooks[hook.file] = hook | ||||
|             self.listbox.insert(tk.END, hook.file) | ||||
| 
 | ||||
|     def click_edit(self) -> None: | ||||
|         hook = self.app.core.hooks.pop(self.selected) | ||||
|         session = self.app.core.session | ||||
|         hook = session.hooks.pop(self.selected) | ||||
|         dialog = HookDialog(self, self.app) | ||||
|         dialog.set(hook) | ||||
|         dialog.show() | ||||
|         self.app.core.hooks[hook.file] = hook | ||||
|         session.hooks[hook.file] = hook | ||||
|         self.listbox.delete(self.selected_index) | ||||
|         self.listbox.insert(self.selected_index, hook.file) | ||||
| 
 | ||||
|     def click_delete(self) -> None: | ||||
|         del self.app.core.hooks[self.selected] | ||||
|         session = self.app.core.session | ||||
|         del session.hooks[self.selected] | ||||
|         self.listbox.delete(tk.ANCHOR) | ||||
|         self.edit_button.config(state=tk.DISABLED) | ||||
|         self.delete_button.config(state=tk.DISABLED) | ||||
|  |  | |||
|  | @ -269,7 +269,7 @@ class LinkConfigurationDialog(Dialog): | |||
|             self.edge.asymmetric_link = None | ||||
| 
 | ||||
|         if self.app.core.is_runtime() and link.options: | ||||
|             session_id = self.app.core.session_id | ||||
|             session_id = self.app.core.session.id | ||||
|             self.app.core.client.edit_link( | ||||
|                 session_id, | ||||
|                 link.node1_id, | ||||
|  |  | |||
|  | @ -13,18 +13,16 @@ from core.gui.wrappers import ConfigOption, Node | |||
| 
 | ||||
| if TYPE_CHECKING: | ||||
|     from core.gui.app import Application | ||||
|     from core.gui.graph.node import CanvasNode | ||||
| 
 | ||||
| 
 | ||||
| class MobilityConfigDialog(Dialog): | ||||
|     def __init__(self, app: "Application", canvas_node: "CanvasNode") -> None: | ||||
|         super().__init__(app, f"{canvas_node.core_node.name} Mobility Configuration") | ||||
|         self.canvas_node: "CanvasNode" = canvas_node | ||||
|         self.node: Node = canvas_node.core_node | ||||
|     def __init__(self, app: "Application", node: Node) -> None: | ||||
|         super().__init__(app, f"{node.name} Mobility Configuration") | ||||
|         self.node: Node = node | ||||
|         self.config_frame: Optional[ConfigFrame] = None | ||||
|         self.has_error: bool = False | ||||
|         try: | ||||
|             config = self.canvas_node.mobility_config | ||||
|             config = self.node.mobility_config | ||||
|             if not config: | ||||
|                 config = self.app.core.get_mobility_config(self.node.id) | ||||
|             self.config: Dict[str, ConfigOption] = config | ||||
|  | @ -56,5 +54,5 @@ class MobilityConfigDialog(Dialog): | |||
| 
 | ||||
|     def click_apply(self) -> None: | ||||
|         self.config_frame.parse_config() | ||||
|         self.canvas_node.mobility_config = self.config | ||||
|         self.node.mobility_config = self.config | ||||
|         self.destroy() | ||||
|  |  | |||
|  | @ -1,38 +1,31 @@ | |||
| import tkinter as tk | ||||
| from tkinter import ttk | ||||
| from typing import TYPE_CHECKING, Dict, Optional | ||||
| from typing import TYPE_CHECKING, Optional | ||||
| 
 | ||||
| import grpc | ||||
| 
 | ||||
| from core.gui.dialogs.dialog import Dialog | ||||
| from core.gui.images import ImageEnum | ||||
| from core.gui.themes import PADX, PADY | ||||
| from core.gui.wrappers import ConfigOption, MobilityAction, Node | ||||
| from core.gui.wrappers import MobilityAction, Node | ||||
| 
 | ||||
| if TYPE_CHECKING: | ||||
|     from core.gui.app import Application | ||||
|     from core.gui.graph.node import CanvasNode | ||||
| 
 | ||||
| ICON_SIZE: int = 16 | ||||
| 
 | ||||
| 
 | ||||
| class MobilityPlayer: | ||||
|     def __init__( | ||||
|         self, | ||||
|         app: "Application", | ||||
|         canvas_node: "CanvasNode", | ||||
|         config: Dict[str, ConfigOption], | ||||
|     ) -> None: | ||||
|     def __init__(self, app: "Application", node: Node) -> None: | ||||
|         self.app: "Application" = app | ||||
|         self.canvas_node: "CanvasNode" = canvas_node | ||||
|         self.config: Dict[str, ConfigOption] = config | ||||
|         self.node: Node = node | ||||
|         self.dialog: Optional[MobilityPlayerDialog] = None | ||||
|         self.state: Optional[MobilityAction] = None | ||||
| 
 | ||||
|     def show(self) -> None: | ||||
|         if self.dialog: | ||||
|             self.dialog.destroy() | ||||
|         self.dialog = MobilityPlayerDialog(self.app, self.canvas_node, self.config) | ||||
|         self.dialog = MobilityPlayerDialog(self.app, self.node) | ||||
|         self.dialog.protocol("WM_DELETE_WINDOW", self.close) | ||||
|         if self.state == MobilityAction.START: | ||||
|             self.set_play() | ||||
|  | @ -64,20 +57,11 @@ class MobilityPlayer: | |||
| 
 | ||||
| 
 | ||||
| class MobilityPlayerDialog(Dialog): | ||||
|     def __init__( | ||||
|         self, | ||||
|         app: "Application", | ||||
|         canvas_node: "CanvasNode", | ||||
|         config: Dict[str, ConfigOption], | ||||
|     ) -> None: | ||||
|         super().__init__( | ||||
|             app, f"{canvas_node.core_node.name} Mobility Player", modal=False | ||||
|         ) | ||||
|     def __init__(self, app: "Application", node: Node) -> None: | ||||
|         super().__init__(app, f"{node.name} Mobility Player", modal=False) | ||||
|         self.resizable(False, False) | ||||
|         self.geometry("") | ||||
|         self.canvas_node: "CanvasNode" = canvas_node | ||||
|         self.node: Node = canvas_node.core_node | ||||
|         self.config: Dict[str, ConfigOption] = config | ||||
|         self.node: Node = node | ||||
|         self.play_button: Optional[ttk.Button] = None | ||||
|         self.pause_button: Optional[ttk.Button] = None | ||||
|         self.stop_button: Optional[ttk.Button] = None | ||||
|  | @ -85,9 +69,10 @@ class MobilityPlayerDialog(Dialog): | |||
|         self.draw() | ||||
| 
 | ||||
|     def draw(self) -> None: | ||||
|         config = self.node.mobility_config | ||||
|         self.top.columnconfigure(0, weight=1) | ||||
| 
 | ||||
|         file_name = self.config["file"].value | ||||
|         file_name = config["file"].value | ||||
|         label = ttk.Label(self.top, text=file_name) | ||||
|         label.grid(sticky="ew", pady=PADY) | ||||
| 
 | ||||
|  | @ -114,13 +99,13 @@ class MobilityPlayerDialog(Dialog): | |||
|         self.stop_button.image = image | ||||
|         self.stop_button.grid(row=0, column=2, sticky="ew", padx=PADX) | ||||
| 
 | ||||
|         loop = tk.IntVar(value=int(self.config["loop"].value == "1")) | ||||
|         loop = tk.IntVar(value=int(config["loop"].value == "1")) | ||||
|         checkbutton = ttk.Checkbutton( | ||||
|             frame, text="Loop?", variable=loop, state=tk.DISABLED | ||||
|         ) | ||||
|         checkbutton.grid(row=0, column=3, padx=PADX) | ||||
| 
 | ||||
|         rate = self.config["refresh_ms"].value | ||||
|         rate = config["refresh_ms"].value | ||||
|         label = ttk.Label(frame, text=f"rate {rate} ms") | ||||
|         label.grid(row=0, column=4) | ||||
| 
 | ||||
|  | @ -146,7 +131,7 @@ class MobilityPlayerDialog(Dialog): | |||
| 
 | ||||
|     def click_play(self) -> None: | ||||
|         self.set_play() | ||||
|         session_id = self.app.core.session_id | ||||
|         session_id = self.app.core.session.id | ||||
|         try: | ||||
|             self.app.core.client.mobility_action( | ||||
|                 session_id, self.node.id, MobilityAction.START.value | ||||
|  | @ -156,7 +141,7 @@ class MobilityPlayerDialog(Dialog): | |||
| 
 | ||||
|     def click_pause(self) -> None: | ||||
|         self.set_pause() | ||||
|         session_id = self.app.core.session_id | ||||
|         session_id = self.app.core.session.id | ||||
|         try: | ||||
|             self.app.core.client.mobility_action( | ||||
|                 session_id, self.node.id, MobilityAction.PAUSE.value | ||||
|  | @ -166,7 +151,7 @@ class MobilityPlayerDialog(Dialog): | |||
| 
 | ||||
|     def click_stop(self) -> None: | ||||
|         self.set_stop() | ||||
|         session_id = self.app.core.session_id | ||||
|         session_id = self.app.core.session.id | ||||
|         try: | ||||
|             self.app.core.client.mobility_action( | ||||
|                 session_id, self.node.id, MobilityAction.STOP.value | ||||
|  |  | |||
|  | @ -10,25 +10,24 @@ from core.gui.dialogs.configserviceconfig import ConfigServiceConfigDialog | |||
| from core.gui.dialogs.dialog import Dialog | ||||
| from core.gui.themes import FRAME_PAD, PADX, PADY | ||||
| from core.gui.widgets import CheckboxList, ListboxScroll | ||||
| from core.gui.wrappers import Node | ||||
| 
 | ||||
| if TYPE_CHECKING: | ||||
|     from core.gui.app import Application | ||||
|     from core.gui.graph.node import CanvasNode | ||||
| 
 | ||||
| 
 | ||||
| class NodeConfigServiceDialog(Dialog): | ||||
|     def __init__( | ||||
|         self, app: "Application", canvas_node: "CanvasNode", services: Set[str] = None | ||||
|         self, app: "Application", node: Node, services: Set[str] = None | ||||
|     ) -> None: | ||||
|         title = f"{canvas_node.core_node.name} Config Services" | ||||
|         title = f"{node.name} Config Services" | ||||
|         super().__init__(app, title) | ||||
|         self.canvas_node: "CanvasNode" = canvas_node | ||||
|         self.node_id: int = canvas_node.core_node.id | ||||
|         self.node: Node = node | ||||
|         self.groups: Optional[ListboxScroll] = None | ||||
|         self.services: Optional[CheckboxList] = None | ||||
|         self.current: Optional[ListboxScroll] = None | ||||
|         if services is None: | ||||
|             services = set(canvas_node.core_node.config_services) | ||||
|             services = set(node.config_services) | ||||
|         self.current_services: Set[str] = services | ||||
|         self.draw() | ||||
| 
 | ||||
|  | @ -102,7 +101,7 @@ class NodeConfigServiceDialog(Dialog): | |||
|         elif not var.get() and name in self.current_services: | ||||
|             self.current_services.remove(name) | ||||
|         self.draw_current_services() | ||||
|         self.canvas_node.core_node.config_services[:] = self.current_services | ||||
|         self.node.config_services[:] = self.current_services | ||||
| 
 | ||||
|     def click_configure(self) -> None: | ||||
|         current_selection = self.current.listbox.curselection() | ||||
|  | @ -111,8 +110,7 @@ class NodeConfigServiceDialog(Dialog): | |||
|                 self, | ||||
|                 self.app, | ||||
|                 self.current.listbox.get(current_selection[0]), | ||||
|                 self.canvas_node, | ||||
|                 self.node_id, | ||||
|                 self.node, | ||||
|             ) | ||||
|             if not dialog.has_error: | ||||
|                 dialog.show() | ||||
|  | @ -132,10 +130,8 @@ class NodeConfigServiceDialog(Dialog): | |||
|                 self.current.listbox.itemconfig(tk.END, bg="green") | ||||
| 
 | ||||
|     def click_save(self) -> None: | ||||
|         self.canvas_node.core_node.config_services[:] = self.current_services | ||||
|         logging.info( | ||||
|             "saved node config services: %s", self.canvas_node.core_node.config_services | ||||
|         ) | ||||
|         self.node.config_services[:] = self.current_services | ||||
|         logging.info("saved node config services: %s", self.node.config_services) | ||||
|         self.destroy() | ||||
| 
 | ||||
|     def click_cancel(self) -> None: | ||||
|  | @ -154,4 +150,4 @@ class NodeConfigServiceDialog(Dialog): | |||
|                     return | ||||
| 
 | ||||
|     def is_custom_service(self, service: str) -> bool: | ||||
|         return service in self.canvas_node.config_service_configs | ||||
|         return service in self.node.config_service_configs | ||||
|  |  | |||
|  | @ -9,22 +9,21 @@ from core.gui.dialogs.dialog import Dialog | |||
| from core.gui.dialogs.serviceconfig import ServiceConfigDialog | ||||
| from core.gui.themes import FRAME_PAD, PADX, PADY | ||||
| from core.gui.widgets import CheckboxList, ListboxScroll | ||||
| from core.gui.wrappers import Node | ||||
| 
 | ||||
| if TYPE_CHECKING: | ||||
|     from core.gui.app import Application | ||||
|     from core.gui.graph.node import CanvasNode | ||||
| 
 | ||||
| 
 | ||||
| class NodeServiceDialog(Dialog): | ||||
|     def __init__(self, app: "Application", canvas_node: "CanvasNode") -> None: | ||||
|         title = f"{canvas_node.core_node.name} Services" | ||||
|     def __init__(self, app: "Application", node: Node) -> None: | ||||
|         title = f"{node.name} Services" | ||||
|         super().__init__(app, title) | ||||
|         self.canvas_node: "CanvasNode" = canvas_node | ||||
|         self.node_id: int = canvas_node.core_node.id | ||||
|         self.node: Node = node | ||||
|         self.groups: Optional[ListboxScroll] = None | ||||
|         self.services: Optional[CheckboxList] = None | ||||
|         self.current: Optional[ListboxScroll] = None | ||||
|         services = set(canvas_node.core_node.services) | ||||
|         services = set(node.services) | ||||
|         self.current_services: Set[str] = services | ||||
|         self.draw() | ||||
| 
 | ||||
|  | @ -104,7 +103,7 @@ class NodeServiceDialog(Dialog): | |||
|             self.current.listbox.insert(tk.END, name) | ||||
|             if self.is_custom_service(name): | ||||
|                 self.current.listbox.itemconfig(tk.END, bg="green") | ||||
|         self.canvas_node.core_node.services[:] = self.current_services | ||||
|         self.node.services = self.current_services.copy() | ||||
| 
 | ||||
|     def click_configure(self) -> None: | ||||
|         current_selection = self.current.listbox.curselection() | ||||
|  | @ -113,8 +112,7 @@ class NodeServiceDialog(Dialog): | |||
|                 self, | ||||
|                 self.app, | ||||
|                 self.current.listbox.get(current_selection[0]), | ||||
|                 self.canvas_node, | ||||
|                 self.node_id, | ||||
|                 self.node, | ||||
|             ) | ||||
| 
 | ||||
|             # if error occurred when creating ServiceConfigDialog, don't show the dialog | ||||
|  | @ -128,8 +126,7 @@ class NodeServiceDialog(Dialog): | |||
|             ) | ||||
| 
 | ||||
|     def click_save(self) -> None: | ||||
|         core_node = self.canvas_node.core_node | ||||
|         core_node.services[:] = self.current_services | ||||
|         self.node.services[:] = self.current_services | ||||
|         self.destroy() | ||||
| 
 | ||||
|     def click_remove(self) -> None: | ||||
|  | @ -144,6 +141,6 @@ class NodeServiceDialog(Dialog): | |||
|                     return | ||||
| 
 | ||||
|     def is_custom_service(self, service: str) -> bool: | ||||
|         has_service_config = service in self.canvas_node.service_configs | ||||
|         has_file_config = service in self.canvas_node.service_file_configs | ||||
|         has_service_config = service in self.node.service_configs | ||||
|         has_file_config = service in self.node.service_file_configs | ||||
|         return has_service_config or has_file_config | ||||
|  |  | |||
|  | @ -107,7 +107,7 @@ class RunToolDialog(Dialog): | |||
|             node_name = self.node_list.listbox.get(selection) | ||||
|             node_id = self.executable_nodes[node_name] | ||||
|             response = self.app.core.client.node_command( | ||||
|                 self.app.core.session_id, node_id, command | ||||
|                 self.app.core.session.id, node_id, command | ||||
|             ) | ||||
|             self.result.text.insert( | ||||
|                 tk.END, f"> {node_name} > {command}:\n{response.output}\n" | ||||
|  |  | |||
|  | @ -12,11 +12,10 @@ from core.gui.dialogs.dialog import Dialog | |||
| from core.gui.images import ImageEnum, Images | ||||
| from core.gui.themes import FRAME_PAD, PADX, PADY | ||||
| from core.gui.widgets import CodeText, ListboxScroll | ||||
| from core.gui.wrappers import NodeServiceData, ServiceValidationMode | ||||
| from core.gui.wrappers import Node, NodeServiceData, ServiceValidationMode | ||||
| 
 | ||||
| if TYPE_CHECKING: | ||||
|     from core.gui.app import Application | ||||
|     from core.gui.graph.node import CanvasNode | ||||
|     from core.gui.coreclient import CoreClient | ||||
| 
 | ||||
| ICON_SIZE: int = 16 | ||||
|  | @ -24,18 +23,12 @@ ICON_SIZE: int = 16 | |||
| 
 | ||||
| class ServiceConfigDialog(Dialog): | ||||
|     def __init__( | ||||
|         self, | ||||
|         master: tk.BaseWidget, | ||||
|         app: "Application", | ||||
|         service_name: str, | ||||
|         canvas_node: "CanvasNode", | ||||
|         node_id: int, | ||||
|         self, master: tk.BaseWidget, app: "Application", service_name: str, node: Node | ||||
|     ) -> None: | ||||
|         title = f"{service_name} Service" | ||||
|         super().__init__(app, title, master=master) | ||||
|         self.core: "CoreClient" = app.core | ||||
|         self.canvas_node: "CanvasNode" = canvas_node | ||||
|         self.node_id: int = node_id | ||||
|         self.node: Node = node | ||||
|         self.service_name: str = service_name | ||||
|         self.radiovar: tk.IntVar = tk.IntVar(value=2) | ||||
|         self.metadata: str = "" | ||||
|  | @ -84,15 +77,13 @@ class ServiceConfigDialog(Dialog): | |||
|         try: | ||||
|             self.app.core.create_nodes_and_links() | ||||
|             default_config = self.app.core.get_node_service( | ||||
|                 self.node_id, self.service_name | ||||
|                 self.node.id, self.service_name | ||||
|             ) | ||||
|             self.default_startup = default_config.startup[:] | ||||
|             self.default_validate = default_config.validate[:] | ||||
|             self.default_shutdown = default_config.shutdown[:] | ||||
|             self.default_directories = default_config.dirs[:] | ||||
|             custom_service_config = self.canvas_node.service_configs.get( | ||||
|                 self.service_name | ||||
|             ) | ||||
|             custom_service_config = self.node.service_configs.get(self.service_name) | ||||
|             self.default_config = default_config | ||||
|             service_config = ( | ||||
|                 custom_service_config if custom_service_config else default_config | ||||
|  | @ -109,15 +100,13 @@ class ServiceConfigDialog(Dialog): | |||
|             self.temp_directories = service_config.dirs[:] | ||||
|             self.original_service_files = { | ||||
|                 x: self.app.core.get_node_service_file( | ||||
|                     self.node_id, self.service_name, x | ||||
|                     self.node.id, self.service_name, x | ||||
|                 ) | ||||
|                 for x in default_config.configs | ||||
|             } | ||||
|             self.temp_service_files = dict(self.original_service_files) | ||||
| 
 | ||||
|             file_configs = self.canvas_node.service_file_configs.get( | ||||
|                 self.service_name, {} | ||||
|             ) | ||||
|             file_configs = self.node.service_file_configs.get(self.service_name, {}) | ||||
|             for file, data in file_configs.items(): | ||||
|                 self.temp_service_files[file] = data | ||||
|         except grpc.RpcError as e: | ||||
|  | @ -453,7 +442,7 @@ class ServiceConfigDialog(Dialog): | |||
|             and not self.has_new_files() | ||||
|             and not self.is_custom_directory() | ||||
|         ): | ||||
|             self.canvas_node.service_configs.pop(self.service_name, None) | ||||
|             self.node.service_configs.pop(self.service_name, None) | ||||
|             self.current_service_color("") | ||||
|             self.destroy() | ||||
|             return | ||||
|  | @ -466,7 +455,7 @@ class ServiceConfigDialog(Dialog): | |||
|             ): | ||||
|                 startup, validate, shutdown = self.get_commands() | ||||
|                 config = self.core.set_node_service( | ||||
|                     self.node_id, | ||||
|                     self.node.id, | ||||
|                     self.service_name, | ||||
|                     dirs=self.temp_directories, | ||||
|                     files=list(self.filename_combobox["values"]), | ||||
|  | @ -474,15 +463,15 @@ class ServiceConfigDialog(Dialog): | |||
|                     validations=validate, | ||||
|                     shutdowns=shutdown, | ||||
|                 ) | ||||
|                 self.canvas_node.service_configs[self.service_name] = config | ||||
|                 self.node.service_configs[self.service_name] = config | ||||
|             for file in self.modified_files: | ||||
|                 file_configs = self.canvas_node.service_file_configs.setdefault( | ||||
|                 file_configs = self.node.service_file_configs.setdefault( | ||||
|                     self.service_name, {} | ||||
|                 ) | ||||
|                 file_configs[file] = self.temp_service_files[file] | ||||
|                 # TODO: check if this is really needed | ||||
|                 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] | ||||
|                 ) | ||||
|             self.current_service_color("green") | ||||
|         except grpc.RpcError as e: | ||||
|  | @ -526,8 +515,8 @@ class ServiceConfigDialog(Dialog): | |||
|         clears out any custom configuration permanently | ||||
|         """ | ||||
|         # clear coreclient data | ||||
|         self.canvas_node.service_configs.pop(self.service_name, None) | ||||
|         file_configs = self.canvas_node.service_file_configs.pop(self.service_name, {}) | ||||
|         self.node.service_configs.pop(self.service_name, None) | ||||
|         file_configs = self.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.modified_files.clear() | ||||
|  | @ -564,9 +553,8 @@ class ServiceConfigDialog(Dialog): | |||
| 
 | ||||
|     def click_copy(self) -> None: | ||||
|         file_name = self.filename_combobox.get() | ||||
|         name = self.canvas_node.core_node.name | ||||
|         dialog = CopyServiceConfigDialog( | ||||
|             self.app, self, name, self.service_name, file_name | ||||
|             self.app, self, self.node.name, self.service_name, file_name | ||||
|         ) | ||||
|         dialog.show() | ||||
| 
 | ||||
|  |  | |||
|  | @ -26,7 +26,7 @@ class SessionOptionsDialog(Dialog): | |||
| 
 | ||||
|     def get_config(self) -> Dict[str, ConfigOption]: | ||||
|         try: | ||||
|             session_id = self.app.core.session_id | ||||
|             session_id = self.app.core.session.id | ||||
|             response = self.app.core.client.get_session_options(session_id) | ||||
|             return ConfigOption.from_dict(response.config) | ||||
|         except grpc.RpcError as e: | ||||
|  | @ -54,7 +54,7 @@ class SessionOptionsDialog(Dialog): | |||
|     def save(self) -> None: | ||||
|         config = self.config_frame.parse_config() | ||||
|         try: | ||||
|             session_id = self.app.core.session_id | ||||
|             session_id = self.app.core.session.id | ||||
|             response = self.app.core.client.set_session_options(session_id, config) | ||||
|             logging.info("saved session config: %s", response) | ||||
|         except grpc.RpcError as e: | ||||
|  |  | |||
|  | @ -201,7 +201,7 @@ class SessionsDialog(Dialog): | |||
|         logging.debug("delete session: %s", self.selected_session) | ||||
|         self.tree.delete(self.selected_id) | ||||
|         self.app.core.delete_session(self.selected_session) | ||||
|         if self.selected_session == self.app.core.session_id: | ||||
|         if self.selected_session == self.app.core.session.id: | ||||
|             self.click_new() | ||||
|             self.destroy() | ||||
|         self.click_select() | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ class WlanConfigDialog(Dialog): | |||
|         self.ranges: Dict[int, int] = {} | ||||
|         self.positive_int: int = self.app.master.register(self.validate_and_update) | ||||
|         try: | ||||
|             config = self.canvas_node.wlan_config | ||||
|             config = self.node.wlan_config | ||||
|             if not config: | ||||
|                 config = self.app.core.get_wlan_config(self.node.id) | ||||
|             self.config: Dict[str, ConfigOption] = config | ||||
|  | @ -83,9 +83,9 @@ class WlanConfigDialog(Dialog): | |||
|         retrieve user's wlan configuration and store the new configuration values | ||||
|         """ | ||||
|         config = self.config_frame.parse_config() | ||||
|         self.canvas_node.wlan_config = self.config | ||||
|         self.node.wlan_config = self.config | ||||
|         if self.app.core.is_runtime(): | ||||
|             session_id = self.app.core.session_id | ||||
|             session_id = self.app.core.session.id | ||||
|             self.app.core.client.set_wlan_config(session_id, self.node.id, config) | ||||
|         self.remove_ranges() | ||||
|         self.destroy() | ||||
|  |  | |||
|  | @ -940,16 +940,19 @@ class CanvasGraph(tk.Canvas): | |||
|             if not copy: | ||||
|                 continue | ||||
|             node = CanvasNode(self.app, scaled_x, scaled_y, copy, canvas_node.image) | ||||
| 
 | ||||
|             # copy configurations and services | ||||
|             node.core_node.services[:] = canvas_node.core_node.services | ||||
|             node.core_node.config_services[:] = canvas_node.core_node.config_services | ||||
|             node.emane_model_configs = deepcopy(canvas_node.emane_model_configs) | ||||
|             node.wlan_config = deepcopy(canvas_node.wlan_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) | ||||
|             node.config_service_configs = deepcopy(canvas_node.config_service_configs) | ||||
|             node.core_node.services = core_node.services.copy() | ||||
|             node.core_node.config_services = core_node.config_services.copy() | ||||
|             node.core_node.emane_model_configs = deepcopy(core_node.emane_model_configs) | ||||
|             node.core_node.wlan_config = deepcopy(core_node.wlan_config) | ||||
|             node.core_node.mobility_config = deepcopy(core_node.mobility_config) | ||||
|             node.core_node.service_configs = deepcopy(core_node.service_configs) | ||||
|             node.core_node.service_file_configs = deepcopy( | ||||
|                 core_node.service_file_configs | ||||
|             ) | ||||
|             node.core_node.config_service_configs = deepcopy( | ||||
|                 core_node.config_service_configs | ||||
|             ) | ||||
| 
 | ||||
|             copy_map[canvas_node.id] = node.id | ||||
|             self.core.canvas_nodes[copy.id] = node | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import functools | ||||
| import logging | ||||
| import tkinter as tk | ||||
| from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Tuple | ||||
| from typing import TYPE_CHECKING, Dict, List, Set | ||||
| 
 | ||||
| import grpc | ||||
| from PIL.ImageTk import PhotoImage | ||||
|  | @ -19,7 +19,7 @@ from core.gui.graph.edges import CanvasEdge, CanvasWirelessEdge | |||
| from core.gui.graph.tooltip import CanvasTooltip | ||||
| from core.gui.images import ImageEnum | ||||
| from core.gui.nodeutils import ANTENNA_SIZE, NodeUtils | ||||
| from core.gui.wrappers import ConfigOption, Interface, Node, NodeServiceData, NodeType | ||||
| from core.gui.wrappers import Interface, Node, NodeType | ||||
| 
 | ||||
| if TYPE_CHECKING: | ||||
|     from core.gui.app import Application | ||||
|  | @ -56,15 +56,6 @@ class CanvasNode: | |||
|         self.wireless_edges: Set[CanvasWirelessEdge] = set() | ||||
|         self.antennas: List[int] = [] | ||||
|         self.antenna_images: Dict[int, PhotoImage] = {} | ||||
|         # possible configurations | ||||
|         self.emane_model_configs: Dict[ | ||||
|             Tuple[str, Optional[int]], Dict[str, ConfigOption] | ||||
|         ] = {} | ||||
|         self.wlan_config: Dict[str, ConfigOption] = {} | ||||
|         self.mobility_config: Dict[str, ConfigOption] = {} | ||||
|         self.service_configs: Dict[str, NodeServiceData] = {} | ||||
|         self.service_file_configs: Dict[str, Dict[str, str]] = {} | ||||
|         self.config_service_configs: Dict[str, Any] = {} | ||||
|         self.setup_bindings() | ||||
|         self.context: tk.Menu = tk.Menu(self.canvas) | ||||
|         themes.style_menu(self.context) | ||||
|  | @ -299,7 +290,7 @@ class CanvasNode: | |||
|             dialog.show() | ||||
| 
 | ||||
|     def show_mobility_config(self) -> None: | ||||
|         dialog = MobilityConfigDialog(self.app, self) | ||||
|         dialog = MobilityConfigDialog(self.app, self.core_node) | ||||
|         if not dialog.has_error: | ||||
|             dialog.show() | ||||
| 
 | ||||
|  | @ -308,15 +299,15 @@ class CanvasNode: | |||
|         mobility_player.show() | ||||
| 
 | ||||
|     def show_emane_config(self) -> None: | ||||
|         dialog = EmaneConfigDialog(self.app, self) | ||||
|         dialog = EmaneConfigDialog(self.app, self.core_node) | ||||
|         dialog.show() | ||||
| 
 | ||||
|     def show_services(self) -> None: | ||||
|         dialog = NodeServiceDialog(self.app, self) | ||||
|         dialog = NodeServiceDialog(self.app, self.core_node) | ||||
|         dialog.show() | ||||
| 
 | ||||
|     def show_config_services(self) -> None: | ||||
|         dialog = NodeConfigServiceDialog(self.app, self) | ||||
|         dialog = NodeConfigServiceDialog(self.app, self.core_node) | ||||
|         dialog.show() | ||||
| 
 | ||||
|     def has_emane_link(self, iface_id: int) -> Node: | ||||
|  |  | |||
|  | @ -33,7 +33,6 @@ class ProgressTask: | |||
|         thread.start() | ||||
| 
 | ||||
|     def run(self) -> None: | ||||
|         logging.info("running task") | ||||
|         try: | ||||
|             values = self.task(*self.args) | ||||
|             if values is None: | ||||
|  | @ -41,7 +40,6 @@ class ProgressTask: | |||
|             elif values and not isinstance(values, tuple): | ||||
|                 values = (values,) | ||||
|             if self.callback: | ||||
|                 logging.info("calling callback") | ||||
|                 self.app.after(0, self.callback, *values) | ||||
|         except Exception as e: | ||||
|             logging.exception("progress task exception") | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| from dataclasses import dataclass, field | ||||
| from enum import Enum | ||||
| from typing import Dict, List, Optional, Tuple | ||||
| from typing import Dict, List, Optional, Set, Tuple | ||||
| 
 | ||||
| from core.api.grpc import common_pb2, configservices_pb2, core_pb2, services_pb2 | ||||
| 
 | ||||
|  | @ -121,8 +121,8 @@ class ConfigService: | |||
| 
 | ||||
| @dataclass | ||||
| class ConfigServiceData: | ||||
|     templates: Dict[str, str] | ||||
|     config: Dict[str, str] | ||||
|     templates: Dict[str, str] = field(default_factory=dict) | ||||
|     config: Dict[str, str] = field(default_factory=dict) | ||||
| 
 | ||||
| 
 | ||||
| @dataclass | ||||
|  | @ -504,8 +504,8 @@ class Node: | |||
|     type: NodeType | ||||
|     model: str = None | ||||
|     position: Position = None | ||||
|     services: List[str] = field(default_factory=list) | ||||
|     config_services: List[str] = field(default_factory=list) | ||||
|     services: Set[str] = field(default_factory=set) | ||||
|     config_services: Set[str] = field(default_factory=set) | ||||
|     emane: str = None | ||||
|     icon: str = None | ||||
|     image: str = None | ||||
|  | @ -538,8 +538,8 @@ class Node: | |||
|             type=NodeType(proto.type), | ||||
|             model=proto.model, | ||||
|             position=Position.from_proto(proto.position), | ||||
|             services=list(proto.services), | ||||
|             config_services=list(proto.config_services), | ||||
|             services=set(proto.services), | ||||
|             config_services=set(proto.config_services), | ||||
|             emane=proto.emane, | ||||
|             icon=proto.icon, | ||||
|             image=proto.image, | ||||
|  | @ -575,9 +575,9 @@ class Session: | |||
|     links: List[Link] | ||||
|     dir: str | ||||
|     user: str | ||||
|     default_services: Dict[str, List[str]] | ||||
|     default_services: Dict[str, Set[str]] | ||||
|     location: SessionLocation | ||||
|     hooks: List[Hook] | ||||
|     hooks: Dict[str, Hook] | ||||
|     emane_models: List[str] | ||||
|     emane_config: Dict[str, ConfigOption] | ||||
|     metadata: Dict[str, str] | ||||
|  | @ -586,8 +586,10 @@ class Session: | |||
|     def from_proto(cls, proto: core_pb2.Session) -> "Session": | ||||
|         nodes: Dict[int, Node] = {x.id: Node.from_proto(x) for x in proto.nodes} | ||||
|         links = [Link.from_proto(x) for x in proto.links] | ||||
|         default_services = {x.node_type: x.services for x in proto.default_services} | ||||
|         hooks = [Hook.from_proto(x) for x in proto.hooks] | ||||
|         default_services = { | ||||
|             x.node_type: set(x.services) for x in proto.default_services | ||||
|         } | ||||
|         hooks = {x.file: Hook.from_proto(x) for x in proto.hooks} | ||||
|         # update nodes with their current configurations | ||||
|         for model in proto.emane_model_configs: | ||||
|             iface_id = None | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue