def check(loglevel, config_file, health_url, timeout): """APRSD Plugin test app.""" config = utils.parse_config(config_file) setup_logging(config, loglevel, False) LOG.debug("APRSD HealthCheck version: {}".format(aprsd.__version__)) try: url = health_url response = requests.get(url, timeout=timeout) response.raise_for_status() except Exception as ex: LOG.error("Failed to fetch healthcheck url '{}' : '{}'".format( url, ex)) sys.exit(-1) else: stats = json.loads(response.text) LOG.debug(stats) email_thread_last_update = stats["stats"]["email"][ "thread_last_update"] delta = parse_delta_str(email_thread_last_update) d = datetime.timedelta(**delta) max_timeout = {"hours": 0.0, "minutes": 5, "seconds": 0} max_delta = datetime.timedelta(**max_timeout) if d > max_delta: LOG.error("Email thread is very old! {}".format(d)) sys.exit(-1) sys.exit(0)
def server(loglevel, quiet, disable_validation, config_file): """Start the aprsd server process.""" signal.signal(signal.SIGINT, signal_handler) click.echo("Load config") config = utils.parse_config(config_file) # Force setting the config to the modules that need it # TODO(Walt): convert these modules to classes that can # Accept the config as a constructor param, instead of this # hacky global setting email.CONFIG = config messaging.CONFIG = config setup_logging(config, loglevel, quiet) LOG.info("APRSD Started version: {}".format(aprsd.__version__)) # TODO(walt): Make email processing/checking optional? # Maybe someone only wants this to process messages with plugins only. valid = email.validate_email_config(config, disable_validation) if not valid: LOG.error("Failed to validate email config options") sys.exit(-1) # start the email thread email.start_thread() # Create the initial PM singleton and Register plugins plugin_manager = plugin.PluginManager(config) plugin_manager.setup_plugins() cl = client.Client(config) # setup and run the main blocking loop while True: # Now use the helper which uses the singleton aprs_client = client.get_client() # setup the consumer of messages and block until a messages try: # This will register a packet consumer with aprslib # When new packets come in the consumer will process # the packet aprs_client.consumer(process_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 cl.reset()
def main(): global CONFIG args = parser.parse_args() setup_logging(args) LOG.info("Test APRS server starting.") time.sleep(1) CONFIG = utils.parse_config(args) ip = CONFIG["aprs"]["host"] port = CONFIG["aprs"]["port"] LOG.info("Start server listening on {}:{}".format(args.ip, args.port)) with socketserver.TCPServer((ip, port), MyAPRSTCPHandler) as server: server.serve_forever()
def test_plugin( loglevel, config_file, plugin_path, fromcall, message, ): """APRSD Plugin test app.""" config = utils.parse_config(config_file) email.CONFIG = config setup_logging(config, loglevel, False) LOG.info("Test APRSD PLugin version: {}".format(aprsd.__version__)) if type(message) is tuple: message = " ".join(message) LOG.info("P'{}' F'{}' C'{}'".format(plugin_path, fromcall, message)) client.Client(config) pm = plugin.PluginManager(config) obj = pm._create_class(plugin_path, plugin.APRSDPluginBase, config=config) reply = obj.run(fromcall, message, 1) LOG.info("Result = '{}'".format(reply))
def send_message(loglevel, quiet, config_file, aprs_login, aprs_password, tocallsign, command): """Send a message to a callsign via APRS_IS.""" global got_ack, got_response click.echo("{} {} {} {}".format(aprs_login, aprs_password, tocallsign, command)) click.echo("Load config") config = utils.parse_config(config_file) if not aprs_login: click.echo("Must set --aprs_login or APRS_LOGIN") return if not aprs_password: click.echo("Must set --aprs-password or APRS_PASSWORD") return config["aprs"]["login"] = aprs_login config["aprs"]["password"] = aprs_password messaging.CONFIG = config setup_logging(config, loglevel, quiet) LOG.info("APRSD Started version: {}".format(aprsd.__version__)) message_number = random.randint(1, 90) if type(command) is tuple: command = " ".join(command) LOG.info("Sending Command '{}'".format(command)) 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("We got ack for our sent message {}".format(ack_num)) messaging.log_packet(packet) got_ack = True else: message = packet.get("message_text", None) LOG.info("We got a new message") fromcall = packet["from"] msg_number = packet.get("msgNo", None) if msg_number: ack = msg_number else: ack = "0" messaging.log_message("Received Message", packet["raw"], message, fromcall=fromcall, ack=ack) got_response = True # Send the ack back? messaging.send_ack_direct(fromcall, ack) if got_ack and got_response: sys.exit(0) cl = client.Client(config) # 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 messaging.send_message_direct(tocallsign, command, message_number) try: # This will register a packet consumer with aprslib # When new packets come in the consumer will process # the packet aprs_client = client.get_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 cl.reset()
def server( loglevel, quiet, disable_validation, config_file, flush, ): """Start the aprsd server process.""" global flask_enabled signal.signal(signal.SIGINT, signal_handler) if not quiet: click.echo("Load config") config = utils.parse_config(config_file) # Force setting the config to the modules that need it # TODO(Walt): convert these modules to classes that can # Accept the config as a constructor param, instead of this # hacky global setting email.CONFIG = config setup_logging(config, loglevel, quiet) if config["aprsd"].get("trace", False): trace.setup_tracing(["method", "api"]) LOG.info("APRSD Started version: {}".format(aprsd.__version__)) stats.APRSDStats(config) email_enabled = config["aprsd"]["email"].get("enabled", False) if email_enabled: # TODO(walt): Make email processing/checking optional? # Maybe someone only wants this to process messages with plugins only. valid = email.validate_email_config(config, disable_validation) if not valid: LOG.error("Failed to validate email config options") sys.exit(-1) else: LOG.info("Email services not enabled.") # Create the initial PM singleton and Register plugins plugin_manager = plugin.PluginManager(config) plugin_manager.setup_plugins() try: cl = client.Client(config) cl.client except LoginError: sys.exit(-1) # Now load the msgTrack from disk if any if flush: LOG.debug("Deleting saved MsgTrack.") messaging.MsgTrack().flush() else: # Try and load saved MsgTrack list LOG.debug("Loading saved MsgTrack object.") messaging.MsgTrack().load() rx_msg_queue = queue.Queue(maxsize=20) tx_msg_queue = queue.Queue(maxsize=20) msg_queues = {"rx": rx_msg_queue, "tx": tx_msg_queue} rx_thread = threads.APRSDRXThread(msg_queues=msg_queues, config=config) tx_thread = threads.APRSDTXThread(msg_queues=msg_queues, config=config) if email_enabled: email_thread = email.APRSDEmailThread(msg_queues=msg_queues, config=config) email_thread.start() rx_thread.start() tx_thread.start() messaging.MsgTrack().restart() keepalive = threads.KeepAliveThread() keepalive.start() try: web_enabled = utils.check_config_option(config, ["aprsd", "web", "enabled"]) except Exception: web_enabled = False if web_enabled: flask_enabled = True app = flask.init_flask(config) app.run( 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