Use new aprsd.callsign as the main callsign

This patch changes how aprsd identifies itself when connected to
any client, which is not relying on the login for each client.
There are 3 supported clients currently
aprsis,
tcpkiss
serialkiss.

Each client has their own potential login/callsign to connect
to the remote.  This patch tells aprsd to use the new config option
aprsd.callsign as a means to identify itself.  It will accept
packets as <aprsd.callsign> and reply as <aprsd.callsign> regardless
of which client object is being used to connect to the remote.

Note: this breaks backwards compatibility.  This patch now requires
the new config option
aprsd:
  callsign: <callsign>
This commit is contained in:
Hemna 2022-07-28 16:24:25 -04:00
parent 5f28788180
commit ad79ed1261
6 changed files with 89 additions and 39 deletions

View File

@ -156,8 +156,8 @@ class KISSClient(Client):
# Ensure that the config vars are correctly set
if KISSClient.is_enabled(config):
config.check_option(
"kiss.callsign",
default_fail=aprsd_config.DEFAULT_CONFIG_DICT["kiss"]["callsign"],
"aprsd.callsign",
default_fail=aprsd_config.DEFAULT_CONFIG_DICT["aprsd"]["callsign"],
)
transport = KISSClient.transport(config)
if transport == TRANSPORT_SERIALKISS:

View File

@ -32,6 +32,7 @@ class Aioax25Client:
device=self.config["kiss"]["serial"]["device"],
baudrate=self.config["kiss"]["serial"].get("baudrate", 9600),
loop=self.loop,
log=LOG,
)
elif "tcp" in self.config["kiss"] and self.config["kiss"]["tcp"].get(
"enabled",
@ -50,30 +51,32 @@ class Aioax25Client:
log=LOG,
)
self.kissdev.open()
self.kissport0 = self.kissdev[0]
LOG.debug("Creating AX25Interface")
self.ax25int = interface.AX25Interface(kissport=self.kissport0, loop=self.loop)
self.ax25int = interface.AX25Interface(
kissport=self.kissdev[0],
loop=self.loop,
log=LOG,
)
LOG.debug("Creating APRSInterface")
self.aprsint = APRSInterface(
ax25int=self.ax25int,
mycall=self.config["kiss"]["callsign"],
mycall=self.config["aprsd"]["callsign"],
log=LOG,
)
self.kissdev.open()
def stop(self):
LOG.debug(self.kissdev)
self.kissdev._close()
self.loop.stop()
self.kissdev.close()
def set_filter(self, filter):
# This does nothing right now.
pass
def consumer(self, callback, blocking=True, immortal=False, raw=False):
callsign = self.config["kiss"]["callsign"]
def consumer(self, callback, blocking=False, immortal=False, raw=False):
callsign = self.config["aprsd"]["callsign"]
call = callsign.split("-")
if len(call) > 1:
callsign = call[0]
@ -81,10 +84,28 @@ class Aioax25Client:
else:
ssid = 0
self.aprsint.bind(callback=callback, callsign=callsign, ssid=ssid, regex=False)
# async def set_after(fut, delay, value):
# # Sleep for *delay* seconds.
# await asyncio.sleep(delay)
#
# # Set *value* as a result of *fut* Future.
# fut.set_result(value)
#
# async def my_wait(fut):
# await fut
#
# fut = self.loop.create_future()
# self.loop.create_task(
# set_after(fut, 5, "nothing")
# )
LOG.debug("RUN FOREVER")
self.loop.run_forever()
# my_wait(fut)
def send(self, msg):
"""Send an APRS Message object."""
LOG.debug(f"Send {msg} TO KISS")
payload = f"{msg._filter_for_send()}"
self.aprsint.send_message(
addressee=msg.tocall,

View File

@ -93,19 +93,22 @@ class SentMessages(objectstore.ObjectStoreMixin):
@wrapt.synchronized(lock)
def set_status(self, id, status):
self.data[id]["last_update"] = str(datetime.datetime.now())
self.data[id]["status"] = status
if id in self.data:
self.data[id]["last_update"] = str(datetime.datetime.now())
self.data[id]["status"] = status
@wrapt.synchronized(lock)
def ack(self, id):
"""The message got an ack!"""
self.data[id]["last_update"] = str(datetime.datetime.now())
self.data[id]["ack"] = True
if id in self.data:
self.data[id]["last_update"] = str(datetime.datetime.now())
self.data[id]["ack"] = True
@wrapt.synchronized(lock)
def reply(self, id, packet):
"""We got a packet back from the sent message."""
self.data[id]["reply"] = packet
if id in self.data:
self.data[id]["reply"] = packet
# HTTPBasicAuth doesn't work on a class method.
@ -126,7 +129,6 @@ class WebChatRXThread(rx.APRSDRXThread):
self.connected = connected
def loop(self):
# setup the consumer of messages and block until a messages
msg = None
try:
@ -227,15 +229,16 @@ class WebChatTXThread(aprsd_thread.APRSDThread):
self.got_ack = True
def process_packet(self, packet):
LOG.info(f"process PACKET {packet}")
tocall = packet.get("addresse", None)
fromcall = packet["from"]
msg = packet.get("message_text", None)
msg_id = packet.get("msgNo", "0")
msg_response = packet.get("response", None)
if tocall == self.config["aprs"]["login"] and msg_response == "ack":
if tocall == self.config["aprsd"]["callsign"] and msg_response == "ack":
self.process_ack_packet(packet)
elif tocall == self.config["aprs"]["login"]:
elif tocall == self.config["aprsd"]["callsign"]:
messaging.log_message(
"Received Message",
packet["raw"],
@ -246,11 +249,11 @@ class WebChatTXThread(aprsd_thread.APRSDThread):
# let any threads do their thing, then ack
# send an ack last
ack = messaging.AckMessage(
self.config["aprs"]["login"],
self.config["aprsd"]["callsign"],
fromcall,
msg_id=msg_id,
)
self.msg_queues["tx"].put(ack)
ack.send()
packets.PacketList().add(packet)
stats.APRSDStats().msgs_rx_inc()
@ -299,7 +302,7 @@ class WebChatFlask(flask_classful.FlaskView):
)
else:
# We might be connected to a KISS socket?
if client.KISSClient.kiss_enabled(self.config):
if client.KISSClient.is_enabled(self.config):
transport = client.KISSClient.transport(self.config)
if transport == client.TRANSPORT_TCPKISS:
aprs_connection = (
@ -324,7 +327,7 @@ class WebChatFlask(flask_classful.FlaskView):
"index.html",
initial_stats=stats,
aprs_connection=aprs_connection,
callsign=self.config["aprs"]["login"],
callsign=self.config["aprsd"]["callsign"],
version=aprsd.__version__,
)
@ -335,7 +338,6 @@ class WebChatFlask(flask_classful.FlaskView):
info = msgs.get_all()
return json.dumps(info)
@trace.trace
def _stats(self):
stats_obj = stats.APRSDStats()
now = datetime.datetime.now()
@ -406,8 +408,8 @@ class SendMessageNamespace(Namespace):
"sent", SentMessages().get(self.msg.id),
namespace="/sendmsg",
)
self._msg_queues["tx"].put(msg)
msg.send()
# self._msg_queues["tx"].put(msg)
def handle_message(self, data):
LOG.debug(f"WS Data {data}")

View File

@ -57,13 +57,13 @@ DEFAULT_CONFIG_DICT = {
"ham": {"callsign": "NOCALL"},
"aprs": {
"enabled": True,
# Only used as the login for aprsis.
"login": "CALLSIGN",
"password": "00000",
"host": "rotate.aprs2.net",
"port": 14580,
},
"kiss": {
"callsign": "NOCALL",
"tcp": {
"enabled": False,
"host": "direwolf.ip.address",
@ -76,11 +76,14 @@ DEFAULT_CONFIG_DICT = {
},
},
"aprsd": {
# Callsign to use for all packets to/from aprsd instance
# regardless of the client (aprsis vs kiss)
"callsign": "NOCALL",
"logfile": "/tmp/aprsd.log",
"logformat": DEFAULT_LOG_FORMAT,
"dateformat": DEFAULT_DATE_FORMAT,
"save_location": DEFAULT_CONFIG_DIR,
"rich_logging": False,
"rich_logging": True,
"trace": False,
"enabled_plugins": CORE_MESSAGE_PLUGINS,
"units": "imperial",
@ -177,16 +180,35 @@ class Config(collections.UserDict):
if not self.exists(path):
if type(path) is list:
path = ".".join(path)
raise exception.MissingConfigOption(path)
raise exception.MissingConfigOptionException(path)
val = self.get(path)
if val == default_fail:
# We have to fail and bail if the user hasn't edited
# this config option.
raise exception.ConfigOptionBogusDefaultException(path, default_fail)
raise exception.ConfigOptionBogusDefaultException(
path, default_fail,
)
def add_config_comments(raw_yaml):
end_idx = utils.end_substr(raw_yaml, "ham:")
if end_idx != -1:
# lets insert a comment
raw_yaml = utils.insert_str(
raw_yaml,
"\n # Callsign that owns this instance of APRSD.",
end_idx,
)
end_idx = utils.end_substr(raw_yaml, "aprsd:")
if end_idx != -1:
# lets insert a comment
raw_yaml = utils.insert_str(
raw_yaml,
"\n # Callsign to use for all APRSD Packets as the to/from."
"\n # regardless of client type (aprsis vs tcpkiss vs serial)",
end_idx,
)
end_idx = utils.end_substr(raw_yaml, "aprs:")
if end_idx != -1:
# lets insert a comment
@ -326,6 +348,11 @@ def parse_config(config_file):
config,
["aprsd"],
)
check_option(
config,
"aprsd.callsign",
default_fail=DEFAULT_CONFIG_DICT["aprsd"]["callsign"],
)
# Ensure they change the admin password
if config.get("aprsd.web.enabled") is True:

View File

@ -41,7 +41,7 @@ class KeepAliveThread(APRSDThread):
stats_obj.set_memory_peak(peak)
try:
login = self.config["aprs"]["login"]
login = self.config["aprsd"]["callsign"]
except KeyError:
login = self.config["ham"]["callsign"]

View File

@ -101,7 +101,7 @@ class APRSDProcessPacketThread(APRSDThread):
# We don't put ack packets destined for us through the
# plugins.
if tocall == self.config["aprs"]["login"] and msg_response == "ack":
if tocall == self.config["aprsd"]["callsign"] and msg_response == "ack":
self.process_ack_packet(packet)
else:
# It's not an ACK for us, so lets run it through
@ -115,12 +115,12 @@ class APRSDProcessPacketThread(APRSDThread):
)
# Only ack messages that were sent directly to us
if tocall == self.config["aprs"]["login"]:
if tocall == self.config["aprsd"]["callsign"]:
stats.APRSDStats().msgs_rx_inc()
# let any threads do their thing, then ack
# send an ack last
ack = messaging.AckMessage(
self.config["aprs"]["login"],
self.config["aprsd"]["callsign"],
fromcall,
msg_id=msg_id,
)
@ -142,7 +142,7 @@ class APRSDProcessPacketThread(APRSDThread):
subreply.send()
else:
msg = messaging.TextMessage(
self.config["aprs"]["login"],
self.config["aprsd"]["callsign"],
fromcall,
subreply,
)
@ -162,7 +162,7 @@ class APRSDProcessPacketThread(APRSDThread):
LOG.debug(f"Sending '{reply}'")
msg = messaging.TextMessage(
self.config["aprs"]["login"],
self.config["aprsd"]["callsign"],
fromcall,
reply,
)
@ -170,10 +170,10 @@ class APRSDProcessPacketThread(APRSDThread):
# If the message was for us and we didn't have a
# response, then we send a usage statement.
if tocall == self.config["aprs"]["login"] and not replied:
if tocall == self.config["aprsd"]["callsign"] and not replied:
LOG.warning("Sending help!")
msg = messaging.TextMessage(
self.config["aprs"]["login"],
self.config["aprsd"]["callsign"],
fromcall,
"Unknown command! Send 'help' message for help",
)
@ -182,10 +182,10 @@ class APRSDProcessPacketThread(APRSDThread):
LOG.error("Plugin failed!!!")
LOG.exception(ex)
# Do we need to send a reply?
if tocall == self.config["aprs"]["login"]:
if tocall == self.config["aprsd"]["callsign"]:
reply = "A Plugin failed! try again?"
msg = messaging.TextMessage(
self.config["aprs"]["login"],
self.config["aprsd"]["callsign"],
fromcall,
reply,
)