1
0
mirror of https://github.com/craigerl/aprsd.git synced 2026-08-19 10:13:44 -04:00

Compare commits

...

11 Commits

Author SHA1 Message Date
hemna 000adef6d4 Prep for 4.0.2 2025-01-25 13:29:04 -05:00
hemna bea481555b update the install from github in Dockerfile 2025-01-25 13:06:53 -05:00
hemna 3c4e200d70 Fix the testing of fortune path 2025-01-25 12:54:18 -05:00
hemna 2f26eb86f4 Added uv.lock 2025-01-25 12:33:29 -05:00
hemna 97ffffc10d Look in multiple places for fortune bin
Update the fortune plugin to look in multiple places for the
fortune binary.  It lives in different places for debian vs alpine.
2025-01-25 12:32:15 -05:00
hemna c1319c3ab8 Removed some verbose output from KISS
This removes some overly verbose output from the KISS driver.
2025-01-25 12:31:27 -05:00
hemna 1f65bbe13a Pass branch in github release_build
Try and pass the build arg BRANCH along with the
building of the image.
2025-01-24 20:50:33 -05:00
hemna 9501a63bd6 Trap for failed parsing of packets on KISS
This adds a try block around the aprslib.parse() for packets incoming
on the KISS interface.  Often times we'll get invalid packets and
this prevents stack dumps to the log.
2025-01-24 17:44:58 -05:00
hemna edeba7f514 Fix for KISS/Fake client drivers
They were both missing a setting of aprsd_keepalive to test
for the logging of the keepalive last time called.
2025-01-24 17:28:59 -05:00
hemna 24f567224c Updated Changelog 2025-01-24 16:46:02 -05:00
hemna e08039431e Update pyproject for README.rst -> md
Updated the pyproject.toml to reflect the name change of
README.rst -> README.md
2025-01-24 16:43:52 -05:00
9 changed files with 1439 additions and 59 deletions
+3 -2
View File
@@ -6,7 +6,7 @@ on:
aprsd_version: aprsd_version:
required: true required: true
options: options:
- 3.0.0 - 4.0.0
logLevel: logLevel:
description: 'Log level' description: 'Log level'
required: true required: true
@@ -42,8 +42,9 @@ jobs:
file: ./Dockerfile file: ./Dockerfile
build-args: | build-args: |
VERSION=${{ inputs.aprsd_version }} VERSION=${{ inputs.aprsd_version }}
BRANCH=${{ inputs.aprsd_version }}
BUILDX_QEMU_ENV=true BUILDX_QEMU_ENV=true
push: true push: true
tags: | tags: |
hemna6969/aprsd:v${{ inputs.aprsd_version }} hemna6969/aprsd:${{ inputs.aprsd_version }}
hemna6969/aprsd:latest hemna6969/aprsd:latest
+22
View File
@@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file. Dates are d
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
#### [4.0.2](https://github.com/craigerl/aprsd/compare/4.0.1...4.0.2)
> 25 January 2025
- Fix for KISS/Fake client drivers [`edeba7f`](https://github.com/craigerl/aprsd/commit/edeba7f5141c3197a3ddff5fe45127894c861e07)
- Trap for failed parsing of packets on KISS [`9501a63`](https://github.com/craigerl/aprsd/commit/9501a63bd61a681daf9eb9e41704e31570b7b385)
- Pass branch in github release_build [`1f65bbe`](https://github.com/craigerl/aprsd/commit/1f65bbe13a33c1fffad650c87c949bbe844d27f6)
- Removed some verbose output from KISS [`c1319c3`](https://github.com/craigerl/aprsd/commit/c1319c3ab8822f24c0e3b2c74d151d4e13a0039a)
- Look in multiple places for fortune bin [`97ffffc`](https://github.com/craigerl/aprsd/commit/97ffffc10dd05bd785134877ddb94437cf9b7f97)
- Added uv.lock [`2f26eb8`](https://github.com/craigerl/aprsd/commit/2f26eb86f44625547f72f7c3612494b1bc44bc99)
- Fix the testing of fortune path [`3c4e200`](https://github.com/craigerl/aprsd/commit/3c4e200d700c24125479bb754b5f68bdf35b85a6)
- update the install from github in Dockerfile [`bea4815`](https://github.com/craigerl/aprsd/commit/bea481555bc1270ab371a22c69973d648e526d54)
#### [4.0.1](https://github.com/craigerl/aprsd/compare/4.0.0...4.0.1)
> 24 January 2025
- Update pyproject for README.rst -> md [`e080394`](https://github.com/craigerl/aprsd/commit/e08039431ebde92a162ab422c05391dc55d3d3fa)
- Updated Changelog [`24f5672`](https://github.com/craigerl/aprsd/commit/24f567224cf8ecdebd51f49804425565883acb94)
### [4.0.0](https://github.com/craigerl/aprsd/compare/3.4.4...4.0.0) ### [4.0.0](https://github.com/craigerl/aprsd/compare/3.4.4...4.0.0)
> 24 January 2025 > 24 January 2025
@@ -51,6 +71,8 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
- reduced logo size 50% [`cf4a29f`](https://github.com/craigerl/aprsd/commit/cf4a29f0cb3ed366b21ec3120a189614e0955180) - reduced logo size 50% [`cf4a29f`](https://github.com/craigerl/aprsd/commit/cf4a29f0cb3ed366b21ec3120a189614e0955180)
- Updated README.md TOC [`375a5e5`](https://github.com/craigerl/aprsd/commit/375a5e5b34718cadc6ee8a51484fc91441440a61) - Updated README.md TOC [`375a5e5`](https://github.com/craigerl/aprsd/commit/375a5e5b34718cadc6ee8a51484fc91441440a61)
- chore: update AUTHORS [skip ci] [`c556f51`](https://github.com/craigerl/aprsd/commit/c556f5126f725904822a75427475d46986f8e9f3) - chore: update AUTHORS [skip ci] [`c556f51`](https://github.com/craigerl/aprsd/commit/c556f5126f725904822a75427475d46986f8e9f3)
- Updated requirements [`4a7a902`](https://github.com/craigerl/aprsd/commit/4a7a902a337759a352560d4d92dc314b1726412a)
- Updated ChangeLog for 4.0.0 [`934ebd2`](https://github.com/craigerl/aprsd/commit/934ebd236d044625b911dd8ca45293f6c5680a68)
#### [3.4.4](https://github.com/craigerl/aprsd/compare/3.4.3...3.4.4) #### [3.4.4](https://github.com/craigerl/aprsd/compare/3.4.3...3.4.4)
+5
View File
@@ -1,3 +1,4 @@
import datetime
import logging import logging
import threading import threading
import time import time
@@ -20,6 +21,9 @@ class APRSDFakeClient(metaclass=trace.TraceWrapperMetaclass):
# flag to tell us to stop # flag to tell us to stop
thread_stop = False thread_stop = False
# date for last time we heard from the server
aprsd_keepalive = datetime.datetime.now()
lock = threading.Lock() lock = threading.Lock()
path = [] path = []
@@ -63,6 +67,7 @@ class APRSDFakeClient(metaclass=trace.TraceWrapperMetaclass):
raw = 'GTOWN>APDW16,WIDE1-1,WIDE2-1:}KM6LYW-9>APZ100,TCPIP,GTOWN*::KM6LYW :KM6LYW: 19 Miles SW' raw = 'GTOWN>APDW16,WIDE1-1,WIDE2-1:}KM6LYW-9>APZ100,TCPIP,GTOWN*::KM6LYW :KM6LYW: 19 Miles SW'
pkt_raw = aprslib.parse(raw) pkt_raw = aprslib.parse(raw)
pkt = core.factory(pkt_raw) pkt = core.factory(pkt_raw)
self.aprsd_keepalive = datetime.datetime.now()
callback(packet=pkt) callback(packet=pkt)
LOG.debug(f'END blocking FAKE consumer {self}') LOG.debug(f'END blocking FAKE consumer {self}')
time.sleep(8) time.sleep(8)
+17 -15
View File
@@ -1,21 +1,24 @@
import datetime
import logging import logging
from ax253 import Frame
import kiss import kiss
from ax253 import Frame
from oslo_config import cfg from oslo_config import cfg
from aprsd import conf # noqa from aprsd import conf # noqa
from aprsd.packets import core from aprsd.packets import core
from aprsd.utils import trace from aprsd.utils import trace
CONF = cfg.CONF CONF = cfg.CONF
LOG = logging.getLogger("APRSD") LOG = logging.getLogger('APRSD')
class KISS3Client: class KISS3Client:
path = [] path = []
# date for last time we heard from the server
aprsd_keepalive = datetime.datetime.now()
def __init__(self): def __init__(self):
self.setup() self.setup()
@@ -26,7 +29,7 @@ class KISS3Client:
# we can be TCP kiss or Serial kiss # we can be TCP kiss or Serial kiss
if CONF.kiss_serial.enabled: if CONF.kiss_serial.enabled:
LOG.debug( LOG.debug(
"KISS({}) Serial connection to {}".format( 'KISS({}) Serial connection to {}'.format(
kiss.__version__, kiss.__version__,
CONF.kiss_serial.device, CONF.kiss_serial.device,
), ),
@@ -39,7 +42,7 @@ class KISS3Client:
self.path = CONF.kiss_serial.path self.path = CONF.kiss_serial.path
elif CONF.kiss_tcp.enabled: elif CONF.kiss_tcp.enabled:
LOG.debug( LOG.debug(
"KISS({}) TCP Connection to {}:{}".format( 'KISS({}) TCP Connection to {}:{}'.format(
kiss.__version__, kiss.__version__,
CONF.kiss_tcp.host, CONF.kiss_tcp.host,
CONF.kiss_tcp.port, CONF.kiss_tcp.port,
@@ -52,7 +55,7 @@ class KISS3Client:
) )
self.path = CONF.kiss_tcp.path self.path = CONF.kiss_tcp.path
LOG.debug("Starting KISS interface connection") LOG.debug('Starting KISS interface connection')
self.kiss.start() self.kiss.start()
@trace.trace @trace.trace
@@ -74,18 +77,17 @@ class KISS3Client:
frame = Frame.from_bytes(frame_bytes) frame = Frame.from_bytes(frame_bytes)
# Now parse it with aprslib # Now parse it with aprslib
kwargs = { kwargs = {
"frame": frame, 'frame': frame,
} }
self._parse_callback(**kwargs) self._parse_callback(**kwargs)
self.aprsd_keepalive = datetime.datetime.now()
except Exception as ex: except Exception as ex:
LOG.error("Failed to parse bytes received from KISS interface.") LOG.error('Failed to parse bytes received from KISS interface.')
LOG.exception(ex) LOG.exception(ex)
def consumer(self, callback): def consumer(self, callback):
LOG.debug("Start blocking KISS consumer")
self._parse_callback = callback self._parse_callback = callback
self.kiss.read(callback=self.parse_frame, min_frames=None) self.kiss.read(callback=self.parse_frame, min_frames=None)
LOG.debug(f"END blocking KISS consumer {self.kiss}")
def send(self, packet): def send(self, packet):
"""Send an APRS Message object.""" """Send an APRS Message object."""
@@ -94,24 +96,24 @@ class KISS3Client:
path = self.path path = self.path
if isinstance(packet, core.Packet): if isinstance(packet, core.Packet):
packet.prepare() packet.prepare()
payload = packet.payload.encode("US-ASCII") payload = packet.payload.encode('US-ASCII')
if packet.path: if packet.path:
path = packet.path path = packet.path
else: else:
msg_payload = f"{packet.raw}{{{str(packet.msgNo)}" msg_payload = f'{packet.raw}{{{str(packet.msgNo)}'
payload = ( payload = (
":{:<9}:{}".format( ':{:<9}:{}'.format(
packet.to_call, packet.to_call,
msg_payload, msg_payload,
) )
).encode("US-ASCII") ).encode('US-ASCII')
LOG.debug( LOG.debug(
f"KISS Send '{payload}' TO '{packet.to_call}' From " f"KISS Send '{payload}' TO '{packet.to_call}' From "
f"'{packet.from_call}' with PATH '{path}'", f"'{packet.from_call}' with PATH '{path}'",
) )
frame = Frame.ui( frame = Frame.ui(
destination="APZ100", destination='APZ100',
source=packet.from_call, source=packet.from_call,
path=path, path=path,
info=payload, info=payload,
+28 -25
View File
@@ -12,7 +12,7 @@ from aprsd.client.drivers import kiss
from aprsd.packets import core from aprsd.packets import core
CONF = cfg.CONF CONF = cfg.CONF
LOG = logging.getLogger("APRSD") LOG = logging.getLogger('APRSD')
LOGU = logger LOGU = logger
@@ -27,15 +27,15 @@ class KISSClient(base.APRSClient):
if serializable: if serializable:
keepalive = keepalive.isoformat() keepalive = keepalive.isoformat()
stats = { stats = {
"connected": self.is_connected, 'connected': self.is_connected,
"connection_keepalive": keepalive, 'connection_keepalive': keepalive,
"transport": self.transport(), 'transport': self.transport(),
} }
if self.transport() == client.TRANSPORT_TCPKISS: if self.transport() == client.TRANSPORT_TCPKISS:
stats["host"] = CONF.kiss_tcp.host stats['host'] = CONF.kiss_tcp.host
stats["port"] = CONF.kiss_tcp.port stats['port'] = CONF.kiss_tcp.port
elif self.transport() == client.TRANSPORT_SERIALKISS: elif self.transport() == client.TRANSPORT_SERIALKISS:
stats["device"] = CONF.kiss_serial.device stats['device'] = CONF.kiss_serial.device
return stats return stats
@staticmethod @staticmethod
@@ -56,15 +56,15 @@ class KISSClient(base.APRSClient):
transport = KISSClient.transport() transport = KISSClient.transport()
if transport == client.TRANSPORT_SERIALKISS: if transport == client.TRANSPORT_SERIALKISS:
if not CONF.kiss_serial.device: if not CONF.kiss_serial.device:
LOG.error("KISS serial enabled, but no device is set.") LOG.error('KISS serial enabled, but no device is set.')
raise exception.MissingConfigOptionException( raise exception.MissingConfigOptionException(
"kiss_serial.device is not set.", 'kiss_serial.device is not set.',
) )
elif transport == client.TRANSPORT_TCPKISS: elif transport == client.TRANSPORT_TCPKISS:
if not CONF.kiss_tcp.host: if not CONF.kiss_tcp.host:
LOG.error("KISS TCP enabled, but no host is set.") LOG.error('KISS TCP enabled, but no host is set.')
raise exception.MissingConfigOptionException( raise exception.MissingConfigOptionException(
"kiss_tcp.host is not set.", 'kiss_tcp.host is not set.',
) )
return True return True
@@ -91,8 +91,8 @@ class KISSClient(base.APRSClient):
if ka := self._client.aprsd_keepalive: if ka := self._client.aprsd_keepalive:
keepalive = timeago.format(ka) keepalive = timeago.format(ka)
else: else:
keepalive = "N/A" keepalive = 'N/A'
LOGU.opt(colors=True).info(f"<green>Client keepalive {keepalive}</green>") LOGU.opt(colors=True).info(f'<green>Client keepalive {keepalive}</green>')
@staticmethod @staticmethod
def transport(): def transport():
@@ -104,8 +104,8 @@ class KISSClient(base.APRSClient):
def decode_packet(self, *args, **kwargs): def decode_packet(self, *args, **kwargs):
"""We get a frame, which has to be decoded.""" """We get a frame, which has to be decoded."""
LOG.debug(f"kwargs {kwargs}") LOG.debug(f'kwargs {kwargs}')
frame = kwargs["frame"] frame = kwargs['frame']
LOG.debug(f"Got an APRS Frame '{frame}'") LOG.debug(f"Got an APRS Frame '{frame}'")
# try and nuke the * from the fromcall sign. # try and nuke the * from the fromcall sign.
# frame.header._source._ch = False # frame.header._source._ch = False
@@ -114,20 +114,23 @@ class KISSClient(base.APRSClient):
# msg = frame.tnc2 # msg = frame.tnc2
# LOG.debug(f"Decoding {msg}") # LOG.debug(f"Decoding {msg}")
raw = aprslib.parse(str(frame)) try:
packet = core.factory(raw) raw = aprslib.parse(str(frame))
if isinstance(packet, core.ThirdPartyPacket): packet = core.factory(raw)
return packet.subpacket if isinstance(packet, core.ThirdPartyPacket):
else: return packet.subpacket
return packet else:
return packet
except Exception as ex:
LOG.error(f'Error decoding packet: {ex}')
def setup_connection(self): def setup_connection(self):
try: try:
self._client = kiss.KISS3Client() self._client = kiss.KISS3Client()
self.connected = self.login_status["success"] = True self.connected = self.login_status['success'] = True
except Exception as ex: except Exception as ex:
self.connected = self.login_status["success"] = False self.connected = self.login_status['success'] = False
self.login_status["message"] = str(ex) self.login_status['message'] = str(ex)
return self._client return self._client
def consumer(self, callback, blocking=False, immortal=False, raw=False): def consumer(self, callback, blocking=False, immortal=False, raw=False):
@@ -135,5 +138,5 @@ class KISSClient(base.APRSClient):
self._client.consumer(callback) self._client.consumer(callback)
self.keepalive = datetime.datetime.now() self.keepalive = datetime.datetime.now()
except Exception as ex: except Exception as ex:
LOG.error(f"Consumer failed {ex}") LOG.error(f'Consumer failed {ex}')
LOG.error(ex) LOG.error(ex)
+21 -15
View File
@@ -5,24 +5,30 @@ import subprocess
from aprsd import packets, plugin from aprsd import packets, plugin
from aprsd.utils import trace from aprsd.utils import trace
LOG = logging.getLogger('APRSD')
LOG = logging.getLogger("APRSD") FORTUNE_PATHS = [
'/usr/games/fortune',
DEFAULT_FORTUNE_PATH = "/usr/games/fortune" '/usr/local/bin/fortune',
'/usr/bin/fortune',
]
class FortunePlugin(plugin.APRSDRegexCommandPluginBase): class FortunePlugin(plugin.APRSDRegexCommandPluginBase):
"""Fortune.""" """Fortune."""
command_regex = r"^([f]|[f]\s|fortune)" command_regex = r'^([f]|[f]\s|fortune)'
command_name = "fortune" command_name = 'fortune'
short_description = "Give me a fortune" short_description = 'Give me a fortune'
fortune_path = None fortune_path = None
def setup(self): def setup(self):
self.fortune_path = shutil.which(DEFAULT_FORTUNE_PATH) for path in FORTUNE_PATHS:
LOG.info(f"Fortune path {self.fortune_path}") self.fortune_path = shutil.which(path)
LOG.info(f'Fortune path {self.fortune_path}')
if self.fortune_path:
break
if not self.fortune_path: if not self.fortune_path:
self.enabled = False self.enabled = False
else: else:
@@ -30,7 +36,7 @@ class FortunePlugin(plugin.APRSDRegexCommandPluginBase):
@trace.trace @trace.trace
def process(self, packet: packets.MessagePacket): def process(self, packet: packets.MessagePacket):
LOG.info("FortunePlugin") LOG.info('FortunePlugin')
# fromcall = packet.get("from") # fromcall = packet.get("from")
# message = packet.get("message_text", None) # message = packet.get("message_text", None)
@@ -39,8 +45,8 @@ class FortunePlugin(plugin.APRSDRegexCommandPluginBase):
reply = None reply = None
try: try:
cmnd = [self.fortune_path, "-s", "-n 60"] cmnd = [self.fortune_path, '-s', '-n 60']
command = " ".join(cmnd) command = ' '.join(cmnd)
output = subprocess.check_output( output = subprocess.check_output(
command, command,
shell=True, shell=True,
@@ -48,10 +54,10 @@ class FortunePlugin(plugin.APRSDRegexCommandPluginBase):
text=True, text=True,
) )
output = ( output = (
output.replace("\r", "") output.replace('\r', '')
.replace("\n", "") .replace('\n', '')
.replace(" ", "") .replace(' ', '')
.replace("\t", " ") .replace('\t', ' ')
) )
except subprocess.CalledProcessError as ex: except subprocess.CalledProcessError as ex:
reply = f"Fortune command failed '{ex.output}'" reply = f"Fortune command failed '{ex.output}'"
+2 -1
View File
@@ -55,7 +55,8 @@ RUN if [ "$INSTALL_TYPE" = "pypi" ]; then \
uv pip install aprsd==$APRSD_PIP_VERSION; \ uv pip install aprsd==$APRSD_PIP_VERSION; \
elif [ "$INSTALL_TYPE" = "github" ]; then \ elif [ "$INSTALL_TYPE" = "github" ]; then \
git clone -b $APRSD_BRANCH https://github.com/craigerl/aprsd; \ git clone -b $APRSD_BRANCH https://github.com/craigerl/aprsd; \
cd /app/aprsd && uv pip install .; \ ls -al /app/aprsd; \
uv pip install /app/aprsd; \
ls -al /app/.venv/lib/python3.11/site-packages/aprsd*; \ ls -al /app/.venv/lib/python3.11/site-packages/aprsd*; \
fi fi
# RUN uv pip install gevent uwsgi # RUN uv pip install gevent uwsgi
+1 -1
View File
@@ -30,7 +30,7 @@ dynamic = ["version", "dependencies", "optional-dependencies"]
# #
# This field corresponds to the "Description" metadata field: # This field corresponds to the "Description" metadata field:
# https://packaging.python.org/specifications/core-metadata/#description-optional # https://packaging.python.org/specifications/core-metadata/#description-optional
readme = {file = "README.rst", content-type = "text/x-rst"} readme = {file = "README.md", content-type = "text/markdown"}
# This is either text indicating the license for the distribution, or a file # This is either text indicating the license for the distribution, or a file
Generated
+1340
View File
File diff suppressed because it is too large Load Diff