diff --git a/aprsd/cmds/server.py b/aprsd/cmds/server.py index 174e024..4edaff3 100644 --- a/aprsd/cmds/server.py +++ b/aprsd/cmds/server.py @@ -96,12 +96,14 @@ def server(ctx, flush): packets.PacketTrack().flush() packets.WatchList().flush() packets.SeenList().flush() + packets.PacketList().flush() else: # Try and load saved MsgTrack list LOG.debug("Loading saved MsgTrack object.") packets.PacketTrack().load() packets.WatchList().load() packets.SeenList().load() + packets.PacketList().load() keepalive = keep_alive.KeepAliveThread() keepalive.start() diff --git a/aprsd/main.py b/aprsd/main.py index cdb88dd..96d2249 100644 --- a/aprsd/main.py +++ b/aprsd/main.py @@ -96,6 +96,7 @@ def signal_handler(sig, frame): packets.PacketTrack().save() packets.WatchList().save() packets.SeenList().save() + packets.PacketList().save() LOG.info(collector.Collector().collect()) # signal.signal(signal.SIGTERM, sys.exit(0)) # sys.exit(0) diff --git a/aprsd/packets/packet_list.py b/aprsd/packets/packet_list.py index 11ec7fe..0813a49 100644 --- a/aprsd/packets/packet_list.py +++ b/aprsd/packets/packet_list.py @@ -7,24 +7,27 @@ from oslo_config import cfg import wrapt from aprsd.packets import seen_list +from aprsd.utils import objectstore CONF = cfg.CONF LOG = logging.getLogger("APRSD") -class PacketList(MutableMapping): +class PacketList(MutableMapping, objectstore.ObjectStoreMixin): _instance = None lock = threading.Lock() _total_rx: int = 0 _total_tx: int = 0 - types = {} def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance = super().__new__(cls) cls._maxlen = 100 - cls.d = OrderedDict() + cls.data = { + "types": {}, + "packets": OrderedDict(), + } return cls._instance @wrapt.synchronized(lock) @@ -33,9 +36,9 @@ class PacketList(MutableMapping): self._total_rx += 1 self._add(packet) ptype = packet.__class__.__name__ - if not ptype in self.types: - self.types[ptype] = {"tx": 0, "rx": 0} - self.types[ptype]["rx"] += 1 + if not ptype in self.data["types"]: + self.data["types"][ptype] = {"tx": 0, "rx": 0} + self.data["types"][ptype]["rx"] += 1 seen_list.SeenList().update_seen(packet) @wrapt.synchronized(lock) @@ -44,9 +47,9 @@ class PacketList(MutableMapping): self._total_tx += 1 self._add(packet) ptype = packet.__class__.__name__ - if not ptype in self.types: - self.types[ptype] = {"tx": 0, "rx": 0} - self.types[ptype]["tx"] += 1 + if not ptype in self.data["types"]: + self.data["types"][ptype] = {"tx": 0, "rx": 0} + self.data["types"][ptype]["tx"] += 1 seen_list.SeenList().update_seen(packet) @wrapt.synchronized(lock) @@ -54,7 +57,7 @@ class PacketList(MutableMapping): self._add(packet) def _add(self, packet): - self[packet.key] = packet + self.data["packets"][packet.key] = packet def copy(self): return self.d.copy() @@ -69,23 +72,23 @@ class PacketList(MutableMapping): def __getitem__(self, key): # self.d.move_to_end(key) - return self.d[key] + return self.data["packets"][key] def __setitem__(self, key, value): - if key in self.d: - self.d.move_to_end(key) - elif len(self.d) == self.maxlen: - self.d.popitem(last=False) - self.d[key] = value + if key in self.data["packets"]: + self.data["packets"].move_to_end(key) + elif len(self.data["packets"]) == self.maxlen: + self.data["packets"].popitem(last=False) + self.data["packets"][key] = value def __delitem__(self, key): - del self.d[key] + del self.data["packets"][key] def __iter__(self): - return self.d.__iter__() + return self.data["packets"].__iter__() def __len__(self): - return len(self.d) + return len(self.data["packets"]) @wrapt.synchronized(lock) def total_rx(self): @@ -100,7 +103,8 @@ class PacketList(MutableMapping): "total_tracked": self.total_tx() + self.total_rx(), "rx": self.total_rx(), "tx": self.total_tx(), - "packets": self.types, + "types": self.data["types"], + "packets": self.data["packets"], } return stats diff --git a/aprsd/packets/seen_list.py b/aprsd/packets/seen_list.py index 5c7774f..9b81831 100644 --- a/aprsd/packets/seen_list.py +++ b/aprsd/packets/seen_list.py @@ -28,11 +28,7 @@ class SeenList(objectstore.ObjectStoreMixin): def stats(self, serializable=False): """Return the stats for the PacketTrack class.""" - stats = self.data - # if serializable: - # for call in self.data: - # stats[call]["last"] = stats[call]["last"].isoformat() - return stats + return self.data @wrapt.synchronized(lock) def update_seen(self, packet): diff --git a/aprsd/utils/json.py b/aprsd/utils/json.py index 29f6565..648238a 100644 --- a/aprsd/utils/json.py +++ b/aprsd/utils/json.py @@ -3,6 +3,8 @@ import decimal import json import sys +from aprsd.packets import core + class EnhancedJSONEncoder(json.JSONEncoder): def default(self, obj): @@ -54,6 +56,8 @@ class SimpleJSONEncoder(json.JSONEncoder): return str(obj) elif isinstance(obj, decimal.Decimal): return str(obj) + elif isinstance(obj, core.Packet): + return obj.to_dict() else: return super().default(obj) diff --git a/aprsd/web/admin/static/js/echarts.js b/aprsd/web/admin/static/js/echarts.js index 607d88b..8d67a73 100644 --- a/aprsd/web/admin/static/js/echarts.js +++ b/aprsd/web/admin/static/js/echarts.js @@ -327,7 +327,6 @@ function updatePacketTypesChart() { option = { series: series } - console.log(option) packet_types_chart.setOption(option); } @@ -381,22 +380,23 @@ function updateAcksChart() { } function update_stats( data ) { - console.log(data); - our_callsign = data["APRSDStats"]["callsign"]; - $("#version").text( data["APRSDStats"]["version"] ); - $("#aprs_connection").html( data["aprs_connection"] ); - $("#uptime").text( "uptime: " + data["APRSDStats"]["uptime"] ); + console.log("update_stats() echarts.js called") + stats = data["stats"]; + our_callsign = stats["APRSDStats"]["callsign"]; + $("#version").text( stats["APRSDStats"]["version"] ); + $("#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'); $("#jsonstats").html(html_pretty); t = Date.parse(data["time"]); ts = new Date(t); - updatePacketData(packets_chart, ts, data["PacketList"]["tx"], data["PacketList"]["rx"]); - updatePacketTypesData(ts, data["PacketList"]["packets"]); + updatePacketData(packets_chart, ts, stats["PacketList"]["tx"], stats["PacketList"]["rx"]); + updatePacketTypesData(ts, stats["PacketList"]["types"]); updatePacketTypesChart(); updateMessagesChart(); 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"]); //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"]); diff --git a/aprsd/web/admin/static/js/main.js b/aprsd/web/admin/static/js/main.js index 0b6389f..99c956a 100644 --- a/aprsd/web/admin/static/js/main.js +++ b/aprsd/web/admin/static/js/main.js @@ -24,11 +24,12 @@ function ord(str){return str.charCodeAt(0);} function update_watchlist( data ) { - // Update the watch list + // Update the watch list + stats = data["stats"]; var watchdiv = $("#watchDiv"); var html_str = '' watchdiv.html('') - jQuery.each(data["WatchList"], function(i, val) { + jQuery.each(stats["WatchList"], function(i, val) { html_str += '' }); html_str += "
HAM CallsignAge since last seen by APRSD
' + i + '' + val["last"] + '
"; @@ -60,12 +61,13 @@ function update_watchlist_from_packet(callsign, val) { } function update_seenlist( data ) { + stats = data["stats"]; var seendiv = $("#seenDiv"); var html_str = '' html_str += '' html_str += '' seendiv.html('') - var seen_list = data["SeenList"] + var seen_list = stats["SeenList"] var len = Object.keys(seen_list).length $('#seen_count').html(len) jQuery.each(seen_list, function(i, val) { @@ -79,6 +81,7 @@ function update_seenlist( data ) { } function update_plugins( data ) { + stats = data["stats"]; var plugindiv = $("#pluginDiv"); var html_str = '
HAM CallsignAge since last seen by APRSDNumber of packets RX
' html_str += '' @@ -87,7 +90,7 @@ function update_plugins( data ) { html_str += '' plugindiv.html('') - var plugins = data["PluginManager"]; + var plugins = stats["PluginManager"]; var keys = Object.keys(plugins); keys.sort(); for (var i=0; i 0) { packetsdiv.html('') } - jQuery.each(data, function(i, val) { - pkt = JSON.parse(val); + jQuery.each(data.packets, function(i, val) { + pkt = val; update_watchlist_from_packet(pkt['from_call'], pkt); if ( packet_list.hasOwnProperty(pkt['timestamp']) == false ) { diff --git a/aprsd/web/admin/templates/index.html b/aprsd/web/admin/templates/index.html index fe992c7..4fe1194 100644 --- a/aprsd/web/admin/templates/index.html +++ b/aprsd/web/admin/templates/index.html @@ -30,7 +30,6 @@ var color = Chart.helpers.color; $(document).ready(function() { - console.log(initial_stats); start_update(); start_charts(); init_messages(); diff --git a/aprsd/wsgi.py b/aprsd/wsgi.py index 8386e33..93eab5c 100644 --- a/aprsd/wsgi.py +++ b/aprsd/wsgi.py @@ -1,3 +1,4 @@ +import datetime import importlib.metadata as imp import io import json @@ -48,10 +49,13 @@ def verify_password(username, password): def _stats(): stats_obj = stats_threads.StatsStore() stats_obj.load() - # now = datetime.datetime.now() - # time_format = "%m-%d-%Y %H:%M:%S" - stats_dict = stats_obj.data - return stats_dict + now = datetime.datetime.now() + time_format = "%m-%d-%Y %H:%M:%S" + stats = { + "time": now.strftime(time_format), + "stats": stats_obj.data, + } + return stats @app.route("/stats") @@ -71,7 +75,7 @@ def index(): transport = "aprs-is" aprs_connection = ( "APRS-IS Server: " - "{}".format(stats["APRSClientStats"]["server_string"]) + "{}".format(stats["stats"]["APRSClientStats"]["server_string"]) ) else: # We might be connected to a KISS socket? @@ -92,8 +96,8 @@ def index(): ) ) - stats["transport"] = transport - stats["aprs_connection"] = aprs_connection + stats["stats"]["APRSClientStats"]["transport"] = transport + stats["stats"]["APRSClientStats"]["aprs_connection"] = aprs_connection entries = conf.conf_to_dict() return flask.render_template( @@ -113,7 +117,6 @@ def index(): @auth.login_required def messages(): - _stats() track = packets.PacketTrack() msgs = [] for id in track: @@ -126,9 +129,10 @@ def messages(): @auth.login_required @app.route("/packets") def get_packets(): - LOG.debug("/packets called") - stats_dict = _stats() - return json.dumps(stats_dict.get("PacketList", {})) + stats = _stats() + stats_dict = stats["stats"] + packets = stats_dict.get("PacketList", {}) + return json.dumps(packets, cls=aprsd_json.SimpleJSONEncoder) @auth.login_required
Plugin NamePlugin Enabled?