mirror of
https://github.com/craigerl/aprsd.git
synced 2026-08-19 01:53:58 -04:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 000adef6d4 | |||
| bea481555b | |||
| 3c4e200d70 | |||
| 2f26eb86f4 | |||
| 97ffffc10d | |||
| c1319c3ab8 | |||
| 1f65bbe13a | |||
| 9501a63bd6 | |||
| edeba7f514 | |||
| 24f567224c | |||
| e08039431e |
@@ -6,7 +6,7 @@ on:
|
||||
aprsd_version:
|
||||
required: true
|
||||
options:
|
||||
- 3.0.0
|
||||
- 4.0.0
|
||||
logLevel:
|
||||
description: 'Log level'
|
||||
required: true
|
||||
@@ -42,8 +42,9 @@ jobs:
|
||||
file: ./Dockerfile
|
||||
build-args: |
|
||||
VERSION=${{ inputs.aprsd_version }}
|
||||
BRANCH=${{ inputs.aprsd_version }}
|
||||
BUILDX_QEMU_ENV=true
|
||||
push: true
|
||||
tags: |
|
||||
hemna6969/aprsd:v${{ inputs.aprsd_version }}
|
||||
hemna6969/aprsd:${{ inputs.aprsd_version }}
|
||||
hemna6969/aprsd:latest
|
||||
|
||||
@@ -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).
|
||||
|
||||
#### [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)
|
||||
|
||||
> 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)
|
||||
- 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)
|
||||
- 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)
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import datetime
|
||||
import logging
|
||||
import threading
|
||||
import time
|
||||
@@ -20,6 +21,9 @@ class APRSDFakeClient(metaclass=trace.TraceWrapperMetaclass):
|
||||
# flag to tell us to stop
|
||||
thread_stop = False
|
||||
|
||||
# date for last time we heard from the server
|
||||
aprsd_keepalive = datetime.datetime.now()
|
||||
|
||||
lock = threading.Lock()
|
||||
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'
|
||||
pkt_raw = aprslib.parse(raw)
|
||||
pkt = core.factory(pkt_raw)
|
||||
self.aprsd_keepalive = datetime.datetime.now()
|
||||
callback(packet=pkt)
|
||||
LOG.debug(f'END blocking FAKE consumer {self}')
|
||||
time.sleep(8)
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
from ax253 import Frame
|
||||
import kiss
|
||||
from ax253 import Frame
|
||||
from oslo_config import cfg
|
||||
|
||||
from aprsd import conf # noqa
|
||||
from aprsd.packets import core
|
||||
from aprsd.utils import trace
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger("APRSD")
|
||||
LOG = logging.getLogger('APRSD')
|
||||
|
||||
|
||||
class KISS3Client:
|
||||
path = []
|
||||
|
||||
# date for last time we heard from the server
|
||||
aprsd_keepalive = datetime.datetime.now()
|
||||
|
||||
def __init__(self):
|
||||
self.setup()
|
||||
|
||||
@@ -26,7 +29,7 @@ class KISS3Client:
|
||||
# we can be TCP kiss or Serial kiss
|
||||
if CONF.kiss_serial.enabled:
|
||||
LOG.debug(
|
||||
"KISS({}) Serial connection to {}".format(
|
||||
'KISS({}) Serial connection to {}'.format(
|
||||
kiss.__version__,
|
||||
CONF.kiss_serial.device,
|
||||
),
|
||||
@@ -39,7 +42,7 @@ class KISS3Client:
|
||||
self.path = CONF.kiss_serial.path
|
||||
elif CONF.kiss_tcp.enabled:
|
||||
LOG.debug(
|
||||
"KISS({}) TCP Connection to {}:{}".format(
|
||||
'KISS({}) TCP Connection to {}:{}'.format(
|
||||
kiss.__version__,
|
||||
CONF.kiss_tcp.host,
|
||||
CONF.kiss_tcp.port,
|
||||
@@ -52,7 +55,7 @@ class KISS3Client:
|
||||
)
|
||||
self.path = CONF.kiss_tcp.path
|
||||
|
||||
LOG.debug("Starting KISS interface connection")
|
||||
LOG.debug('Starting KISS interface connection')
|
||||
self.kiss.start()
|
||||
|
||||
@trace.trace
|
||||
@@ -74,18 +77,17 @@ class KISS3Client:
|
||||
frame = Frame.from_bytes(frame_bytes)
|
||||
# Now parse it with aprslib
|
||||
kwargs = {
|
||||
"frame": frame,
|
||||
'frame': frame,
|
||||
}
|
||||
self._parse_callback(**kwargs)
|
||||
self.aprsd_keepalive = datetime.datetime.now()
|
||||
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)
|
||||
|
||||
def consumer(self, callback):
|
||||
LOG.debug("Start blocking KISS consumer")
|
||||
self._parse_callback = callback
|
||||
self.kiss.read(callback=self.parse_frame, min_frames=None)
|
||||
LOG.debug(f"END blocking KISS consumer {self.kiss}")
|
||||
|
||||
def send(self, packet):
|
||||
"""Send an APRS Message object."""
|
||||
@@ -94,24 +96,24 @@ class KISS3Client:
|
||||
path = self.path
|
||||
if isinstance(packet, core.Packet):
|
||||
packet.prepare()
|
||||
payload = packet.payload.encode("US-ASCII")
|
||||
payload = packet.payload.encode('US-ASCII')
|
||||
if packet.path:
|
||||
path = packet.path
|
||||
else:
|
||||
msg_payload = f"{packet.raw}{{{str(packet.msgNo)}"
|
||||
msg_payload = f'{packet.raw}{{{str(packet.msgNo)}'
|
||||
payload = (
|
||||
":{:<9}:{}".format(
|
||||
':{:<9}:{}'.format(
|
||||
packet.to_call,
|
||||
msg_payload,
|
||||
)
|
||||
).encode("US-ASCII")
|
||||
).encode('US-ASCII')
|
||||
|
||||
LOG.debug(
|
||||
f"KISS Send '{payload}' TO '{packet.to_call}' From "
|
||||
f"'{packet.from_call}' with PATH '{path}'",
|
||||
)
|
||||
frame = Frame.ui(
|
||||
destination="APZ100",
|
||||
destination='APZ100',
|
||||
source=packet.from_call,
|
||||
path=path,
|
||||
info=payload,
|
||||
|
||||
+28
-25
@@ -12,7 +12,7 @@ from aprsd.client.drivers import kiss
|
||||
from aprsd.packets import core
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger("APRSD")
|
||||
LOG = logging.getLogger('APRSD')
|
||||
LOGU = logger
|
||||
|
||||
|
||||
@@ -27,15 +27,15 @@ class KISSClient(base.APRSClient):
|
||||
if serializable:
|
||||
keepalive = keepalive.isoformat()
|
||||
stats = {
|
||||
"connected": self.is_connected,
|
||||
"connection_keepalive": keepalive,
|
||||
"transport": self.transport(),
|
||||
'connected': self.is_connected,
|
||||
'connection_keepalive': keepalive,
|
||||
'transport': self.transport(),
|
||||
}
|
||||
if self.transport() == client.TRANSPORT_TCPKISS:
|
||||
stats["host"] = CONF.kiss_tcp.host
|
||||
stats["port"] = CONF.kiss_tcp.port
|
||||
stats['host'] = CONF.kiss_tcp.host
|
||||
stats['port'] = CONF.kiss_tcp.port
|
||||
elif self.transport() == client.TRANSPORT_SERIALKISS:
|
||||
stats["device"] = CONF.kiss_serial.device
|
||||
stats['device'] = CONF.kiss_serial.device
|
||||
return stats
|
||||
|
||||
@staticmethod
|
||||
@@ -56,15 +56,15 @@ class KISSClient(base.APRSClient):
|
||||
transport = KISSClient.transport()
|
||||
if transport == client.TRANSPORT_SERIALKISS:
|
||||
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(
|
||||
"kiss_serial.device is not set.",
|
||||
'kiss_serial.device is not set.',
|
||||
)
|
||||
elif transport == client.TRANSPORT_TCPKISS:
|
||||
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(
|
||||
"kiss_tcp.host is not set.",
|
||||
'kiss_tcp.host is not set.',
|
||||
)
|
||||
|
||||
return True
|
||||
@@ -91,8 +91,8 @@ class KISSClient(base.APRSClient):
|
||||
if ka := self._client.aprsd_keepalive:
|
||||
keepalive = timeago.format(ka)
|
||||
else:
|
||||
keepalive = "N/A"
|
||||
LOGU.opt(colors=True).info(f"<green>Client keepalive {keepalive}</green>")
|
||||
keepalive = 'N/A'
|
||||
LOGU.opt(colors=True).info(f'<green>Client keepalive {keepalive}</green>')
|
||||
|
||||
@staticmethod
|
||||
def transport():
|
||||
@@ -104,8 +104,8 @@ class KISSClient(base.APRSClient):
|
||||
|
||||
def decode_packet(self, *args, **kwargs):
|
||||
"""We get a frame, which has to be decoded."""
|
||||
LOG.debug(f"kwargs {kwargs}")
|
||||
frame = kwargs["frame"]
|
||||
LOG.debug(f'kwargs {kwargs}')
|
||||
frame = kwargs['frame']
|
||||
LOG.debug(f"Got an APRS Frame '{frame}'")
|
||||
# try and nuke the * from the fromcall sign.
|
||||
# frame.header._source._ch = False
|
||||
@@ -114,20 +114,23 @@ class KISSClient(base.APRSClient):
|
||||
# msg = frame.tnc2
|
||||
# LOG.debug(f"Decoding {msg}")
|
||||
|
||||
raw = aprslib.parse(str(frame))
|
||||
packet = core.factory(raw)
|
||||
if isinstance(packet, core.ThirdPartyPacket):
|
||||
return packet.subpacket
|
||||
else:
|
||||
return packet
|
||||
try:
|
||||
raw = aprslib.parse(str(frame))
|
||||
packet = core.factory(raw)
|
||||
if isinstance(packet, core.ThirdPartyPacket):
|
||||
return packet.subpacket
|
||||
else:
|
||||
return packet
|
||||
except Exception as ex:
|
||||
LOG.error(f'Error decoding packet: {ex}')
|
||||
|
||||
def setup_connection(self):
|
||||
try:
|
||||
self._client = kiss.KISS3Client()
|
||||
self.connected = self.login_status["success"] = True
|
||||
self.connected = self.login_status['success'] = True
|
||||
except Exception as ex:
|
||||
self.connected = self.login_status["success"] = False
|
||||
self.login_status["message"] = str(ex)
|
||||
self.connected = self.login_status['success'] = False
|
||||
self.login_status['message'] = str(ex)
|
||||
return self._client
|
||||
|
||||
def consumer(self, callback, blocking=False, immortal=False, raw=False):
|
||||
@@ -135,5 +138,5 @@ class KISSClient(base.APRSClient):
|
||||
self._client.consumer(callback)
|
||||
self.keepalive = datetime.datetime.now()
|
||||
except Exception as ex:
|
||||
LOG.error(f"Consumer failed {ex}")
|
||||
LOG.error(f'Consumer failed {ex}')
|
||||
LOG.error(ex)
|
||||
|
||||
+21
-15
@@ -5,24 +5,30 @@ import subprocess
|
||||
from aprsd import packets, plugin
|
||||
from aprsd.utils import trace
|
||||
|
||||
LOG = logging.getLogger('APRSD')
|
||||
|
||||
LOG = logging.getLogger("APRSD")
|
||||
|
||||
DEFAULT_FORTUNE_PATH = "/usr/games/fortune"
|
||||
FORTUNE_PATHS = [
|
||||
'/usr/games/fortune',
|
||||
'/usr/local/bin/fortune',
|
||||
'/usr/bin/fortune',
|
||||
]
|
||||
|
||||
|
||||
class FortunePlugin(plugin.APRSDRegexCommandPluginBase):
|
||||
"""Fortune."""
|
||||
|
||||
command_regex = r"^([f]|[f]\s|fortune)"
|
||||
command_name = "fortune"
|
||||
short_description = "Give me a fortune"
|
||||
command_regex = r'^([f]|[f]\s|fortune)'
|
||||
command_name = 'fortune'
|
||||
short_description = 'Give me a fortune'
|
||||
|
||||
fortune_path = None
|
||||
|
||||
def setup(self):
|
||||
self.fortune_path = shutil.which(DEFAULT_FORTUNE_PATH)
|
||||
LOG.info(f"Fortune path {self.fortune_path}")
|
||||
for path in FORTUNE_PATHS:
|
||||
self.fortune_path = shutil.which(path)
|
||||
LOG.info(f'Fortune path {self.fortune_path}')
|
||||
if self.fortune_path:
|
||||
break
|
||||
if not self.fortune_path:
|
||||
self.enabled = False
|
||||
else:
|
||||
@@ -30,7 +36,7 @@ class FortunePlugin(plugin.APRSDRegexCommandPluginBase):
|
||||
|
||||
@trace.trace
|
||||
def process(self, packet: packets.MessagePacket):
|
||||
LOG.info("FortunePlugin")
|
||||
LOG.info('FortunePlugin')
|
||||
|
||||
# fromcall = packet.get("from")
|
||||
# message = packet.get("message_text", None)
|
||||
@@ -39,8 +45,8 @@ class FortunePlugin(plugin.APRSDRegexCommandPluginBase):
|
||||
reply = None
|
||||
|
||||
try:
|
||||
cmnd = [self.fortune_path, "-s", "-n 60"]
|
||||
command = " ".join(cmnd)
|
||||
cmnd = [self.fortune_path, '-s', '-n 60']
|
||||
command = ' '.join(cmnd)
|
||||
output = subprocess.check_output(
|
||||
command,
|
||||
shell=True,
|
||||
@@ -48,10 +54,10 @@ class FortunePlugin(plugin.APRSDRegexCommandPluginBase):
|
||||
text=True,
|
||||
)
|
||||
output = (
|
||||
output.replace("\r", "")
|
||||
.replace("\n", "")
|
||||
.replace(" ", "")
|
||||
.replace("\t", " ")
|
||||
output.replace('\r', '')
|
||||
.replace('\n', '')
|
||||
.replace(' ', '')
|
||||
.replace('\t', ' ')
|
||||
)
|
||||
except subprocess.CalledProcessError as ex:
|
||||
reply = f"Fortune command failed '{ex.output}'"
|
||||
|
||||
+2
-1
@@ -55,7 +55,8 @@ RUN if [ "$INSTALL_TYPE" = "pypi" ]; then \
|
||||
uv pip install aprsd==$APRSD_PIP_VERSION; \
|
||||
elif [ "$INSTALL_TYPE" = "github" ]; then \
|
||||
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*; \
|
||||
fi
|
||||
# RUN uv pip install gevent uwsgi
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ dynamic = ["version", "dependencies", "optional-dependencies"]
|
||||
#
|
||||
# This field corresponds to the "Description" metadata field:
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user