1
0
mirror of https://github.com/craigerl/aprsd.git synced 2025-06-13 20:02:26 -04:00

Updated packet_list to allow infinit max store

This patch adds logic of setting packet_list_stats_maxlen -1
meaning keep every packet for stats.
This commit is contained in:
Hemna 2025-01-30 10:04:59 -08:00
parent 1606585d41
commit 19c12e70f3
2 changed files with 133 additions and 128 deletions

View File

@ -3,220 +3,219 @@ from pathlib import Path
from oslo_config import cfg
home = str(Path.home())
DEFAULT_CONFIG_DIR = f"{home}/.config/aprsd/"
APRSD_DEFAULT_MAGIC_WORD = "CHANGEME!!!"
DEFAULT_CONFIG_DIR = f'{home}/.config/aprsd/'
APRSD_DEFAULT_MAGIC_WORD = 'CHANGEME!!!'
watch_list_group = cfg.OptGroup(
name="watch_list",
title="Watch List settings",
name='watch_list',
title='Watch List settings',
)
registry_group = cfg.OptGroup(
name="aprs_registry",
title="APRS Registry settings",
name='aprs_registry',
title='APRS Registry settings',
)
aprsd_opts = [
cfg.StrOpt(
"callsign",
'callsign',
required=True,
help="Callsign to use for messages sent by APRSD",
help='Callsign to use for messages sent by APRSD',
),
cfg.BoolOpt(
"enable_save",
'enable_save',
default=True,
help="Enable saving of watch list, packet tracker between restarts.",
help='Enable saving of watch list, packet tracker between restarts.',
),
cfg.StrOpt(
"save_location",
'save_location',
default=DEFAULT_CONFIG_DIR,
help="Save location for packet tracking files.",
help='Save location for packet tracking files.',
),
cfg.BoolOpt(
"trace_enabled",
'trace_enabled',
default=False,
help="Enable code tracing",
help='Enable code tracing',
),
cfg.StrOpt(
"units",
default="imperial",
help="Units for display, imperial or metric",
'units',
default='imperial',
help='Units for display, imperial or metric',
),
cfg.IntOpt(
"ack_rate_limit_period",
'ack_rate_limit_period',
default=1,
help="The wait period in seconds per Ack packet being sent."
"1 means 1 ack packet per second allowed."
"2 means 1 pack packet every 2 seconds allowed",
help='The wait period in seconds per Ack packet being sent.'
'1 means 1 ack packet per second allowed.'
'2 means 1 pack packet every 2 seconds allowed',
),
cfg.IntOpt(
"msg_rate_limit_period",
'msg_rate_limit_period',
default=2,
help="Wait period in seconds per non AckPacket being sent."
"2 means 1 packet every 2 seconds allowed."
"5 means 1 pack packet every 5 seconds allowed",
help='Wait period in seconds per non AckPacket being sent.'
'2 means 1 packet every 2 seconds allowed.'
'5 means 1 pack packet every 5 seconds allowed',
),
cfg.IntOpt(
"packet_dupe_timeout",
'packet_dupe_timeout',
default=300,
help="The number of seconds before a packet is not considered a duplicate.",
help='The number of seconds before a packet is not considered a duplicate.',
),
cfg.BoolOpt(
"enable_beacon",
'enable_beacon',
default=False,
help="Enable sending of a GPS Beacon packet to locate this service. "
"Requires latitude and longitude to be set.",
help='Enable sending of a GPS Beacon packet to locate this service. '
'Requires latitude and longitude to be set.',
),
cfg.IntOpt(
"beacon_interval",
'beacon_interval',
default=1800,
help="The number of seconds between beacon packets.",
help='The number of seconds between beacon packets.',
),
cfg.StrOpt(
"beacon_symbol",
default="/",
help="The symbol to use for the GPS Beacon packet. See: http://www.aprs.net/vm/DOS/SYMBOLS.HTM",
'beacon_symbol',
default='/',
help='The symbol to use for the GPS Beacon packet. See: http://www.aprs.net/vm/DOS/SYMBOLS.HTM',
),
cfg.StrOpt(
"latitude",
'latitude',
default=None,
help="Latitude for the GPS Beacon button. If not set, the button will not be enabled.",
help='Latitude for the GPS Beacon button. If not set, the button will not be enabled.',
),
cfg.StrOpt(
"longitude",
'longitude',
default=None,
help="Longitude for the GPS Beacon button. If not set, the button will not be enabled.",
help='Longitude for the GPS Beacon button. If not set, the button will not be enabled.',
),
cfg.StrOpt(
"log_packet_format",
choices=["compact", "multiline", "both"],
default="compact",
'log_packet_format',
choices=['compact', 'multiline', 'both'],
default='compact',
help="When logging packets 'compact' will use a single line formatted for each packet."
"'multiline' will use multiple lines for each packet and is the traditional format."
"both will log both compact and multiline.",
'both will log both compact and multiline.',
),
cfg.IntOpt(
"default_packet_send_count",
'default_packet_send_count',
default=3,
help="The number of times to send a non ack packet before giving up.",
help='The number of times to send a non ack packet before giving up.',
),
cfg.IntOpt(
"default_ack_send_count",
'default_ack_send_count',
default=3,
help="The number of times to send an ack packet in response to recieving a packet.",
help='The number of times to send an ack packet in response to recieving a packet.',
),
cfg.IntOpt(
"packet_list_maxlen",
'packet_list_maxlen',
default=100,
help="The maximum number of packets to store in the packet list.",
help='The maximum number of packets to store in the packet list.',
),
cfg.IntOpt(
"packet_list_stats_maxlen",
'packet_list_stats_maxlen',
default=20,
help="The maximum number of packets to send in the stats dict for admin ui.",
help='The maximum number of packets to send in the stats dict for admin ui. -1 means no max.',
),
cfg.BoolOpt(
"enable_seen_list",
'enable_seen_list',
default=True,
help="Enable the Callsign seen list tracking feature. This allows aprsd to keep track of "
"callsigns that have been seen and when they were last seen.",
help='Enable the Callsign seen list tracking feature. This allows aprsd to keep track of '
'callsigns that have been seen and when they were last seen.',
),
cfg.BoolOpt(
"enable_packet_logging",
'enable_packet_logging',
default=True,
help="Set this to False, to disable logging of packets to the log file.",
help='Set this to False, to disable logging of packets to the log file.',
),
cfg.BoolOpt(
"load_help_plugin",
'load_help_plugin',
default=True,
help="Set this to False to disable the help plugin.",
help='Set this to False to disable the help plugin.',
),
cfg.BoolOpt(
"enable_sending_ack_packets",
'enable_sending_ack_packets',
default=True,
help="Set this to False, to disable sending of ack packets. This will entirely stop"
"APRSD from sending ack packets.",
help='Set this to False, to disable sending of ack packets. This will entirely stop'
'APRSD from sending ack packets.',
),
]
watch_list_opts = [
cfg.BoolOpt(
"enabled",
'enabled',
default=False,
help="Enable the watch list feature. Still have to enable "
"the correct plugin. Built-in plugin to use is "
"aprsd.plugins.notify.NotifyPlugin",
help='Enable the watch list feature. Still have to enable '
'the correct plugin. Built-in plugin to use is '
'aprsd.plugins.notify.NotifyPlugin',
),
cfg.ListOpt(
"callsigns",
help="Callsigns to watch for messsages",
'callsigns',
help='Callsigns to watch for messsages',
),
cfg.StrOpt(
"alert_callsign",
help="The Ham Callsign to send messages to for watch list alerts.",
'alert_callsign',
help='The Ham Callsign to send messages to for watch list alerts.',
),
cfg.IntOpt(
"packet_keep_count",
'packet_keep_count',
default=10,
help="The number of packets to store.",
help='The number of packets to store.',
),
cfg.IntOpt(
"alert_time_seconds",
'alert_time_seconds',
default=3600,
help="Time to wait before alert is sent on new message for "
"users in callsigns.",
help='Time to wait before alert is sent on new message for users in callsigns.',
),
]
enabled_plugins_opts = [
cfg.ListOpt(
"enabled_plugins",
'enabled_plugins',
default=[
"aprsd.plugins.fortune.FortunePlugin",
"aprsd.plugins.location.LocationPlugin",
"aprsd.plugins.ping.PingPlugin",
"aprsd.plugins.time.TimePlugin",
"aprsd.plugins.weather.OWMWeatherPlugin",
"aprsd.plugins.version.VersionPlugin",
"aprsd.plugins.notify.NotifySeenPlugin",
'aprsd.plugins.fortune.FortunePlugin',
'aprsd.plugins.location.LocationPlugin',
'aprsd.plugins.ping.PingPlugin',
'aprsd.plugins.time.TimePlugin',
'aprsd.plugins.weather.OWMWeatherPlugin',
'aprsd.plugins.version.VersionPlugin',
'aprsd.plugins.notify.NotifySeenPlugin',
],
help="Comma separated list of enabled plugins for APRSD."
"To enable installed external plugins add them here."
"The full python path to the class name must be used",
help='Comma separated list of enabled plugins for APRSD.'
'To enable installed external plugins add them here.'
'The full python path to the class name must be used',
),
]
registry_opts = [
cfg.BoolOpt(
"enabled",
'enabled',
default=False,
help="Enable sending aprs registry information. This will let the "
help='Enable sending aprs registry information. This will let the '
"APRS registry know about your service and it's uptime. "
"No personal information is sent, just the callsign, uptime and description. "
"The service callsign is the callsign set in [DEFAULT] section.",
'No personal information is sent, just the callsign, uptime and description. '
'The service callsign is the callsign set in [DEFAULT] section.',
),
cfg.StrOpt(
"description",
'description',
default=None,
help="Description of the service to send to the APRS registry. "
"This is what will show up in the APRS registry."
"If not set, the description will be the same as the callsign.",
help='Description of the service to send to the APRS registry. '
'This is what will show up in the APRS registry.'
'If not set, the description will be the same as the callsign.',
),
cfg.StrOpt(
"registry_url",
default="https://aprs.hemna.com/api/v1/registry",
help="The APRS registry domain name to send the information to.",
'registry_url',
default='https://aprs.hemna.com/api/v1/registry',
help='The APRS registry domain name to send the information to.',
),
cfg.StrOpt(
"service_website",
'service_website',
default=None,
help="The website for your APRS service to send to the APRS registry.",
help='The website for your APRS service to send to the APRS registry.',
),
cfg.IntOpt(
"frequency_seconds",
'frequency_seconds',
default=3600,
help="The frequency in seconds to send the APRS registry information.",
help='The frequency in seconds to send the APRS registry information.',
),
]
@ -232,7 +231,7 @@ def register_opts(config):
def list_opts():
return {
"DEFAULT": (aprsd_opts + enabled_plugins_opts),
'DEFAULT': (aprsd_opts + enabled_plugins_opts),
watch_list_group.name: watch_list_opts,
registry_group.name: registry_opts,
}

View File

@ -7,7 +7,7 @@ from aprsd.packets import core
from aprsd.utils import objectstore
CONF = cfg.CONF
LOG = logging.getLogger("APRSD")
LOG = logging.getLogger('APRSD')
class PacketList(objectstore.ObjectStoreMixin):
@ -27,8 +27,8 @@ class PacketList(objectstore.ObjectStoreMixin):
def _init_data(self):
self.data = {
"types": {},
"packets": OrderedDict(),
'types': {},
'packets': OrderedDict(),
}
def rx(self, packet: type[core.Packet]):
@ -37,11 +37,11 @@ class PacketList(objectstore.ObjectStoreMixin):
self._total_rx += 1
self._add(packet)
ptype = packet.__class__.__name__
type_stats = self.data["types"].setdefault(
type_stats = self.data['types'].setdefault(
ptype,
{"tx": 0, "rx": 0},
{'tx': 0, 'rx': 0},
)
type_stats["rx"] += 1
type_stats['rx'] += 1
def tx(self, packet: type[core.Packet]):
"""Add a packet that was received."""
@ -49,32 +49,32 @@ class PacketList(objectstore.ObjectStoreMixin):
self._total_tx += 1
self._add(packet)
ptype = packet.__class__.__name__
type_stats = self.data["types"].setdefault(
type_stats = self.data['types'].setdefault(
ptype,
{"tx": 0, "rx": 0},
{'tx': 0, 'rx': 0},
)
type_stats["tx"] += 1
type_stats['tx'] += 1
def add(self, packet):
with self.lock:
self._add(packet)
def _add(self, packet):
if not self.data.get("packets"):
if not self.data.get('packets'):
self._init_data()
if packet.key in self.data["packets"]:
self.data["packets"].move_to_end(packet.key)
elif len(self.data["packets"]) == self.maxlen:
self.data["packets"].popitem(last=False)
self.data["packets"][packet.key] = packet
if packet.key in self.data['packets']:
self.data['packets'].move_to_end(packet.key)
elif len(self.data['packets']) == self.maxlen:
self.data['packets'].popitem(last=False)
self.data['packets'][packet.key] = packet
def find(self, packet):
with self.lock:
return self.data["packets"][packet.key]
return self.data['packets'][packet.key]
def __len__(self):
with self.lock:
return len(self.data["packets"])
return len(self.data['packets'])
def total_rx(self):
with self.lock:
@ -87,17 +87,23 @@ class PacketList(objectstore.ObjectStoreMixin):
def stats(self, serializable=False) -> dict:
with self.lock:
# Get last N packets directly using list slicing
packets_list = list(self.data.get("packets", {}).values())
pkts = packets_list[-CONF.packet_list_stats_maxlen :][::-1]
if CONF.packet_list_stats_maxlen >= 0:
packets_list = list(self.data.get('packets', {}).values())
pkts = packets_list[-CONF.packet_list_stats_maxlen :][::-1]
else:
# We have to copy here, because this get() results in a pointer
# to the packets internally here, which can change after this
# function returns, which would cause a problem trying to save
# the stats to disk.
pkts = self.data.get('packets', {}).copy()
stats = {
"total_tracked": self._total_rx
'total_tracked': self._total_rx
+ self._total_tx, # Fixed typo: was rx + rx
"rx": self._total_rx,
"tx": self._total_tx,
"types": self.data.get("types", {}), # Changed default from [] to {}
"packet_count": len(self.data.get("packets", [])),
"maxlen": self.maxlen,
"packets": pkts,
'rx': self._total_rx,
'tx': self._total_tx,
'types': self.data.get('types', {}), # Changed default from [] to {}
'packet_count': len(self.data.get('packets', [])),
'maxlen': self.maxlen,
'packets': pkts,
}
return stats