diff --git a/aprsd/client.py b/aprsd/client.py index f17e027..71a8ea1 100644 --- a/aprsd/client.py +++ b/aprsd/client.py @@ -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: diff --git a/aprsd/clients/kiss.py b/aprsd/clients/kiss.py index 7ea1ce6..7facca7 100644 --- a/aprsd/clients/kiss.py +++ b/aprsd/clients/kiss.py @@ -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, diff --git a/aprsd/cmds/webchat.py b/aprsd/cmds/webchat.py index fc518a8..3aa85ad 100644 --- a/aprsd/cmds/webchat.py +++ b/aprsd/cmds/webchat.py @@ -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}") diff --git a/aprsd/config.py b/aprsd/config.py index 93b56ea..c96abf6 100644 --- a/aprsd/config.py +++ b/aprsd/config.py @@ -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: diff --git a/aprsd/threads/keep_alive.py b/aprsd/threads/keep_alive.py index 3b70eeb..95c7ea0 100644 --- a/aprsd/threads/keep_alive.py +++ b/aprsd/threads/keep_alive.py @@ -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"] diff --git a/aprsd/threads/rx.py b/aprsd/threads/rx.py index 5046e20..b28dbff 100644 --- a/aprsd/threads/rx.py +++ b/aprsd/threads/rx.py @@ -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, )