Compare commits

..

No commits in common. "deae9af4c6de3d733af1e8cbf745495ff63c3aad" and "190bb0742eb79f712d0a1bdedff69751362b74f3" have entirely different histories.

6 changed files with 37 additions and 54 deletions

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "rsbbs" name = "rsbbs"
dynamic = ["version"] version = "0.1.0"
authors = [ authors = [
{ name="John Burwell", email="john@atatdotdot.com" }, { name="John Burwell", email="john@atatdotdot.com" },
] ]
@ -31,6 +31,3 @@ repository = "https://git.b-wells.us/jmbwell/rsbbs"
[tool.setuptools.package-data] [tool.setuptools.package-data]
rsbbs = ["config_default.yaml"] rsbbs = ["config_default.yaml"]
[tool.setuptools.dynamic]
version = {attr = "rsbbs.__version__"}

View File

@ -29,9 +29,10 @@ class Commands():
# aliases, # aliases,
# helpmsg, # helpmsg,
# function, # function,
# arg: # callback,
# arg attributes..., # {arg:
# ) # {arg attributes},
# ...})
('bye', ('bye',
['b', 'q'], ['b', 'q'],
'Sign off and disconnect', 'Sign off and disconnect',
@ -93,7 +94,7 @@ class Commands():
'Send a new message to a user', 'Send a new message to a user',
self.responder.send, self.responder.send,
{ {
'--callsign': {'help': 'Message recipient callsign'}, 'callsign': {'help': 'Message recipient callsign'},
'--subject': {'help': 'Message subject'}, '--subject': {'help': 'Message subject'},
'--message': {'help': 'Message'}, '--message': {'help': 'Message'},
},), },),
@ -103,7 +104,7 @@ class Commands():
'Send a private message to a user', 'Send a private message to a user',
self.responder.send_private, self.responder.send_private,
{ {
'--callsign': {'help': 'Message recipient callsign'}, 'callsign': {'help': 'Message recipient callsign'},
'--subject': {'help': 'Message subject'}, '--subject': {'help': 'Message subject'},
'--message': {'help': 'Message'}, '--message': {'help': 'Message'},
},),] },),]

View File

@ -25,52 +25,45 @@ import yaml
class Config(): class Config():
def __init__(self, app_name, args): def __init__(self, app_name, args):
self.app_name = app_name self._app_name = app_name
self._argv_config_file = args.config_file self._config_file_path = args.config_file
self._load_config() self._load_config()
# Put the messages db file in the system's user data directory
self.config['db_path'] = os.path.join( self.config['db_path'] = os.path.join(
platformdirs.user_data_dir( platformdirs.user_data_dir(appname=app_name, ensure_exists=True),
appname=self.app_name,
ensure_exists=True),
'messages.db') 'messages.db')
# Grab some config from the command line for convenience self.config['debug'] = args.debug
self.config['args'] = args self.config['args'] = args
self.config['calling_station'] = args.calling_station.upper() or None self.config['calling_station'] = args.calling_station.upper() or None
self.config['debug'] = args.debug
# The main thing people want from Config is config values, so let's pretend
# everything anyone asks of Config that isn't otherwise defined is probably
# a config value they want
def __getattr__(self, __name: str): def __getattr__(self, __name: str):
return self.config[__name] return self.config[__name]
@property @property
def config_file(self): def config_path(self):
# Use either the specified file or a file in a system config location # Use either the specified file or a file in a system config location
config_file = self._argv_config_file or os.path.join( config_path = self._config_file_path or os.path.join(
platformdirs.user_config_dir( platformdirs.user_config_dir(
appname=self.app_name, appname=self._app_name,
ensure_exists=True), ensure_exists=True),
'config.yaml' 'config.yaml'
) )
return config_file return config_path
def _init_config_file(self): def _init_config_file(self):
# If the file doesn't exist there, create it from the default file # If the file doesn't exist there, create it from the default file
# included in the package # included in the package
if not os.path.exists(self.config_file): if not os.path.exists(self.config_path):
config_default_file = pkg_resources.resource_filename( config_default_file_path = pkg_resources.resource_filename(
__name__, __name__,
'config_default.yaml') 'config_default.yaml')
try: try:
with open(config_default_file, 'r') as f: with open(config_default_file_path, 'r') as f:
config_default = yaml.load(f, Loader=yaml.FullLoader) config_template = yaml.load(f, Loader=yaml.FullLoader)
with open(self.config_file, 'w') as f: with open(self.config_path, 'w') as f:
yaml.dump(config_default, f) yaml.dump(config_template, f)
except Exception as e: except Exception as e:
print(f"Error creating configuration file: {e}") print(f"Error creating configuration file: {e}")
exit(1) exit(1)
@ -84,7 +77,7 @@ class Config():
""" """
# Load it # Load it
try: try:
with open(self.config_file, 'r') as f: with open(self.config_path, 'r') as f:
self.config = yaml.load(f, Loader=yaml.FullLoader) self.config = yaml.load(f, Loader=yaml.FullLoader)
except Exception as e: except Exception as e:
print(f"Error loading configuration file: {e}") print(f"Error loading configuration file: {e}")

View File

@ -174,7 +174,7 @@ class Console():
self._write_output(f"Heard stations not available.") self._write_output(f"Heard stations not available.")
def help(self, args): def help(self, args):
self.parser.print_help() self.parser.parser.print_help()
def list(self, args): def list(self, args):
"""List all public messages and private messages to the caller.""" """List all public messages and private messages to the caller."""
@ -267,7 +267,7 @@ class Console():
# Parse the BBS interactive commands for the rest of time # Parse the BBS interactive commands for the rest of time
for line in sys.stdin: for line in sys.stdin:
try: try:
args = self.parser.parse_args(line.split()) args = self.parser.parser.parse_args(line.split())
args.func(args) args.func(args)
except Exception: except Exception:
if self.config.debug: if self.config.debug:

View File

@ -21,12 +21,15 @@ import argparse
from rsbbs.commands import Commands from rsbbs.commands import Commands
# We want to override the error and exit methods of ArgumentParser
# to prevent it exiting unexpectedly or spewing error data over the air
class BBSArgumentParser(argparse.ArgumentParser): class BBSArgumentParser(argparse.ArgumentParser):
# Override the error handler to prevent spewing error cruft over the air # Override the error handler to prevent exiting on error
# def error(self, message): # def error(self, message):
# print(message) # print(message)
# raise
# Override the exit handler to prevent disconnecting unexpectedly
def exit(self, arg1, arg2): def exit(self, arg1, arg2):
pass pass
@ -34,17 +37,9 @@ class BBSArgumentParser(argparse.ArgumentParser):
class Parser(BBSArgumentParser): class Parser(BBSArgumentParser):
def __init__(self, commands: Commands): def __init__(self, commands: Commands):
self._init_parser(commands) self.init_parser(commands)
# The only thing anyone should ever access from Parser is its parser def init_parser(self, commands):
# attribute, so let's save everyone a step.
def __getattribute__(self, attr):
try:
return object.__getattribute__(self, attr)
except AttributeError:
return getattr(self.parser, attr)
def _init_parser(self, commands):
# Root parser for BBS commands # Root parser for BBS commands
self.parser = BBSArgumentParser( self.parser = BBSArgumentParser(
description='BBS Main Menu', description='BBS Main Menu',
@ -60,14 +55,11 @@ class Parser(BBSArgumentParser):
# Loop through the commands and add each as a subparser # Loop through the commands and add each as a subparser
for name, aliases, help_msg, func, arguments in commands.commands: for name, aliases, help_msg, func, arguments in commands.commands:
# Add the command attributes
subparser = subparsers.add_parser( subparser = subparsers.add_parser(
name, name,
aliases=aliases, aliases=aliases,
help=help_msg, help=help_msg,
) )
# Add the command parameters
for arg_name, options in arguments.items(): for arg_name, options in arguments.items():
subparser.add_argument(arg_name, **options) subparser.add_argument(arg_name, **options)
# Trick to pass a function to call when the command is entered
subparser.set_defaults(func=func) subparser.set_defaults(func=func)

View File

@ -30,7 +30,7 @@ from rsbbs.parser import Parser
def main(): def main():
# Parse and handle the system invocation arguments # Parse and handle the system invocation arguments
argv_parser = argparse.ArgumentParser( sysv_parser = argparse.ArgumentParser(
description=("The BBS for ax.25 and packet radio " description=("The BBS for ax.25 and packet radio "
"that is really simple.")) "that is really simple."))
@ -45,23 +45,23 @@ def main():
'Path to config.yaml file', False], 'Path to config.yaml file', False],
] ]
for arg in args_list: for arg in args_list:
argv_parser.add_argument( sysv_parser.add_argument(
arg[0], arg[1], action=arg[2], default=arg[3], dest=arg[4], arg[0], arg[1], action=arg[2], default=arg[3], dest=arg[4],
help=arg[5], required=arg[6]) help=arg[5], required=arg[6])
# Version arg is special: # Version arg is special:
argv_parser.add_argument( sysv_parser.add_argument(
'-v', '--version', '-v', '--version',
action='version', action='version',
version=f"{argv_parser.prog} version {__version__}") version=f"{sysv_parser.prog} version {__version__}")
# Parse the args from the system # Parse the args from the system
argv_args = argv_parser.parse_args(sys.argv[1:]) sysv_args = sysv_parser.parse_args(sys.argv[1:])
# Load configuration # Load configuration
config = Config( config = Config(
app_name='rsbbs', app_name='rsbbs',
args=argv_args) args=sysv_args)
# Init the contoller # Init the contoller
controller = Controller(config) controller = Controller(config)