mirror of
https://github.com/craigerl/aprsd.git
synced 2025-07-15 23:15:14 -04:00
This patch adds basic ratelimiting to sending out AckPackets and non AckPackets. This provides a basic way to prevent aprsd from sending out packets as fast as possible, which isn't great for a bandwidth limited network. This patch also adds some keepalive checks to all threads in the threadslist as well as the network client objects (apris, kiss)
82 lines
2.0 KiB
Python
82 lines
2.0 KiB
Python
import abc
|
|
import logging
|
|
import threading
|
|
|
|
import wrapt
|
|
|
|
|
|
LOG = logging.getLogger("APRSD")
|
|
|
|
|
|
class APRSDThreadList:
|
|
"""Singleton class that keeps track of application wide threads."""
|
|
|
|
_instance = None
|
|
|
|
threads_list = []
|
|
lock = threading.Lock()
|
|
|
|
def __new__(cls, *args, **kwargs):
|
|
if cls._instance is None:
|
|
cls._instance = super().__new__(cls)
|
|
cls.threads_list = []
|
|
return cls._instance
|
|
|
|
@wrapt.synchronized(lock)
|
|
def add(self, thread_obj):
|
|
self.threads_list.append(thread_obj)
|
|
|
|
@wrapt.synchronized(lock)
|
|
def remove(self, thread_obj):
|
|
self.threads_list.remove(thread_obj)
|
|
|
|
@wrapt.synchronized(lock)
|
|
def stop_all(self):
|
|
"""Iterate over all threads and call stop on them."""
|
|
for th in self.threads_list:
|
|
LOG.info(f"Stopping Thread {th.name}")
|
|
if hasattr(th, "packet"):
|
|
LOG.info(F"{th.name} packet {th.packet}")
|
|
th.stop()
|
|
|
|
@wrapt.synchronized(lock)
|
|
def __len__(self):
|
|
return len(self.threads_list)
|
|
|
|
|
|
class APRSDThread(threading.Thread, metaclass=abc.ABCMeta):
|
|
|
|
def __init__(self, name):
|
|
super().__init__(name=name)
|
|
self.thread_stop = False
|
|
APRSDThreadList().add(self)
|
|
|
|
def _should_quit(self):
|
|
""" see if we have a quit message from the global queue."""
|
|
if self.thread_stop:
|
|
return True
|
|
|
|
def stop(self):
|
|
self.thread_stop = True
|
|
|
|
@abc.abstractmethod
|
|
def loop(self):
|
|
pass
|
|
|
|
def _cleanup(self):
|
|
"""Add code to subclass to do any cleanup"""
|
|
|
|
def __str__(self):
|
|
out = f"Thread <{self.__class__.__name__}({self.name}) Alive? {self.is_alive()}>"
|
|
return out
|
|
|
|
def run(self):
|
|
LOG.debug("Starting")
|
|
while not self._should_quit():
|
|
can_loop = self.loop()
|
|
if not can_loop:
|
|
self.stop()
|
|
self._cleanup()
|
|
APRSDThreadList().remove(self)
|
|
LOG.debug("Exiting")
|