pygui: changes to make use of wrapped session object and wrapped nodes to maintain and retrieving configurations information

This commit is contained in:
Blake Harnden 2020-07-28 00:03:15 -07:00
parent 3bdd6292cd
commit 588afaad13
21 changed files with 284 additions and 455 deletions

View file

@ -580,6 +580,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
service_configs = grpcutils.get_node_service_configs(session) service_configs = grpcutils.get_node_service_configs(session)
config_service_configs = grpcutils.get_node_config_service_configs(session) config_service_configs = grpcutils.get_node_config_service_configs(session)
session_proto = core_pb2.Session( session_proto = core_pb2.Session(
id=session.id,
state=session.state.value, state=session.state.value,
nodes=nodes, nodes=nodes,
links=links, links=links,

View file

@ -37,7 +37,6 @@ from core.gui.wrappers import (
ConfigOption, ConfigOption,
ConfigService, ConfigService,
ExceptionEvent, ExceptionEvent,
Hook,
Interface, Interface,
Link, Link,
LinkEvent, LinkEvent,
@ -61,6 +60,10 @@ GUI_SOURCE = "gui"
CPU_USAGE_DELAY = 3 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: class CoreClient:
def __init__(self, app: "Application", proxy: bool) -> None: def __init__(self, app: "Application", proxy: bool) -> None:
""" """
@ -69,14 +72,13 @@ class CoreClient:
self.app: "Application" = app self.app: "Application" = app
self.master: tk.Tk = app.master self.master: tk.Tk = app.master
self._client: client.CoreGrpcClient = client.CoreGrpcClient(proxy=proxy) 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.services: Dict[str, Set[str]] = {}
self.config_services_groups: Dict[str, Set[str]] = {} self.config_services_groups: Dict[str, Set[str]] = {}
self.config_services: Dict[str, ConfigService] = {} 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 # loaded configuration data
self.servers: Dict[str, CoreServer] = {} self.servers: Dict[str, CoreServer] = {}
@ -87,15 +89,12 @@ class CoreClient:
# helpers # helpers
self.iface_to_edge: Dict[Tuple[int, ...], Tuple[int, ...]] = {} self.iface_to_edge: Dict[Tuple[int, ...], Tuple[int, ...]] = {}
self.ifaces_manager: InterfaceManager = InterfaceManager(self.app) self.ifaces_manager: InterfaceManager = InterfaceManager(self.app)
self.observer: Optional[str] = None
# session data # 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.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_throughputs: Optional[grpc.Future] = None
self.handling_cpu_usage: Optional[grpc.Future] = None self.handling_cpu_usage: Optional[grpc.Future] = None
self.handling_events: Optional[grpc.Future] = None self.handling_events: Optional[grpc.Future] = None
@ -104,15 +103,15 @@ class CoreClient:
@property @property
def client(self) -> client.CoreGrpcClient: def client(self) -> client.CoreGrpcClient:
if self.session_id: if self.session:
response = self._client.check_session(self.session_id) response = self._client.check_session(self.session.id)
if not response.result: if not response.result:
throughputs_enabled = self.handling_throughputs is not None throughputs_enabled = self.handling_throughputs is not None
self.cancel_throughputs() self.cancel_throughputs()
self.cancel_events() self.cancel_events()
self._client.create_session(self.session_id) self._client.create_session(self.session.id)
self.handling_events = self._client.events( self.handling_events = self._client.events(
self.session_id, self.handle_events self.session.id, self.handle_events
) )
if throughputs_enabled: if throughputs_enabled:
self.enable_throughputs() self.enable_throughputs()
@ -126,8 +125,6 @@ class CoreClient:
# session data # session data
self.canvas_nodes.clear() self.canvas_nodes.clear()
self.links.clear() self.links.clear()
self.hooks.clear()
self.emane_config = None
self.close_mobility_players() self.close_mobility_players()
self.mobility_players.clear() self.mobility_players.clear()
# clear streams # clear streams
@ -145,12 +142,10 @@ class CoreClient:
# read distributed servers # read distributed servers
for server in self.app.guiconfig.servers: for server in self.app.guiconfig.servers:
self.servers[server.name] = server self.servers[server.name] = server
# read custom nodes # read custom nodes
for custom_node in self.app.guiconfig.nodes: for custom_node in self.app.guiconfig.nodes:
node_draw = NodeDraw.from_custom(custom_node) node_draw = NodeDraw.from_custom(custom_node)
self.custom_nodes[custom_node.name] = node_draw self.custom_nodes[custom_node.name] = node_draw
# read observers # read observers
for observer in self.app.guiconfig.observers: for observer in self.app.guiconfig.observers:
self.custom_observers[observer.name] = observer self.custom_observers[observer.name] = observer
@ -158,11 +153,11 @@ class CoreClient:
def handle_events(self, event: core_pb2.Event) -> None: def handle_events(self, event: core_pb2.Event) -> None:
if event.source == GUI_SOURCE: if event.source == GUI_SOURCE:
return return
if event.session_id != self.session_id: if event.session_id != self.session.id:
logging.warning( logging.warning(
"ignoring event session(%s) current(%s)", "ignoring event session(%s) current(%s)",
event.session_id, event.session_id,
self.session_id, self.session.id,
) )
return return
@ -173,7 +168,7 @@ class CoreClient:
logging.info("session event: %s", event) logging.info("session event: %s", event)
session_event = event.session_event session_event = event.session_event
if session_event.event <= SessionState.SHUTDOWN.value: 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}: elif session_event.event in {7, 8, 9}:
node_id = session_event.node_id node_id = session_event.node_id
dialog = self.mobility_players.get(node_id) dialog = self.mobility_players.get(node_id)
@ -253,7 +248,7 @@ class CoreClient:
def enable_throughputs(self) -> None: def enable_throughputs(self) -> None:
self.handling_throughputs = self.client.throughputs( self.handling_throughputs = self.client.throughputs(
self.session_id, self.handle_throughputs self.session.id, self.handle_throughputs
) )
def cancel_throughputs(self) -> None: def cancel_throughputs(self) -> None:
@ -283,11 +278,11 @@ class CoreClient:
def handle_throughputs(self, event: core_pb2.ThroughputsEvent) -> None: def handle_throughputs(self, event: core_pb2.ThroughputsEvent) -> None:
event = ThroughputsEvent.from_proto(event) event = ThroughputsEvent.from_proto(event)
if event.session_id != self.session_id: if event.session_id != self.session.id:
logging.warning( logging.warning(
"ignoring throughput event session(%s) current(%s)", "ignoring throughput event session(%s) current(%s)",
event.session_id, event.session_id,
self.session_id, self.session.id,
) )
return return
logging.debug("handling throughputs event: %s", event) logging.debug("handling throughputs event: %s", event)
@ -300,126 +295,33 @@ class CoreClient:
logging.info("exception event: %s", event) logging.info("exception event: %s", event)
self.app.statusbar.add_alert(event) self.app.statusbar.add_alert(event)
def join_session(self, session_id: int, query_location: bool = True) -> None: def join_session(self, session_id: int) -> None:
logging.info("join session(%s)", session_id) logging.info("joining 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
self.reset() self.reset()
# get session data
try: try:
response = self.client.get_session(self.session_id) response = self.client.get_session(session_id)
session = Session.from_proto(response.session) self.session = Session.from_proto(response.session)
self.state = session.state 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.handling_events = self.client.events(
self.session_id, self.handle_events self.session.id, self.handle_events
) )
self.ifaces_manager.joined(self.session.links)
# set session user self.app.canvas.reset_and_redraw(self.session)
self.client.set_session_user(self.session_id, self.user) self.parse_metadata()
self.app.canvas.organize()
# get session service defaults if self.is_runtime():
response = self.client.get_service_defaults(self.session_id) self.show_mobility_players()
self.default_services = { self.app.after(0, self.app.joined_session_update)
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)
except grpc.RpcError as e: except grpc.RpcError as e:
self.app.show_grpc_exception("Join Session Error", 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: 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 # canvas setting
config = self.session.metadata
canvas_config = config.get("canvas") canvas_config = config.get("canvas")
logging.debug("canvas metadata: %s", canvas_config) logging.debug("canvas metadata: %s", canvas_config)
if canvas_config: if canvas_config:
@ -447,7 +349,7 @@ class CoreClient:
if shapes_config: if shapes_config:
shapes_config = json.loads(shapes_config) shapes_config = json.loads(shapes_config)
for shape_config in 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"] shape_type = shape_config["type"]
try: try:
shape_type = ShapeType(shape_type) shape_type = ShapeType(shape_type)
@ -478,8 +380,9 @@ class CoreClient:
try: try:
response = self.client.create_session() response = self.client.create_session()
logging.info("created session: %s", response) logging.info("created session: %s", response)
self.join_session(response.session_id)
location_config = self.app.guiconfig.location location_config = self.app.guiconfig.location
self.location = SessionLocation( self.session.location = SessionLocation(
x=location_config.x, x=location_config.x,
y=location_config.y, y=location_config.y,
z=location_config.z, z=location_config.z,
@ -488,13 +391,12 @@ class CoreClient:
alt=location_config.alt, alt=location_config.alt,
scale=location_config.scale, scale=location_config.scale,
) )
self.join_session(response.session_id, query_location=False)
except grpc.RpcError as e: except grpc.RpcError as e:
self.app.show_grpc_exception("New Session Error", e) self.app.show_grpc_exception("New Session Error", e)
def delete_session(self, session_id: int = None) -> None: def delete_session(self, session_id: int = None) -> None:
if session_id is None: if session_id is None:
session_id = self.session_id session_id = self.session.id
try: try:
response = self.client.delete_session(session_id) response = self.client.delete_session(session_id)
logging.info("deleted session(%s), Result: %s", session_id, response) logging.info("deleted session(%s), Result: %s", session_id, response)
@ -507,13 +409,11 @@ class CoreClient:
""" """
try: try:
self.client.connect() self.client.connect()
# get all available services
# get service information
response = self.client.get_services() response = self.client.get_services()
for service in response.services: for service in response.services:
group_services = self.services.setdefault(service.group, set()) group_services = self.services.setdefault(service.group, set())
group_services.add(service.name) group_services.add(service.name)
# get config service informations # get config service informations
response = self.client.get_config_services() response = self.client.get_config_services()
for service in response.services: for service in response.services:
@ -522,7 +422,6 @@ class CoreClient:
service.group, set() service.group, set()
) )
group_services.add(service.name) group_services.add(service.name)
# join provided session, create new session, or show dialog to select an # join provided session, create new session, or show dialog to select an
# existing session # existing session
response = self.client.get_sessions() response = self.client.get_sessions()
@ -553,14 +452,14 @@ class CoreClient:
try: try:
position = core_node.position.to_proto() position = core_node.position.to_proto()
self.client.edit_node( 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: except grpc.RpcError as e:
self.app.show_grpc_exception("Edit Node Error", e) self.app.show_grpc_exception("Edit Node Error", e)
def send_servers(self) -> None: def send_servers(self) -> None:
for server in self.servers.values(): 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]]: def start_session(self) -> Tuple[bool, List[str]]:
self.ifaces_manager.reset_mac() self.ifaces_manager.reset_mac()
@ -576,26 +475,23 @@ class CoreClient:
wlan_configs = self.get_wlan_configs_proto() wlan_configs = self.get_wlan_configs_proto()
mobility_configs = self.get_mobility_configs_proto() mobility_configs = self.get_mobility_configs_proto()
emane_model_configs = self.get_emane_model_configs_proto() emane_model_configs = self.get_emane_model_configs_proto()
hooks = [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() service_configs = self.get_service_configs_proto()
file_configs = self.get_service_file_configs_proto() file_configs = self.get_service_file_configs_proto()
asymmetric_links = [ asymmetric_links = [
x.asymmetric_link for x in self.links.values() if x.asymmetric_link x.asymmetric_link for x in self.links.values() if x.asymmetric_link
] ]
config_service_configs = self.get_config_service_configs_proto() config_service_configs = self.get_config_service_configs_proto()
if self.emane_config: emane_config = to_dict(self.session.emane_config)
emane_config = {x: self.emane_config[x].value for x in self.emane_config}
else:
emane_config = None
result = False result = False
exceptions = [] exceptions = []
try: try:
self.send_servers() self.send_servers()
response = self.client.start_session( response = self.client.start_session(
self.session_id, self.session.id,
nodes, nodes,
links, links,
self.location.to_proto(), self.session.location.to_proto(),
hooks, hooks,
emane_config, emane_config,
emane_model_configs, emane_model_configs,
@ -607,7 +503,7 @@ class CoreClient:
config_service_configs, config_service_configs,
) )
logging.info( 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: if response.result:
self.set_metadata() self.set_metadata()
@ -619,7 +515,7 @@ class CoreClient:
def stop_session(self, session_id: int = None) -> bool: def stop_session(self, session_id: int = None) -> bool:
if not session_id: if not session_id:
session_id = self.session_id session_id = self.session.id
result = False result = False
try: try:
response = self.client.stop_session(session_id) response = self.client.stop_session(session_id)
@ -630,15 +526,12 @@ class CoreClient:
return result return result
def show_mobility_players(self) -> None: def show_mobility_players(self) -> None:
for canvas_node in self.canvas_nodes.values(): for node in self.session.nodes.values():
if canvas_node.core_node.type != NodeType.WIRELESS_LAN: if node.type != NodeType.WIRELESS_LAN:
continue continue
if canvas_node.mobility_config: if node.mobility_config:
mobility_player = MobilityPlayer( mobility_player = MobilityPlayer(self.app, node)
self.app, canvas_node, canvas_node.mobility_config self.mobility_players[node.id] = mobility_player
)
node_id = canvas_node.core_node.id
self.mobility_players[node_id] = mobility_player
mobility_player.show() mobility_player.show()
def set_metadata(self) -> None: def set_metadata(self) -> None:
@ -662,8 +555,8 @@ class CoreClient:
shapes = json.dumps(shapes) shapes = json.dumps(shapes)
metadata = {"canvas": canvas_config, "shapes": shapes} metadata = {"canvas": canvas_config, "shapes": shapes}
response = self.client.set_session_metadata(self.session_id, metadata) response = self.client.set_session_metadata(self.session.id, metadata)
logging.info("set session metadata %s, result: %s", metadata, response) logging.debug("set session metadata %s, result: %s", metadata, response)
def launch_terminal(self, node_id: int) -> None: def launch_terminal(self, node_id: int) -> None:
try: try:
@ -675,7 +568,7 @@ class CoreClient:
parent=self.app, parent=self.app,
) )
return 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} &" cmd = f"{terminal} {response.terminal} &"
logging.info("launching terminal %s", cmd) logging.info("launching terminal %s", cmd)
os.system(cmd) os.system(cmd)
@ -687,10 +580,10 @@ class CoreClient:
Save core session as to an xml file Save core session as to an xml file
""" """
try: try:
if self.state != SessionState.RUNTIME: if not self.is_runtime():
logging.debug("Send session data to the daemon") logging.debug("Send session data to the daemon")
self.send_data() 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) logging.info("saved xml file %s, result: %s", file_path, response)
except grpc.RpcError as e: except grpc.RpcError as e:
self.app.show_grpc_exception("Save XML Error", 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) self.app.show_grpc_exception("Open XML Error", e)
def get_node_service(self, node_id: int, service_name: str) -> NodeServiceData: 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( logging.debug(
"get node(%s) %s service, response: %s", node_id, service_name, response "get node(%s) %s service, response: %s", node_id, service_name, response
) )
@ -724,7 +617,7 @@ class CoreClient:
shutdowns: List[str], shutdowns: List[str],
) -> NodeServiceData: ) -> NodeServiceData:
response = self.client.set_node_service( response = self.client.set_node_service(
self.session_id, self.session.id,
node_id, node_id,
service_name, service_name,
directories=dirs, directories=dirs,
@ -744,14 +637,14 @@ class CoreClient:
shutdowns, shutdowns,
response, 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) return NodeServiceData.from_proto(response.service)
def get_node_service_file( def get_node_service_file(
self, node_id: int, service_name: str, file_name: str self, node_id: int, service_name: str, file_name: str
) -> str: ) -> str:
response = self.client.get_node_service_file( 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( logging.debug(
"get service file for node(%s), service: %s, file: %s, result: %s", "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 self, node_id: int, service_name: str, file_name: str, data: str
) -> None: ) -> None:
response = self.client.set_node_service_file( 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( logging.info(
"set node(%s) service file, service: %s, file: %s, data: %s, result: %s", "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()] 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()] 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: 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) logging.debug("create node: %s", response)
for link_proto in link_protos: for link_proto in link_protos:
response = self.client.add_link( response = self.client.add_link(
self.session_id, self.session.id,
link_proto.node1_id, link_proto.node1_id,
link_proto.node2_id, link_proto.node2_id,
link_proto.iface1, link_proto.iface1,
@ -806,15 +699,15 @@ class CoreClient:
self.create_nodes_and_links() self.create_nodes_and_links()
for config_proto in self.get_wlan_configs_proto(): for config_proto in self.get_wlan_configs_proto():
self.client.set_wlan_config( 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(): for config_proto in self.get_mobility_configs_proto():
self.client.set_mobility_config( 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(): for config_proto in self.get_service_configs_proto():
self.client.set_node_service( self.client.set_node_service(
self.session_id, self.session.id,
config_proto.node_id, config_proto.node_id,
config_proto.service, config_proto.service,
startup=config_proto.startup, startup=config_proto.startup,
@ -823,38 +716,37 @@ class CoreClient:
) )
for config_proto in self.get_service_file_configs_proto(): for config_proto in self.get_service_file_configs_proto():
self.client.set_node_service_file( self.client.set_node_service_file(
self.session_id, self.session.id,
config_proto.node_id, config_proto.node_id,
config_proto.service, config_proto.service,
config_proto.file, config_proto.file,
config_proto.data, config_proto.data,
) )
for hook in self.hooks.values(): for hook in self.session.hooks.values():
self.client.add_hook( 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(): for config_proto in self.get_emane_model_configs_proto():
self.client.set_emane_model_config( self.client.set_emane_model_config(
self.session_id, self.session.id,
config_proto.node_id, config_proto.node_id,
config_proto.model, config_proto.model,
config_proto.config, config_proto.config,
config_proto.iface_id, config_proto.iface_id,
) )
if self.emane_config: config = to_dict(self.session.emane_config)
config = {x: self.emane_config[x].value for x in self.emane_config} self.client.set_emane_config(self.session.id, config)
self.client.set_emane_config(self.session_id, config) location = self.session.location
if self.location: self.client.set_session_location(
self.client.set_session_location( self.session.id,
self.session_id, location.x,
self.location.x, location.y,
self.location.y, location.z,
self.location.z, location.lat,
self.location.lat, location.lon,
self.location.lon, location.alt,
self.location.alt, location.scale,
self.location.scale, )
)
self.set_metadata() self.set_metadata()
def close(self) -> None: def close(self) -> None:
@ -888,16 +780,16 @@ class CoreClient:
image = "ubuntu:latest" image = "ubuntu:latest"
emane = None emane = None
if node_type == NodeType.EMANE: if node_type == NodeType.EMANE:
if not self.emane_models: if not self.session.emane_models:
dialog = EmaneInstallDialog(self.app) dialog = EmaneInstallDialog(self.app)
dialog.show() dialog.show()
return return
emane = self.emane_models[0] emane = self.session.emane_models[0]
name = f"EMANE{node_id}" name = f"emane{node_id}"
elif node_type == NodeType.WIRELESS_LAN: elif node_type == NodeType.WIRELESS_LAN:
name = f"WLAN{node_id}" name = f"wlan{node_id}"
elif node_type in [NodeType.RJ45, NodeType.TUNNEL]: elif node_type in [NodeType.RJ45, NodeType.TUNNEL]:
name = "UNASSIGNED" name = "unassigned"
else: else:
name = f"n{node_id}" name = f"n{node_id}"
node = Node( node = Node(
@ -914,13 +806,13 @@ class CoreClient:
node.services[:] = services node.services[:] = services
# assign default services to CORE node # assign default services to CORE node
else: else:
services = self.default_services.get(model) services = self.session.default_services.get(model)
if services: if services:
node.services[:] = services node.services = services.copy()
logging.info( logging.info(
"add node(%s) to session(%s), coordinates(%s, %s)", "add node(%s) to session(%s), coordinates(%s, %s)",
node.name, node.name,
self.session_id, self.session.id,
x, x,
y, y,
) )
@ -1005,60 +897,56 @@ class CoreClient:
def get_wlan_configs_proto(self) -> List[wlan_pb2.WlanConfig]: def get_wlan_configs_proto(self) -> List[wlan_pb2.WlanConfig]:
configs = [] configs = []
for canvas_node in self.canvas_nodes.values(): for node in self.session.nodes.values():
if canvas_node.core_node.type != NodeType.WIRELESS_LAN: if node.type != NodeType.WIRELESS_LAN:
continue continue
if not canvas_node.wlan_config: if not node.wlan_config:
continue continue
config = ConfigOption.to_dict(canvas_node.wlan_config) config = ConfigOption.to_dict(node.wlan_config)
node_id = canvas_node.core_node.id wlan_config = wlan_pb2.WlanConfig(node_id=node.id, config=config)
wlan_config = wlan_pb2.WlanConfig(node_id=node_id, config=config)
configs.append(wlan_config) configs.append(wlan_config)
return configs return configs
def get_mobility_configs_proto(self) -> List[mobility_pb2.MobilityConfig]: def get_mobility_configs_proto(self) -> List[mobility_pb2.MobilityConfig]:
configs = [] configs = []
for canvas_node in self.canvas_nodes.values(): for node in self.session.nodes.values():
if canvas_node.core_node.type != NodeType.WIRELESS_LAN: if node.type != NodeType.WIRELESS_LAN:
continue continue
if not canvas_node.mobility_config: if not node.mobility_config:
continue continue
config = ConfigOption.to_dict(canvas_node.mobility_config) config = ConfigOption.to_dict(node.mobility_config)
node_id = canvas_node.core_node.id
mobility_config = mobility_pb2.MobilityConfig( mobility_config = mobility_pb2.MobilityConfig(
node_id=node_id, config=config node_id=node.id, config=config
) )
configs.append(mobility_config) configs.append(mobility_config)
return configs return configs
def get_emane_model_configs_proto(self) -> List[emane_pb2.EmaneModelConfig]: def get_emane_model_configs_proto(self) -> List[emane_pb2.EmaneModelConfig]:
configs = [] configs = []
for canvas_node in self.canvas_nodes.values(): for node in self.session.nodes.values():
if canvas_node.core_node.type != NodeType.EMANE: if node.type != NodeType.EMANE:
continue continue
node_id = canvas_node.core_node.id for key, config in node.emane_model_configs.items():
for key, config in canvas_node.emane_model_configs.items():
model, iface_id = key model, iface_id = key
config = ConfigOption.to_dict(config) config = ConfigOption.to_dict(config)
if iface_id is None: if iface_id is None:
iface_id = -1 iface_id = -1
config_proto = emane_pb2.EmaneModelConfig( 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) configs.append(config_proto)
return configs return configs
def get_service_configs_proto(self) -> List[services_pb2.ServiceConfig]: def get_service_configs_proto(self) -> List[services_pb2.ServiceConfig]:
configs = [] configs = []
for canvas_node in self.canvas_nodes.values(): for node in self.session.nodes.values():
if not NodeUtils.is_container_node(canvas_node.core_node.type): if not NodeUtils.is_container_node(node.type):
continue continue
if not canvas_node.service_configs: if not node.service_configs:
continue continue
node_id = canvas_node.core_node.id for name, config in node.service_configs.items():
for name, config in canvas_node.service_configs.items():
config_proto = services_pb2.ServiceConfig( config_proto = services_pb2.ServiceConfig(
node_id=node_id, node_id=node.id,
service=name, service=name,
directories=config.dirs, directories=config.dirs,
files=config.configs, files=config.configs,
@ -1071,16 +959,15 @@ class CoreClient:
def get_service_file_configs_proto(self) -> List[services_pb2.ServiceFileConfig]: def get_service_file_configs_proto(self) -> List[services_pb2.ServiceFileConfig]:
configs = [] configs = []
for canvas_node in self.canvas_nodes.values(): for node in self.session.nodes.values():
if not NodeUtils.is_container_node(canvas_node.core_node.type): if not NodeUtils.is_container_node(node.type):
continue continue
if not canvas_node.service_file_configs: if not node.service_file_configs:
continue continue
node_id = canvas_node.core_node.id for service, file_configs in node.service_file_configs.items():
for service, file_configs in canvas_node.service_file_configs.items():
for file, data in file_configs.items(): for file, data in file_configs.items():
config_proto = services_pb2.ServiceFileConfig( 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) configs.append(config_proto)
return configs return configs
@ -1089,29 +976,27 @@ class CoreClient:
self self
) -> List[configservices_pb2.ConfigServiceConfig]: ) -> List[configservices_pb2.ConfigServiceConfig]:
config_service_protos = [] config_service_protos = []
for canvas_node in self.canvas_nodes.values(): for node in self.session.nodes.values():
if not NodeUtils.is_container_node(canvas_node.core_node.type): if not NodeUtils.is_container_node(node.type):
continue continue
if not canvas_node.config_service_configs: if not node.config_service_configs:
continue continue
node_id = canvas_node.core_node.id for name, service_config in node.config_service_configs.items():
for name, service_config in canvas_node.config_service_configs.items():
config = service_config.get("config", {})
config_proto = configservices_pb2.ConfigServiceConfig( config_proto = configservices_pb2.ConfigServiceConfig(
node_id=node_id, node_id=node.id,
name=name, name=name,
templates=service_config["templates"], templates=service_config.templates,
config=config, config=service_config.config,
) )
config_service_protos.append(config_proto) config_service_protos.append(config_proto)
return config_service_protos return config_service_protos
def run(self, node_id: int) -> str: def run(self, node_id: int) -> str:
logging.info("running node(%s) cmd: %s", node_id, self.observer) 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]: 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 config = response.config
logging.debug( logging.debug(
"get wlan configuration from node %s, result configuration: %s", "get wlan configuration from node %s, result configuration: %s",
@ -1121,7 +1006,7 @@ class CoreClient:
return ConfigOption.from_dict(config) return ConfigOption.from_dict(config)
def get_mobility_config(self, node_id: int) -> Dict[str, ConfigOption]: 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 config = response.config
logging.debug( logging.debug(
"get mobility config from node %s, result configuration: %s", "get mobility config from node %s, result configuration: %s",
@ -1136,7 +1021,7 @@ class CoreClient:
if iface_id is None: if iface_id is None:
iface_id = -1 iface_id = -1
response = self.client.get_emane_model_config( 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 config = response.config
logging.debug( logging.debug(

View file

@ -27,7 +27,7 @@ class SizeAndScaleDialog(Dialog):
width, height = self.canvas.current_dimensions width, height = self.canvas.current_dimensions
self.pixel_width: tk.IntVar = tk.IntVar(value=width) self.pixel_width: tk.IntVar = tk.IntVar(value=width)
self.pixel_height: tk.IntVar = tk.IntVar(value=height) 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.x: tk.DoubleVar = tk.DoubleVar(value=location.x)
self.y: tk.DoubleVar = tk.DoubleVar(value=location.y) self.y: tk.DoubleVar = tk.DoubleVar(value=location.y)
self.lat: tk.DoubleVar = tk.DoubleVar(value=location.lat) self.lat: tk.DoubleVar = tk.DoubleVar(value=location.lat)
@ -192,7 +192,7 @@ class SizeAndScaleDialog(Dialog):
self.canvas.redraw_canvas((width, height)) self.canvas.redraw_canvas((width, height))
if self.canvas.wallpaper: if self.canvas.wallpaper:
self.canvas.redraw_wallpaper() self.canvas.redraw_wallpaper()
location = self.app.core.location location = self.app.core.session.location
location.x = self.x.get() location.x = self.x.get()
location.y = self.y.get() location.y = self.y.get()
location.lat = self.lat.get() location.lat = self.lat.get()

View file

@ -11,28 +11,26 @@ import grpc
from core.gui.dialogs.dialog import Dialog from core.gui.dialogs.dialog import Dialog
from core.gui.themes import FRAME_PAD, PADX, PADY from core.gui.themes import FRAME_PAD, PADX, PADY
from core.gui.widgets import CodeText, ConfigFrame, ListboxScroll 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: if TYPE_CHECKING:
from core.gui.app import Application from core.gui.app import Application
from core.gui.graph.node import CanvasNode
from core.gui.coreclient import CoreClient from core.gui.coreclient import CoreClient
class ConfigServiceConfigDialog(Dialog): class ConfigServiceConfigDialog(Dialog):
def __init__( def __init__(
self, self, master: tk.BaseWidget, app: "Application", service_name: str, node: Node
master: tk.BaseWidget,
app: "Application",
service_name: str,
canvas_node: "CanvasNode",
node_id: int,
) -> None: ) -> None:
title = f"{service_name} Config Service" title = f"{service_name} Config Service"
super().__init__(app, title, master=master) super().__init__(app, title, master=master)
self.core: "CoreClient" = app.core self.core: "CoreClient" = app.core
self.canvas_node: "CanvasNode" = canvas_node self.node: Node = node
self.node_id: int = node_id
self.service_name: str = service_name self.service_name: str = service_name
self.radiovar: tk.IntVar = tk.IntVar() self.radiovar: tk.IntVar = tk.IntVar()
self.radiovar.set(2) self.radiovar.set(2)
@ -50,7 +48,7 @@ class ConfigServiceConfigDialog(Dialog):
self.validation_time: Optional[int] = None self.validation_time: Optional[int] = None
self.validation_period: tk.StringVar = tk.StringVar() self.validation_period: tk.StringVar = tk.StringVar()
self.modes: List[str] = [] 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.notebook: Optional[ttk.Notebook] = None
self.templates_combobox: Optional[ttk.Combobox] = 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) response = self.core.client.get_config_service_defaults(self.service_name)
self.original_service_files = response.templates self.original_service_files = response.templates
self.temp_service_files = dict(self.original_service_files) self.temp_service_files = dict(self.original_service_files)
self.modes = sorted(x.name for x in response.modes) self.modes = sorted(x.name for x in response.modes)
self.mode_configs = {x.name: x.config 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.config = ConfigOption.from_dict(response.config)
self.default_config = {x.name: x.value for x in self.config.values()} self.default_config = {x.name: x.value for x in self.config.values()}
custom_config = service_config.get("config") service_config = self.node.config_service_configs.get(self.service_name)
if custom_config: if service_config:
for key, value in custom_config.items(): for key, value in service_config.config.items():
self.config[key].value = value self.config[key].value = value
logging.info("default config: %s", self.default_config) logging.info("default config: %s", self.default_config)
for file, data in service_config.templates.items():
custom_templates = service_config.get("templates", {}) self.modified_files.add(file)
for file, data in custom_templates.items(): self.temp_service_files[file] = data
self.modified_files.add(file)
self.temp_service_files[file] = data
except grpc.RpcError as e: except grpc.RpcError as e:
self.app.show_grpc_exception("Get Config Service Error", e) self.app.show_grpc_exception("Get Config Service Error", e)
self.has_error = True self.has_error = True
@ -313,20 +304,18 @@ class ConfigServiceConfigDialog(Dialog):
def click_apply(self) -> None: def click_apply(self) -> None:
current_listbox = self.master.current.listbox current_listbox = self.master.current.listbox
if not self.is_custom(): 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="") current_listbox.itemconfig(current_listbox.curselection()[0], bg="")
self.destroy() self.destroy()
return return
service_config = self.node.config_service_configs.get(self.service_name)
service_config = self.canvas_node.config_service_configs.setdefault( if not service_config:
self.service_name, {} service_config = ConfigServiceData()
)
if self.config_frame: if self.config_frame:
self.config_frame.parse_config() self.config_frame.parse_config()
service_config["config"] = {x.name: x.value for x in self.config.values()} service_config.config = {x.name: x.value for x in self.config.values()}
templates_config = service_config.setdefault("templates", {})
for file in self.modified_files: 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) all_current = current_listbox.get(0, tk.END)
current_listbox.itemconfig(all_current.index(self.service_name), bg="green") current_listbox.itemconfig(all_current.index(self.service_name), bg="green")
self.destroy() self.destroy()
@ -360,9 +349,9 @@ class ConfigServiceConfigDialog(Dialog):
return has_custom_templates or has_custom_config return has_custom_templates or has_custom_config
def click_defaults(self) -> None: 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( 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) self.temp_service_files = dict(self.original_service_files)
filename = self.templates_combobox.get() filename = self.templates_combobox.get()

View file

@ -43,16 +43,15 @@ class CopyServiceConfigDialog(Dialog):
listbox_scroll = ListboxScroll(self.top) listbox_scroll = ListboxScroll(self.top)
listbox_scroll.grid(sticky="nsew", pady=PADY) listbox_scroll.grid(sticky="nsew", pady=PADY)
self.listbox = listbox_scroll.listbox self.listbox = listbox_scroll.listbox
for canvas_node in self.app.canvas.nodes.values(): for node in self.app.core.session.nodes.values():
file_configs = canvas_node.service_file_configs.get(self.service) file_configs = node.service_file_configs.get(self.service)
if not file_configs: if not file_configs:
continue continue
data = file_configs.get(self.file_name) data = file_configs.get(self.file_name)
if not data: if not data:
continue continue
name = canvas_node.core_node.name self.nodes[node.name] = node.id
self.nodes[name] = canvas_node.id self.listbox.insert(tk.END, node.name)
self.listbox.insert(tk.END, name)
frame = ttk.Frame(self.top) frame = ttk.Frame(self.top)
frame.grid(sticky="ew") frame.grid(sticky="ew")
@ -70,9 +69,9 @@ class CopyServiceConfigDialog(Dialog):
if not selection: if not selection:
return return
name = self.listbox.get(selection) name = self.listbox.get(selection)
canvas_node_id = self.nodes[name] node_id = self.nodes[name]
canvas_node = self.app.canvas.nodes[canvas_node_id] node = self.app.core.session.nodes[node_id]
data = canvas_node.service_file_configs[self.service][self.file_name] data = node.service_file_configs[self.service][self.file_name]
self.dialog.temp_service_files[self.file_name] = data self.dialog.temp_service_files[self.file_name] = data
self.dialog.modified_files.add(self.file_name) self.dialog.modified_files.add(self.file_name)
self.dialog.service_file_data.text.delete(1.0, tk.END) self.dialog.service_file_data.text.delete(1.0, tk.END)
@ -84,9 +83,9 @@ class CopyServiceConfigDialog(Dialog):
if not selection: if not selection:
return return
name = self.listbox.get(selection) name = self.listbox.get(selection)
canvas_node_id = self.nodes[name] node_id = self.nodes[name]
canvas_node = self.app.canvas.nodes[canvas_node_id] node = self.app.core.session.nodes[node_id]
data = canvas_node.service_file_configs[self.service][self.file_name] data = node.service_file_configs[self.service][self.file_name]
dialog = ViewConfigDialog( dialog = ViewConfigDialog(
self.app, self, name, self.service, self.file_name, data self.app, self, name, self.service, self.file_name, data
) )

View file

@ -16,7 +16,6 @@ from core.gui.wrappers import ConfigOption, Node
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 GlobalEmaneDialog(Dialog): class GlobalEmaneDialog(Dialog):
@ -29,8 +28,9 @@ class GlobalEmaneDialog(Dialog):
def draw(self) -> None: def draw(self) -> None:
self.top.columnconfigure(0, weight=1) self.top.columnconfigure(0, weight=1)
self.top.rowconfigure(0, weight=1) self.top.rowconfigure(0, weight=1)
session = self.app.core.session
self.config_frame = ConfigFrame( 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.draw_config()
self.config_frame.grid(sticky="nsew", pady=PADY) self.config_frame.grid(sticky="nsew", pady=PADY)
@ -58,24 +58,19 @@ class EmaneModelDialog(Dialog):
self, self,
master: tk.BaseWidget, master: tk.BaseWidget,
app: "Application", app: "Application",
canvas_node: "CanvasNode", node: Node,
model: str, model: str,
iface_id: int = None, iface_id: int = None,
) -> None: ) -> None:
super().__init__( super().__init__(app, f"{node.name} {model} Configuration", master=master)
app, f"{canvas_node.core_node.name} {model} Configuration", master=master self.node: Node = node
)
self.canvas_node: "CanvasNode" = canvas_node
self.node: Node = canvas_node.core_node
self.model: str = f"emane_{model}" self.model: str = f"emane_{model}"
self.iface_id: int = iface_id self.iface_id: int = iface_id
self.config_frame: Optional[ConfigFrame] = None self.config_frame: Optional[ConfigFrame] = None
self.enabled: bool = not self.app.core.is_runtime() self.enabled: bool = not self.app.core.is_runtime()
self.has_error: bool = False self.has_error: bool = False
try: try:
config = self.canvas_node.emane_model_configs.get( config = self.node.emane_model_configs.get((self.model, self.iface_id))
(self.model, self.iface_id)
)
if not config: if not config:
config = self.app.core.get_emane_model_config( config = self.app.core.get_emane_model_config(
self.node.id, self.model, self.iface_id self.node.id, self.model, self.iface_id
@ -110,19 +105,18 @@ class EmaneModelDialog(Dialog):
def click_apply(self) -> None: def click_apply(self) -> None:
self.config_frame.parse_config() self.config_frame.parse_config()
key = (self.model, self.iface_id) 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() self.destroy()
class EmaneConfigDialog(Dialog): class EmaneConfigDialog(Dialog):
def __init__(self, app: "Application", canvas_node: "CanvasNode") -> None: def __init__(self, app: "Application", node: Node) -> None:
super().__init__(app, f"{canvas_node.core_node.name} EMANE Configuration") super().__init__(app, f"{node.name} EMANE Configuration")
self.canvas_node: "CanvasNode" = canvas_node self.node: Node = node
self.node: Node = canvas_node.core_node
self.radiovar: tk.IntVar = tk.IntVar() self.radiovar: tk.IntVar = tk.IntVar()
self.radiovar.set(1) self.radiovar.set(1)
self.emane_models: List[str] = [ 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] model = self.node.emane.split("_")[1]
self.emane_model: tk.StringVar = tk.StringVar(value=model) self.emane_model: tk.StringVar = tk.StringVar(value=model)
@ -231,7 +225,7 @@ class EmaneConfigDialog(Dialog):
draw emane model configuration draw emane model configuration
""" """
model_name = self.emane_model.get() 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: if not dialog.has_error:
dialog.show() dialog.show()

View file

@ -113,8 +113,9 @@ class HooksDialog(Dialog):
listbox_scroll.grid(sticky="nsew", pady=PADY) listbox_scroll.grid(sticky="nsew", pady=PADY)
self.listbox = listbox_scroll.listbox self.listbox = listbox_scroll.listbox
self.listbox.bind("<<ListboxSelect>>", self.select) self.listbox.bind("<<ListboxSelect>>", self.select)
for hook_file in self.app.core.hooks: session = self.app.core.session
self.listbox.insert(tk.END, hook_file) for file in session.hooks:
self.listbox.insert(tk.END, file)
frame = ttk.Frame(self.top) frame = ttk.Frame(self.top)
frame.grid(sticky="ew") frame.grid(sticky="ew")
@ -138,20 +139,22 @@ class HooksDialog(Dialog):
dialog.show() dialog.show()
hook = dialog.hook hook = dialog.hook
if 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) self.listbox.insert(tk.END, hook.file)
def click_edit(self) -> None: 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 = HookDialog(self, self.app)
dialog.set(hook) dialog.set(hook)
dialog.show() dialog.show()
self.app.core.hooks[hook.file] = hook session.hooks[hook.file] = hook
self.listbox.delete(self.selected_index) self.listbox.delete(self.selected_index)
self.listbox.insert(self.selected_index, hook.file) self.listbox.insert(self.selected_index, hook.file)
def click_delete(self) -> None: def click_delete(self) -> None:
del self.app.core.hooks[self.selected] session = self.app.core.session
del session.hooks[self.selected]
self.listbox.delete(tk.ANCHOR) self.listbox.delete(tk.ANCHOR)
self.edit_button.config(state=tk.DISABLED) self.edit_button.config(state=tk.DISABLED)
self.delete_button.config(state=tk.DISABLED) self.delete_button.config(state=tk.DISABLED)

View file

@ -269,7 +269,7 @@ class LinkConfigurationDialog(Dialog):
self.edge.asymmetric_link = None self.edge.asymmetric_link = None
if self.app.core.is_runtime() and link.options: 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( self.app.core.client.edit_link(
session_id, session_id,
link.node1_id, link.node1_id,

View file

@ -13,18 +13,16 @@ from core.gui.wrappers import ConfigOption, Node
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 MobilityConfigDialog(Dialog): class MobilityConfigDialog(Dialog):
def __init__(self, app: "Application", canvas_node: "CanvasNode") -> None: def __init__(self, app: "Application", node: Node) -> None:
super().__init__(app, f"{canvas_node.core_node.name} Mobility Configuration") super().__init__(app, f"{node.name} Mobility Configuration")
self.canvas_node: "CanvasNode" = canvas_node self.node: Node = node
self.node: Node = canvas_node.core_node
self.config_frame: Optional[ConfigFrame] = None self.config_frame: Optional[ConfigFrame] = None
self.has_error: bool = False self.has_error: bool = False
try: try:
config = self.canvas_node.mobility_config config = self.node.mobility_config
if not config: if not config:
config = self.app.core.get_mobility_config(self.node.id) config = self.app.core.get_mobility_config(self.node.id)
self.config: Dict[str, ConfigOption] = config self.config: Dict[str, ConfigOption] = config
@ -56,5 +54,5 @@ class MobilityConfigDialog(Dialog):
def click_apply(self) -> None: def click_apply(self) -> None:
self.config_frame.parse_config() self.config_frame.parse_config()
self.canvas_node.mobility_config = self.config self.node.mobility_config = self.config
self.destroy() self.destroy()

View file

@ -1,38 +1,31 @@
import tkinter as tk import tkinter as tk
from tkinter import ttk from tkinter import ttk
from typing import TYPE_CHECKING, Dict, Optional from typing import TYPE_CHECKING, Optional
import grpc import grpc
from core.gui.dialogs.dialog import Dialog from core.gui.dialogs.dialog import Dialog
from core.gui.images import ImageEnum from core.gui.images import ImageEnum
from core.gui.themes import PADX, PADY 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: if TYPE_CHECKING:
from core.gui.app import Application from core.gui.app import Application
from core.gui.graph.node import CanvasNode
ICON_SIZE: int = 16 ICON_SIZE: int = 16
class MobilityPlayer: class MobilityPlayer:
def __init__( def __init__(self, app: "Application", node: Node) -> None:
self,
app: "Application",
canvas_node: "CanvasNode",
config: Dict[str, ConfigOption],
) -> None:
self.app: "Application" = app self.app: "Application" = app
self.canvas_node: "CanvasNode" = canvas_node self.node: Node = node
self.config: Dict[str, ConfigOption] = config
self.dialog: Optional[MobilityPlayerDialog] = None self.dialog: Optional[MobilityPlayerDialog] = None
self.state: Optional[MobilityAction] = None self.state: Optional[MobilityAction] = None
def show(self) -> None: def show(self) -> None:
if self.dialog: if self.dialog:
self.dialog.destroy() 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) self.dialog.protocol("WM_DELETE_WINDOW", self.close)
if self.state == MobilityAction.START: if self.state == MobilityAction.START:
self.set_play() self.set_play()
@ -64,20 +57,11 @@ class MobilityPlayer:
class MobilityPlayerDialog(Dialog): class MobilityPlayerDialog(Dialog):
def __init__( def __init__(self, app: "Application", node: Node) -> None:
self, super().__init__(app, f"{node.name} Mobility Player", modal=False)
app: "Application",
canvas_node: "CanvasNode",
config: Dict[str, ConfigOption],
) -> None:
super().__init__(
app, f"{canvas_node.core_node.name} Mobility Player", modal=False
)
self.resizable(False, False) self.resizable(False, False)
self.geometry("") self.geometry("")
self.canvas_node: "CanvasNode" = canvas_node self.node: Node = node
self.node: Node = canvas_node.core_node
self.config: Dict[str, ConfigOption] = config
self.play_button: Optional[ttk.Button] = None self.play_button: Optional[ttk.Button] = None
self.pause_button: Optional[ttk.Button] = None self.pause_button: Optional[ttk.Button] = None
self.stop_button: Optional[ttk.Button] = None self.stop_button: Optional[ttk.Button] = None
@ -85,9 +69,10 @@ class MobilityPlayerDialog(Dialog):
self.draw() self.draw()
def draw(self) -> None: def draw(self) -> None:
config = self.node.mobility_config
self.top.columnconfigure(0, weight=1) 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 = ttk.Label(self.top, text=file_name)
label.grid(sticky="ew", pady=PADY) label.grid(sticky="ew", pady=PADY)
@ -114,13 +99,13 @@ class MobilityPlayerDialog(Dialog):
self.stop_button.image = image self.stop_button.image = image
self.stop_button.grid(row=0, column=2, sticky="ew", padx=PADX) 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( checkbutton = ttk.Checkbutton(
frame, text="Loop?", variable=loop, state=tk.DISABLED frame, text="Loop?", variable=loop, state=tk.DISABLED
) )
checkbutton.grid(row=0, column=3, padx=PADX) 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 = ttk.Label(frame, text=f"rate {rate} ms")
label.grid(row=0, column=4) label.grid(row=0, column=4)
@ -146,7 +131,7 @@ class MobilityPlayerDialog(Dialog):
def click_play(self) -> None: def click_play(self) -> None:
self.set_play() self.set_play()
session_id = self.app.core.session_id session_id = self.app.core.session.id
try: try:
self.app.core.client.mobility_action( self.app.core.client.mobility_action(
session_id, self.node.id, MobilityAction.START.value session_id, self.node.id, MobilityAction.START.value
@ -156,7 +141,7 @@ class MobilityPlayerDialog(Dialog):
def click_pause(self) -> None: def click_pause(self) -> None:
self.set_pause() self.set_pause()
session_id = self.app.core.session_id session_id = self.app.core.session.id
try: try:
self.app.core.client.mobility_action( self.app.core.client.mobility_action(
session_id, self.node.id, MobilityAction.PAUSE.value session_id, self.node.id, MobilityAction.PAUSE.value
@ -166,7 +151,7 @@ class MobilityPlayerDialog(Dialog):
def click_stop(self) -> None: def click_stop(self) -> None:
self.set_stop() self.set_stop()
session_id = self.app.core.session_id session_id = self.app.core.session.id
try: try:
self.app.core.client.mobility_action( self.app.core.client.mobility_action(
session_id, self.node.id, MobilityAction.STOP.value session_id, self.node.id, MobilityAction.STOP.value

View file

@ -10,25 +10,24 @@ from core.gui.dialogs.configserviceconfig import ConfigServiceConfigDialog
from core.gui.dialogs.dialog import Dialog from core.gui.dialogs.dialog import Dialog
from core.gui.themes import FRAME_PAD, PADX, PADY from core.gui.themes import FRAME_PAD, PADX, PADY
from core.gui.widgets import CheckboxList, ListboxScroll from core.gui.widgets import CheckboxList, ListboxScroll
from core.gui.wrappers import Node
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 NodeConfigServiceDialog(Dialog): class NodeConfigServiceDialog(Dialog):
def __init__( def __init__(
self, app: "Application", canvas_node: "CanvasNode", services: Set[str] = None self, app: "Application", node: Node, services: Set[str] = None
) -> None: ) -> None:
title = f"{canvas_node.core_node.name} Config Services" title = f"{node.name} Config Services"
super().__init__(app, title) super().__init__(app, title)
self.canvas_node: "CanvasNode" = canvas_node self.node: Node = node
self.node_id: int = canvas_node.core_node.id
self.groups: Optional[ListboxScroll] = None self.groups: Optional[ListboxScroll] = None
self.services: Optional[CheckboxList] = None self.services: Optional[CheckboxList] = None
self.current: Optional[ListboxScroll] = None self.current: Optional[ListboxScroll] = None
if services is 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.current_services: Set[str] = services
self.draw() self.draw()
@ -102,7 +101,7 @@ class NodeConfigServiceDialog(Dialog):
elif not var.get() and name in self.current_services: elif not var.get() and name in self.current_services:
self.current_services.remove(name) self.current_services.remove(name)
self.draw_current_services() 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: def click_configure(self) -> None:
current_selection = self.current.listbox.curselection() current_selection = self.current.listbox.curselection()
@ -111,8 +110,7 @@ class NodeConfigServiceDialog(Dialog):
self, self,
self.app, self.app,
self.current.listbox.get(current_selection[0]), self.current.listbox.get(current_selection[0]),
self.canvas_node, self.node,
self.node_id,
) )
if not dialog.has_error: if not dialog.has_error:
dialog.show() dialog.show()
@ -132,10 +130,8 @@ class NodeConfigServiceDialog(Dialog):
self.current.listbox.itemconfig(tk.END, bg="green") self.current.listbox.itemconfig(tk.END, bg="green")
def click_save(self) -> None: def click_save(self) -> None:
self.canvas_node.core_node.config_services[:] = self.current_services self.node.config_services[:] = self.current_services
logging.info( logging.info("saved node config services: %s", self.node.config_services)
"saved node config services: %s", self.canvas_node.core_node.config_services
)
self.destroy() self.destroy()
def click_cancel(self) -> None: def click_cancel(self) -> None:
@ -154,4 +150,4 @@ class NodeConfigServiceDialog(Dialog):
return return
def is_custom_service(self, service: str) -> bool: 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

View file

@ -9,22 +9,21 @@ from core.gui.dialogs.dialog import Dialog
from core.gui.dialogs.serviceconfig import ServiceConfigDialog from core.gui.dialogs.serviceconfig import ServiceConfigDialog
from core.gui.themes import FRAME_PAD, PADX, PADY from core.gui.themes import FRAME_PAD, PADX, PADY
from core.gui.widgets import CheckboxList, ListboxScroll from core.gui.widgets import CheckboxList, ListboxScroll
from core.gui.wrappers import Node
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 NodeServiceDialog(Dialog): class NodeServiceDialog(Dialog):
def __init__(self, app: "Application", canvas_node: "CanvasNode") -> None: def __init__(self, app: "Application", node: Node) -> None:
title = f"{canvas_node.core_node.name} Services" title = f"{node.name} Services"
super().__init__(app, title) super().__init__(app, title)
self.canvas_node: "CanvasNode" = canvas_node self.node: Node = node
self.node_id: int = canvas_node.core_node.id
self.groups: Optional[ListboxScroll] = None self.groups: Optional[ListboxScroll] = None
self.services: Optional[CheckboxList] = None self.services: Optional[CheckboxList] = None
self.current: Optional[ListboxScroll] = None self.current: Optional[ListboxScroll] = None
services = set(canvas_node.core_node.services) services = set(node.services)
self.current_services: Set[str] = services self.current_services: Set[str] = services
self.draw() self.draw()
@ -104,7 +103,7 @@ class NodeServiceDialog(Dialog):
self.current.listbox.insert(tk.END, name) self.current.listbox.insert(tk.END, name)
if self.is_custom_service(name): if self.is_custom_service(name):
self.current.listbox.itemconfig(tk.END, bg="green") 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: def click_configure(self) -> None:
current_selection = self.current.listbox.curselection() current_selection = self.current.listbox.curselection()
@ -113,8 +112,7 @@ class NodeServiceDialog(Dialog):
self, self,
self.app, self.app,
self.current.listbox.get(current_selection[0]), self.current.listbox.get(current_selection[0]),
self.canvas_node, self.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
@ -128,8 +126,7 @@ class NodeServiceDialog(Dialog):
) )
def click_save(self) -> None: def click_save(self) -> None:
core_node = self.canvas_node.core_node self.node.services[:] = self.current_services
core_node.services[:] = self.current_services
self.destroy() self.destroy()
def click_remove(self) -> None: def click_remove(self) -> None:
@ -144,6 +141,6 @@ class NodeServiceDialog(Dialog):
return return
def is_custom_service(self, service: str) -> bool: def is_custom_service(self, service: str) -> bool:
has_service_config = service in self.canvas_node.service_configs has_service_config = service in self.node.service_configs
has_file_config = service in self.canvas_node.service_file_configs has_file_config = service in self.node.service_file_configs
return has_service_config or has_file_config return has_service_config or has_file_config

View file

@ -107,7 +107,7 @@ class RunToolDialog(Dialog):
node_name = self.node_list.listbox.get(selection) node_name = self.node_list.listbox.get(selection)
node_id = self.executable_nodes[node_name] node_id = self.executable_nodes[node_name]
response = self.app.core.client.node_command( 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( self.result.text.insert(
tk.END, f"> {node_name} > {command}:\n{response.output}\n" tk.END, f"> {node_name} > {command}:\n{response.output}\n"

View file

@ -12,11 +12,10 @@ from core.gui.dialogs.dialog import Dialog
from core.gui.images import ImageEnum, Images from core.gui.images import ImageEnum, Images
from core.gui.themes import FRAME_PAD, PADX, PADY from core.gui.themes import FRAME_PAD, PADX, PADY
from core.gui.widgets import CodeText, ListboxScroll 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: if TYPE_CHECKING:
from core.gui.app import Application from core.gui.app import Application
from core.gui.graph.node import CanvasNode
from core.gui.coreclient import CoreClient from core.gui.coreclient import CoreClient
ICON_SIZE: int = 16 ICON_SIZE: int = 16
@ -24,18 +23,12 @@ ICON_SIZE: int = 16
class ServiceConfigDialog(Dialog): class ServiceConfigDialog(Dialog):
def __init__( def __init__(
self, self, master: tk.BaseWidget, app: "Application", service_name: str, node: Node
master: tk.BaseWidget,
app: "Application",
service_name: str,
canvas_node: "CanvasNode",
node_id: int,
) -> None: ) -> None:
title = f"{service_name} Service" title = f"{service_name} Service"
super().__init__(app, title, master=master) super().__init__(app, title, master=master)
self.core: "CoreClient" = app.core self.core: "CoreClient" = app.core
self.canvas_node: "CanvasNode" = canvas_node self.node: Node = node
self.node_id: int = node_id
self.service_name: str = service_name self.service_name: str = service_name
self.radiovar: tk.IntVar = tk.IntVar(value=2) self.radiovar: tk.IntVar = tk.IntVar(value=2)
self.metadata: str = "" self.metadata: str = ""
@ -84,15 +77,13 @@ class ServiceConfigDialog(Dialog):
try: try:
self.app.core.create_nodes_and_links() self.app.core.create_nodes_and_links()
default_config = self.app.core.get_node_service( 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_startup = default_config.startup[:]
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.canvas_node.service_configs.get( custom_service_config = self.node.service_configs.get(self.service_name)
self.service_name
)
self.default_config = default_config self.default_config = default_config
service_config = ( service_config = (
custom_service_config if custom_service_config else default_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.temp_directories = service_config.dirs[:]
self.original_service_files = { self.original_service_files = {
x: self.app.core.get_node_service_file( 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 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_configs = self.canvas_node.service_file_configs.get( file_configs = self.node.service_file_configs.get(self.service_name, {})
self.service_name, {}
)
for file, data in file_configs.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:
@ -453,7 +442,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.canvas_node.service_configs.pop(self.service_name, None) self.node.service_configs.pop(self.service_name, None)
self.current_service_color("") self.current_service_color("")
self.destroy() self.destroy()
return return
@ -466,7 +455,7 @@ class ServiceConfigDialog(Dialog):
): ):
startup, validate, shutdown = self.get_commands() startup, validate, shutdown = self.get_commands()
config = self.core.set_node_service( config = self.core.set_node_service(
self.node_id, self.node.id,
self.service_name, self.service_name,
dirs=self.temp_directories, dirs=self.temp_directories,
files=list(self.filename_combobox["values"]), files=list(self.filename_combobox["values"]),
@ -474,15 +463,15 @@ class ServiceConfigDialog(Dialog):
validations=validate, validations=validate,
shutdowns=shutdown, 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: 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, {} self.service_name, {}
) )
file_configs[file] = self.temp_service_files[file] file_configs[file] = self.temp_service_files[file]
# TODO: check if this is really needed # TODO: check if this is really needed
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]
) )
self.current_service_color("green") self.current_service_color("green")
except grpc.RpcError as e: except grpc.RpcError as e:
@ -526,8 +515,8 @@ class ServiceConfigDialog(Dialog):
clears out any custom configuration permanently clears out any custom configuration permanently
""" """
# clear coreclient data # clear coreclient data
self.canvas_node.service_configs.pop(self.service_name, None) self.node.service_configs.pop(self.service_name, None)
file_configs = self.canvas_node.service_file_configs.pop(self.service_name, {}) file_configs = self.node.service_file_configs.pop(self.service_name, {})
file_configs.pop(self.service_name, None) 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()
@ -564,9 +553,8 @@ class ServiceConfigDialog(Dialog):
def click_copy(self) -> None: def click_copy(self) -> None:
file_name = self.filename_combobox.get() file_name = self.filename_combobox.get()
name = self.canvas_node.core_node.name
dialog = CopyServiceConfigDialog( dialog = CopyServiceConfigDialog(
self.app, self, name, self.service_name, file_name self.app, self, self.node.name, self.service_name, file_name
) )
dialog.show() dialog.show()

View file

@ -26,7 +26,7 @@ class SessionOptionsDialog(Dialog):
def get_config(self) -> Dict[str, ConfigOption]: def get_config(self) -> Dict[str, ConfigOption]:
try: 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) response = self.app.core.client.get_session_options(session_id)
return ConfigOption.from_dict(response.config) return ConfigOption.from_dict(response.config)
except grpc.RpcError as e: except grpc.RpcError as e:
@ -54,7 +54,7 @@ class SessionOptionsDialog(Dialog):
def save(self) -> None: def save(self) -> None:
config = self.config_frame.parse_config() config = self.config_frame.parse_config()
try: 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) response = self.app.core.client.set_session_options(session_id, config)
logging.info("saved session config: %s", response) logging.info("saved session config: %s", response)
except grpc.RpcError as e: except grpc.RpcError as e:

View file

@ -201,7 +201,7 @@ class SessionsDialog(Dialog):
logging.debug("delete session: %s", self.selected_session) logging.debug("delete session: %s", self.selected_session)
self.tree.delete(self.selected_id) self.tree.delete(self.selected_id)
self.app.core.delete_session(self.selected_session) 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.click_new()
self.destroy() self.destroy()
self.click_select() self.click_select()

View file

@ -29,7 +29,7 @@ class WlanConfigDialog(Dialog):
self.ranges: Dict[int, int] = {} self.ranges: Dict[int, int] = {}
self.positive_int: int = self.app.master.register(self.validate_and_update) self.positive_int: int = self.app.master.register(self.validate_and_update)
try: try:
config = self.canvas_node.wlan_config config = self.node.wlan_config
if not config: if not config:
config = self.app.core.get_wlan_config(self.node.id) config = self.app.core.get_wlan_config(self.node.id)
self.config: Dict[str, ConfigOption] = config self.config: Dict[str, ConfigOption] = config
@ -83,9 +83,9 @@ class WlanConfigDialog(Dialog):
retrieve user's wlan configuration and store the new configuration values retrieve user's wlan configuration and store the new configuration values
""" """
config = self.config_frame.parse_config() 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(): 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.app.core.client.set_wlan_config(session_id, self.node.id, config)
self.remove_ranges() self.remove_ranges()
self.destroy() self.destroy()

View file

@ -940,16 +940,19 @@ class CanvasGraph(tk.Canvas):
if not copy: if not copy:
continue continue
node = CanvasNode(self.app, scaled_x, scaled_y, copy, canvas_node.image) node = CanvasNode(self.app, scaled_x, scaled_y, copy, canvas_node.image)
# copy configurations and services # copy configurations and services
node.core_node.services[:] = canvas_node.core_node.services node.core_node.services = core_node.services.copy()
node.core_node.config_services[:] = canvas_node.core_node.config_services node.core_node.config_services = core_node.config_services.copy()
node.emane_model_configs = deepcopy(canvas_node.emane_model_configs) node.core_node.emane_model_configs = deepcopy(core_node.emane_model_configs)
node.wlan_config = deepcopy(canvas_node.wlan_config) node.core_node.wlan_config = deepcopy(core_node.wlan_config)
node.mobility_config = deepcopy(canvas_node.mobility_config) node.core_node.mobility_config = deepcopy(core_node.mobility_config)
node.service_configs = deepcopy(canvas_node.service_configs) node.core_node.service_configs = deepcopy(core_node.service_configs)
node.service_file_configs = deepcopy(canvas_node.service_file_configs) node.core_node.service_file_configs = deepcopy(
node.config_service_configs = deepcopy(canvas_node.config_service_configs) core_node.service_file_configs
)
node.core_node.config_service_configs = deepcopy(
core_node.config_service_configs
)
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

View file

@ -1,7 +1,7 @@
import functools import functools
import logging import logging
import tkinter as tk 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 import grpc
from PIL.ImageTk import PhotoImage 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.graph.tooltip import CanvasTooltip
from core.gui.images import ImageEnum from core.gui.images import ImageEnum
from core.gui.nodeutils import ANTENNA_SIZE, NodeUtils 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: if TYPE_CHECKING:
from core.gui.app import Application from core.gui.app import Application
@ -56,15 +56,6 @@ class CanvasNode:
self.wireless_edges: Set[CanvasWirelessEdge] = set() self.wireless_edges: Set[CanvasWirelessEdge] = set()
self.antennas: List[int] = [] self.antennas: List[int] = []
self.antenna_images: Dict[int, PhotoImage] = {} 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.setup_bindings()
self.context: tk.Menu = tk.Menu(self.canvas) self.context: tk.Menu = tk.Menu(self.canvas)
themes.style_menu(self.context) themes.style_menu(self.context)
@ -299,7 +290,7 @@ class CanvasNode:
dialog.show() dialog.show()
def show_mobility_config(self) -> None: def show_mobility_config(self) -> None:
dialog = MobilityConfigDialog(self.app, self) dialog = MobilityConfigDialog(self.app, self.core_node)
if not dialog.has_error: if not dialog.has_error:
dialog.show() dialog.show()
@ -308,15 +299,15 @@ class CanvasNode:
mobility_player.show() mobility_player.show()
def show_emane_config(self) -> None: def show_emane_config(self) -> None:
dialog = EmaneConfigDialog(self.app, self) dialog = EmaneConfigDialog(self.app, self.core_node)
dialog.show() dialog.show()
def show_services(self) -> None: def show_services(self) -> None:
dialog = NodeServiceDialog(self.app, self) dialog = NodeServiceDialog(self.app, self.core_node)
dialog.show() dialog.show()
def show_config_services(self) -> None: def show_config_services(self) -> None:
dialog = NodeConfigServiceDialog(self.app, self) dialog = NodeConfigServiceDialog(self.app, self.core_node)
dialog.show() dialog.show()
def has_emane_link(self, iface_id: int) -> Node: def has_emane_link(self, iface_id: int) -> Node:

View file

@ -33,7 +33,6 @@ class ProgressTask:
thread.start() thread.start()
def run(self) -> None: def run(self) -> None:
logging.info("running task")
try: try:
values = self.task(*self.args) values = self.task(*self.args)
if values is None: if values is None:
@ -41,7 +40,6 @@ class ProgressTask:
elif values and not isinstance(values, tuple): elif values and not isinstance(values, tuple):
values = (values,) values = (values,)
if self.callback: if self.callback:
logging.info("calling callback")
self.app.after(0, self.callback, *values) self.app.after(0, self.callback, *values)
except Exception as e: except Exception as e:
logging.exception("progress task exception") logging.exception("progress task exception")

View file

@ -1,6 +1,6 @@
from dataclasses import dataclass, field from dataclasses import dataclass, field
from enum import Enum 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 from core.api.grpc import common_pb2, configservices_pb2, core_pb2, services_pb2
@ -121,8 +121,8 @@ class ConfigService:
@dataclass @dataclass
class ConfigServiceData: class ConfigServiceData:
templates: Dict[str, str] templates: Dict[str, str] = field(default_factory=dict)
config: Dict[str, str] config: Dict[str, str] = field(default_factory=dict)
@dataclass @dataclass
@ -504,8 +504,8 @@ class Node:
type: NodeType type: NodeType
model: str = None model: str = None
position: Position = None position: Position = None
services: List[str] = field(default_factory=list) services: Set[str] = field(default_factory=set)
config_services: List[str] = field(default_factory=list) config_services: Set[str] = field(default_factory=set)
emane: str = None emane: str = None
icon: str = None icon: str = None
image: str = None image: str = None
@ -538,8 +538,8 @@ class Node:
type=NodeType(proto.type), type=NodeType(proto.type),
model=proto.model, model=proto.model,
position=Position.from_proto(proto.position), position=Position.from_proto(proto.position),
services=list(proto.services), services=set(proto.services),
config_services=list(proto.config_services), config_services=set(proto.config_services),
emane=proto.emane, emane=proto.emane,
icon=proto.icon, icon=proto.icon,
image=proto.image, image=proto.image,
@ -575,9 +575,9 @@ class Session:
links: List[Link] links: List[Link]
dir: str dir: str
user: str user: str
default_services: Dict[str, List[str]] default_services: Dict[str, Set[str]]
location: SessionLocation location: SessionLocation
hooks: List[Hook] hooks: Dict[str, Hook]
emane_models: List[str] emane_models: List[str]
emane_config: Dict[str, ConfigOption] emane_config: Dict[str, ConfigOption]
metadata: Dict[str, str] metadata: Dict[str, str]
@ -586,8 +586,10 @@ class Session:
def from_proto(cls, proto: core_pb2.Session) -> "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} 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] links = [Link.from_proto(x) for x in proto.links]
default_services = {x.node_type: x.services for x in proto.default_services} default_services = {
hooks = [Hook.from_proto(x) for x in proto.hooks] 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 # update nodes with their current configurations
for model in proto.emane_model_configs: for model in proto.emane_model_configs:
iface_id = None iface_id = None