1
0
mirror of https://github.com/craigerl/aprsd.git synced 2024-11-21 15:51:52 -05:00

Compare commits

..

2 Commits

Author SHA1 Message Date
1c50c39e61 Updated server client checks
Moved the client settings and configuration checks prior to
trying to start the client.
2024-11-20 18:01:21 -05:00
06c1fb985e Update Client to report login status
This patch updates the aprsd client base class to report login succes
and any error string associated with a login failure.  Also exposes
the login status so anyone using the client to check for login failure.

Update webchat, listen, server commands to check for initial login
failures and exit if the login failed.  No reason to continue on
if the login fails.
2024-11-20 15:55:02 -05:00
11 changed files with 113 additions and 39 deletions

View File

@ -23,13 +23,24 @@ class APRSISClient(base.APRSClient):
max_timeout = {"hours": 0.0, "minutes": 2, "seconds": 0}
self.max_delta = datetime.timedelta(**max_timeout)
def stats(self) -> dict:
def stats(self, serializable=False) -> dict:
stats = {}
if self.is_configured():
if self._client:
keepalive = self._client.aprsd_keepalive
server_string = self._client.server_string
if serializable:
keepalive = keepalive.isoformat()
else:
keepalive = "None"
server_string = "None"
stats = {
"server_string": self._client.server_string,
"sever_keepalive": self._client.aprsd_keepalive,
"connected": self.is_connected,
"filter": self.filter,
"keepalive": keepalive,
"login_status": self.login_status,
"server_string": server_string,
"transport": self.transport(),
}
return stats
@ -99,22 +110,31 @@ class APRSISClient(base.APRSClient):
self.connected = False
backoff = 1
aprs_client = None
retries = 3
retry_count = 0
while not self.connected:
retry_count += 1
if retry_count >= retries:
break
try:
LOG.info(f"Creating aprslib client({host}:{port}) and logging in {user}.")
aprs_client = aprsis.Aprsdis(user, passwd=password, host=host, port=port)
# Force the log to be the same
aprs_client.logger = LOG
aprs_client.connect()
self.connected = True
self.connected = self.login_status["success"] = True
self.login_status["message"] = aprs_client.server_string
backoff = 1
except LoginError as e:
LOG.error(f"Failed to login to APRS-IS Server '{e}'")
self.connected = False
self.connected = self.login_status["success"] = False
self.login_status["message"] = e.message
LOG.error(e.message)
time.sleep(backoff)
except Exception as e:
LOG.error(f"Unable to connect to APRS-IS server. '{e}' ")
self.connected = False
self.connected = self.login_status["success"] = False
self.login_status["message"] = e.message
time.sleep(backoff)
# Don't allow the backoff to go to inifinity.
if backoff > 5:
@ -135,5 +155,7 @@ class APRSISClient(base.APRSClient):
except Exception as e:
LOG.error(e)
LOG.info(e.__cause__)
raise e
else:
LOG.warning("client is None, might be resetting.")
self.connected = False

View File

@ -19,6 +19,10 @@ class APRSClient:
_client = None
connected = False
login_status = {
"success": False,
"message": None,
}
filter = None
lock = threading.Lock()
@ -38,6 +42,18 @@ class APRSClient:
dict: Statistics about the connection and packet handling
"""
@property
def is_connected(self):
return self.connected
@property
def login_success(self):
return self.login_status.get("success", False)
@property
def login_failure(self):
return self.login_status["message"]
def set_filter(self, filter):
self.filter = filter
if self._client:

View File

@ -27,6 +27,9 @@ class Aprsdis(aprslib.IS):
# date for last time we heard from the server
aprsd_keepalive = datetime.datetime.now()
# Which server we are connected to?
server_string = "None"
# timeout in seconds
select_timeout = 1
lock = threading.Lock()

View File

@ -14,8 +14,11 @@ LOG = logging.getLogger("APRSD")
class APRSDFakeClient(base.APRSClient, metaclass=trace.TraceWrapperMetaclass):
def stats(self) -> dict:
return {}
def stats(self, serializable=False) -> dict:
return {
"transport": "Fake",
"connected": True,
}
@staticmethod
def is_enabled():

View File

@ -17,12 +17,18 @@ class KISSClient(base.APRSClient):
_client = None
def stats(self) -> dict:
def stats(self, serializable=False) -> dict:
stats = {}
if self.is_configured():
return {
stats = {
"connected": self.is_connected,
"transport": self.transport(),
}
if self.transport() == client.TRANSPORT_TCPKISS:
stats["host"] = CONF.kiss_tcp.host
stats["port"] = CONF.kiss_tcp.port
elif self.transport() == client.TRANSPORT_SERIALKISS:
stats["device"] = CONF.kiss_serial.device
return stats
@staticmethod

View File

@ -17,22 +17,4 @@ class APRSClientStats:
@wrapt.synchronized(lock)
def stats(self, serializable=False):
cl = client.client_factory.create()
stats = {
"transport": cl.transport(),
"filter": cl.filter,
"connected": cl.connected,
}
if cl.transport() == client.TRANSPORT_APRSIS:
stats["server_string"] = cl.client.server_string
keepalive = cl.client.aprsd_keepalive
if serializable:
keepalive = keepalive.isoformat()
stats["server_keepalive"] = keepalive
elif cl.transport() == client.TRANSPORT_TCPKISS:
stats["host"] = CONF.kiss_tcp.host
stats["port"] = CONF.kiss_tcp.port
elif cl.transport() == client.TRANSPORT_SERIALKISS:
stats["device"] = CONF.kiss_serial.device
return stats
return client.client_factory.create().stats(serializable=serializable)

View File

@ -256,6 +256,12 @@ def listen(
LOG.info("Creating client connection")
aprs_client = client_factory.create()
LOG.info(aprs_client)
if not aprs_client.login_success:
# We failed to login, will just quit!
msg = f"Login Failure: {aprs_client.login_failure}"
LOG.error(msg)
print(msg)
sys.exit(-1)
LOG.debug(f"Filter by '{filter}'")
aprs_client.set_filter(filter)

View File

@ -54,10 +54,27 @@ def server(ctx, flush):
LOG.error("No Clients are enabled in config.")
sys.exit(-1)
# Make sure we have 1 client transport enabled
if not client_factory.is_client_enabled():
LOG.error("No Clients are enabled in config.")
sys.exit(-1)
if not client_factory.is_client_configured():
LOG.error("APRS client is not properly configured in config file.")
sys.exit(-1)
# Creates the client object
LOG.info("Creating client connection")
aprs_client = client_factory.create()
LOG.info(aprs_client)
if not aprs_client.login_success:
# We failed to login, will just quit!
msg = f"Login Failure: {aprs_client.login_failure}"
LOG.error(msg)
print(msg)
sys.exit(-1)
# Check to make sure the login worked.
# Create the initial PM singleton and Register plugins
# We register plugins first here so we can register each
@ -78,15 +95,6 @@ def server(ctx, flush):
for p in watchlist_plugins:
LOG.info(p)
# Make sure we have 1 client transport enabled
if not client_factory.is_client_enabled():
LOG.error("No Clients are enabled in config.")
sys.exit(-1)
if not client_factory.is_client_configured():
LOG.error("APRS client is not properly configured in config file.")
sys.exit(-1)
if not CONF.enable_seen_list:
# just deregister the class from the packet collector
packet_collector.PacketCollector().unregister(seen_list.SeenList)

View File

@ -24,7 +24,9 @@ from aprsd import utils as aprsd_utils
from aprsd.client import client_factory, kiss
from aprsd.main import cli
from aprsd.threads import aprsd as aprsd_threads
from aprsd.threads import keep_alive, rx, tx
from aprsd.threads import keep_alive, rx
from aprsd.threads import stats as stats_thread
from aprsd.threads import tx
from aprsd.utils import trace
@ -614,10 +616,24 @@ def webchat(ctx, flush, port):
LOG.error("APRS client is not properly configured in config file.")
sys.exit(-1)
# Creates the client object
LOG.info("Creating client connection")
aprs_client = client_factory.create()
LOG.info(aprs_client)
if not aprs_client.login_success:
# We failed to login, will just quit!
msg = f"Login Failure: {aprs_client.login_failure}"
LOG.error(msg)
print(msg)
sys.exit(-1)
keepalive = keep_alive.KeepAliveThread()
LOG.info("Start KeepAliveThread")
keepalive.start()
stats_store_thread = stats_thread.APRSDStatsStoreThread()
stats_store_thread.start()
socketio = init_flask(loglevel, quiet)
rx_thread = rx.APRSDPluginRXThread(
packet_queue=threads.packet_queue,

View File

@ -5,6 +5,7 @@ import tracemalloc
from loguru import logger
from oslo_config import cfg
import timeago
from aprsd import packets, utils
from aprsd.client import client_factory
@ -98,6 +99,9 @@ class KeepAliveThread(APRSDThread):
# check the APRS connection
cl = client_factory.create()
cl_stats = cl.stats()
keepalive = timeago.format(cl_stats.get("keepalive", None))
LOGU.opt(colors=True).info(f"<green>Client keepalive {keepalive}</green>")
# Reset the connection if it's dead and this isn't our
# First time through the loop.
# The first time through the loop can happen at startup where

View File

@ -18,6 +18,8 @@ LOG = logging.getLogger("APRSD")
class APRSDRXThread(APRSDThread):
_client = None
def __init__(self, packet_queue):
super().__init__("RX_PKT")
self.packet_queue = packet_queue
@ -33,6 +35,12 @@ class APRSDRXThread(APRSDThread):
self._client = client_factory.create()
time.sleep(1)
return True
if not self._client.is_connected:
self._client = client_factory.create()
time.sleep(1)
return True
# setup the consumer of messages and block until a messages
try:
# This will register a packet consumer with aprslib