Admin UI working again

This commit is contained in:
Hemna 2024-04-05 15:02:26 -04:00
parent 333feee805
commit 0ca9072c97
9 changed files with 65 additions and 52 deletions

View File

@ -96,12 +96,14 @@ def server(ctx, flush):
packets.PacketTrack().flush() packets.PacketTrack().flush()
packets.WatchList().flush() packets.WatchList().flush()
packets.SeenList().flush() packets.SeenList().flush()
packets.PacketList().flush()
else: else:
# Try and load saved MsgTrack list # Try and load saved MsgTrack list
LOG.debug("Loading saved MsgTrack object.") LOG.debug("Loading saved MsgTrack object.")
packets.PacketTrack().load() packets.PacketTrack().load()
packets.WatchList().load() packets.WatchList().load()
packets.SeenList().load() packets.SeenList().load()
packets.PacketList().load()
keepalive = keep_alive.KeepAliveThread() keepalive = keep_alive.KeepAliveThread()
keepalive.start() keepalive.start()

View File

@ -96,6 +96,7 @@ def signal_handler(sig, frame):
packets.PacketTrack().save() packets.PacketTrack().save()
packets.WatchList().save() packets.WatchList().save()
packets.SeenList().save() packets.SeenList().save()
packets.PacketList().save()
LOG.info(collector.Collector().collect()) LOG.info(collector.Collector().collect())
# signal.signal(signal.SIGTERM, sys.exit(0)) # signal.signal(signal.SIGTERM, sys.exit(0))
# sys.exit(0) # sys.exit(0)

View File

@ -7,24 +7,27 @@ from oslo_config import cfg
import wrapt import wrapt
from aprsd.packets import seen_list from aprsd.packets import seen_list
from aprsd.utils import objectstore
CONF = cfg.CONF CONF = cfg.CONF
LOG = logging.getLogger("APRSD") LOG = logging.getLogger("APRSD")
class PacketList(MutableMapping): class PacketList(MutableMapping, objectstore.ObjectStoreMixin):
_instance = None _instance = None
lock = threading.Lock() lock = threading.Lock()
_total_rx: int = 0 _total_rx: int = 0
_total_tx: int = 0 _total_tx: int = 0
types = {}
def __new__(cls, *args, **kwargs): def __new__(cls, *args, **kwargs):
if cls._instance is None: if cls._instance is None:
cls._instance = super().__new__(cls) cls._instance = super().__new__(cls)
cls._maxlen = 100 cls._maxlen = 100
cls.d = OrderedDict() cls.data = {
"types": {},
"packets": OrderedDict(),
}
return cls._instance return cls._instance
@wrapt.synchronized(lock) @wrapt.synchronized(lock)
@ -33,9 +36,9 @@ class PacketList(MutableMapping):
self._total_rx += 1 self._total_rx += 1
self._add(packet) self._add(packet)
ptype = packet.__class__.__name__ ptype = packet.__class__.__name__
if not ptype in self.types: if not ptype in self.data["types"]:
self.types[ptype] = {"tx": 0, "rx": 0} self.data["types"][ptype] = {"tx": 0, "rx": 0}
self.types[ptype]["rx"] += 1 self.data["types"][ptype]["rx"] += 1
seen_list.SeenList().update_seen(packet) seen_list.SeenList().update_seen(packet)
@wrapt.synchronized(lock) @wrapt.synchronized(lock)
@ -44,9 +47,9 @@ class PacketList(MutableMapping):
self._total_tx += 1 self._total_tx += 1
self._add(packet) self._add(packet)
ptype = packet.__class__.__name__ ptype = packet.__class__.__name__
if not ptype in self.types: if not ptype in self.data["types"]:
self.types[ptype] = {"tx": 0, "rx": 0} self.data["types"][ptype] = {"tx": 0, "rx": 0}
self.types[ptype]["tx"] += 1 self.data["types"][ptype]["tx"] += 1
seen_list.SeenList().update_seen(packet) seen_list.SeenList().update_seen(packet)
@wrapt.synchronized(lock) @wrapt.synchronized(lock)
@ -54,7 +57,7 @@ class PacketList(MutableMapping):
self._add(packet) self._add(packet)
def _add(self, packet): def _add(self, packet):
self[packet.key] = packet self.data["packets"][packet.key] = packet
def copy(self): def copy(self):
return self.d.copy() return self.d.copy()
@ -69,23 +72,23 @@ class PacketList(MutableMapping):
def __getitem__(self, key): def __getitem__(self, key):
# self.d.move_to_end(key) # self.d.move_to_end(key)
return self.d[key] return self.data["packets"][key]
def __setitem__(self, key, value): def __setitem__(self, key, value):
if key in self.d: if key in self.data["packets"]:
self.d.move_to_end(key) self.data["packets"].move_to_end(key)
elif len(self.d) == self.maxlen: elif len(self.data["packets"]) == self.maxlen:
self.d.popitem(last=False) self.data["packets"].popitem(last=False)
self.d[key] = value self.data["packets"][key] = value
def __delitem__(self, key): def __delitem__(self, key):
del self.d[key] del self.data["packets"][key]
def __iter__(self): def __iter__(self):
return self.d.__iter__() return self.data["packets"].__iter__()
def __len__(self): def __len__(self):
return len(self.d) return len(self.data["packets"])
@wrapt.synchronized(lock) @wrapt.synchronized(lock)
def total_rx(self): def total_rx(self):
@ -100,7 +103,8 @@ class PacketList(MutableMapping):
"total_tracked": self.total_tx() + self.total_rx(), "total_tracked": self.total_tx() + self.total_rx(),
"rx": self.total_rx(), "rx": self.total_rx(),
"tx": self.total_tx(), "tx": self.total_tx(),
"packets": self.types, "types": self.data["types"],
"packets": self.data["packets"],
} }
return stats return stats

View File

@ -28,11 +28,7 @@ class SeenList(objectstore.ObjectStoreMixin):
def stats(self, serializable=False): def stats(self, serializable=False):
"""Return the stats for the PacketTrack class.""" """Return the stats for the PacketTrack class."""
stats = self.data return self.data
# if serializable:
# for call in self.data:
# stats[call]["last"] = stats[call]["last"].isoformat()
return stats
@wrapt.synchronized(lock) @wrapt.synchronized(lock)
def update_seen(self, packet): def update_seen(self, packet):

View File

@ -3,6 +3,8 @@ import decimal
import json import json
import sys import sys
from aprsd.packets import core
class EnhancedJSONEncoder(json.JSONEncoder): class EnhancedJSONEncoder(json.JSONEncoder):
def default(self, obj): def default(self, obj):
@ -54,6 +56,8 @@ class SimpleJSONEncoder(json.JSONEncoder):
return str(obj) return str(obj)
elif isinstance(obj, decimal.Decimal): elif isinstance(obj, decimal.Decimal):
return str(obj) return str(obj)
elif isinstance(obj, core.Packet):
return obj.to_dict()
else: else:
return super().default(obj) return super().default(obj)

View File

@ -327,7 +327,6 @@ function updatePacketTypesChart() {
option = { option = {
series: series series: series
} }
console.log(option)
packet_types_chart.setOption(option); packet_types_chart.setOption(option);
} }
@ -381,22 +380,23 @@ function updateAcksChart() {
} }
function update_stats( data ) { function update_stats( data ) {
console.log(data); console.log("update_stats() echarts.js called")
our_callsign = data["APRSDStats"]["callsign"]; stats = data["stats"];
$("#version").text( data["APRSDStats"]["version"] ); our_callsign = stats["APRSDStats"]["callsign"];
$("#aprs_connection").html( data["aprs_connection"] ); $("#version").text( stats["APRSDStats"]["version"] );
$("#uptime").text( "uptime: " + data["APRSDStats"]["uptime"] ); $("#aprs_connection").html( stats["aprs_connection"] );
$("#uptime").text( "uptime: " + stats["APRSDStats"]["uptime"] );
const html_pretty = Prism.highlight(JSON.stringify(data, null, '\t'), Prism.languages.json, 'json'); const html_pretty = Prism.highlight(JSON.stringify(data, null, '\t'), Prism.languages.json, 'json');
$("#jsonstats").html(html_pretty); $("#jsonstats").html(html_pretty);
t = Date.parse(data["time"]); t = Date.parse(data["time"]);
ts = new Date(t); ts = new Date(t);
updatePacketData(packets_chart, ts, data["PacketList"]["tx"], data["PacketList"]["rx"]); updatePacketData(packets_chart, ts, stats["PacketList"]["tx"], stats["PacketList"]["rx"]);
updatePacketTypesData(ts, data["PacketList"]["packets"]); updatePacketTypesData(ts, stats["PacketList"]["types"]);
updatePacketTypesChart(); updatePacketTypesChart();
updateMessagesChart(); updateMessagesChart();
updateAcksChart(); updateAcksChart();
updateMemChart(ts, data["APRSDStats"]["memory_current"], data["APRSDStats"]["memory_peak"]); updateMemChart(ts, stats["APRSDStats"]["memory_current"], stats["APRSDStats"]["memory_peak"]);
//updateQuadData(message_chart, short_time, data["stats"]["messages"]["sent"], data["stats"]["messages"]["received"], data["stats"]["messages"]["ack_sent"], data["stats"]["messages"]["ack_recieved"]); //updateQuadData(message_chart, short_time, data["stats"]["messages"]["sent"], data["stats"]["messages"]["received"], data["stats"]["messages"]["ack_sent"], data["stats"]["messages"]["ack_recieved"]);
//updateDualData(email_chart, short_time, data["stats"]["email"]["sent"], data["stats"]["email"]["recieved"]); //updateDualData(email_chart, short_time, data["stats"]["email"]["sent"], data["stats"]["email"]["recieved"]);
//updateDualData(memory_chart, short_time, data["stats"]["aprsd"]["memory_peak"], data["stats"]["aprsd"]["memory_current"]); //updateDualData(memory_chart, short_time, data["stats"]["aprsd"]["memory_peak"], data["stats"]["aprsd"]["memory_current"]);

View File

@ -24,11 +24,12 @@ function ord(str){return str.charCodeAt(0);}
function update_watchlist( data ) { function update_watchlist( data ) {
// Update the watch list // Update the watch list
stats = data["stats"];
var watchdiv = $("#watchDiv"); var watchdiv = $("#watchDiv");
var html_str = '<table class="ui celled striped table"><thead><tr><th>HAM Callsign</th><th>Age since last seen by APRSD</th></tr></thead><tbody>' var html_str = '<table class="ui celled striped table"><thead><tr><th>HAM Callsign</th><th>Age since last seen by APRSD</th></tr></thead><tbody>'
watchdiv.html('') watchdiv.html('')
jQuery.each(data["WatchList"], function(i, val) { jQuery.each(stats["WatchList"], function(i, val) {
html_str += '<tr><td class="collapsing"><img id="callsign_'+i+'" class="aprsd_1"></img>' + i + '</td><td>' + val["last"] + '</td></tr>' html_str += '<tr><td class="collapsing"><img id="callsign_'+i+'" class="aprsd_1"></img>' + i + '</td><td>' + val["last"] + '</td></tr>'
}); });
html_str += "</tbody></table>"; html_str += "</tbody></table>";
@ -60,12 +61,13 @@ function update_watchlist_from_packet(callsign, val) {
} }
function update_seenlist( data ) { function update_seenlist( data ) {
stats = data["stats"];
var seendiv = $("#seenDiv"); var seendiv = $("#seenDiv");
var html_str = '<table class="ui celled striped table">' var html_str = '<table class="ui celled striped table">'
html_str += '<thead><tr><th>HAM Callsign</th><th>Age since last seen by APRSD</th>' html_str += '<thead><tr><th>HAM Callsign</th><th>Age since last seen by APRSD</th>'
html_str += '<th>Number of packets RX</th></tr></thead><tbody>' html_str += '<th>Number of packets RX</th></tr></thead><tbody>'
seendiv.html('') seendiv.html('')
var seen_list = data["SeenList"] var seen_list = stats["SeenList"]
var len = Object.keys(seen_list).length var len = Object.keys(seen_list).length
$('#seen_count').html(len) $('#seen_count').html(len)
jQuery.each(seen_list, function(i, val) { jQuery.each(seen_list, function(i, val) {
@ -79,6 +81,7 @@ function update_seenlist( data ) {
} }
function update_plugins( data ) { function update_plugins( data ) {
stats = data["stats"];
var plugindiv = $("#pluginDiv"); var plugindiv = $("#pluginDiv");
var html_str = '<table class="ui celled striped table"><thead><tr>' var html_str = '<table class="ui celled striped table"><thead><tr>'
html_str += '<th>Plugin Name</th><th>Plugin Enabled?</th>' html_str += '<th>Plugin Name</th><th>Plugin Enabled?</th>'
@ -87,7 +90,7 @@ function update_plugins( data ) {
html_str += '</tr></thead><tbody>' html_str += '</tr></thead><tbody>'
plugindiv.html('') plugindiv.html('')
var plugins = data["PluginManager"]; var plugins = stats["PluginManager"];
var keys = Object.keys(plugins); var keys = Object.keys(plugins);
keys.sort(); keys.sort();
for (var i=0; i<keys.length; i++) { // now lets iterate in sort order for (var i=0; i<keys.length; i++) { // now lets iterate in sort order
@ -107,8 +110,8 @@ function update_packets( data ) {
if (size_dict(packet_list) == 0 && size_dict(data) > 0) { if (size_dict(packet_list) == 0 && size_dict(data) > 0) {
packetsdiv.html('') packetsdiv.html('')
} }
jQuery.each(data, function(i, val) { jQuery.each(data.packets, function(i, val) {
pkt = JSON.parse(val); pkt = val;
update_watchlist_from_packet(pkt['from_call'], pkt); update_watchlist_from_packet(pkt['from_call'], pkt);
if ( packet_list.hasOwnProperty(pkt['timestamp']) == false ) { if ( packet_list.hasOwnProperty(pkt['timestamp']) == false ) {

View File

@ -30,7 +30,6 @@
var color = Chart.helpers.color; var color = Chart.helpers.color;
$(document).ready(function() { $(document).ready(function() {
console.log(initial_stats);
start_update(); start_update();
start_charts(); start_charts();
init_messages(); init_messages();

View File

@ -1,3 +1,4 @@
import datetime
import importlib.metadata as imp import importlib.metadata as imp
import io import io
import json import json
@ -48,10 +49,13 @@ def verify_password(username, password):
def _stats(): def _stats():
stats_obj = stats_threads.StatsStore() stats_obj = stats_threads.StatsStore()
stats_obj.load() stats_obj.load()
# now = datetime.datetime.now() now = datetime.datetime.now()
# time_format = "%m-%d-%Y %H:%M:%S" time_format = "%m-%d-%Y %H:%M:%S"
stats_dict = stats_obj.data stats = {
return stats_dict "time": now.strftime(time_format),
"stats": stats_obj.data,
}
return stats
@app.route("/stats") @app.route("/stats")
@ -71,7 +75,7 @@ def index():
transport = "aprs-is" transport = "aprs-is"
aprs_connection = ( aprs_connection = (
"APRS-IS Server: <a href='http://status.aprs2.net' >" "APRS-IS Server: <a href='http://status.aprs2.net' >"
"{}</a>".format(stats["APRSClientStats"]["server_string"]) "{}</a>".format(stats["stats"]["APRSClientStats"]["server_string"])
) )
else: else:
# We might be connected to a KISS socket? # We might be connected to a KISS socket?
@ -92,8 +96,8 @@ def index():
) )
) )
stats["transport"] = transport stats["stats"]["APRSClientStats"]["transport"] = transport
stats["aprs_connection"] = aprs_connection stats["stats"]["APRSClientStats"]["aprs_connection"] = aprs_connection
entries = conf.conf_to_dict() entries = conf.conf_to_dict()
return flask.render_template( return flask.render_template(
@ -113,7 +117,6 @@ def index():
@auth.login_required @auth.login_required
def messages(): def messages():
_stats()
track = packets.PacketTrack() track = packets.PacketTrack()
msgs = [] msgs = []
for id in track: for id in track:
@ -126,9 +129,10 @@ def messages():
@auth.login_required @auth.login_required
@app.route("/packets") @app.route("/packets")
def get_packets(): def get_packets():
LOG.debug("/packets called") stats = _stats()
stats_dict = _stats() stats_dict = stats["stats"]
return json.dumps(stats_dict.get("PacketList", {})) packets = stats_dict.get("PacketList", {})
return json.dumps(packets, cls=aprsd_json.SimpleJSONEncoder)
@auth.login_required @auth.login_required