finish service file config

This commit is contained in:
Huy Pham 2019-11-22 11:45:44 -08:00
commit 3e2cc80a80
20 changed files with 222 additions and 276 deletions

View file

@ -26,7 +26,7 @@ class Application(tk.Frame):
self.statusbar = None self.statusbar = None
# setup # setup
self.config = appconfig.read() self.guiconfig = appconfig.read()
self.style = ttk.Style() self.style = ttk.Style()
self.setup_theme() self.setup_theme()
self.core = CoreClient(self) self.core = CoreClient(self)
@ -36,7 +36,7 @@ class Application(tk.Frame):
def setup_theme(self): def setup_theme(self):
themes.load(self.style) themes.load(self.style)
self.style.theme_use(self.config["preferences"]["theme"]) self.style.theme_use(self.guiconfig["preferences"]["theme"])
func = partial(themes.update_menu, self.style) func = partial(themes.update_menu, self.style)
self.master.bind_class("Menu", "<<ThemeChanged>>", func) self.master.bind_class("Menu", "<<ThemeChanged>>", func)
@ -88,7 +88,7 @@ class Application(tk.Frame):
menu_action.on_quit() menu_action.on_quit()
def save_config(self): def save_config(self):
appconfig.save(self.config) appconfig.save(self.guiconfig)
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -75,6 +75,15 @@ def check_directory():
"terminal": terminal, "terminal": terminal,
"gui3d": "/usr/local/bin/std3d.sh", "gui3d": "/usr/local/bin/std3d.sh",
}, },
"location": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"lat": 47.5791667,
"lon": -122.132322,
"alt": 2.0,
"scale": 150.0,
},
"servers": [{"name": "example", "address": "127.0.0.1", "port": 50051}], "servers": [{"name": "example", "address": "127.0.0.1", "port": 50051}],
"nodes": [], "nodes": [],
"observers": [{"name": "hello", "cmd": "echo hello"}], "observers": [{"name": "hello", "cmd": "echo hello"}],

View file

@ -6,7 +6,6 @@ import os
from core.api.grpc import client, core_pb2 from core.api.grpc import client, core_pb2
from coretk.dialogs.sessions import SessionsDialog from coretk.dialogs.sessions import SessionsDialog
from coretk.emaneodelnodeconfig import EmaneModelNodeConfig
from coretk.interface import InterfaceManager from coretk.interface import InterfaceManager
from coretk.nodeutils import NodeDraw, NodeUtils from coretk.nodeutils import NodeDraw, NodeUtils
@ -60,6 +59,7 @@ class CoreClient:
# data for managing the current session # data for managing the current session
self.canvas_nodes = {} self.canvas_nodes = {}
self.location = None
self.interface_to_edge = {} self.interface_to_edge = {}
self.state = None self.state = None
self.links = {} self.links = {}
@ -71,7 +71,6 @@ class CoreClient:
self.wlan_configs = {} self.wlan_configs = {}
self.mobility_configs = {} self.mobility_configs = {}
self.emane_model_configs = {} self.emane_model_configs = {}
self.emaneconfig_management = EmaneModelNodeConfig(app)
self.emane_config = None self.emane_config = None
self.created_nodes = set() self.created_nodes = set()
self.created_links = set() self.created_links = set()
@ -84,12 +83,12 @@ class CoreClient:
def read_config(self): def read_config(self):
# read distributed server # read distributed server
for config in self.app.config.get("servers", []): for config in self.app.guiconfig.get("servers", []):
server = CoreServer(config["name"], config["address"], config["port"]) server = CoreServer(config["name"], config["address"], config["port"])
self.servers[server.name] = server self.servers[server.name] = server
# read custom nodes # read custom nodes
for config in self.app.config.get("nodes", []): for config in self.app.guiconfig.get("nodes", []):
name = config["name"] name = config["name"]
image_file = config["image"] image_file = config["image"]
services = set(config["services"]) services = set(config["services"])
@ -97,14 +96,14 @@ class CoreClient:
self.custom_nodes[name] = node_draw self.custom_nodes[name] = node_draw
# read observers # read observers
for config in self.app.config.get("observers", []): for config in self.app.guiconfig.get("observers", []):
observer = Observer(config["name"], config["cmd"]) observer = Observer(config["name"], config["cmd"])
self.custom_observers[observer.name] = observer self.custom_observers[observer.name] = observer
def handle_events(self, event): def handle_events(self, event):
logging.info("event: %s", event) logging.info("event: %s", event)
if event.HasField("link_event"): if event.HasField("link_event"):
self.app.canvas.wireless_draw.hangle_link_event(event.link_event) self.app.canvas.wireless_draw.handle_link_event(event.link_event)
elif event.HasField("session_event"): elif event.HasField("session_event"):
if event.session_event.event <= core_pb2.SessionState.SHUTDOWN: if event.session_event.event <= core_pb2.SessionState.SHUTDOWN:
self.state = event.session_event.event self.state = event.session_event.event
@ -122,7 +121,7 @@ class CoreClient:
throughputs_belong_to_session throughputs_belong_to_session
) )
def join_session(self, session_id): def join_session(self, session_id, query_location=True):
self.master.config(cursor="watch") self.master.config(cursor="watch")
self.master.update() self.master.update()
@ -149,13 +148,17 @@ class CoreClient:
self.state = session.state self.state = session.state
self.client.events(self.session_id, self.handle_events) self.client.events(self.session_id, self.handle_events)
# get location
if query_location:
response = self.client.get_session_location(self.session_id)
self.location = response.location
# get emane models # get emane models
response = self.client.get_emane_models(self.session_id) response = self.client.get_emane_models(self.session_id)
self.emane_models = response.models self.emane_models = response.models
# get hooks # get hooks
response = self.client.get_hooks(self.session_id) response = self.client.get_hooks(self.session_id)
logging.info("joined session hooks: %s", response)
for hook in response.hooks: for hook in response.hooks:
self.hooks[hook.file] = hook self.hooks[hook.file] = hook
@ -163,19 +166,16 @@ class CoreClient:
for node in session.nodes: for node in session.nodes:
if node.type == core_pb2.NodeType.WIRELESS_LAN: if node.type == core_pb2.NodeType.WIRELESS_LAN:
response = self.client.get_wlan_config(self.session_id, node.id) response = self.client.get_wlan_config(self.session_id, node.id)
logging.debug("wlan config(%s): %s", node.id, response)
self.wlan_configs[node.id] = response.config self.wlan_configs[node.id] = response.config
# get mobility configs # get mobility configs
response = self.client.get_mobility_configs(self.session_id) response = self.client.get_mobility_configs(self.session_id)
logging.debug("mobility configs: %s", response)
for node_id in response.configs: for node_id in response.configs:
node_config = response.configs[node_id].config node_config = response.configs[node_id].config
self.mobility_configs[node_id] = node_config self.mobility_configs[node_id] = node_config
# get emane config # get emane config
response = self.client.get_emane_config(self.session_id) response = self.client.get_emane_config(self.session_id)
logging.debug("emane config: %s", response)
self.emane_config = response.config self.emane_config = response.config
# get emane model config # get emane model config
@ -212,7 +212,17 @@ class CoreClient:
""" """
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"]
self.location = core_pb2.SessionLocation(
x=location_config["x"],
y=location_config["y"],
z=location_config["z"],
lat=location_config["lat"],
lon=location_config["lon"],
alt=location_config["alt"],
scale=location_config["scale"],
)
self.join_session(response.session_id, query_location=False)
def delete_session(self, custom_sid=None): def delete_session(self, custom_sid=None):
if custom_sid is None: if custom_sid is None:
@ -321,13 +331,14 @@ class CoreClient:
self.session_id, self.session_id,
nodes, nodes,
links, links,
hooks=hooks, self.location,
wlan_configs=wlan_configs, hooks,
emane_config=emane_config, emane_config,
emane_model_configs=emane_model_configs, emane_model_configs,
mobility_configs=mobility_configs, wlan_configs,
service_configs=service_configs, mobility_configs,
service_file_configs=file_configs, service_configs,
file_configs,
) )
logging.debug("Start session %s, result: %s", self.session_id, response.result) logging.debug("Start session %s, result: %s", self.session_id, response.result)
print(self.client.get_session(self.session_id)) print(self.client.get_session(self.session_id))
@ -477,11 +488,6 @@ class CoreClient:
image=image, image=image,
emane=emane, emane=emane,
) )
# set default emane configuration for emane node
if node_type == core_pb2.NodeType.EMANE:
self.emaneconfig_management.set_default_config(node_id)
logging.debug( logging.debug(
"adding node to core session: %s, coords: (%s, %s), name: %s", "adding node to core session: %s, coords: (%s, %s), name: %s",
self.session_id, self.session_id,
@ -501,50 +507,28 @@ class CoreClient:
:return: nothing :return: nothing
""" """
# delete the nodes # delete the nodes
for node_id in node_ids: for i in node_ids:
try: try:
del self.canvas_nodes[node_id] del self.canvas_nodes[i]
self.reusable.append(node_id) self.reusable.append(i)
if i in self.mobility_configs:
del self.mobility_configs[i]
if i in self.wlan_configs:
del self.wlan_configs[i]
for key in list(self.emane_model_configs):
node_id, _, _ = key
if node_id == i:
del self.emane_model_configs[key]
except KeyError: except KeyError:
logging.error("invalid canvas id: %s", node_id) logging.error("invalid canvas id: %s", i)
self.reusable.sort() self.reusable.sort()
# delete the edges and interfaces # delete the edges and interfaces
node_interface_pairs = []
for i in edge_tokens: for i in edge_tokens:
try: try:
link = self.links.pop(i) self.links.pop(i)
if link.interface_one is not None:
node_interface_pairs.append(
(link.node_one_id, link.interface_one.id)
)
if link.interface_two is not None:
node_interface_pairs.append(
(link.node_two_id, link.interface_two.id)
)
except KeyError: except KeyError:
logging.error("coreclient.py invalid edge token ") logging.error("invalid edge token: %s", i)
# delete global emane config if there no longer exist any emane cloud
# TODO: should not need to worry about this
node_types = [x.core_node.type for x in self.canvas_nodes.values()]
if core_pb2.NodeType.EMANE not in node_types:
self.emane_config = None
# delete any mobility configuration, wlan configuration
for i in node_ids:
if i in self.mobility_configs:
del self.mobility_configs[i]
if i in self.wlan_configs:
del self.wlan_configs[i]
# delete emane configurations
for i in node_interface_pairs:
if i in self.emaneconfig_management.configurations:
self.emaneconfig_management.configurations.pop(i)
for i in node_ids:
if tuple([i, None]) in self.emaneconfig_management.configurations:
self.emaneconfig_management.configurations.pop(tuple([i, None]))
def create_interface(self, canvas_node): def create_interface(self, canvas_node):
interface = None interface = None
@ -618,13 +602,11 @@ class CoreClient:
def get_emane_model_configs_proto(self): def get_emane_model_configs_proto(self):
configs = [] configs = []
emane_configs = self.emaneconfig_management.configurations for key, config in self.emane_model_configs.items():
for key, value in emane_configs.items(): node_id, model, interface = key
node_id, interface_id = key config = {x: config[x].value for x in config}
model, options = value
config = {x: options[x].value for x in options}
config_proto = core_pb2.EmaneModelConfig( config_proto = core_pb2.EmaneModelConfig(
node_id=node_id, interface_id=interface_id, model=model, config=config node_id=node_id, interface_id=interface, model=model, config=config
) )
configs.append(config_proto) configs.append(config_proto)
return configs return configs
@ -671,3 +653,17 @@ class CoreClient:
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
return config return config
def get_emane_model_config(self, node_id, model, interface=None):
config = self.emane_model_configs.get((node_id, model, interface))
if not config:
if interface is None:
interface = -1
response = self.client.get_emane_model_config(
self.session_id, node_id, model, interface
)
config = response.config
return config
def set_emane_model_config(self, node_id, model, config, interface=None):
self.emane_model_configs[(node_id, model, interface)] = config

View file

@ -6,8 +6,8 @@ from tkinter import font, ttk
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
FRAME_PAD = 5 PAD = 5
PADX = 5 PIXEL_SCALE = 100
class SizeAndScaleDialog(Dialog): class SizeAndScaleDialog(Dialog):
@ -19,9 +19,7 @@ class SizeAndScaleDialog(Dialog):
""" """
super().__init__(master, app, "Canvas Size and Scale", modal=True) super().__init__(master, app, "Canvas Size and Scale", modal=True)
self.canvas = self.app.canvas self.canvas = self.app.canvas
self.meter_per_pixel = self.canvas.meters_per_pixel
self.section_font = font.Font(weight="bold") self.section_font = font.Font(weight="bold")
# get current canvas dimensions # get current canvas dimensions
plot = self.canvas.find_withtag("rectangle") plot = self.canvas.find_withtag("rectangle")
x0, y0, x1, y1 = self.canvas.bbox(plot[0]) x0, y0, x1, y1 = self.canvas.bbox(plot[0])
@ -29,14 +27,15 @@ class SizeAndScaleDialog(Dialog):
height = abs(y0 - y1) - 2 height = abs(y0 - y1) - 2
self.pixel_width = tk.IntVar(value=width) self.pixel_width = tk.IntVar(value=width)
self.pixel_height = tk.IntVar(value=height) self.pixel_height = tk.IntVar(value=height)
self.meters_width = tk.IntVar(value=width * self.meter_per_pixel) location = self.app.core.location
self.meters_height = tk.IntVar(value=height * self.meter_per_pixel) self.x = tk.DoubleVar(value=location.x)
self.scale = tk.IntVar(value=self.meter_per_pixel * 100) self.y = tk.DoubleVar(value=location.y)
self.x = tk.IntVar(value=0) self.lat = tk.DoubleVar(value=location.lat)
self.y = tk.IntVar(value=0) self.lon = tk.DoubleVar(value=location.lon)
self.lat = tk.DoubleVar(value=47.5791667) self.alt = tk.DoubleVar(value=location.alt)
self.lon = tk.DoubleVar(value=-122.132322) self.scale = tk.DoubleVar(value=location.scale)
self.alt = tk.DoubleVar(value=2.0) self.meters_width = tk.IntVar(value=width / PIXEL_SCALE * location.scale)
self.meters_height = tk.IntVar(value=height / PIXEL_SCALE * location.scale)
self.save_default = tk.BooleanVar(value=False) self.save_default = tk.BooleanVar(value=False)
self.draw() self.draw()
@ -49,7 +48,7 @@ class SizeAndScaleDialog(Dialog):
self.draw_buttons() self.draw_buttons()
def draw_size(self): def draw_size(self):
label_frame = ttk.Labelframe(self.top, text="Size", padding=FRAME_PAD) label_frame = ttk.Labelframe(self.top, text="Size", padding=PAD)
label_frame.grid(sticky="ew") label_frame.grid(sticky="ew")
label_frame.columnconfigure(0, weight=1) label_frame.columnconfigure(0, weight=1)
@ -59,13 +58,13 @@ class SizeAndScaleDialog(Dialog):
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
frame.columnconfigure(3, weight=1) frame.columnconfigure(3, weight=1)
label = ttk.Label(frame, text="Width") label = ttk.Label(frame, text="Width")
label.grid(row=0, column=0, sticky="w", padx=PADX) label.grid(row=0, column=0, sticky="w", padx=PAD)
entry = ttk.Entry(frame, textvariable=self.pixel_width) entry = ttk.Entry(frame, textvariable=self.pixel_width)
entry.grid(row=0, column=1, sticky="ew", padx=PADX) entry.grid(row=0, column=1, sticky="ew", padx=PAD)
label = ttk.Label(frame, text="x Height") label = ttk.Label(frame, text="x Height")
label.grid(row=0, column=2, sticky="w", padx=PADX) label.grid(row=0, column=2, sticky="w", padx=PAD)
entry = ttk.Entry(frame, textvariable=self.pixel_height) entry = ttk.Entry(frame, textvariable=self.pixel_height)
entry.grid(row=0, column=3, sticky="ew", padx=PADX) entry.grid(row=0, column=3, sticky="ew", padx=PAD)
label = ttk.Label(frame, text="Pixels") label = ttk.Label(frame, text="Pixels")
label.grid(row=0, column=4, sticky="w") label.grid(row=0, column=4, sticky="w")
@ -75,35 +74,33 @@ class SizeAndScaleDialog(Dialog):
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
frame.columnconfigure(3, weight=1) frame.columnconfigure(3, weight=1)
label = ttk.Label(frame, text="Width") label = ttk.Label(frame, text="Width")
label.grid(row=0, column=0, sticky="w", padx=PADX) label.grid(row=0, column=0, sticky="w", padx=PAD)
entry = ttk.Entry(frame, textvariable=self.meters_width) entry = ttk.Entry(frame, textvariable=self.meters_width)
entry.grid(row=0, column=1, sticky="ew", padx=PADX) entry.grid(row=0, column=1, sticky="ew", padx=PAD)
label = ttk.Label(frame, text="x Height") label = ttk.Label(frame, text="x Height")
label.grid(row=0, column=2, sticky="w", padx=PADX) label.grid(row=0, column=2, sticky="w", padx=PAD)
entry = ttk.Entry(frame, textvariable=self.meters_height) entry = ttk.Entry(frame, textvariable=self.meters_height)
entry.grid(row=0, column=3, sticky="ew", padx=PADX) entry.grid(row=0, column=3, sticky="ew", padx=PAD)
label = ttk.Label(frame, text="Meters") label = ttk.Label(frame, text="Meters")
label.grid(row=0, column=4, sticky="w") label.grid(row=0, column=4, sticky="w")
def draw_scale(self): def draw_scale(self):
label_frame = ttk.Labelframe(self.top, text="Scale", padding=FRAME_PAD) label_frame = ttk.Labelframe(self.top, text="Scale", padding=PAD)
label_frame.grid(sticky="ew") label_frame.grid(sticky="ew")
label_frame.columnconfigure(0, weight=1) label_frame.columnconfigure(0, weight=1)
frame = ttk.Frame(label_frame) frame = ttk.Frame(label_frame)
frame.grid(sticky="ew") frame.grid(sticky="ew")
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
label = ttk.Label(frame, text="100 Pixels =") label = ttk.Label(frame, text=f"{PIXEL_SCALE} Pixels =")
label.grid(row=0, column=0, sticky="w", padx=PADX) label.grid(row=0, column=0, sticky="w", padx=PAD)
entry = ttk.Entry(frame, textvariable=self.scale) entry = ttk.Entry(frame, textvariable=self.scale)
entry.grid(row=0, column=1, sticky="ew", padx=PADX) entry.grid(row=0, column=1, sticky="ew", padx=PAD)
label = ttk.Label(frame, text="Meters") label = ttk.Label(frame, text="Meters")
label.grid(row=0, column=2, sticky="w") label.grid(row=0, column=2, sticky="w")
def draw_reference_point(self): def draw_reference_point(self):
label_frame = ttk.Labelframe( label_frame = ttk.Labelframe(self.top, text="Reference Point", padding=PAD)
self.top, text="Reference Point", padding=FRAME_PAD
)
label_frame.grid(sticky="ew") label_frame.grid(sticky="ew")
label_frame.columnconfigure(0, weight=1) label_frame.columnconfigure(0, weight=1)
@ -118,14 +115,14 @@ class SizeAndScaleDialog(Dialog):
frame.columnconfigure(3, weight=1) frame.columnconfigure(3, weight=1)
label = ttk.Label(frame, text="X") label = ttk.Label(frame, text="X")
label.grid(row=0, column=0, sticky="w", padx=PADX) label.grid(row=0, column=0, sticky="w", padx=PAD)
entry = ttk.Entry(frame, textvariable=self.x) entry = ttk.Entry(frame, textvariable=self.x)
entry.grid(row=0, column=1, sticky="ew", padx=PADX) entry.grid(row=0, column=1, sticky="ew", padx=PAD)
label = ttk.Label(frame, text="Y") label = ttk.Label(frame, text="Y")
label.grid(row=0, column=2, sticky="w", padx=PADX) label.grid(row=0, column=2, sticky="w", padx=PAD)
entry = ttk.Entry(frame, textvariable=self.y) entry = ttk.Entry(frame, textvariable=self.y)
entry.grid(row=0, column=3, sticky="ew", padx=PADX) entry.grid(row=0, column=3, sticky="ew", padx=PAD)
label = ttk.Label(label_frame, text="Translates To") label = ttk.Label(label_frame, text="Translates To")
label.grid() label.grid()
@ -137,17 +134,17 @@ class SizeAndScaleDialog(Dialog):
frame.columnconfigure(5, weight=1) frame.columnconfigure(5, weight=1)
label = ttk.Label(frame, text="Lat") label = ttk.Label(frame, text="Lat")
label.grid(row=0, column=0, sticky="w", padx=PADX) label.grid(row=0, column=0, sticky="w", padx=PAD)
entry = ttk.Entry(frame, textvariable=self.lat) entry = ttk.Entry(frame, textvariable=self.lat)
entry.grid(row=0, column=1, sticky="ew", padx=PADX) entry.grid(row=0, column=1, sticky="ew", padx=PAD)
label = ttk.Label(frame, text="Lon") label = ttk.Label(frame, text="Lon")
label.grid(row=0, column=2, sticky="w", padx=PADX) label.grid(row=0, column=2, sticky="w", padx=PAD)
entry = ttk.Entry(frame, textvariable=self.lon) entry = ttk.Entry(frame, textvariable=self.lon)
entry.grid(row=0, column=3, sticky="ew", padx=PADX) entry.grid(row=0, column=3, sticky="ew", padx=PAD)
label = ttk.Label(frame, text="Alt") label = ttk.Label(frame, text="Alt")
label.grid(row=0, column=4, sticky="w", padx=PADX) label.grid(row=0, column=4, sticky="w", padx=PAD)
entry = ttk.Entry(frame, textvariable=self.alt) entry = ttk.Entry(frame, textvariable=self.alt)
entry.grid(row=0, column=5, sticky="ew") entry.grid(row=0, column=5, sticky="ew")
@ -164,16 +161,31 @@ class SizeAndScaleDialog(Dialog):
frame.grid(sticky="ew") frame.grid(sticky="ew")
button = ttk.Button(frame, text="Apply", command=self.click_apply) button = ttk.Button(frame, text="Apply", command=self.click_apply)
button.grid(row=0, column=0, sticky="ew", padx=PADX) button.grid(row=0, column=0, sticky="ew", padx=PAD)
button = ttk.Button(frame, text="Cancel", command=self.destroy) button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew") button.grid(row=0, column=1, sticky="ew")
def click_apply(self): def click_apply(self):
meter_per_pixel = float(self.scale.get()) / 100
width, height = self.pixel_width.get(), self.pixel_height.get() width, height = self.pixel_width.get(), self.pixel_height.get()
self.canvas.meters_per_pixel = meter_per_pixel
self.canvas.redraw_grid(width, height) self.canvas.redraw_grid(width, height)
if self.canvas.wallpaper: if self.canvas.wallpaper:
self.canvas.redraw() self.canvas.redraw()
location = self.app.core.location
location.x = self.x.get()
location.y = self.y.get()
location.lat = self.lat.get()
location.lon = self.lon.get()
location.alt = self.alt.get()
location.scale = self.scale.get()
if self.save_default.get():
location_config = self.app.guiconfig["location"]
location_config["x"] = location.x
location_config["y"] = location.y
location_config["z"] = location.z
location_config["lat"] = location.lat
location_config["lon"] = location.lon
location_config["alt"] = location.alt
location_config["scale"] = location.scale
self.app.save_config()
self.destroy() self.destroy()

View file

@ -180,17 +180,17 @@ class CustomNodesDialog(Dialog):
self.services.update(dialog.current_services) self.services.update(dialog.current_services)
def click_save(self): def click_save(self):
self.app.config["nodes"].clear() self.app.guiconfig["nodes"].clear()
for name in sorted(self.app.core.custom_nodes): for name in sorted(self.app.core.custom_nodes):
node_draw = self.app.core.custom_nodes[name] node_draw = self.app.core.custom_nodes[name]
self.app.config["nodes"].append( self.app.guiconfig["nodes"].append(
{ {
"name": name, "name": name,
"image": node_draw.image_file, "image": node_draw.image_file,
"services": list(node_draw.services), "services": list(node_draw.services),
} }
) )
logging.info("saving custom nodes: %s", self.app.config["nodes"]) logging.info("saving custom nodes: %s", self.app.guiconfig["nodes"])
self.app.save_config() self.app.save_config()
self.destroy() self.destroy()

View file

@ -46,16 +46,15 @@ class GlobalEmaneDialog(Dialog):
class EmaneModelDialog(Dialog): class EmaneModelDialog(Dialog):
def __init__(self, master, app, node, model): def __init__(self, master, app, node, model, interface=None):
super().__init__(master, app, f"{node.name} {model} Configuration", modal=True) super().__init__(master, app, f"{node.name} {model} Configuration", modal=True)
self.node = node self.node = node
self.model = f"emane_{model}" self.model = f"emane_{model}"
self.interface = interface
self.config_frame = None self.config_frame = None
session_id = self.app.core.session_id self.config = self.app.core.get_emane_model_config(
response = self.app.core.client.get_emane_model_config( self.node.id, self.model, self.interface
session_id, self.node.id, self.model
) )
self.config = response.config
self.draw() self.draw()
def draw(self): def draw(self):
@ -79,8 +78,8 @@ class EmaneModelDialog(Dialog):
def click_apply(self): def click_apply(self):
self.config_frame.parse_config() self.config_frame.parse_config()
self.app.core.emaneconfig_management.set_custom_emane_cloud_config( self.app.core.set_emane_model_config(
self.node.id, self.model self.node.id, self.model, self.config, self.interface
) )
self.destroy() self.destroy()

View file

@ -95,7 +95,7 @@ class ObserverDialog(Dialog):
for name in sorted(self.app.core.custom_observers): for name in sorted(self.app.core.custom_observers):
observer = self.app.core.custom_observers[name] observer = self.app.core.custom_observers[name]
observers.append({"name": observer.name, "cmd": observer.cmd}) observers.append({"name": observer.name, "cmd": observer.cmd})
self.app.config["observers"] = observers self.app.guiconfig["observers"] = observers
self.app.save_config() self.app.save_config()
self.destroy() self.destroy()

View file

@ -9,7 +9,7 @@ from coretk.dialogs.dialog import Dialog
class PreferencesDialog(Dialog): class PreferencesDialog(Dialog):
def __init__(self, master, app): def __init__(self, master, app):
super().__init__(master, app, "Preferences", modal=True) super().__init__(master, app, "Preferences", modal=True)
preferences = self.app.config["preferences"] preferences = self.app.guiconfig["preferences"]
self.editor = tk.StringVar(value=preferences["editor"]) self.editor = tk.StringVar(value=preferences["editor"])
self.theme = tk.StringVar(value=preferences["theme"]) self.theme = tk.StringVar(value=preferences["theme"])
self.terminal = tk.StringVar(value=preferences["terminal"]) self.terminal = tk.StringVar(value=preferences["terminal"])
@ -76,7 +76,7 @@ class PreferencesDialog(Dialog):
self.app.style.theme_use(theme) self.app.style.theme_use(theme)
def click_save(self): def click_save(self):
preferences = self.app.config["preferences"] preferences = self.app.guiconfig["preferences"]
preferences["terminal"] = self.terminal.get() preferences["terminal"] = self.terminal.get()
preferences["editor"] = self.editor.get() preferences["editor"] = self.editor.get()
preferences["gui3d"] = self.gui3d.get() preferences["gui3d"] = self.gui3d.get()

View file

@ -115,7 +115,7 @@ class ServersDialog(Dialog):
servers.append( servers.append(
{"name": server.name, "address": server.address, "port": server.port} {"name": server.name, "address": server.address, "port": server.port}
) )
self.app.config["servers"] = servers self.app.guiconfig["servers"] = servers
self.app.save_config() self.app.save_config()
self.destroy() self.destroy()

View file

@ -1,78 +0,0 @@
"""
emane model configurations
"""
import logging
class EmaneModelNodeConfig:
def __init__(self, app):
"""
create an instance for EmaneModelNodeConfig
:param app: application
"""
# dict(tuple(node_id, interface_id, model) : config)
self.configurations = {}
# dict(int, list(int)) stores emane node maps to mdr nodes that are linked to that emane node
self.links = {}
self.app = app
def set_default_config(self, node_id):
"""
set a default emane configuration for a newly created emane
:param int node_id: node id
:return: nothing
"""
session_id = self.app.core.session_id
client = self.app.core.client
default_emane_model = self.app.core.emane_models[0]
response = client.get_emane_model_config(
session_id, node_id, default_emane_model
)
logging.info(
"emanemodelnodeconfig.py get emane model config (%s), result: %s",
node_id,
response,
)
self.configurations[tuple([node_id, None])] = tuple(
[default_emane_model, response.config]
)
self.links[node_id] = []
def set_default_for_mdr(self, emane_node_id, mdr_node_id, interface_id):
"""
set emane configuration of an mdr node on the correct interface
:param int emane_node_id: emane node id
:param int mdr_node_id: mdr node id
:param int interface_id: interface id
:return: nothing
"""
self.configurations[tuple([mdr_node_id, interface_id])] = self.configurations[
tuple([emane_node_id, None])
]
self.links[emane_node_id].append(tuple([mdr_node_id, interface_id]))
def set_custom_emane_cloud_config(self, emane_node_id, model_name):
"""
set custom configuration for an emane node, if model is changed, update the nodes connected to that emane node
:param int emane_node_id: emane node id
:param str model_name: model name
:return: nothing
"""
prev_model_name = self.configurations[tuple([emane_node_id, None])][0]
session_id = self.app.core.session_id
response = self.app.core.client.get_emane_model_config(
session_id, emane_node_id, model_name
)
self.configurations[tuple([emane_node_id, None])] = tuple(
[model_name, response.config]
)
if prev_model_name != model_name:
for k in self.links[emane_node_id]:
self.configurations[k] = tuple([model_name, response.config])

View file

@ -18,6 +18,8 @@ from coretk.nodedelete import CanvasComponentManagement
from coretk.nodeutils import NodeUtils from coretk.nodeutils import NodeUtils
from coretk.wirelessconnection import WirelessConnection from coretk.wirelessconnection import WirelessConnection
NODE_TEXT_OFFSET = 5
class GraphMode(enum.Enum): class GraphMode(enum.Enum):
SELECT = 0 SELECT = 0
@ -49,7 +51,6 @@ class CanvasGraph(tk.Canvas):
self.edges = {} self.edges = {}
self.drawing_edge = None self.drawing_edge = None
self.grid = None self.grid = None
self.meters_per_pixel = 1.5
self.canvas_management = CanvasComponentManagement(self, core) self.canvas_management = CanvasComponentManagement(self, core)
self.setup_bindings() self.setup_bindings()
self.draw_grid() self.draw_grid()
@ -176,48 +177,53 @@ class CanvasGraph(tk.Canvas):
node_one = canvas_node_one.core_node node_one = canvas_node_one.core_node
canvas_node_two = self.core.canvas_nodes[link.node_two_id] canvas_node_two = self.core.canvas_nodes[link.node_two_id]
node_two = canvas_node_two.core_node node_two = canvas_node_two.core_node
is_wired = link.type == core_pb2.LinkType.WIRED if link.type == core_pb2.LinkType.WIRELESS:
edge = CanvasEdge( self.wireless_draw.add_connection(link.node_one_id, link.node_two_id)
node_one.position.x, else:
node_one.position.y, is_node_one_wireless = NodeUtils.is_wireless_node(node_one.type)
node_two.position.x, is_node_two_wireless = NodeUtils.is_wireless_node(node_two.type)
node_two.position.y, has_no_wireless = not (is_node_one_wireless or is_node_two_wireless)
canvas_node_one.id, edge = CanvasEdge(
self, node_one.position.x,
is_wired=is_wired, node_one.position.y,
) node_two.position.x,
edge.token = tuple(sorted((canvas_node_one.id, canvas_node_two.id))) node_two.position.y,
edge.dst = canvas_node_two.id canvas_node_one.id,
canvas_node_one.edges.add(edge) self,
canvas_node_two.edges.add(edge) is_wired=has_no_wireless,
self.edges[edge.token] = edge )
self.core.links[edge.token] = link edge.token = tuple(sorted((canvas_node_one.id, canvas_node_two.id)))
self.helper.redraw_antenna(link, canvas_node_one, canvas_node_two) edge.dst = canvas_node_two.id
canvas_node_one.edges.add(edge)
canvas_node_two.edges.add(edge)
self.edges[edge.token] = edge
self.core.links[edge.token] = link
self.helper.redraw_antenna(canvas_node_one, canvas_node_two)
# TODO add back the link info to grpc manager also redraw # TODO add back the link info to grpc manager also redraw
# TODO will include throughput and ipv6 in the future # TODO will include throughput and ipv6 in the future
interface_one = link.interface_one interface_one = link.interface_one
interface_two = link.interface_two interface_two = link.interface_two
ip4_src = None ip4_src = None
ip4_dst = None ip4_dst = None
ip6_src = None ip6_src = None
ip6_dst = None ip6_dst = None
if interface_one is not None: if interface_one is not None:
ip4_src = interface_one.ip4 ip4_src = interface_one.ip4
ip6_src = interface_one.ip6 ip6_src = interface_one.ip6
if interface_two is not None: if interface_two is not None:
ip4_dst = interface_two.ip4 ip4_dst = interface_two.ip4
ip6_dst = interface_two.ip6 ip6_dst = interface_two.ip6
edge.link_info = LinkInfo( edge.link_info = LinkInfo(
canvas=self, canvas=self,
edge=edge, edge=edge,
ip4_src=ip4_src, ip4_src=ip4_src,
ip6_src=ip6_src, ip6_src=ip6_src,
ip4_dst=ip4_dst, ip4_dst=ip4_dst,
ip6_dst=ip6_dst, ip6_dst=ip6_dst,
) )
canvas_node_one.interfaces.append(interface_one) canvas_node_one.interfaces.append(interface_one)
canvas_node_two.interfaces.append(interface_two) canvas_node_two.interfaces.append(interface_two)
# raise the nodes so they on top of the links # raise the nodes so they on top of the links
self.tag_raise("node") self.tag_raise("node")
@ -611,8 +617,10 @@ class CanvasNode:
self.id = self.canvas.create_image( self.id = self.canvas.create_image(
x, y, anchor=tk.CENTER, image=self.image, tags="node" x, y, anchor=tk.CENTER, image=self.image, tags="node"
) )
image_box = self.canvas.bbox(self.id)
y = image_box[3] + NODE_TEXT_OFFSET
self.text_id = self.canvas.create_text( self.text_id = self.canvas.create_text(
x, y + 20, text=self.core_node.name, tags="nodename" x, y, text=self.core_node.name, tags="nodename"
) )
self.antenna_draw = WlanAntennaManager(self.canvas, self.id) self.antenna_draw = WlanAntennaManager(self.canvas, self.id)
self.tooltip = CanvasTooltip(self.canvas) self.tooltip = CanvasTooltip(self.canvas)

View file

@ -4,8 +4,8 @@ Some graph helper functions
import logging import logging
import tkinter as tk import tkinter as tk
from core.api.grpc import core_pb2
from coretk.images import ImageEnum, Images from coretk.images import ImageEnum, Images
from coretk.nodeutils import NodeUtils
CANVAS_COMPONENT_TAGS = ["edge", "node", "nodename", "wallpaper", "linkinfo"] CANVAS_COMPONENT_TAGS = ["edge", "node", "nodename", "wallpaper", "linkinfo"]
@ -31,34 +31,30 @@ class GraphHelper:
def draw_wireless_case(self, src_id, dst_id, edge): def draw_wireless_case(self, src_id, dst_id, edge):
src_node_type = self.canvas.nodes[src_id].core_node.type src_node_type = self.canvas.nodes[src_id].core_node.type
dst_node_type = self.canvas.nodes[dst_id].core_node.type dst_node_type = self.canvas.nodes[dst_id].core_node.type
is_src_wlan = src_node_type == core_pb2.NodeType.WIRELESS_LAN is_src_wireless = NodeUtils.is_wireless_node(src_node_type)
is_dst_wlan = dst_node_type == core_pb2.NodeType.WIRELESS_LAN is_dst_wireless = NodeUtils.is_wireless_node(dst_node_type)
if is_src_wlan or is_dst_wlan: if is_src_wireless or is_dst_wireless:
self.canvas.itemconfig(edge.id, state=tk.HIDDEN) self.canvas.itemconfig(edge.id, state=tk.HIDDEN)
edge.wired = False edge.wired = False
if edge.token not in self.canvas.edges: if edge.token not in self.canvas.edges:
if is_src_wlan and is_dst_wlan: if is_src_wireless and is_dst_wireless:
self.canvas.nodes[src_id].antenna_draw.add_antenna() self.canvas.nodes[src_id].antenna_draw.add_antenna()
elif is_src_wlan: elif is_src_wireless:
self.canvas.nodes[dst_id].antenna_draw.add_antenna() self.canvas.nodes[dst_id].antenna_draw.add_antenna()
else: else:
self.canvas.nodes[src_id].antenna_draw.add_antenna() self.canvas.nodes[src_id].antenna_draw.add_antenna()
edge.wired = True edge.wired = True
def redraw_antenna(self, link, node_one, node_two): def redraw_antenna(self, node_one, node_two):
is_node_one_wlan = node_one.core_node.type == core_pb2.NodeType.WIRELESS_LAN is_node_one_wireless = NodeUtils.is_wireless_node(node_one.core_node.type)
is_node_two_wlan = node_two.core_node.type == core_pb2.NodeType.WIRELESS_LAN is_node_two_wireless = NodeUtils.is_wireless_node(node_two.core_node.type)
if link.type == core_pb2.LinkType.WIRELESS: if is_node_one_wireless or is_node_two_wireless:
if is_node_one_wlan and is_node_two_wlan: if is_node_one_wireless and not is_node_two_wireless:
node_one.antenna_draw.add_antenna()
elif is_node_one_wlan and not is_node_two_wlan:
node_two.antenna_draw.add_antenna() node_two.antenna_draw.add_antenna()
elif not is_node_one_wlan and is_node_two_wlan: elif not is_node_one_wireless and is_node_two_wireless:
node_one.antenna_draw.add_antenna() node_one.antenna_draw.add_antenna()
else: else:
logging.error( logging.error("bad link between two wireless nodes")
"graph_helper.py WIRELESS link but both nodes are non-wireless node"
)
def update_wlan_connection(self, old_x, old_y, new_x, new_y, edge_ids): def update_wlan_connection(self, old_x, old_y, new_x, new_y, edge_ids):
for eid in edge_ids: for eid in edge_ids:

View file

@ -4,8 +4,6 @@ from PIL import Image, ImageTk
from coretk.appconfig import LOCAL_ICONS_PATH from coretk.appconfig import LOCAL_ICONS_PATH
NODE_WIDTH = 32
class Images: class Images:
images = {} images = {}

View file

@ -18,7 +18,6 @@ class LinkInfo:
""" """
self.canvas = canvas self.canvas = canvas
self.edge = edge self.edge = edge
# self.edge_id = edge.id
self.radius = 37 self.radius = 37
self.core = self.canvas.core self.core = self.canvas.core

View file

@ -444,9 +444,7 @@ class Menubar(tk.Menu):
menu.add_command(label="Comments...", state=tk.DISABLED) menu.add_command(label="Comments...", state=tk.DISABLED)
menu.add_command(label="Hooks...", command=self.menuaction.session_hooks) menu.add_command(label="Hooks...", command=self.menuaction.session_hooks)
menu.add_command(label="Reset node positions", state=tk.DISABLED) menu.add_command(label="Reset node positions", state=tk.DISABLED)
menu.add_command( menu.add_command(label="Servers...", command=self.menuaction.session_servers)
label="Emulation servers...", command=self.menuaction.session_servers
)
menu.add_command(label="Options...", command=self.menuaction.session_options) menu.add_command(label="Options...", command=self.menuaction.session_options)
self.add_cascade(label="Session", menu=menu) self.add_cascade(label="Session", menu=menu)
@ -458,7 +456,7 @@ class Menubar(tk.Menu):
""" """
menu = tk.Menu(self) menu = tk.Menu(self)
menu.add_command( menu.add_command(
label="Core Github (www)", command=self.menuaction.help_core_github label="Core GitHub (www)", command=self.menuaction.help_core_github
) )
menu.add_command( menu.add_command(
label="Core Documentation (www)", label="Core Documentation (www)",

View file

@ -1,7 +1,7 @@
from core.api.grpc.core_pb2 import NodeType from core.api.grpc.core_pb2 import NodeType
from coretk.images import ImageEnum, Images from coretk.images import ImageEnum, Images
ICON_SIZE = 32 ICON_SIZE = 48
class NodeDraw: class NodeDraw:
@ -46,6 +46,7 @@ class NodeUtils:
NODE_ICONS = {} NODE_ICONS = {}
CONTAINER_NODES = {NodeType.DEFAULT, NodeType.DOCKER, NodeType.LXC} CONTAINER_NODES = {NodeType.DEFAULT, NodeType.DOCKER, NodeType.LXC}
IMAGE_NODES = {NodeType.DOCKER, NodeType.LXC} IMAGE_NODES = {NodeType.DOCKER, NodeType.LXC}
WIRELESS_NODES = {NodeType.WIRELESS_LAN, NodeType.EMANE}
NODE_MODELS = {"router", "host", "PC", "mdr", "prouter"} NODE_MODELS = {"router", "host", "PC", "mdr", "prouter"}
@classmethod @classmethod
@ -60,8 +61,14 @@ class NodeUtils:
def is_image_node(cls, node_type): def is_image_node(cls, node_type):
return node_type in cls.IMAGE_NODES return node_type in cls.IMAGE_NODES
@classmethod
def is_wireless_node(cls, node_type):
return node_type in cls.WIRELESS_NODES
@classmethod @classmethod
def node_icon(cls, node_type, model): def node_icon(cls, node_type, model):
if model == "":
model = None
return cls.NODE_ICONS[(node_type, model)] return cls.NODE_ICONS[(node_type, model)]
@classmethod @classmethod

View file

@ -137,6 +137,8 @@ def update_menu(style, event):
bg = style.lookup(".", "background") bg = style.lookup(".", "background")
fg = style.lookup(".", "foreground") fg = style.lookup(".", "foreground")
abg = style.lookup(".", "lightcolor") abg = style.lookup(".", "lightcolor")
if not abg:
abg = bg
event.widget.config( event.widget.config(
background=bg, foreground=fg, activebackground=abg, activeforeground=fg background=bg, foreground=fg, activebackground=abg, activeforeground=fg
) )

View file

@ -11,7 +11,7 @@ class WirelessConnection:
# map a (node_one_id, node_two_id) to a wlan canvas id # map a (node_one_id, node_two_id) to a wlan canvas id
self.map = {} self.map = {}
def add_wlan_connection(self, node_one_id, node_two_id): def add_connection(self, node_one_id, node_two_id):
canvas_node_one = self.core.canvas_nodes[node_one_id] canvas_node_one = self.core.canvas_nodes[node_one_id]
canvas_node_two = self.core.canvas_nodes[node_two_id] canvas_node_two = self.core.canvas_nodes[node_two_id]
key = tuple(sorted((node_one_id, node_two_id))) key = tuple(sorted((node_one_id, node_two_id)))
@ -25,7 +25,7 @@ class WirelessConnection:
canvas_node_one.wlans.append(wlan_canvas_id) canvas_node_one.wlans.append(wlan_canvas_id)
canvas_node_two.wlans.append(wlan_canvas_id) canvas_node_two.wlans.append(wlan_canvas_id)
def delete_wlan_connection(self, node_one_id, node_two_id): def delete_connection(self, node_one_id, node_two_id):
canvas_node_one = self.core.canvas_nodes[node_one_id] canvas_node_one = self.core.canvas_nodes[node_one_id]
canvas_node_two = self.core.canvas_nodes[node_two_id] canvas_node_two = self.core.canvas_nodes[node_two_id]
key = tuple(sorted((node_one_id, node_two_id))) key = tuple(sorted((node_one_id, node_two_id)))
@ -35,13 +35,13 @@ class WirelessConnection:
self.canvas.delete(wlan_canvas_id) self.canvas.delete(wlan_canvas_id)
self.map.pop(key, None) self.map.pop(key, None)
def hangle_link_event(self, link_event): def handle_link_event(self, link_event):
if link_event.message_type == core_pb2.MessageType.ADD: if link_event.message_type == core_pb2.MessageType.ADD:
self.add_wlan_connection( self.add_connection(
link_event.link.node_one_id, link_event.link.node_two_id link_event.link.node_one_id, link_event.link.node_two_id
) )
if link_event.message_type == core_pb2.MessageType.DELETE: if link_event.message_type == core_pb2.MessageType.DELETE:
self.delete_wlan_connection( self.delete_connection(
link_event.link.node_one_id, link_event.link.node_two_id link_event.link.node_one_id, link_event.link.node_two_id
) )

View file

@ -704,7 +704,7 @@ class Session:
self.services.add_services(node, node.type, options.services) self.services.add_services(node, node.type, options.services)
# ensure default emane configuration # ensure default emane configuration
if isinstance(node, EmaneNet): if isinstance(node, EmaneNet) and options.emane:
self.emane.set_model_config(_id, options.emane) self.emane.set_model_config(_id, options.emane)
# set default wlan config if needed # set default wlan config if needed
if isinstance(node, WlanNode): if isinstance(node, WlanNode):

View file

@ -1017,7 +1017,7 @@ class WlanNode(CoreNetwork):
""" """
apitype = NodeTypes.WIRELESS_LAN.value apitype = NodeTypes.WIRELESS_LAN.value
linktype = LinkTypes.WIRELESS.value linktype = LinkTypes.WIRED.value
policy = "DROP" policy = "DROP"
type = "wlan" type = "wlan"