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)
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(
self,
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.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.errors import CoreCommandError, CoreError
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)
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:
session = self.get_session(request.session_id, context)
event_types = set(request.events)

View file

@ -271,7 +271,7 @@ class CoreClient:
def handle_exception_event(self, event: ExceptionEvent) -> None:
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:
logging.info("join session(%s)", session_id)

View file

@ -52,6 +52,7 @@ class AlertsDialog(Dialog):
for alarm in self.app.statusbar.core_alarms:
exception = alarm.exception_event
level_name = ExceptionLevel.Enum.Name(exception.level)
node_id = exception.node_id if exception.node_id else ""
insert_id = self.tree.insert(
"",
tk.END,
@ -60,7 +61,7 @@ class AlertsDialog(Dialog):
exception.date,
level_name,
alarm.session_id,
exception.node_id,
node_id,
exception.source,
),
tags=(level_name,),
@ -98,15 +99,17 @@ class AlertsDialog(Dialog):
button.grid(row=0, column=1, sticky="ew")
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():
self.tree.delete(item)
self.app.statusbar.core_alarms.clear()
self.app.statusbar.clear_alerts()
def click_select(self, event: tk.Event) -> None:
current = self.tree.selection()[0]
alarm = self.alarm_map[current]
self.codetext.text.config(state=tk.NORMAL)
self.codetext.text.delete("1.0", "end")
self.codetext.text.insert("1.0", alarm.exception_event.text)
self.codetext.text.delete(1.0, tk.END)
self.codetext.text.insert(1.0, alarm.exception_event.text)
self.codetext.text.config(state=tk.DISABLED)

View file

@ -5,7 +5,7 @@ import tkinter as tk
from tkinter import ttk
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.themes import Styles
@ -22,6 +22,7 @@ class StatusBar(ttk.Frame):
self.zoom: Optional[ttk.Label] = None
self.cpu_usage: Optional[ttk.Label] = None
self.alerts_button: Optional[ttk.Button] = None
self.alert_style = Styles.no_alert
self.running: bool = False
self.core_alarms: List[ExceptionEvent] = []
self.draw()
@ -60,10 +61,30 @@ class StatusBar(ttk.Frame):
self.cpu_usage.grid(row=0, column=2, sticky="ew")
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")
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:
dialog = AlertsDialog(self.app)
dialog.show()

View file

@ -14,6 +14,7 @@ class Styles:
tooltip_frame: str = "Tooltip.TFrame"
service_checkbutton: str = "Service.TCheckbutton"
picker_button: str = "Picker.TButton"
no_alert: str = "NAlert.TButton"
green_alert: str = "GAlert.TButton"
red_alert: str = "RAlert.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:
style = ttk.Style()
style.configure(Styles.picker_button, font="TkSmallCaptionFont")
style.configure(
Styles.green_alert,
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",
Styles.no_alert, 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:

View file

@ -43,6 +43,8 @@ service CoreApi {
}
rpc AddSessionServer (AddSessionServerRequest) returns (AddSessionServerResponse) {
}
rpc SessionAlert (SessionAlertRequest) returns (SessionAlertResponse) {
}
// streams
rpc Events (EventsRequest) returns (stream Event) {
@ -318,6 +320,18 @@ message AddSessionServerResponse {
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 {
int32 session_id = 1;
repeated EventType.Enum events = 2;