mirror of
https://github.com/craigerl/aprsd.git
synced 2026-03-10 01:49:36 -04:00
this patch adds the new PacketCollector class. It's a single point for collecting information about packets sent and recieved from the APRS client. Basically instead of having the packetlist call the seen list when we get a packet, we simply call the PacketCollector.rx(), which in turn calls each registered PacketMonitor class. This allows us to decouple the packet stats like classses inside of APRSD. More importantly, it allows extensions to append their own PacketMonitor class to the chain without modifying ARPSD.
175 lines
4.6 KiB
Python
175 lines
4.6 KiB
Python
import logging
|
|
import sys
|
|
import time
|
|
|
|
import aprslib
|
|
from aprslib.exceptions import LoginError
|
|
import click
|
|
from oslo_config import cfg
|
|
|
|
import aprsd
|
|
from aprsd import cli_helper, client, packets
|
|
from aprsd import conf # noqa : F401
|
|
from aprsd.main import cli
|
|
from aprsd.packets import collector
|
|
from aprsd.threads import tx
|
|
|
|
|
|
CONF = cfg.CONF
|
|
LOG = logging.getLogger("APRSD")
|
|
|
|
|
|
@cli.command()
|
|
@cli_helper.add_options(cli_helper.common_options)
|
|
@click.option(
|
|
"--aprs-login",
|
|
envvar="APRS_LOGIN",
|
|
show_envvar=True,
|
|
help="What callsign to send the message from. Defaults to config entry.",
|
|
)
|
|
@click.option(
|
|
"--aprs-password",
|
|
envvar="APRS_PASSWORD",
|
|
show_envvar=True,
|
|
help="the APRS-IS password for APRS_LOGIN. Defaults to config entry.",
|
|
)
|
|
@click.option(
|
|
"--no-ack",
|
|
"-n",
|
|
is_flag=True,
|
|
show_default=True,
|
|
default=False,
|
|
help="Don't wait for an ack, just sent it to APRS-IS and bail.",
|
|
)
|
|
@click.option(
|
|
"--wait-response",
|
|
"-w",
|
|
is_flag=True,
|
|
show_default=True,
|
|
default=False,
|
|
help="Wait for a response to the message?",
|
|
)
|
|
@click.option("--raw", default=None, help="Send a raw message. Implies --no-ack")
|
|
@click.argument("tocallsign", required=True)
|
|
@click.argument("command", nargs=-1, required=True)
|
|
@click.pass_context
|
|
@cli_helper.process_standard_options
|
|
def send_message(
|
|
ctx,
|
|
aprs_login,
|
|
aprs_password,
|
|
no_ack,
|
|
wait_response,
|
|
raw,
|
|
tocallsign,
|
|
command,
|
|
):
|
|
"""Send a message to a callsign via APRS_IS."""
|
|
global got_ack, got_response
|
|
quiet = ctx.obj["quiet"]
|
|
|
|
if not aprs_login:
|
|
if CONF.aprs_network.login == conf.client.DEFAULT_LOGIN:
|
|
click.echo("Must set --aprs_login or APRS_LOGIN")
|
|
ctx.exit(-1)
|
|
return
|
|
else:
|
|
aprs_login = CONF.aprs_network.login
|
|
|
|
if not aprs_password:
|
|
if not CONF.aprs_network.password:
|
|
click.echo("Must set --aprs-password or APRS_PASSWORD")
|
|
ctx.exit(-1)
|
|
return
|
|
else:
|
|
aprs_password = CONF.aprs_network.password
|
|
|
|
LOG.info(f"APRSD LISTEN Started version: {aprsd.__version__}")
|
|
if type(command) is tuple:
|
|
command = " ".join(command)
|
|
if not quiet:
|
|
if raw:
|
|
LOG.info(f"L'{aprs_login}' R'{raw}'")
|
|
else:
|
|
LOG.info(f"L'{aprs_login}' To'{tocallsign}' C'{command}'")
|
|
|
|
packets.PacketList()
|
|
packets.WatchList()
|
|
packets.SeenList()
|
|
|
|
got_ack = False
|
|
got_response = False
|
|
|
|
def rx_packet(packet):
|
|
global got_ack, got_response
|
|
cl = client.factory.create()
|
|
packet = cl.decode_packet(packet)
|
|
collector.PacketCollector().rx(packet)
|
|
packet.log("RX")
|
|
# LOG.debug("Got packet back {}".format(packet))
|
|
if isinstance(packet, packets.AckPacket):
|
|
got_ack = True
|
|
else:
|
|
got_response = True
|
|
from_call = packet.from_call
|
|
our_call = CONF.callsign.lower()
|
|
tx.send(
|
|
packets.AckPacket(
|
|
from_call=our_call,
|
|
to_call=from_call,
|
|
msgNo=packet.msgNo,
|
|
),
|
|
direct=True,
|
|
)
|
|
|
|
if got_ack:
|
|
if wait_response:
|
|
if got_response:
|
|
sys.exit(0)
|
|
else:
|
|
sys.exit(0)
|
|
|
|
try:
|
|
client.ClientFactory.setup()
|
|
client.factory.create().client
|
|
except LoginError:
|
|
sys.exit(-1)
|
|
|
|
# Send a message
|
|
# then we setup a consumer to rx messages
|
|
# We should get an ack back as well as a new message
|
|
# we should bail after we get the ack and send an ack back for the
|
|
# message
|
|
if raw:
|
|
tx.send(
|
|
packets.Packet(from_call="", to_call="", raw=raw),
|
|
direct=True,
|
|
)
|
|
sys.exit(0)
|
|
else:
|
|
tx.send(
|
|
packets.MessagePacket(
|
|
from_call=aprs_login,
|
|
to_call=tocallsign,
|
|
message_text=command,
|
|
),
|
|
direct=True,
|
|
)
|
|
|
|
if no_ack:
|
|
sys.exit(0)
|
|
|
|
try:
|
|
# This will register a packet consumer with aprslib
|
|
# When new packets come in the consumer will process
|
|
# the packet
|
|
aprs_client = client.factory.create().client
|
|
aprs_client.consumer(rx_packet, raw=False)
|
|
except aprslib.exceptions.ConnectionDrop:
|
|
LOG.error("Connection dropped, reconnecting")
|
|
time.sleep(5)
|
|
# Force the deletion of the client object connected to aprs
|
|
# This will cause a reconnect, next time client.get_client()
|
|
# is called
|
|
aprs_client.reset()
|