mirror of
				https://github.com/craigerl/aprsd.git
				synced 2025-10-31 12:50:30 -04:00 
			
		
		
		
	Lots of fixes
This commit is contained in:
		
							parent
							
								
									4c0150dd97
								
							
						
					
					
						commit
						231c15b1af
					
				| @ -1,29 +1,48 @@ | |||||||
| repos: | repos: | ||||||
| -   repo: https://github.com/pre-commit/pre-commit-hooks | - repo: https://github.com/pre-commit/pre-commit-hooks | ||||||
|     rev: v3.2.0 |   rev: v3.4.0 | ||||||
|     hooks: |   hooks: | ||||||
|     -   id: trailing-whitespace |     - id: trailing-whitespace | ||||||
|     -   id: end-of-file-fixer |     - id: end-of-file-fixer | ||||||
|     -   id: check-yaml |     - id: check-yaml | ||||||
|     -   id: check-added-large-files |     - id: check-added-large-files | ||||||
|     -   id: fix-encoding-pragma |     - id: detect-private-key | ||||||
|     -   id: detect-private-key |     - id: check-merge-conflict | ||||||
|     -   id: check-merge-conflict |     - id: check-case-conflict | ||||||
|     -   id: check-case-conflict |     - id: check-docstring-first | ||||||
|     -   id: check-docstring-first |     - id: check-builtin-literals | ||||||
|     -   id: check-builtin-literals |     - id: double-quote-string-fixer | ||||||
| -   repo: https://github.com/psf/black |  | ||||||
|     rev: 19.3b0 |  | ||||||
|     hooks: |  | ||||||
|     -   id: black |  | ||||||
| 
 | 
 | ||||||
| -   repo: https://github.com/pre-commit/mirrors-isort | - repo: https://github.com/asottile/setup-cfg-fmt | ||||||
|     rev: v5.7.0 |   rev: v1.16.0 | ||||||
|     hooks: |   hooks: | ||||||
|     -   id: isort |     - id: setup-cfg-fmt | ||||||
| 
 | 
 | ||||||
| -   repo: https://gitlab.com/pycqa/flake8 | - repo: https://github.com/asottile/add-trailing-comma | ||||||
|     rev: 3.8.1 |   rev: v2.0.2 | ||||||
|     hooks: |   hooks: | ||||||
|       - id: flake8 |     - id: add-trailing-comma | ||||||
|         additional_dependencies: [flake8-bugbear] |       args: [--py36-plus] | ||||||
|  | 
 | ||||||
|  | - repo: https://github.com/asottile/pyupgrade | ||||||
|  |   rev: v2.7.4 | ||||||
|  |   hooks: | ||||||
|  |     - id: pyupgrade | ||||||
|  |       args: | ||||||
|  |         - --py3-plus | ||||||
|  | 
 | ||||||
|  | - repo: https://github.com/pre-commit/mirrors-isort | ||||||
|  |   rev: v5.7.0 | ||||||
|  |   hooks: | ||||||
|  |     - id: isort | ||||||
|  | 
 | ||||||
|  | - repo: https://github.com/psf/black | ||||||
|  |   rev: 20.8b1 | ||||||
|  |   hooks: | ||||||
|  |     - id: black | ||||||
|  | 
 | ||||||
|  | - repo: https://gitlab.com/pycqa/flake8 | ||||||
|  |   rev: 3.8.4 | ||||||
|  |   hooks: | ||||||
|  |     - id: flake8 | ||||||
|  |       additional_dependencies: [flake8-bugbear] | ||||||
|  | |||||||
| @ -1,5 +1,3 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| 
 |  | ||||||
| # Licensed under the Apache License, Version 2.0 (the "License"); you may | # Licensed under the Apache License, Version 2.0 (the "License"); you may | ||||||
| # not use this file except in compliance with the License. You may obtain | # not use this file except in compliance with the License. You may obtain | ||||||
| # a copy of the License at | # a copy of the License at | ||||||
|  | |||||||
| @ -1,7 +1,5 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| import logging | import logging | ||||||
| import select | import select | ||||||
| import socket |  | ||||||
| import time | import time | ||||||
| 
 | 
 | ||||||
| import aprslib | import aprslib | ||||||
| @ -9,7 +7,7 @@ import aprslib | |||||||
| LOG = logging.getLogger("APRSD") | LOG = logging.getLogger("APRSD") | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Client(object): | class Client: | ||||||
|     """Singleton client class that constructs the aprslib connection.""" |     """Singleton client class that constructs the aprslib connection.""" | ||||||
| 
 | 
 | ||||||
|     _instance = None |     _instance = None | ||||||
| @ -19,7 +17,7 @@ class Client(object): | |||||||
|     def __new__(cls, *args, **kwargs): |     def __new__(cls, *args, **kwargs): | ||||||
|         """This magic turns this into a singleton.""" |         """This magic turns this into a singleton.""" | ||||||
|         if cls._instance is None: |         if cls._instance is None: | ||||||
|             cls._instance = super(Client, cls).__new__(cls) |             cls._instance = super().__new__(cls) | ||||||
|             # Put any initialization here. |             # Put any initialization here. | ||||||
|         return cls._instance |         return cls._instance | ||||||
| 
 | 
 | ||||||
| @ -82,7 +80,7 @@ class Aprsdis(aprslib.IS): | |||||||
|         """ |         """ | ||||||
|         try: |         try: | ||||||
|             self.sock.setblocking(0) |             self.sock.setblocking(0) | ||||||
|         except socket.error as e: |         except OSError as e: | ||||||
|             self.logger.error("socket error when setblocking(0): %s" % str(e)) |             self.logger.error("socket error when setblocking(0): %s" % str(e)) | ||||||
|             raise aprslib.ConnectionDrop("connection dropped") |             raise aprslib.ConnectionDrop("connection dropped") | ||||||
| 
 | 
 | ||||||
| @ -93,7 +91,10 @@ class Aprsdis(aprslib.IS): | |||||||
|             # set a select timeout, so we get a chance to exit |             # set a select timeout, so we get a chance to exit | ||||||
|             # when user hits CTRL-C |             # when user hits CTRL-C | ||||||
|             readable, writable, exceptional = select.select( |             readable, writable, exceptional = select.select( | ||||||
|                 [self.sock], [], [], self.select_timeout |                 [self.sock], | ||||||
|  |                 [], | ||||||
|  |                 [], | ||||||
|  |                 self.select_timeout, | ||||||
|             ) |             ) | ||||||
|             if not readable: |             if not readable: | ||||||
|                 continue |                 continue | ||||||
| @ -105,7 +106,7 @@ class Aprsdis(aprslib.IS): | |||||||
|                 if not short_buf: |                 if not short_buf: | ||||||
|                     self.logger.error("socket.recv(): returned empty") |                     self.logger.error("socket.recv(): returned empty") | ||||||
|                     raise aprslib.ConnectionDrop("connection dropped") |                     raise aprslib.ConnectionDrop("connection dropped") | ||||||
|             except socket.error as e: |             except OSError as e: | ||||||
|                 # self.logger.error("socket error on recv(): %s" % str(e)) |                 # self.logger.error("socket error on recv(): %s" % str(e)) | ||||||
|                 if "Resource temporarily unavailable" in str(e): |                 if "Resource temporarily unavailable" in str(e): | ||||||
|                     if not blocking: |                     if not blocking: | ||||||
|  | |||||||
| @ -1,18 +1,15 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| import datetime | import datetime | ||||||
| import email | import email | ||||||
|  | from email.mime.text import MIMEText | ||||||
| import imaplib | import imaplib | ||||||
| import logging | import logging | ||||||
| import re | import re | ||||||
| import smtplib | import smtplib | ||||||
| import time | import time | ||||||
| from email.mime.text import MIMEText |  | ||||||
| 
 |  | ||||||
| import imapclient |  | ||||||
| import six |  | ||||||
| from validate_email import validate_email |  | ||||||
| 
 | 
 | ||||||
| from aprsd import messaging, threads | from aprsd import messaging, threads | ||||||
|  | import imapclient | ||||||
|  | from validate_email import validate_email | ||||||
| 
 | 
 | ||||||
| LOG = logging.getLogger("APRSD") | LOG = logging.getLogger("APRSD") | ||||||
| 
 | 
 | ||||||
| @ -30,7 +27,10 @@ def _imap_connect(): | |||||||
| 
 | 
 | ||||||
|     try: |     try: | ||||||
|         server = imapclient.IMAPClient( |         server = imapclient.IMAPClient( | ||||||
|             CONFIG["imap"]["host"], port=imap_port, use_uid=True, ssl=use_ssl |             CONFIG["imap"]["host"], | ||||||
|  |             port=imap_port, | ||||||
|  |             use_uid=True, | ||||||
|  |             ssl=use_ssl, | ||||||
|         ) |         ) | ||||||
|     except Exception: |     except Exception: | ||||||
|         LOG.error("Failed to connect IMAP server") |         LOG.error("Failed to connect IMAP server") | ||||||
| @ -53,7 +53,7 @@ def _smtp_connect(): | |||||||
|     use_ssl = CONFIG["smtp"].get("use_ssl", False) |     use_ssl = CONFIG["smtp"].get("use_ssl", False) | ||||||
|     msg = "{}{}:{}".format("SSL " if use_ssl else "", host, smtp_port) |     msg = "{}{}:{}".format("SSL " if use_ssl else "", host, smtp_port) | ||||||
|     LOG.debug( |     LOG.debug( | ||||||
|         "Connect to SMTP host {} with user '{}'".format(msg, CONFIG["imap"]["login"]) |         "Connect to SMTP host {} with user '{}'".format(msg, CONFIG["imap"]["login"]), | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     try: |     try: | ||||||
| @ -84,7 +84,7 @@ def validate_shortcuts(config): | |||||||
| 
 | 
 | ||||||
|     LOG.info( |     LOG.info( | ||||||
|         "Validating {} Email shortcuts. This can take up to 10 seconds" |         "Validating {} Email shortcuts. This can take up to 10 seconds" | ||||||
|         " per shortcut".format(len(shortcuts)) |         " per shortcut".format(len(shortcuts)), | ||||||
|     ) |     ) | ||||||
|     delete_keys = [] |     delete_keys = [] | ||||||
|     for key in shortcuts: |     for key in shortcuts: | ||||||
| @ -102,8 +102,8 @@ def validate_shortcuts(config): | |||||||
|         if not is_valid: |         if not is_valid: | ||||||
|             LOG.error( |             LOG.error( | ||||||
|                 "'{}' is an invalid email address. Removing shortcut".format( |                 "'{}' is an invalid email address. Removing shortcut".format( | ||||||
|                     shortcuts[key] |                     shortcuts[key], | ||||||
|                 ) |                 ), | ||||||
|             ) |             ) | ||||||
|             delete_keys.append(key) |             delete_keys.append(key) | ||||||
| 
 | 
 | ||||||
| @ -173,14 +173,18 @@ def parse_email(msgid, data, server): | |||||||
| 
 | 
 | ||||||
|             if part.get_content_type() == "text/plain": |             if part.get_content_type() == "text/plain": | ||||||
|                 LOG.debug("Email got text/plain") |                 LOG.debug("Email got text/plain") | ||||||
|                 text = six.text_type( |                 text = str( | ||||||
|                     part.get_payload(decode=True), str(charset), "ignore" |                     part.get_payload(decode=True), | ||||||
|  |                     str(charset), | ||||||
|  |                     "ignore", | ||||||
|                 ).encode("utf8", "replace") |                 ).encode("utf8", "replace") | ||||||
| 
 | 
 | ||||||
|             if part.get_content_type() == "text/html": |             if part.get_content_type() == "text/html": | ||||||
|                 LOG.debug("Email got text/html") |                 LOG.debug("Email got text/html") | ||||||
|                 html = six.text_type( |                 html = str( | ||||||
|                     part.get_payload(decode=True), str(charset), "ignore" |                     part.get_payload(decode=True), | ||||||
|  |                     str(charset), | ||||||
|  |                     "ignore", | ||||||
|                 ).encode("utf8", "replace") |                 ).encode("utf8", "replace") | ||||||
| 
 | 
 | ||||||
|             if text is not None: |             if text is not None: | ||||||
| @ -192,12 +196,15 @@ def parse_email(msgid, data, server): | |||||||
|         # email.uscc.net sends no charset, blows up unicode function below |         # email.uscc.net sends no charset, blows up unicode function below | ||||||
|         LOG.debug("Email is not multipart") |         LOG.debug("Email is not multipart") | ||||||
|         if msg.get_content_charset() is None: |         if msg.get_content_charset() is None: | ||||||
|             text = six.text_type( |             text = str(msg.get_payload(decode=True), "US-ASCII", "ignore").encode( | ||||||
|                 msg.get_payload(decode=True), "US-ASCII", "ignore" |                 "utf8", | ||||||
|             ).encode("utf8", "replace") |                 "replace", | ||||||
|  |             ) | ||||||
|         else: |         else: | ||||||
|             text = six.text_type( |             text = str( | ||||||
|                 msg.get_payload(decode=True), msg.get_content_charset(), "ignore" |                 msg.get_payload(decode=True), | ||||||
|  |                 msg.get_content_charset(), | ||||||
|  |                 "ignore", | ||||||
|             ).encode("utf8", "replace") |             ).encode("utf8", "replace") | ||||||
|         body = text.strip() |         body = text.strip() | ||||||
| 
 | 
 | ||||||
| @ -266,11 +273,11 @@ def resend_email(count, fromcall): | |||||||
|     month = date.strftime("%B")[:3]  # Nov, Mar, Apr |     month = date.strftime("%B")[:3]  # Nov, Mar, Apr | ||||||
|     day = date.day |     day = date.day | ||||||
|     year = date.year |     year = date.year | ||||||
|     today = "%s-%s-%s" % (day, month, year) |     today = "{}-{}-{}".format(day, month, year) | ||||||
| 
 | 
 | ||||||
|     shortcuts = CONFIG["shortcuts"] |     shortcuts = CONFIG["shortcuts"] | ||||||
|     # swap key/value |     # swap key/value | ||||||
|     shortcuts_inverted = dict([[v, k] for k, v in shortcuts.items()]) |     shortcuts_inverted = {v: k for k, v in shortcuts.items()} | ||||||
| 
 | 
 | ||||||
|     try: |     try: | ||||||
|         server = _imap_connect() |         server = _imap_connect() | ||||||
| @ -310,7 +317,7 @@ def resend_email(count, fromcall): | |||||||
|         # thinking this is a duplicate message. |         # thinking this is a duplicate message. | ||||||
|         # The FT1XDR pretty much ignores the aprs message number in this |         # The FT1XDR pretty much ignores the aprs message number in this | ||||||
|         # regard.  The FTM400 gets it right. |         # regard.  The FTM400 gets it right. | ||||||
|         reply = "No new msg %s:%s:%s" % ( |         reply = "No new msg {}:{}:{}".format( | ||||||
|             str(h).zfill(2), |             str(h).zfill(2), | ||||||
|             str(m).zfill(2), |             str(m).zfill(2), | ||||||
|             str(s).zfill(2), |             str(s).zfill(2), | ||||||
| @ -328,7 +335,7 @@ def resend_email(count, fromcall): | |||||||
| 
 | 
 | ||||||
| class APRSDEmailThread(threads.APRSDThread): | class APRSDEmailThread(threads.APRSDThread): | ||||||
|     def __init__(self, msg_queues, config): |     def __init__(self, msg_queues, config): | ||||||
|         super(APRSDEmailThread, self).__init__("EmailThread") |         super().__init__("EmailThread") | ||||||
|         self.msg_queues = msg_queues |         self.msg_queues = msg_queues | ||||||
|         self.config = config |         self.config = config | ||||||
| 
 | 
 | ||||||
| @ -354,13 +361,13 @@ class APRSDEmailThread(threads.APRSDThread): | |||||||
| 
 | 
 | ||||||
|                 shortcuts = CONFIG["shortcuts"] |                 shortcuts = CONFIG["shortcuts"] | ||||||
|                 # swap key/value |                 # swap key/value | ||||||
|                 shortcuts_inverted = dict([[v, k] for k, v in shortcuts.items()]) |                 shortcuts_inverted = {v: k for k, v in shortcuts.items()} | ||||||
| 
 | 
 | ||||||
|                 date = datetime.datetime.now() |                 date = datetime.datetime.now() | ||||||
|                 month = date.strftime("%B")[:3]  # Nov, Mar, Apr |                 month = date.strftime("%B")[:3]  # Nov, Mar, Apr | ||||||
|                 day = date.day |                 day = date.day | ||||||
|                 year = date.year |                 year = date.year | ||||||
|                 today = "%s-%s-%s" % (day, month, year) |                 today = "{}-{}-{}".format(day, month, year) | ||||||
| 
 | 
 | ||||||
|                 server = None |                 server = None | ||||||
|                 try: |                 try: | ||||||
| @ -378,7 +385,8 @@ class APRSDEmailThread(threads.APRSDThread): | |||||||
|                     envelope = data[b"ENVELOPE"] |                     envelope = data[b"ENVELOPE"] | ||||||
|                     # LOG.debug('ID:%d  "%s" (%s)' % (msgid, envelope.subject.decode(), envelope.date)) |                     # LOG.debug('ID:%d  "%s" (%s)' % (msgid, envelope.subject.decode(), envelope.date)) | ||||||
|                     f = re.search( |                     f = re.search( | ||||||
|                         r"'([[A-a][0-9]_-]+@[[A-a][0-9]_-\.]+)", str(envelope.from_[0]) |                         r"'([[A-a][0-9]_-]+@[[A-a][0-9]_-\.]+)", | ||||||
|  |                         str(envelope.from_[0]), | ||||||
|                     ) |                     ) | ||||||
|                     if f is not None: |                     if f is not None: | ||||||
|                         from_addr = f.group(1) |                         from_addr = f.group(1) | ||||||
|  | |||||||
| @ -1,10 +1,9 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| import argparse | import argparse | ||||||
| import logging | import logging | ||||||
|  | from logging.handlers import RotatingFileHandler | ||||||
| import socketserver | import socketserver | ||||||
| import sys | import sys | ||||||
| import time | import time | ||||||
| from logging.handlers import RotatingFileHandler |  | ||||||
| 
 | 
 | ||||||
| from aprsd import utils | from aprsd import utils | ||||||
| 
 | 
 | ||||||
| @ -74,7 +73,7 @@ def main(): | |||||||
| 
 | 
 | ||||||
|     ip = CONFIG["aprs"]["host"] |     ip = CONFIG["aprs"]["host"] | ||||||
|     port = CONFIG["aprs"]["port"] |     port = CONFIG["aprs"]["port"] | ||||||
|     LOG.info("Start server listening on %s:%s" % (args.ip, args.port)) |     LOG.info("Start server listening on {}:{}".format(args.ip, args.port)) | ||||||
| 
 | 
 | ||||||
|     with socketserver.TCPServer((ip, port), MyAPRSTCPHandler) as server: |     with socketserver.TCPServer((ip, port), MyAPRSTCPHandler) as server: | ||||||
|         server.serve_forever() |         server.serve_forever() | ||||||
|  | |||||||
| @ -1,4 +1,3 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| # | # | ||||||
| # @author Sinu John | # @author Sinu John | ||||||
| #         sinuvian at gmail dot com | #         sinuvian at gmail dot com | ||||||
|  | |||||||
| @ -1,4 +1,3 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| # | # | ||||||
| # Listen on amateur radio aprs-is network for messages and respond to them. | # Listen on amateur radio aprs-is network for messages and respond to them. | ||||||
| # You must have an amateur radio callsign to use this software.  You must | # You must have an amateur radio callsign to use this software.  You must | ||||||
| @ -22,23 +21,22 @@ | |||||||
| 
 | 
 | ||||||
| # python included libs | # python included libs | ||||||
| import logging | import logging | ||||||
|  | from logging import NullHandler | ||||||
|  | from logging.handlers import RotatingFileHandler | ||||||
| import os | import os | ||||||
| import queue | import queue | ||||||
| import signal | import signal | ||||||
| import sys | import sys | ||||||
| import threading | import threading | ||||||
| import time | import time | ||||||
| from logging import NullHandler |  | ||||||
| from logging.handlers import RotatingFileHandler |  | ||||||
| 
 |  | ||||||
| import aprslib |  | ||||||
| import click |  | ||||||
| import click_completion |  | ||||||
| import yaml |  | ||||||
| 
 | 
 | ||||||
| # local imports here | # local imports here | ||||||
| import aprsd | import aprsd | ||||||
| from aprsd import client, email, messaging, plugin, threads, utils | from aprsd import client, email, messaging, plugin, threads, utils | ||||||
|  | import aprslib | ||||||
|  | import click | ||||||
|  | import click_completion | ||||||
|  | import yaml | ||||||
| 
 | 
 | ||||||
| # setup the global logger | # setup the global logger | ||||||
| # logging.basicConfig(level=logging.DEBUG) # level=10 | # logging.basicConfig(level=logging.DEBUG) # level=10 | ||||||
| @ -99,7 +97,9 @@ def main(): | |||||||
| 
 | 
 | ||||||
| @main.command() | @main.command() | ||||||
| @click.option( | @click.option( | ||||||
|     "-i", "--case-insensitive/--no-case-insensitive", help="Case insensitive completion" |     "-i", | ||||||
|  |     "--case-insensitive/--no-case-insensitive", | ||||||
|  |     help="Case insensitive completion", | ||||||
| ) | ) | ||||||
| @click.argument( | @click.argument( | ||||||
|     "shell", |     "shell", | ||||||
| @ -118,10 +118,14 @@ def show(shell, case_insensitive): | |||||||
| 
 | 
 | ||||||
| @main.command() | @main.command() | ||||||
| @click.option( | @click.option( | ||||||
|     "--append/--overwrite", help="Append the completion code to the file", default=None |     "--append/--overwrite", | ||||||
|  |     help="Append the completion code to the file", | ||||||
|  |     default=None, | ||||||
| ) | ) | ||||||
| @click.option( | @click.option( | ||||||
|     "-i", "--case-insensitive/--no-case-insensitive", help="Case insensitive completion" |     "-i", | ||||||
|  |     "--case-insensitive/--no-case-insensitive", | ||||||
|  |     help="Case insensitive completion", | ||||||
| ) | ) | ||||||
| @click.argument( | @click.argument( | ||||||
|     "shell", |     "shell", | ||||||
| @ -137,16 +141,19 @@ def install(append, case_insensitive, shell, path): | |||||||
|         else {} |         else {} | ||||||
|     ) |     ) | ||||||
|     shell, path = click_completion.core.install( |     shell, path = click_completion.core.install( | ||||||
|         shell=shell, path=path, append=append, extra_env=extra_env |         shell=shell, | ||||||
|  |         path=path, | ||||||
|  |         append=append, | ||||||
|  |         extra_env=extra_env, | ||||||
|     ) |     ) | ||||||
|     click.echo("%s completion installed in %s" % (shell, path)) |     click.echo("{} completion installed in {}".format(shell, path)) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def signal_handler(signal, frame): | def signal_handler(signal, frame): | ||||||
|     global server_vent |     global server_vent | ||||||
| 
 | 
 | ||||||
|     LOG.info( |     LOG.info( | ||||||
|         "Ctrl+C, Sending all threads exit! Can take up to 10 seconds to exit all threads" |         "Ctrl+C, Sending all threads exit! Can take up to 10 seconds to exit all threads", | ||||||
|     ) |     ) | ||||||
|     threads.APRSDThreadList().stop_all() |     threads.APRSDThreadList().stop_all() | ||||||
|     server_event.set() |     server_event.set() | ||||||
| @ -191,7 +198,8 @@ def sample_config(): | |||||||
|     default="DEBUG", |     default="DEBUG", | ||||||
|     show_default=True, |     show_default=True, | ||||||
|     type=click.Choice( |     type=click.Choice( | ||||||
|         ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"], case_sensitive=False |         ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"], | ||||||
|  |         case_sensitive=False, | ||||||
|     ), |     ), | ||||||
|     show_choices=True, |     show_choices=True, | ||||||
|     help="The log level to use for aprsd.log", |     help="The log level to use for aprsd.log", | ||||||
| @ -220,7 +228,13 @@ def sample_config(): | |||||||
| @click.argument("tocallsign") | @click.argument("tocallsign") | ||||||
| @click.argument("command", nargs=-1) | @click.argument("command", nargs=-1) | ||||||
| def send_message( | def send_message( | ||||||
|     loglevel, quiet, config_file, aprs_login, aprs_password, tocallsign, command |     loglevel, | ||||||
|  |     quiet, | ||||||
|  |     config_file, | ||||||
|  |     aprs_login, | ||||||
|  |     aprs_password, | ||||||
|  |     tocallsign, | ||||||
|  |     command, | ||||||
| ): | ): | ||||||
|     """Send a message to a callsign via APRS_IS.""" |     """Send a message to a callsign via APRS_IS.""" | ||||||
|     global got_ack, got_response |     global got_ack, got_response | ||||||
| @ -273,7 +287,9 @@ def send_message( | |||||||
|             got_response = True |             got_response = True | ||||||
|             # Send the ack back? |             # Send the ack back? | ||||||
|             ack = messaging.AckMessage( |             ack = messaging.AckMessage( | ||||||
|                 config["aprs"]["login"], fromcall, msg_id=msg_number |                 config["aprs"]["login"], | ||||||
|  |                 fromcall, | ||||||
|  |                 msg_id=msg_number, | ||||||
|             ) |             ) | ||||||
|             ack.send_direct() |             ack.send_direct() | ||||||
| 
 | 
 | ||||||
| @ -312,7 +328,8 @@ def send_message( | |||||||
|     default="DEBUG", |     default="DEBUG", | ||||||
|     show_default=True, |     show_default=True, | ||||||
|     type=click.Choice( |     type=click.Choice( | ||||||
|         ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"], case_sensitive=False |         ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"], | ||||||
|  |         case_sensitive=False, | ||||||
|     ), |     ), | ||||||
|     show_choices=True, |     show_choices=True, | ||||||
|     help="The log level to use for aprsd.log", |     help="The log level to use for aprsd.log", | ||||||
|  | |||||||
| @ -1,14 +1,13 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| import abc | import abc | ||||||
| import datetime | import datetime | ||||||
| import logging | import logging | ||||||
|  | from multiprocessing import RawValue | ||||||
| import os | import os | ||||||
| import pathlib | import pathlib | ||||||
| import pickle | import pickle | ||||||
| import re | import re | ||||||
| import threading | import threading | ||||||
| import time | import time | ||||||
| from multiprocessing import RawValue |  | ||||||
| 
 | 
 | ||||||
| from aprsd import client, threads, utils | from aprsd import client, threads, utils | ||||||
| 
 | 
 | ||||||
| @ -19,7 +18,7 @@ LOG = logging.getLogger("APRSD") | |||||||
| NULL_MESSAGE = -1 | NULL_MESSAGE = -1 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class MsgTrack(object): | class MsgTrack: | ||||||
|     """Class to keep track of outstanding text messages. |     """Class to keep track of outstanding text messages. | ||||||
| 
 | 
 | ||||||
|     This is a thread safe class that keeps track of active |     This is a thread safe class that keeps track of active | ||||||
| @ -47,7 +46,7 @@ class MsgTrack(object): | |||||||
| 
 | 
 | ||||||
|     def __new__(cls, *args, **kwargs): |     def __new__(cls, *args, **kwargs): | ||||||
|         if cls._instance is None: |         if cls._instance is None: | ||||||
|             cls._instance = super(MsgTrack, cls).__new__(cls) |             cls._instance = super().__new__(cls) | ||||||
|             cls._instance.track = {} |             cls._instance.track = {} | ||||||
|             cls._instance.lock = threading.Lock() |             cls._instance.lock = threading.Lock() | ||||||
|         return cls._instance |         return cls._instance | ||||||
| @ -129,7 +128,7 @@ class MsgTrack(object): | |||||||
|             self.track = {} |             self.track = {} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class MessageCounter(object): | class MessageCounter: | ||||||
|     """ |     """ | ||||||
|     Global message id counter class. |     Global message id counter class. | ||||||
| 
 | 
 | ||||||
| @ -147,7 +146,7 @@ class MessageCounter(object): | |||||||
|     def __new__(cls, *args, **kwargs): |     def __new__(cls, *args, **kwargs): | ||||||
|         """Make this a singleton class.""" |         """Make this a singleton class.""" | ||||||
|         if cls._instance is None: |         if cls._instance is None: | ||||||
|             cls._instance = super(MessageCounter, cls).__new__(cls) |             cls._instance = super().__new__(cls) | ||||||
|             cls._instance.val = RawValue("i", 1) |             cls._instance.val = RawValue("i", 1) | ||||||
|             cls._instance.lock = threading.Lock() |             cls._instance.lock = threading.Lock() | ||||||
|         return cls._instance |         return cls._instance | ||||||
| @ -173,7 +172,7 @@ class MessageCounter(object): | |||||||
|             return str(self.val.value) |             return str(self.val.value) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Message(object, metaclass=abc.ABCMeta): | class Message(metaclass=abc.ABCMeta): | ||||||
|     """Base Message Class.""" |     """Base Message Class.""" | ||||||
| 
 | 
 | ||||||
|     # The message id to send over the air |     # The message id to send over the air | ||||||
| @ -204,7 +203,7 @@ class TextMessage(Message): | |||||||
|     message = None |     message = None | ||||||
| 
 | 
 | ||||||
|     def __init__(self, fromcall, tocall, message, msg_id=None, allow_delay=True): |     def __init__(self, fromcall, tocall, message, msg_id=None, allow_delay=True): | ||||||
|         super(TextMessage, self).__init__(fromcall, tocall, msg_id) |         super().__init__(fromcall, tocall, msg_id) | ||||||
|         self.message = message |         self.message = message | ||||||
|         # do we try and save this message for later if we don't get |         # do we try and save this message for later if we don't get | ||||||
|         # an ack?  Some messages we don't want to do this ever. |         # an ack?  Some messages we don't want to do this ever. | ||||||
| @ -213,7 +212,10 @@ class TextMessage(Message): | |||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|         """Build raw string to send over the air.""" |         """Build raw string to send over the air.""" | ||||||
|         return "{}>APRS::{}:{}{{{}\n".format( |         return "{}>APRS::{}:{}{{{}\n".format( | ||||||
|             self.fromcall, self.tocall.ljust(9), self._filter_for_send(), str(self.id) |             self.fromcall, | ||||||
|  |             self.tocall.ljust(9), | ||||||
|  |             self._filter_for_send(), | ||||||
|  |             str(self.id), | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
| @ -222,7 +224,11 @@ class TextMessage(Message): | |||||||
|             now = datetime.datetime.now() |             now = datetime.datetime.now() | ||||||
|             delta = now - self.last_send_time |             delta = now - self.last_send_time | ||||||
|         return "{}>{} Msg({})({}): '{}'".format( |         return "{}>{} Msg({})({}): '{}'".format( | ||||||
|             self.fromcall, self.tocall, self.id, delta, self.message |             self.fromcall, | ||||||
|  |             self.tocall, | ||||||
|  |             self.id, | ||||||
|  |             delta, | ||||||
|  |             self.message, | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def _filter_for_send(self): |     def _filter_for_send(self): | ||||||
| @ -259,9 +265,7 @@ class SendMessageThread(threads.APRSDThread): | |||||||
|     def __init__(self, message): |     def __init__(self, message): | ||||||
|         self.msg = message |         self.msg = message | ||||||
|         name = self.msg.message[:5] |         name = self.msg.message[:5] | ||||||
|         super(SendMessageThread, self).__init__( |         super().__init__("SendMessage-{}-{}".format(self.msg.id, name)) | ||||||
|             "SendMessage-{}-{}".format(self.msg.id, name) |  | ||||||
|         ) |  | ||||||
| 
 | 
 | ||||||
|     def loop(self): |     def loop(self): | ||||||
|         """Loop until a message is acked or it gets delayed. |         """Loop until a message is acked or it gets delayed. | ||||||
| @ -326,11 +330,13 @@ class AckMessage(Message): | |||||||
|     """Class for building Acks and sending them.""" |     """Class for building Acks and sending them.""" | ||||||
| 
 | 
 | ||||||
|     def __init__(self, fromcall, tocall, msg_id): |     def __init__(self, fromcall, tocall, msg_id): | ||||||
|         super(AckMessage, self).__init__(fromcall, tocall, msg_id=msg_id) |         super().__init__(fromcall, tocall, msg_id=msg_id) | ||||||
| 
 | 
 | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|         return "{}>APRS::{}:ack{}\n".format( |         return "{}>APRS::{}:ack{}\n".format( | ||||||
|             self.fromcall, self.tocall.ljust(9), self.id |             self.fromcall, | ||||||
|  |             self.tocall.ljust(9), | ||||||
|  |             self.id, | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
| @ -378,7 +384,7 @@ class AckMessage(Message): | |||||||
| class SendAckThread(threads.APRSDThread): | class SendAckThread(threads.APRSDThread): | ||||||
|     def __init__(self, ack): |     def __init__(self, ack): | ||||||
|         self.ack = ack |         self.ack = ack | ||||||
|         super(SendAckThread, self).__init__("SendAck-{}".format(self.ack.id)) |         super().__init__("SendAck-{}".format(self.ack.id)) | ||||||
| 
 | 
 | ||||||
|     def loop(self): |     def loop(self): | ||||||
|         """Separate thread to send acks with retries.""" |         """Separate thread to send acks with retries.""" | ||||||
|  | |||||||
| @ -1,4 +1,3 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| # The base plugin class | # The base plugin class | ||||||
| import abc | import abc | ||||||
| import fnmatch | import fnmatch | ||||||
| @ -12,14 +11,12 @@ import shutil | |||||||
| import subprocess | import subprocess | ||||||
| import time | import time | ||||||
| 
 | 
 | ||||||
| import pluggy |  | ||||||
| import requests |  | ||||||
| import six |  | ||||||
| from thesmuggler import smuggle |  | ||||||
| 
 |  | ||||||
| import aprsd | import aprsd | ||||||
| from aprsd import email, messaging | from aprsd import email, messaging | ||||||
| from aprsd.fuzzyclock import fuzzy | from aprsd.fuzzyclock import fuzzy | ||||||
|  | import pluggy | ||||||
|  | import requests | ||||||
|  | from thesmuggler import smuggle | ||||||
| 
 | 
 | ||||||
| # setup the global logger | # setup the global logger | ||||||
| LOG = logging.getLogger("APRSD") | LOG = logging.getLogger("APRSD") | ||||||
| @ -39,7 +36,7 @@ CORE_PLUGINS = [ | |||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class PluginManager(object): | class PluginManager: | ||||||
|     # The singleton instance object for this class |     # The singleton instance object for this class | ||||||
|     _instance = None |     _instance = None | ||||||
| 
 | 
 | ||||||
| @ -52,7 +49,7 @@ class PluginManager(object): | |||||||
|     def __new__(cls, *args, **kwargs): |     def __new__(cls, *args, **kwargs): | ||||||
|         """This magic turns this into a singleton.""" |         """This magic turns this into a singleton.""" | ||||||
|         if cls._instance is None: |         if cls._instance is None: | ||||||
|             cls._instance = super(PluginManager, cls).__new__(cls) |             cls._instance = super().__new__(cls) | ||||||
|             # Put any initialization here. |             # Put any initialization here. | ||||||
|         return cls._instance |         return cls._instance | ||||||
| 
 | 
 | ||||||
| @ -79,7 +76,7 @@ class PluginManager(object): | |||||||
|                     for mem_name, obj in inspect.getmembers(module): |                     for mem_name, obj in inspect.getmembers(module): | ||||||
|                         if inspect.isclass(obj) and self.is_plugin(obj): |                         if inspect.isclass(obj) and self.is_plugin(obj): | ||||||
|                             self.obj_list.append( |                             self.obj_list.append( | ||||||
|                                 {"name": mem_name, "obj": obj(self.config)} |                                 {"name": mem_name, "obj": obj(self.config)}, | ||||||
|                             ) |                             ) | ||||||
| 
 | 
 | ||||||
|         return self.obj_list |         return self.obj_list | ||||||
| @ -108,14 +105,16 @@ class PluginManager(object): | |||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|         assert hasattr(module, class_name), "class {} is not in {}".format( |         assert hasattr(module, class_name), "class {} is not in {}".format( | ||||||
|             class_name, module_name |             class_name, | ||||||
|  |             module_name, | ||||||
|         ) |         ) | ||||||
|         # click.echo('reading class {} from module {}'.format( |         # click.echo('reading class {} from module {}'.format( | ||||||
|         #     class_name, module_name)) |         #     class_name, module_name)) | ||||||
|         cls = getattr(module, class_name) |         cls = getattr(module, class_name) | ||||||
|         if super_cls is not None: |         if super_cls is not None: | ||||||
|             assert issubclass(cls, super_cls), "class {} should inherit from {}".format( |             assert issubclass(cls, super_cls), "class {} should inherit from {}".format( | ||||||
|                 class_name, super_cls.__name__ |                 class_name, | ||||||
|  |                 super_cls.__name__, | ||||||
|             ) |             ) | ||||||
|         # click.echo('initialising {} with params {}'.format(class_name, kwargs)) |         # click.echo('initialising {} with params {}'.format(class_name, kwargs)) | ||||||
|         obj = cls(**kwargs) |         obj = cls(**kwargs) | ||||||
| @ -131,13 +130,17 @@ class PluginManager(object): | |||||||
|         plugin_obj = None |         plugin_obj = None | ||||||
|         try: |         try: | ||||||
|             plugin_obj = self._create_class( |             plugin_obj = self._create_class( | ||||||
|                 plugin_name, APRSDPluginBase, config=self.config |                 plugin_name, | ||||||
|  |                 APRSDPluginBase, | ||||||
|  |                 config=self.config, | ||||||
|             ) |             ) | ||||||
|             if plugin_obj: |             if plugin_obj: | ||||||
|                 LOG.info( |                 LOG.info( | ||||||
|                     "Registering Command plugin '{}'({})  '{}'".format( |                     "Registering Command plugin '{}'({})  '{}'".format( | ||||||
|                         plugin_name, plugin_obj.version, plugin_obj.command_regex |                         plugin_name, | ||||||
|                     ) |                         plugin_obj.version, | ||||||
|  |                         plugin_obj.command_regex, | ||||||
|  |                     ), | ||||||
|                 ) |                 ) | ||||||
|                 self._pluggy_pm.register(plugin_obj) |                 self._pluggy_pm.register(plugin_obj) | ||||||
|         except Exception as ex: |         except Exception as ex: | ||||||
| @ -173,8 +176,10 @@ class PluginManager(object): | |||||||
|                     if plugin_obj: |                     if plugin_obj: | ||||||
|                         LOG.info( |                         LOG.info( | ||||||
|                             "Registering Command plugin '{}'({}) '{}'".format( |                             "Registering Command plugin '{}'({}) '{}'".format( | ||||||
|                                 o["name"], o["obj"].version, o["obj"].command_regex |                                 o["name"], | ||||||
|                             ) |                                 o["obj"].version, | ||||||
|  |                                 o["obj"].command_regex, | ||||||
|  |                             ), | ||||||
|                         ) |                         ) | ||||||
|                         self._pluggy_pm.register(o["obj"]) |                         self._pluggy_pm.register(o["obj"]) | ||||||
| 
 | 
 | ||||||
| @ -203,8 +208,7 @@ class APRSDCommandSpec: | |||||||
|         pass |         pass | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @six.add_metaclass(abc.ABCMeta) | class APRSDPluginBase(metaclass=abc.ABCMeta): | ||||||
| class APRSDPluginBase(object): |  | ||||||
|     def __init__(self, config): |     def __init__(self, config): | ||||||
|         """The aprsd config object is stored.""" |         """The aprsd config object is stored.""" | ||||||
|         self.config = config |         self.config = config | ||||||
| @ -257,7 +261,8 @@ class FortunePlugin(APRSDPluginBase): | |||||||
| 
 | 
 | ||||||
|         try: |         try: | ||||||
|             process = subprocess.Popen( |             process = subprocess.Popen( | ||||||
|                 [fortune_path, "-s", "-n 60"], stdout=subprocess.PIPE |                 [fortune_path, "-s", "-n 60"], | ||||||
|  |                 stdout=subprocess.PIPE, | ||||||
|             ) |             ) | ||||||
|             reply = process.communicate()[0] |             reply = process.communicate()[0] | ||||||
|             reply = reply.decode(errors="ignore").rstrip() |             reply = reply.decode(errors="ignore").rstrip() | ||||||
| @ -406,7 +411,10 @@ class TimePlugin(APRSDPluginBase): | |||||||
|         m = stm.tm_min |         m = stm.tm_min | ||||||
|         cur_time = fuzzy(h, m, 1) |         cur_time = fuzzy(h, m, 1) | ||||||
|         reply = "{} ({}:{} PDT) ({})".format( |         reply = "{} ({}:{} PDT) ({})".format( | ||||||
|             cur_time, str(h), str(m).rjust(2, "0"), message.rstrip() |             cur_time, | ||||||
|  |             str(h), | ||||||
|  |             str(m).rjust(2, "0"), | ||||||
|  |             message.rstrip(), | ||||||
|         ) |         ) | ||||||
|         return reply |         return reply | ||||||
| 
 | 
 | ||||||
| @ -497,7 +505,7 @@ class EmailPlugin(APRSDPluginBase): | |||||||
|                     # send recipient link to aprs.fi map |                     # send recipient link to aprs.fi map | ||||||
|                     if content == "mapme": |                     if content == "mapme": | ||||||
|                         content = "Click for my location: http://aprs.fi/{}".format( |                         content = "Click for my location: http://aprs.fi/{}".format( | ||||||
|                             self.config["ham"]["callsign"] |                             self.config["ham"]["callsign"], | ||||||
|                         ) |                         ) | ||||||
|                     too_soon = 0 |                     too_soon = 0 | ||||||
|                     now = time.time() |                     now = time.time() | ||||||
| @ -521,7 +529,7 @@ class EmailPlugin(APRSDPluginBase): | |||||||
|                                 LOG.debug( |                                 LOG.debug( | ||||||
|                                     "DEBUG: email_sent_dict is big (" |                                     "DEBUG: email_sent_dict is big (" | ||||||
|                                     + str(len(self.email_sent_dict)) |                                     + str(len(self.email_sent_dict)) | ||||||
|                                     + ") clearing out." |                                     + ") clearing out.", | ||||||
|                                 ) |                                 ) | ||||||
|                                 self.email_sent_dict.clear() |                                 self.email_sent_dict.clear() | ||||||
|                             self.email_sent_dict[ack] = now |                             self.email_sent_dict[ack] = now | ||||||
| @ -529,7 +537,7 @@ class EmailPlugin(APRSDPluginBase): | |||||||
|                         LOG.info( |                         LOG.info( | ||||||
|                             "Email for message number " |                             "Email for message number " | ||||||
|                             + ack |                             + ack | ||||||
|                             + " recently sent, not sending again." |                             + " recently sent, not sending again.", | ||||||
|                         ) |                         ) | ||||||
|             else: |             else: | ||||||
|                 reply = "Bad email address" |                 reply = "Bad email address" | ||||||
|  | |||||||
| @ -1,13 +1,11 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| import abc | import abc | ||||||
| import logging | import logging | ||||||
| import queue | import queue | ||||||
| import threading | import threading | ||||||
| import time | import time | ||||||
| 
 | 
 | ||||||
| import aprslib |  | ||||||
| 
 |  | ||||||
| from aprsd import client, messaging, plugin | from aprsd import client, messaging, plugin | ||||||
|  | import aprslib | ||||||
| 
 | 
 | ||||||
| LOG = logging.getLogger("APRSD") | LOG = logging.getLogger("APRSD") | ||||||
| 
 | 
 | ||||||
| @ -16,7 +14,7 @@ TX_THREAD = "TX" | |||||||
| EMAIL_THREAD = "Email" | EMAIL_THREAD = "Email" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class APRSDThreadList(object): | class APRSDThreadList: | ||||||
|     """Singleton class that keeps track of application wide threads.""" |     """Singleton class that keeps track of application wide threads.""" | ||||||
| 
 | 
 | ||||||
|     _instance = None |     _instance = None | ||||||
| @ -26,7 +24,7 @@ class APRSDThreadList(object): | |||||||
| 
 | 
 | ||||||
|     def __new__(cls, *args, **kwargs): |     def __new__(cls, *args, **kwargs): | ||||||
|         if cls._instance is None: |         if cls._instance is None: | ||||||
|             cls._instance = super(APRSDThreadList, cls).__new__(cls) |             cls._instance = super().__new__(cls) | ||||||
|             cls.lock = threading.Lock() |             cls.lock = threading.Lock() | ||||||
|             cls.threads_list = [] |             cls.threads_list = [] | ||||||
|         return cls._instance |         return cls._instance | ||||||
| @ -48,7 +46,7 @@ class APRSDThreadList(object): | |||||||
| 
 | 
 | ||||||
| class APRSDThread(threading.Thread, metaclass=abc.ABCMeta): | class APRSDThread(threading.Thread, metaclass=abc.ABCMeta): | ||||||
|     def __init__(self, name): |     def __init__(self, name): | ||||||
|         super(APRSDThread, self).__init__(name=name) |         super().__init__(name=name) | ||||||
|         self.thread_stop = False |         self.thread_stop = False | ||||||
|         APRSDThreadList().add(self) |         APRSDThreadList().add(self) | ||||||
| 
 | 
 | ||||||
| @ -67,7 +65,7 @@ class APRSDThread(threading.Thread, metaclass=abc.ABCMeta): | |||||||
| 
 | 
 | ||||||
| class APRSDRXThread(APRSDThread): | class APRSDRXThread(APRSDThread): | ||||||
|     def __init__(self, msg_queues, config): |     def __init__(self, msg_queues, config): | ||||||
|         super(APRSDRXThread, self).__init__("RX_MSG") |         super().__init__("RX_MSG") | ||||||
|         self.msg_queues = msg_queues |         self.msg_queues = msg_queues | ||||||
|         self.config = config |         self.config = config | ||||||
| 
 | 
 | ||||||
| @ -112,7 +110,11 @@ class APRSDRXThread(APRSDThread): | |||||||
|         ack_num = packet.get("msgNo") |         ack_num = packet.get("msgNo") | ||||||
|         LOG.info("Got ack for message {}".format(ack_num)) |         LOG.info("Got ack for message {}".format(ack_num)) | ||||||
|         messaging.log_message( |         messaging.log_message( | ||||||
|             "ACK", packet["raw"], None, ack=ack_num, fromcall=packet["from"] |             "ACK", | ||||||
|  |             packet["raw"], | ||||||
|  |             None, | ||||||
|  |             ack=ack_num, | ||||||
|  |             fromcall=packet["from"], | ||||||
|         ) |         ) | ||||||
|         tracker = messaging.MsgTrack() |         tracker = messaging.MsgTrack() | ||||||
|         tracker.remove(ack_num) |         tracker.remove(ack_num) | ||||||
| @ -153,7 +155,9 @@ class APRSDRXThread(APRSDThread): | |||||||
|                     LOG.debug("Sending '{}'".format(reply)) |                     LOG.debug("Sending '{}'".format(reply)) | ||||||
| 
 | 
 | ||||||
|                     msg = messaging.TextMessage( |                     msg = messaging.TextMessage( | ||||||
|                         self.config["aprs"]["login"], fromcall, reply |                         self.config["aprs"]["login"], | ||||||
|  |                         fromcall, | ||||||
|  |                         reply, | ||||||
|                     ) |                     ) | ||||||
|                     self.msg_queues["tx"].put(msg) |                     self.msg_queues["tx"].put(msg) | ||||||
|                 else: |                 else: | ||||||
| @ -166,7 +170,9 @@ class APRSDRXThread(APRSDThread): | |||||||
| 
 | 
 | ||||||
|                 reply = "Usage: {}".format(", ".join(names)) |                 reply = "Usage: {}".format(", ".join(names)) | ||||||
|                 msg = messaging.TextMessage( |                 msg = messaging.TextMessage( | ||||||
|                     self.config["aprs"]["login"], fromcall, reply |                     self.config["aprs"]["login"], | ||||||
|  |                     fromcall, | ||||||
|  |                     reply, | ||||||
|                 ) |                 ) | ||||||
|                 self.msg_queues["tx"].put(msg) |                 self.msg_queues["tx"].put(msg) | ||||||
|         except Exception as ex: |         except Exception as ex: | ||||||
| @ -178,7 +184,9 @@ class APRSDRXThread(APRSDThread): | |||||||
|         # let any threads do their thing, then ack |         # let any threads do their thing, then ack | ||||||
|         # send an ack last |         # send an ack last | ||||||
|         ack = messaging.AckMessage( |         ack = messaging.AckMessage( | ||||||
|             self.config["aprs"]["login"], fromcall, msg_id=msg_id |             self.config["aprs"]["login"], | ||||||
|  |             fromcall, | ||||||
|  |             msg_id=msg_id, | ||||||
|         ) |         ) | ||||||
|         self.msg_queues["tx"].put(ack) |         self.msg_queues["tx"].put(ack) | ||||||
|         LOG.debug("Packet processing complete") |         LOG.debug("Packet processing complete") | ||||||
| @ -213,7 +221,7 @@ class APRSDRXThread(APRSDThread): | |||||||
| 
 | 
 | ||||||
| class APRSDTXThread(APRSDThread): | class APRSDTXThread(APRSDThread): | ||||||
|     def __init__(self, msg_queues, config): |     def __init__(self, msg_queues, config): | ||||||
|         super(APRSDTXThread, self).__init__("TX_MSG") |         super().__init__("TX_MSG") | ||||||
|         self.msg_queues = msg_queues |         self.msg_queues = msg_queues | ||||||
|         self.config = config |         self.config = config | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,17 +1,15 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """Utilities and helper functions.""" | """Utilities and helper functions.""" | ||||||
| 
 | 
 | ||||||
| import errno | import errno | ||||||
| import functools | import functools | ||||||
| import os | import os | ||||||
|  | from pathlib import Path | ||||||
| import sys | import sys | ||||||
| import threading | import threading | ||||||
| from pathlib import Path |  | ||||||
| 
 |  | ||||||
| import click |  | ||||||
| import yaml |  | ||||||
| 
 | 
 | ||||||
| from aprsd import plugin | from aprsd import plugin | ||||||
|  | import click | ||||||
|  | import yaml | ||||||
| 
 | 
 | ||||||
| # an example of what should be in the ~/.aprsd/config.yml | # an example of what should be in the ~/.aprsd/config.yml | ||||||
| DEFAULT_CONFIG_DICT = { | DEFAULT_CONFIG_DICT = { | ||||||
| @ -103,13 +101,13 @@ def get_config(config_file): | |||||||
|     """This tries to read the yaml config from <config_file>.""" |     """This tries to read the yaml config from <config_file>.""" | ||||||
|     config_file_expanded = os.path.expanduser(config_file) |     config_file_expanded = os.path.expanduser(config_file) | ||||||
|     if os.path.exists(config_file_expanded): |     if os.path.exists(config_file_expanded): | ||||||
|         with open(config_file_expanded, "r") as stream: |         with open(config_file_expanded) as stream: | ||||||
|             config = yaml.load(stream, Loader=yaml.FullLoader) |             config = yaml.load(stream, Loader=yaml.FullLoader) | ||||||
|             return config |             return config | ||||||
|     else: |     else: | ||||||
|         if config_file == DEFAULT_CONFIG_FILE: |         if config_file == DEFAULT_CONFIG_FILE: | ||||||
|             click.echo( |             click.echo( | ||||||
|                 "{} is missing, creating config file".format(config_file_expanded) |                 "{} is missing, creating config file".format(config_file_expanded), | ||||||
|             ) |             ) | ||||||
|             create_default_config() |             create_default_config() | ||||||
|             msg = ( |             msg = ( | ||||||
| @ -144,7 +142,10 @@ def parse_config(config_file): | |||||||
|             if name and name not in config[section]: |             if name and name not in config[section]: | ||||||
|                 if not default: |                 if not default: | ||||||
|                     fail( |                     fail( | ||||||
|                         "'%s' was not in '%s' section of config file" % (name, section) |                         "'{}' was not in '{}' section of config file".format( | ||||||
|  |                             name, | ||||||
|  |                             section, | ||||||
|  |                         ), | ||||||
|                     ) |                     ) | ||||||
|                 else: |                 else: | ||||||
|                     config[section][name] = default |                     config[section][name] = default | ||||||
| @ -166,7 +167,10 @@ def parse_config(config_file): | |||||||
|     # special check here to make sure user has edited the config file |     # special check here to make sure user has edited the config file | ||||||
|     # and changed the ham callsign |     # and changed the ham callsign | ||||||
|     check_option( |     check_option( | ||||||
|         config, "ham", "callsign", default_fail=DEFAULT_CONFIG_DICT["ham"]["callsign"] |         config, | ||||||
|  |         "ham", | ||||||
|  |         "callsign", | ||||||
|  |         default_fail=DEFAULT_CONFIG_DICT["ham"]["callsign"], | ||||||
|     ) |     ) | ||||||
|     check_option(config, "aprs", "login") |     check_option(config, "aprs", "login") | ||||||
|     check_option(config, "aprs", "password") |     check_option(config, "aprs", "password") | ||||||
|  | |||||||
| @ -1,4 +1,3 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| import logging | import logging | ||||||
| 
 | 
 | ||||||
| from aprsd import plugin | from aprsd import plugin | ||||||
|  | |||||||
							
								
								
									
										36
									
								
								pyproject.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								pyproject.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | |||||||
|  | [build-system] | ||||||
|  | requires = ["setuptools>=46.0", "wheel"] | ||||||
|  | build-backend = "setuptools.build_meta" | ||||||
|  | 
 | ||||||
|  | [tool.black] | ||||||
|  | # Use the more relaxed max line length permitted in PEP8. | ||||||
|  | line-length = 88 | ||||||
|  | target-version = ["py36", "py37", "py38"] | ||||||
|  | # black will automatically exclude all files listed in .gitignore | ||||||
|  | include = '\.pyi?$' | ||||||
|  | exclude = ''' | ||||||
|  | /( | ||||||
|  |     \.git | ||||||
|  |   | \.hg | ||||||
|  |   | \.mypy_cache | ||||||
|  |   | \.tox | ||||||
|  |   | \.venv | ||||||
|  |   | _build | ||||||
|  |   | buck-out | ||||||
|  |   | build | ||||||
|  |   | dist | ||||||
|  | )/ | ||||||
|  | ''' | ||||||
|  | 
 | ||||||
|  | [tool.isort] | ||||||
|  | profile = "black" | ||||||
|  | line_length = 88 | ||||||
|  | force_sort_within_sections = true | ||||||
|  | # Inform isort of paths to import names that should be considered part of the "First Party" group. | ||||||
|  | src_paths = ["src/openstack_loadtest"] | ||||||
|  | skip_gitignore = true | ||||||
|  | # If you need to skip/exclude folders, consider using skip_glob as that will allow the | ||||||
|  | # isort defaults for skip to remain without the need to duplicate them. | ||||||
|  | 
 | ||||||
|  | [tool.coverage.run] | ||||||
|  | branch = true | ||||||
							
								
								
									
										11
									
								
								setup.cfg
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								setup.cfg
									
									
									
									
									
								
							| @ -1,15 +1,16 @@ | |||||||
| [metadata] | [metadata] | ||||||
| name = aprsd | name = aprsd | ||||||
| summary = Amateur radio APRS daemon which listens for messages and responds | long_description = file: README.rst | ||||||
| description-file = | long_description_content_type = text/x-rst | ||||||
|     README.rst |  | ||||||
| long-description-content-type = text/x-rst; charset=UTF-8 |  | ||||||
| author = Craig Lamparter | author = Craig Lamparter | ||||||
| author-email = something@somewhere.com | author_email = something@somewhere.com | ||||||
| classifier = | classifier = | ||||||
|     Topic :: Communications :: Ham Radio |     Topic :: Communications :: Ham Radio | ||||||
|     Operating System :: POSIX :: Linux |     Operating System :: POSIX :: Linux | ||||||
|     Programming Language :: Python |     Programming Language :: Python | ||||||
|  | description_file = | ||||||
|  |     README.rst | ||||||
|  | summary = Amateur radio APRS daemon which listens for messages and responds | ||||||
| 
 | 
 | ||||||
| [global] | [global] | ||||||
| setup-hooks = | setup-hooks = | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								setup.py
									
									
									
									
									
								
							| @ -1,4 +1,3 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| # Copyright (c) 2013 Hewlett-Packard Development Company, L.P. | # Copyright (c) 2013 Hewlett-Packard Development Company, L.P. | ||||||
| # | # | ||||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | # Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | |||||||
| @ -1,4 +1,3 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| import sys | import sys | ||||||
| import unittest | import unittest | ||||||
| 
 | 
 | ||||||
| @ -7,7 +6,7 @@ from aprsd import email | |||||||
| if sys.version_info >= (3, 2): | if sys.version_info >= (3, 2): | ||||||
|     from unittest import mock |     from unittest import mock | ||||||
| else: | else: | ||||||
|     import mock |     from unittest import mock | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestMain(unittest.TestCase): | class TestMain(unittest.TestCase): | ||||||
|  | |||||||
| @ -1,4 +1,3 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| import unittest | import unittest | ||||||
| from unittest import mock | from unittest import mock | ||||||
| 
 | 
 | ||||||
| @ -57,7 +56,10 @@ class TestPlugin(unittest.TestCase): | |||||||
| 
 | 
 | ||||||
|         message = "time" |         message = "time" | ||||||
|         expected = "{} ({}:{} PDT) ({})".format( |         expected = "{} ({}:{} PDT) ({})".format( | ||||||
|             cur_time, str(h), str(m).rjust(2, "0"), message.rstrip() |             cur_time, | ||||||
|  |             str(h), | ||||||
|  |             str(m).rjust(2, "0"), | ||||||
|  |             message.rstrip(), | ||||||
|         ) |         ) | ||||||
|         actual = time_plugin.run(fromcall, message, ack) |         actual = time_plugin.run(fromcall, message, ack) | ||||||
|         self.assertEqual(expected, actual) |         self.assertEqual(expected, actual) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user