grpc/pygui: added grpc alert api, updated pygui to better handle and display alerts
This commit is contained in:
parent
e34002b851
commit
f8d862a296
7 changed files with 97 additions and 31 deletions
|
@ -445,6 +445,23 @@ class CoreGrpcClient:
|
||||||
)
|
)
|
||||||
return self.stub.AddSessionServer(request)
|
return self.stub.AddSessionServer(request)
|
||||||
|
|
||||||
|
def alert(
|
||||||
|
self,
|
||||||
|
session_id: int,
|
||||||
|
level: core_pb2.ExceptionLevel,
|
||||||
|
source: str,
|
||||||
|
text: str,
|
||||||
|
node_id: int = None,
|
||||||
|
) -> core_pb2.SessionAlertResponse:
|
||||||
|
request = core_pb2.SessionAlertRequest(
|
||||||
|
session_id=session_id,
|
||||||
|
level=level,
|
||||||
|
source=source,
|
||||||
|
text=text,
|
||||||
|
node_id=node_id,
|
||||||
|
)
|
||||||
|
return self.stub.SessionAlert(request)
|
||||||
|
|
||||||
def events(
|
def events(
|
||||||
self,
|
self,
|
||||||
session_id: int,
|
session_id: int,
|
||||||
|
|
|
@ -109,7 +109,12 @@ from core.api.grpc.wlan_pb2 import (
|
||||||
)
|
)
|
||||||
from core.emulator.coreemu import CoreEmu
|
from core.emulator.coreemu import CoreEmu
|
||||||
from core.emulator.data import InterfaceData, LinkData, LinkOptions, NodeOptions
|
from core.emulator.data import InterfaceData, LinkData, LinkOptions, NodeOptions
|
||||||
from core.emulator.enumerations import EventTypes, LinkTypes, MessageFlags
|
from core.emulator.enumerations import (
|
||||||
|
EventTypes,
|
||||||
|
ExceptionLevels,
|
||||||
|
LinkTypes,
|
||||||
|
MessageFlags,
|
||||||
|
)
|
||||||
from core.emulator.session import NT, Session
|
from core.emulator.session import NT, Session
|
||||||
from core.errors import CoreCommandError, CoreError
|
from core.errors import CoreCommandError, CoreError
|
||||||
from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
|
from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
|
||||||
|
@ -584,6 +589,15 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
|
||||||
session.distributed.add_server(request.name, request.host)
|
session.distributed.add_server(request.name, request.host)
|
||||||
return core_pb2.AddSessionServerResponse(result=True)
|
return core_pb2.AddSessionServerResponse(result=True)
|
||||||
|
|
||||||
|
def SessionAlert(
|
||||||
|
self, request: core_pb2.SessionAlertRequest, context: ServicerContext
|
||||||
|
) -> core_pb2.SessionAlertResponse:
|
||||||
|
session = self.get_session(request.session_id, context)
|
||||||
|
level = ExceptionLevels(request.level)
|
||||||
|
node_id = request.node_id if request.node_id else None
|
||||||
|
session.exception(level, request.source, request.text, node_id)
|
||||||
|
return core_pb2.SessionAlertResponse(result=True)
|
||||||
|
|
||||||
def Events(self, request: core_pb2.EventsRequest, context: ServicerContext) -> None:
|
def Events(self, request: core_pb2.EventsRequest, context: ServicerContext) -> None:
|
||||||
session = self.get_session(request.session_id, context)
|
session = self.get_session(request.session_id, context)
|
||||||
event_types = set(request.events)
|
event_types = set(request.events)
|
||||||
|
|
|
@ -271,7 +271,7 @@ class CoreClient:
|
||||||
|
|
||||||
def handle_exception_event(self, event: ExceptionEvent) -> None:
|
def handle_exception_event(self, event: ExceptionEvent) -> None:
|
||||||
logging.info("exception event: %s", event)
|
logging.info("exception event: %s", event)
|
||||||
self.app.statusbar.core_alarms.append(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, query_location: bool = True) -> None:
|
||||||
logging.info("join session(%s)", session_id)
|
logging.info("join session(%s)", session_id)
|
||||||
|
|
|
@ -52,6 +52,7 @@ class AlertsDialog(Dialog):
|
||||||
for alarm in self.app.statusbar.core_alarms:
|
for alarm in self.app.statusbar.core_alarms:
|
||||||
exception = alarm.exception_event
|
exception = alarm.exception_event
|
||||||
level_name = ExceptionLevel.Enum.Name(exception.level)
|
level_name = ExceptionLevel.Enum.Name(exception.level)
|
||||||
|
node_id = exception.node_id if exception.node_id else ""
|
||||||
insert_id = self.tree.insert(
|
insert_id = self.tree.insert(
|
||||||
"",
|
"",
|
||||||
tk.END,
|
tk.END,
|
||||||
|
@ -60,7 +61,7 @@ class AlertsDialog(Dialog):
|
||||||
exception.date,
|
exception.date,
|
||||||
level_name,
|
level_name,
|
||||||
alarm.session_id,
|
alarm.session_id,
|
||||||
exception.node_id,
|
node_id,
|
||||||
exception.source,
|
exception.source,
|
||||||
),
|
),
|
||||||
tags=(level_name,),
|
tags=(level_name,),
|
||||||
|
@ -98,15 +99,17 @@ class AlertsDialog(Dialog):
|
||||||
button.grid(row=0, column=1, sticky="ew")
|
button.grid(row=0, column=1, sticky="ew")
|
||||||
|
|
||||||
def reset_alerts(self) -> None:
|
def reset_alerts(self) -> None:
|
||||||
self.codetext.text.delete("1.0", tk.END)
|
self.codetext.text.config(state=tk.NORMAL)
|
||||||
|
self.codetext.text.delete(1.0, tk.END)
|
||||||
|
self.codetext.text.config(state=tk.DISABLED)
|
||||||
for item in self.tree.get_children():
|
for item in self.tree.get_children():
|
||||||
self.tree.delete(item)
|
self.tree.delete(item)
|
||||||
self.app.statusbar.core_alarms.clear()
|
self.app.statusbar.clear_alerts()
|
||||||
|
|
||||||
def click_select(self, event: tk.Event) -> None:
|
def click_select(self, event: tk.Event) -> None:
|
||||||
current = self.tree.selection()[0]
|
current = self.tree.selection()[0]
|
||||||
alarm = self.alarm_map[current]
|
alarm = self.alarm_map[current]
|
||||||
self.codetext.text.config(state=tk.NORMAL)
|
self.codetext.text.config(state=tk.NORMAL)
|
||||||
self.codetext.text.delete("1.0", "end")
|
self.codetext.text.delete(1.0, tk.END)
|
||||||
self.codetext.text.insert("1.0", alarm.exception_event.text)
|
self.codetext.text.insert(1.0, alarm.exception_event.text)
|
||||||
self.codetext.text.config(state=tk.DISABLED)
|
self.codetext.text.config(state=tk.DISABLED)
|
||||||
|
|
|
@ -5,7 +5,7 @@ import tkinter as tk
|
||||||
from tkinter import ttk
|
from tkinter import ttk
|
||||||
from typing import TYPE_CHECKING, List, Optional
|
from typing import TYPE_CHECKING, List, Optional
|
||||||
|
|
||||||
from core.api.grpc.core_pb2 import ExceptionEvent
|
from core.api.grpc.core_pb2 import ExceptionEvent, ExceptionLevel
|
||||||
from core.gui.dialogs.alerts import AlertsDialog
|
from core.gui.dialogs.alerts import AlertsDialog
|
||||||
from core.gui.themes import Styles
|
from core.gui.themes import Styles
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ class StatusBar(ttk.Frame):
|
||||||
self.zoom: Optional[ttk.Label] = None
|
self.zoom: Optional[ttk.Label] = None
|
||||||
self.cpu_usage: Optional[ttk.Label] = None
|
self.cpu_usage: Optional[ttk.Label] = None
|
||||||
self.alerts_button: Optional[ttk.Button] = None
|
self.alerts_button: Optional[ttk.Button] = None
|
||||||
|
self.alert_style = Styles.no_alert
|
||||||
self.running: bool = False
|
self.running: bool = False
|
||||||
self.core_alarms: List[ExceptionEvent] = []
|
self.core_alarms: List[ExceptionEvent] = []
|
||||||
self.draw()
|
self.draw()
|
||||||
|
@ -60,10 +61,30 @@ class StatusBar(ttk.Frame):
|
||||||
self.cpu_usage.grid(row=0, column=2, sticky="ew")
|
self.cpu_usage.grid(row=0, column=2, sticky="ew")
|
||||||
|
|
||||||
self.alerts_button = ttk.Button(
|
self.alerts_button = ttk.Button(
|
||||||
self, text="Alerts", command=self.click_alerts, style=Styles.green_alert
|
self, text="Alerts", command=self.click_alerts, style=self.alert_style
|
||||||
)
|
)
|
||||||
self.alerts_button.grid(row=0, column=3, sticky="ew")
|
self.alerts_button.grid(row=0, column=3, sticky="ew")
|
||||||
|
|
||||||
|
def add_alert(self, event: ExceptionEvent) -> None:
|
||||||
|
self.core_alarms.append(event)
|
||||||
|
level = event.exception_event.level
|
||||||
|
self._set_alert_style(level)
|
||||||
|
label = f"Alerts ({len(self.core_alarms)})"
|
||||||
|
self.alerts_button.config(text=label, style=self.alert_style)
|
||||||
|
|
||||||
|
def _set_alert_style(self, level: ExceptionLevel) -> None:
|
||||||
|
if level in [ExceptionLevel.FATAL, ExceptionLevel.ERROR]:
|
||||||
|
self.alert_style = Styles.red_alert
|
||||||
|
elif level == ExceptionLevel.WARNING and self.alert_style != Styles.red_alert:
|
||||||
|
self.alert_style = Styles.yellow_alert
|
||||||
|
elif self.alert_style == Styles.no_alert:
|
||||||
|
self.alert_style = Styles.green_alert
|
||||||
|
|
||||||
|
def clear_alerts(self):
|
||||||
|
self.core_alarms.clear()
|
||||||
|
self.alert_style = Styles.no_alert
|
||||||
|
self.alerts_button.config(text="Alerts", style=self.alert_style)
|
||||||
|
|
||||||
def click_alerts(self) -> None:
|
def click_alerts(self) -> None:
|
||||||
dialog = AlertsDialog(self.app)
|
dialog = AlertsDialog(self.app)
|
||||||
dialog.show()
|
dialog.show()
|
||||||
|
|
|
@ -14,6 +14,7 @@ class Styles:
|
||||||
tooltip_frame: str = "Tooltip.TFrame"
|
tooltip_frame: str = "Tooltip.TFrame"
|
||||||
service_checkbutton: str = "Service.TCheckbutton"
|
service_checkbutton: str = "Service.TCheckbutton"
|
||||||
picker_button: str = "Picker.TButton"
|
picker_button: str = "Picker.TButton"
|
||||||
|
no_alert: str = "NAlert.TButton"
|
||||||
green_alert: str = "GAlert.TButton"
|
green_alert: str = "GAlert.TButton"
|
||||||
red_alert: str = "RAlert.TButton"
|
red_alert: str = "RAlert.TButton"
|
||||||
yellow_alert: str = "YAlert.TButton"
|
yellow_alert: str = "YAlert.TButton"
|
||||||
|
@ -175,33 +176,29 @@ def style_listbox(widget: tk.Widget) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _alert_style(style: ttk.Style, name: str, background: str):
|
||||||
|
style.configure(
|
||||||
|
name,
|
||||||
|
background=background,
|
||||||
|
padding=0,
|
||||||
|
relief=tk.RIDGE,
|
||||||
|
borderwidth=1,
|
||||||
|
font="TkDefaultFont",
|
||||||
|
foreground="black",
|
||||||
|
highlightbackground="white",
|
||||||
|
)
|
||||||
|
style.map(name, background=[("!active", background), ("active", "white")])
|
||||||
|
|
||||||
|
|
||||||
def theme_change(event: tk.Event) -> None:
|
def theme_change(event: tk.Event) -> None:
|
||||||
style = ttk.Style()
|
style = ttk.Style()
|
||||||
style.configure(Styles.picker_button, font="TkSmallCaptionFont")
|
style.configure(Styles.picker_button, font="TkSmallCaptionFont")
|
||||||
style.configure(
|
style.configure(
|
||||||
Styles.green_alert,
|
Styles.no_alert, padding=0, relief=tk.RIDGE, borderwidth=1, font="TkDefaultFont"
|
||||||
background="green",
|
|
||||||
padding=0,
|
|
||||||
relief=tk.RIDGE,
|
|
||||||
borderwidth=1,
|
|
||||||
font="TkDefaultFont",
|
|
||||||
)
|
|
||||||
style.configure(
|
|
||||||
Styles.yellow_alert,
|
|
||||||
background="yellow",
|
|
||||||
padding=0,
|
|
||||||
relief=tk.RIDGE,
|
|
||||||
borderwidth=1,
|
|
||||||
font="TkDefaultFont",
|
|
||||||
)
|
|
||||||
style.configure(
|
|
||||||
Styles.red_alert,
|
|
||||||
background="red",
|
|
||||||
padding=0,
|
|
||||||
relief=tk.RIDGE,
|
|
||||||
borderwidth=1,
|
|
||||||
font="TkDefaultFont",
|
|
||||||
)
|
)
|
||||||
|
_alert_style(style, Styles.green_alert, "green")
|
||||||
|
_alert_style(style, Styles.yellow_alert, "yellow")
|
||||||
|
_alert_style(style, Styles.red_alert, "red")
|
||||||
|
|
||||||
|
|
||||||
def scale_fonts(fonts_size: Dict[str, int], scale: float) -> None:
|
def scale_fonts(fonts_size: Dict[str, int], scale: float) -> None:
|
||||||
|
|
|
@ -43,6 +43,8 @@ service CoreApi {
|
||||||
}
|
}
|
||||||
rpc AddSessionServer (AddSessionServerRequest) returns (AddSessionServerResponse) {
|
rpc AddSessionServer (AddSessionServerRequest) returns (AddSessionServerResponse) {
|
||||||
}
|
}
|
||||||
|
rpc SessionAlert (SessionAlertRequest) returns (SessionAlertResponse) {
|
||||||
|
}
|
||||||
|
|
||||||
// streams
|
// streams
|
||||||
rpc Events (EventsRequest) returns (stream Event) {
|
rpc Events (EventsRequest) returns (stream Event) {
|
||||||
|
@ -318,6 +320,18 @@ message AddSessionServerResponse {
|
||||||
bool result = 1;
|
bool result = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message SessionAlertRequest {
|
||||||
|
int32 session_id = 1;
|
||||||
|
ExceptionLevel.Enum level = 2;
|
||||||
|
string source = 3;
|
||||||
|
string text = 4;
|
||||||
|
int32 node_id = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SessionAlertResponse {
|
||||||
|
bool result = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message EventsRequest {
|
message EventsRequest {
|
||||||
int32 session_id = 1;
|
int32 session_id = 1;
|
||||||
repeated EventType.Enum events = 2;
|
repeated EventType.Enum events = 2;
|
||||||
|
|
Loading…
Add table
Reference in a new issue