grpc/pygui: added grpc alert api, updated pygui to better handle and display alerts

This commit is contained in:
Blake Harnden 2020-07-22 19:19:22 -07:00
parent e34002b851
commit f8d862a296
7 changed files with 97 additions and 31 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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