Exemple #1
0
    def index(self):
        stats = self._stats()
        LOG.debug(
            "watch list? {}".format(self.config["aprsd"]["watch_list"], ), )
        wl = packets.WatchList()
        if wl.is_enabled():
            watch_count = len(wl)
            watch_age = wl.max_delta()
        else:
            watch_count = 0
            watch_age = 0

        sl = packets.SeenList()
        seen_count = len(sl)

        pm = plugin.PluginManager()
        plugins = pm.get_plugins()
        plugin_count = len(plugins)

        if self.config["aprs"].get("enabled", True):
            transport = "aprs-is"
            aprs_connection = (
                "APRS-IS Server: <a href='http://status.aprs2.net' >"
                "{}</a>".format(stats["stats"]["aprs-is"]["server"]))
        else:
            # We might be connected to a KISS socket?
            if client.KISSClient.kiss_enabled(self.config):
                transport = client.KISSClient.transport(self.config)
                if transport == client.TRANSPORT_TCPKISS:
                    aprs_connection = ("TCPKISS://{}:{}".format(
                        self.config["kiss"]["tcp"]["host"],
                        self.config["kiss"]["tcp"]["port"],
                    ))
                elif transport == client.TRANSPORT_SERIALKISS:
                    aprs_connection = ("SerialKISS://{}@{} baud".format(
                        self.config["kiss"]["serial"]["device"],
                        self.config["kiss"]["serial"]["baudrate"],
                    ))

        stats["transport"] = transport
        stats["aprs_connection"] = aprs_connection

        return flask.render_template(
            "index.html",
            initial_stats=stats,
            aprs_connection=aprs_connection,
            callsign=self.config["aprs"]["login"],
            version=aprsd.__version__,
            config_json=json.dumps(self.config.data),
            watch_count=watch_count,
            watch_age=watch_age,
            seen_count=seen_count,
            plugin_count=plugin_count,
        )
Exemple #2
0
    def config_and_init(self, config=None):
        if not config:
            self.config = aprsd_config.Config(aprsd_config.DEFAULT_CONFIG_DICT)
            self.config["ham"]["callsign"] = self.fromcall
            self.config["aprs"]["login"] = fake.FAKE_TO_CALLSIGN
            self.config["services"]["aprs.fi"]["apiKey"] = "something"
        else:
            self.config = config

        # Inintialize the stats object with the config
        stats.APRSDStats(self.config)
        packets.WatchList(config=self.config)
        packets.SeenList(config=self.config)
        messaging.MsgTrack(config=self.config)
Exemple #3
0
def signal_handler(sig, frame):
    global flask_enabled

    click.echo("signal_handler: called")
    threads.APRSDThreadList().stop_all()
    if "subprocess" not in str(frame):
        LOG.info(
            "Ctrl+C, Sending all threads exit! Can take up to 10 seconds {}".
            format(datetime.datetime.now(), ), )
        time.sleep(1.5)
        messaging.MsgTrack().save()
        packets.WatchList().save()
        packets.SeenList().save()
        LOG.info(stats.APRSDStats())
        # signal.signal(signal.SIGTERM, sys.exit(0))
        # sys.exit(0)
    if flask_enabled:
        signal.signal(signal.SIGTERM, sys.exit(0))
Exemple #4
0
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
    config = ctx.obj["config"]
    quiet = ctx.obj["quiet"]

    if not aprs_login:
        if not config.exists("aprs.login"):
            click.echo("Must set --aprs_login or APRS_LOGIN")
            ctx.exit(-1)
            return
    else:
        config["aprs"]["login"] = aprs_login

    if not aprs_password:
        if not config.exists("aprs.password"):
            click.echo("Must set --aprs-password or APRS_PASSWORD")
            ctx.exit(-1)
            return
    else:
        config["aprs"]["password"] = aprs_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(config=config)
    packets.WatchList(config=config)
    packets.SeenList(config=config)

    got_ack = False
    got_response = False

    def rx_packet(packet):
        global got_ack, got_response
        # LOG.debug("Got packet back {}".format(packet))
        resp = packet.get("response", None)
        if resp == "ack":
            ack_num = packet.get("msgNo")
            LOG.info(f"We got ack for our sent message {ack_num}")
            messaging.log_packet(packet)
            got_ack = True
        else:
            message = packet.get("message_text", None)
            fromcall = packet["from"]
            msg_number = packet.get("msgNo", "0")
            messaging.log_message(
                "Received Message",
                packet["raw"],
                message,
                fromcall=fromcall,
                ack=msg_number,
            )
            got_response = True
            # Send the ack back?
            ack = messaging.AckMessage(
                config["aprs"]["login"],
                fromcall,
                msg_id=msg_number,
            )
            ack.send_direct()

        if got_ack:
            if wait_response:
                if got_response:
                    sys.exit(0)
            else:
                sys.exit(0)

    try:
        client.ClientFactory.setup(config)
        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:
        msg = messaging.RawMessage(raw)
        msg.send_direct()
        sys.exit(0)
    else:
        msg = messaging.TextMessage(aprs_login, tocallsign, command)
    msg.send_direct()

    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()
Exemple #5
0
    def stats(self):
        now = datetime.datetime.now()
        if self._email_thread_last_time:
            last_update = str(now - self._email_thread_last_time)
        else:
            last_update = "never"

        if self._aprsis_keepalive:
            last_aprsis_keepalive = str(now - self._aprsis_keepalive)
        else:
            last_aprsis_keepalive = "never"

        pm = plugin.PluginManager()
        plugins = pm.get_plugins()
        plugin_stats = {}

        def full_name_with_qualname(obj):
            return "{}.{}".format(
                obj.__class__.__module__,
                obj.__class__.__qualname__,
            )

        for p in plugins:
            plugin_stats[full_name_with_qualname(p)] = {
                "enabled": p.enabled,
                "rx": p.rx_count,
                "tx": p.tx_count,
                "version": p.version,
            }

        wl = packets.WatchList()
        sl = packets.SeenList()

        stats = {
            "aprsd": {
                "version": aprsd.__version__,
                "uptime": utils.strfdelta(self.uptime),
                "memory_current": self.memory,
                "memory_current_str": utils.human_size(self.memory),
                "memory_peak": self.memory_peak,
                "memory_peak_str": utils.human_size(self.memory_peak),
                "watch_list": wl.get_all(),
                "seen_list": sl.get_all(),
            },
            "aprs-is": {
                "server": self.aprsis_server,
                "callsign": self.config["aprs"]["login"],
                "last_update": last_aprsis_keepalive,
            },
            "messages": {
                "tracked": self.msgs_tracked,
                "sent": self.msgs_tx,
                "recieved": self.msgs_rx,
                "ack_sent": self.ack_tx,
                "ack_recieved": self.ack_rx,
                "mic-e recieved": self.msgs_mice_rx,
            },
            "email": {
                "enabled": self.config["aprsd"]["email"]["enabled"],
                "sent": self._email_tx,
                "recieved": self._email_rx,
                "thread_last_update": last_update,
            },
            "plugins": plugin_stats,
        }
        return stats
Exemple #6
0
def server(ctx, flush):
    """Start the aprsd server gateway process."""
    ctx.obj["config_file"]
    loglevel = ctx.obj["loglevel"]
    quiet = ctx.obj["quiet"]
    config = ctx.obj["config"]

    signal.signal(signal.SIGINT, aprsd_main.signal_handler)
    signal.signal(signal.SIGTERM, aprsd_main.signal_handler)

    if not quiet:
        click.echo("Load config")

    level, msg = utils._check_version()
    if level:
        LOG.warning(msg)
    else:
        LOG.info(msg)
    LOG.info(f"APRSD Started version: {aprsd.__version__}")

    flat_config = utils.flatten_dict(config)
    LOG.info("Using CONFIG values:")
    for x in flat_config:
        if "password" in x or "aprsd.web.users.admin" in x:
            LOG.info(f"{x} = XXXXXXXXXXXXXXXXXXX")
        else:
            LOG.info(f"{x} = {flat_config[x]}")

    if config["aprsd"].get("trace", False):
        trace.setup_tracing(["method", "api"])
    stats.APRSDStats(config)

    # Initialize the client factory and create
    # The correct client object ready for use
    client.ClientFactory.setup(config)
    # Make sure we have 1 client transport enabled
    if not client.factory.is_client_enabled():
        LOG.error("No Clients are enabled in config.")
        sys.exit(-1)

    if not client.factory.is_client_configured():
        LOG.error("APRS client is not properly configured in config file.")
        sys.exit(-1)

    # Creates the client object
    LOG.info("Creating client connection")
    client.factory.create().client

    # Now load the msgTrack from disk if any
    packets.PacketList(config=config)
    if flush:
        LOG.debug("Deleting saved MsgTrack.")
        messaging.MsgTrack(config=config).flush()
        packets.WatchList(config=config)
        packets.SeenList(config=config)
    else:
        # Try and load saved MsgTrack list
        LOG.debug("Loading saved MsgTrack object.")
        messaging.MsgTrack(config=config).load()
        packets.WatchList(config=config).load()
        packets.SeenList(config=config).load()

    # Create the initial PM singleton and Register plugins
    LOG.info("Loading Plugin Manager and registering plugins")
    plugin_manager = plugin.PluginManager(config)
    plugin_manager.setup_plugins()

    rx_thread = threads.APRSDRXThread(
        msg_queues=threads.msg_queues,
        config=config,
    )
    rx_thread.start()

    messaging.MsgTrack().restart()

    keepalive = threads.KeepAliveThread(config=config)
    keepalive.start()

    web_enabled = config.get("aprsd.web.enabled", default=False)

    if web_enabled:
        aprsd_main.flask_enabled = True
        (socketio, app) = flask.init_flask(config, loglevel, quiet)
        socketio.run(
            app,
            host=config["aprsd"]["web"]["host"],
            port=config["aprsd"]["web"]["port"],
        )

    # If there are items in the msgTracker, then save them
    LOG.info("APRSD Exiting.")
    return 0
Exemple #7
0
def listen(
    ctx,
    aprs_login,
    aprs_password,
    filter,
):
    """Listen to packets on the APRS-IS Network based on FILTER.

    FILTER is the APRS Filter to use.\n
     see http://www.aprs-is.net/javAPRSFilter.aspx\n
    r/lat/lon/dist - Range Filter Pass posits and objects within dist km from lat/lon.\n
    p/aa/bb/cc... - Prefix Filter Pass traffic with fromCall that start with aa or bb or cc.\n
    b/call1/call2... - Budlist Filter Pass all traffic from exact call: call1, call2, ... (* wild card allowed) \n
    o/obj1/obj2... - Object Filter Pass all objects with the exact name of obj1, obj2, ... (* wild card allowed)\n

    """
    config = ctx.obj["config"]

    if not aprs_login:
        click.echo(ctx.get_help())
        click.echo("")
        ctx.fail("Must set --aprs_login or APRS_LOGIN")
        ctx.exit()

    if not aprs_password:
        click.echo(ctx.get_help())
        click.echo("")
        ctx.fail("Must set --aprs-password or APRS_PASSWORD")
        ctx.exit()

    config["aprs"]["login"] = aprs_login
    config["aprs"]["password"] = aprs_password

    LOG.info(f"APRSD Listen Started version: {aprsd.__version__}")

    flat_config = utils.flatten_dict(config)
    LOG.info("Using CONFIG values:")
    for x in flat_config:
        if "password" in x or "aprsd.web.users.admin" in x:
            LOG.info(f"{x} = XXXXXXXXXXXXXXXXXXX")
        else:
            LOG.info(f"{x} = {flat_config[x]}")

    stats.APRSDStats(config)

    # Try and load saved MsgTrack list
    LOG.debug("Loading saved MsgTrack object.")
    messaging.MsgTrack(config=config).load()
    packets.WatchList(config=config).load()
    packets.SeenList(config=config).load()

    @trace.trace
    def rx_packet(packet):
        resp = packet.get("response", None)
        if resp == "ack":
            ack_num = packet.get("msgNo")
            console.log(f"We saw an ACK {ack_num} Ignoring")
            messaging.log_packet(packet)
        else:
            message = packet.get("message_text", None)
            fromcall = packet["from"]
            msg_number = packet.get("msgNo", "0")
            messaging.log_message(
                "Received Message",
                packet["raw"],
                message,
                fromcall=fromcall,
                ack=msg_number,
                console=console,
            )

    # Initialize the client factory and create
    # The correct client object ready for use
    client.ClientFactory.setup(config)
    # Make sure we have 1 client transport enabled
    if not client.factory.is_client_enabled():
        LOG.error("No Clients are enabled in config.")
        sys.exit(-1)

    # Creates the client object
    LOG.info("Creating client connection")
    client.factory.create().client
    aprs_client = client.factory.create().client

    LOG.debug(f"Filter by '{filter}'")
    aprs_client.set_filter(filter)

    while True:
        try:
            # This will register a packet consumer with aprslib
            # When new packets come in the consumer will process
            # the packet
            with console.status("Listening for packets"):
                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()
        except aprslib.exceptions.UnknownFormat:
            LOG.error("Got a Bad packet")
Exemple #8
0
def test_plugin(
    ctx,
    aprs_login,
    plugin_path,
    load_all,
    number,
    message,
):
    """Test an individual APRSD plugin given a python path."""
    config = ctx.obj["config"]

    if not aprs_login:
        if not config.exists("aprs.login"):
            click.echo("Must set --aprs_login or APRS_LOGIN")
            ctx.exit(-1)
            return
        else:
            fromcall = config.get("aprs.login")
    else:
        fromcall = aprs_login

    if not plugin_path:
        click.echo(ctx.get_help())
        click.echo("")
        ctx.fail("Failed to provide -p option to test a plugin")
        return

    if type(message) is tuple:
        message = " ".join(message)

    if config["aprsd"].get("trace", False):
        trace.setup_tracing(["method", "api"])

    client.Client(config)
    stats.APRSDStats(config)
    messaging.MsgTrack(config=config)
    packets.WatchList(config=config)
    packets.SeenList(config=config)

    pm = plugin.PluginManager(config)
    if load_all:
        pm.setup_plugins()
    else:
        pm._init()
    obj = pm._create_class(plugin_path, plugin.APRSDPluginBase, config=config)
    if not obj:
        click.echo(ctx.get_help())
        click.echo("")
        ctx.fail(f"Failed to create object from plugin path '{plugin_path}'")
        ctx.exit()

    # Register the plugin they wanted tested.
    LOG.info(
        "Testing plugin {} Version {}".format(
            obj.__class__,
            obj.version,
        ), )
    pm._pluggy_pm.register(obj)
    login = config["aprs"]["login"]

    packet = {
        "from": fromcall,
        "addresse": login,
        "message_text": message,
        "format": "message",
        "msgNo": 1,
    }
    LOG.info(f"P'{plugin_path}'  F'{fromcall}'   C'{message}'")

    for x in range(number):
        reply = pm.run(packet)
        # Plugin might have threads, so lets stop them so we can exit.
        # obj.stop_threads()
        LOG.info(f"Result{x} = '{reply}'")
    pm.stop()