1
0
mirror of https://github.com/craigerl/aprsd.git synced 2026-03-09 09:29:45 -04:00

Fix client / driver inconsistencies from protocol

The client registry defined a protocol that all drivers had
to implement.  This patch ensures that all methods are
consistent in the protocol definition.
This commit is contained in:
Walter Boring 2026-01-23 09:18:35 -05:00
parent ee61bf5fd5
commit 3bcd03a514
14 changed files with 70 additions and 38 deletions

View File

@ -73,17 +73,15 @@ class APRSDClient(metaclass=trace.TraceWrapperMetaclass):
return True
return False
@property
def login_success(self):
if not self.driver:
return False
return self.driver.login_success
return self.driver.login_success()
@property
def login_failure(self):
if not self.driver:
return None
return self.driver.login_failure
return self.driver.login_failure()
def set_filter(self, filter):
self.filter = filter

View File

@ -146,14 +146,20 @@ class APRSISDriver:
@property
def filter(self):
if not self._client:
return ''
return self._client.filter
@property
def server_string(self):
if not self._client:
return None
return self._client.server_string
@property
def keepalive(self):
if not self._client:
return datetime.datetime.now()
return self._client.aprsd_keepalive
def _is_stale_connection(self):

View File

@ -34,18 +34,29 @@ class APRSDFakeDriver(metaclass=trace.TraceWrapperMetaclass):
@staticmethod
def is_enabled():
if CONF.fake_client.enabled:
return True
return False
return CONF.fake_client.enabled
@staticmethod
def is_configured():
return APRSDFakeDriver.is_enabled
return CONF.fake_client.enabled
@property
def is_alive(self):
"""If the connection is alive or not."""
return not self.thread_stop
@property
def filter(self) -> str:
return 'FAKE'
@staticmethod
def transport() -> str:
return 'FAKE'
@property
def keepalive(self) -> datetime.datetime:
return datetime.datetime.now()
def close(self):
self.thread_stop = True
LOG.info('Shutdown APRSDFakeDriver driver.')
@ -121,6 +132,6 @@ class APRSDFakeDriver(metaclass=trace.TraceWrapperMetaclass):
def stats(self, serializable: bool = False) -> dict:
return {
'driver': self.__class__.__name__,
'is_alive': self.is_alive(),
'is_alive': self.is_alive,
'transport': 'fake',
}

View File

@ -169,7 +169,7 @@ class KISSDriver(metaclass=trace.TraceWrapperMetaclass):
stats = {
'client': self.__class__.__name__,
'transport': self.transport,
'transport': self.transport(),
'connected': self._connected,
'path': self.path,
'packets_sent': self.packets_sent,

View File

@ -1,3 +1,4 @@
import datetime
from typing import Callable, Protocol, runtime_checkable
from aprsd.packets import core
@ -13,17 +14,29 @@ class ClientDriver(Protocol):
"""
@staticmethod
def is_enabled(self) -> bool:
def is_enabled() -> bool:
pass
@staticmethod
def is_configured(self) -> bool:
def is_configured() -> bool:
pass
@property
def is_alive(self) -> bool:
pass
@property
def filter(self) -> str:
pass
@staticmethod
def transport() -> str:
pass
@property
def keepalive(self) -> datetime.datetime:
pass
def close(self) -> None:
pass

View File

@ -54,8 +54,8 @@ class SerialKISSDriver(KISSDriver):
# This is initialized in setup_connection()
self.socket = None
@property
def transport(self) -> str:
@staticmethod
def transport() -> str:
return client.TRANSPORT_SERIALKISS
@staticmethod
@ -235,6 +235,7 @@ class SerialKISSDriver(KISSDriver):
self.last_packet_sent = datetime.datetime.now()
# Increment packets sent counter
self.packets_sent += 1
return True
@trace.no_trace
def stats(self, serializable: bool = False) -> Dict[str, Any]:

View File

@ -59,8 +59,8 @@ class TCPKISSDriver(KISSDriver):
# This is initialized in setup_connection()
self.socket = None
@property
def transport(self) -> str:
@staticmethod
def transport() -> str:
return client.TRANSPORT_TCPKISS
@staticmethod
@ -139,6 +139,7 @@ class TCPKISSDriver(KISSDriver):
self.last_packet_sent = datetime.datetime.now()
# Increment packets sent counter
self.packets_sent += 1
return True
def setup_connection(self):
"""Set up the KISS interface."""

View File

@ -281,9 +281,9 @@ def listen(
LOG.info('Creating client connection')
aprs_client = APRSDClient()
LOG.info(aprs_client)
if not aprs_client.login_success:
if not aprs_client.login_success():
# We failed to login, will just quit!
msg = f'Login Failure: {aprs_client.login_failure}'
msg = f'Login Failure: {aprs_client.login_failure()}'
LOG.error(msg)
print(msg)
sys.exit(-1)

View File

@ -80,9 +80,9 @@ def server(ctx, flush, enable_packet_stats):
LOG.info('Creating client connection')
aprs_client = APRSDClient()
LOG.info(aprs_client)
if not aprs_client.login_success:
if not aprs_client.login_success():
# We failed to login, will just quit!
msg = f'Login Failure: {aprs_client.login_failure}'
msg = f'Login Failure: {aprs_client.login_failure()}'
LOG.error(msg)
print(msg)
sys.exit(-1)

View File

@ -40,10 +40,10 @@ class TestAPRSDFakeDriver(unittest.TestCase):
def test_is_alive(self):
"""Test is_alive returns True when thread_stop is False."""
self.driver.thread_stop = False
self.assertTrue(self.driver.is_alive())
self.assertTrue(self.driver.is_alive)
self.driver.thread_stop = True
self.assertFalse(self.driver.is_alive())
self.assertFalse(self.driver.is_alive)
def test_close(self):
"""Test close sets thread_stop to True."""

View File

@ -11,9 +11,13 @@ class ConcreteKISSDriver(KISSDriver):
def __init__(self):
super().__init__()
self.transport = 'test'
self.path = '/dev/test'
@staticmethod
def transport() -> str:
"""Return transport type."""
return 'test'
def read_frame(self):
"""Implementation of abstract method."""
return None

View File

@ -77,8 +77,8 @@ class TestTCPKISSDriver(unittest.TestCase):
self.assertFalse(self.driver._running)
def test_transport_property(self):
"""Test transport property returns correct value."""
self.assertEqual(self.driver.transport, 'tcpkiss')
"""Test transport method returns correct value."""
self.assertEqual(self.driver.transport(), 'tcpkiss')
def test_is_enabled_true(self):
"""Test is_enabled returns True when KISS TCP is enabled."""

View File

@ -149,31 +149,31 @@ class TestAPRSDClient(unittest.TestCase):
self.registry_patcher.start()
def test_login_success_property(self):
"""Test login_success property."""
"""Test login_success method."""
client = APRSDClient(auto_connect=False)
self.mock_driver.login_status['success'] = True
self.assertTrue(client.login_success)
self.assertTrue(client.login_success())
self.mock_driver.login_status['success'] = False
self.assertFalse(client.login_success)
self.assertFalse(client.login_success())
def test_login_success_no_driver(self):
"""Test login_success property when driver is None."""
"""Test login_success method when driver is None."""
client = APRSDClient(auto_connect=False)
client.driver = None
self.assertFalse(client.login_success)
self.assertFalse(client.login_success())
def test_login_failure_property(self):
"""Test login_failure property."""
"""Test login_failure method."""
client = APRSDClient(auto_connect=False)
self.mock_driver.login_status['message'] = 'Test failure'
self.assertEqual(client.login_failure, 'Test failure')
self.assertEqual(client.login_failure(), 'Test failure')
def test_login_failure_no_driver(self):
"""Test login_failure property when driver is None."""
"""Test login_failure method when driver is None."""
client = APRSDClient(auto_connect=False)
client.driver = None
self.assertIsNone(client.login_failure)
self.assertIsNone(client.login_failure())
def test_set_filter(self):
"""Test set_filter() method."""

View File

@ -61,14 +61,12 @@ class MockClientDriver:
stats['path'] = self.path
return stats
@property
def login_success(self):
"""Property to get login success status."""
"""Method to get login success status."""
return self.login_status['success']
@property
def login_failure(self):
"""Property to get login failure message."""
"""Method to get login failure message."""
return self.login_status['message']
def _decode_packet(self, *args, **kwargs):