1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-27 13:34:28 +00:00
royalnet/royalnet/__main__.py

208 lines
9.7 KiB
Python
Raw Normal View History

2019-09-28 16:04:35 +00:00
import click
import typing
import importlib
import royalnet as r
import multiprocessing
import keyring
2019-11-15 19:47:32 +00:00
from logging import Formatter, StreamHandler, getLogger, Logger
2019-09-28 16:04:35 +00:00
@click.command()
@click.option("--telegram/--no-telegram", default=None,
2019-11-05 10:30:06 +00:00
help="Enable/disable the Telegram bot.")
2019-09-28 16:04:35 +00:00
@click.option("--discord/--no-discord", default=None,
2019-11-05 10:30:06 +00:00
help="Enable/disable the Discord bot.")
2019-11-15 19:47:32 +00:00
@click.option("--constellation/--no-constellation", default=None,
help="Enable/disable the Constellation web server.")
@click.option("--herald/--no-herald", default=None,
help="Enable/disable the integrated Herald server."
" If turned off, Royalnet will try to connect to another server.")
@click.option("--remote-herald-address", type=str, default=None,
help="If --no-herald is specified, connect to the Herald server at this URL instead.")
@click.option("-c", "--constellation-port", default=44445,
help="The port on which the Constellation will serve webpages on.")
@click.option("-a", "--alchemy-url", type=str, default=None,
help="The Alchemy database path.")
@click.option("-h", "--herald-port", type=int, default=44444,
help="The port on which the Herald should be running.")
@click.option("-p", "--pack", type=str, multiple=True, default=tuple(),
help="Import the pack with the specified name and use it in the Royalnet instance.")
2019-09-28 16:04:35 +00:00
@click.option("-s", "--secrets-name", type=str, default="__default__",
help="The name in the keyring that the secrets are stored with.")
2019-11-15 19:47:32 +00:00
@click.option("-l", "--log-level", type=str, default="INFO",
help="Select how much information you want to be printed on the console."
" Valid log levels are: FATAL/ERROR/WARNING/INFO/DEBUG")
2019-09-28 16:04:35 +00:00
def run(telegram: typing.Optional[bool],
discord: typing.Optional[bool],
2019-11-15 19:47:32 +00:00
constellation: typing.Optional[bool],
herald: typing.Optional[bool],
remote_herald_address: typing.Optional[str],
constellation_port: int,
alchemy_url: typing.Optional[str],
herald_port: int,
pack: typing.Tuple[str],
secrets_name: str,
2019-11-15 19:47:32 +00:00
log_level: str):
# Initialize logging
royalnet_log: Logger = getLogger("royalnet")
royalnet_log.setLevel(log_level)
stream_handler = StreamHandler()
2019-11-20 00:55:04 +00:00
stream_handler.formatter = Formatter("{asctime}\t| {processName}\t| {levelname}\t| {name}\t| {message}", style="{")
2019-11-15 19:47:32 +00:00
royalnet_log.addHandler(stream_handler)
2019-11-20 00:55:04 +00:00
royalnet_log.debug("Logging: ready")
2019-09-28 16:04:35 +00:00
2019-11-15 19:47:32 +00:00
def get_secret(username: str):
return keyring.get_password(f"Royalnet/{secrets_name}", username)
2019-09-28 16:04:35 +00:00
# Enable / Disable interfaces
interfaces = {
"telegram": telegram,
2019-11-05 10:30:06 +00:00
"discord": discord,
2019-11-15 19:47:32 +00:00
"herald": herald,
"constellation": constellation,
2019-09-28 16:04:35 +00:00
}
# If any interface is True, then the undefined ones should be False
if any(interfaces[name] is True for name in interfaces):
for name in interfaces:
if interfaces[name] is None:
interfaces[name] = False
# Likewise, if any interface is False, then the undefined ones should be True
elif any(interfaces[name] is False for name in interfaces):
for name in interfaces:
if interfaces[name] is None:
interfaces[name] = True
# Otherwise, if no interfaces are specified, all should be enabled
else:
assert all(interfaces[name] is None for name in interfaces)
for name in interfaces:
interfaces[name] = True
2019-11-15 19:47:32 +00:00
herald_process: typing.Optional[multiprocessing.Process] = None
# Start the Herald server
if interfaces["herald"]:
herald_config = r.herald.Config(name="<server>",
address="127.0.0.1",
port=herald_port,
secret=get_secret("herald"),
secure=False,
path="/")
2019-11-19 15:49:34 +00:00
herald_process = multiprocessing.Process(name="Herald Server",
2019-11-15 19:47:32 +00:00
target=r.herald.Server(config=herald_config).run_blocking,
2019-09-28 16:04:35 +00:00
daemon=True)
2019-11-15 19:47:32 +00:00
herald_process.start()
else:
herald_config = r.herald.Config(name=...,
address=remote_herald_address,
port=herald_port,
secret=get_secret("herald"),
secure=False,
path="/")
2019-09-28 16:04:35 +00:00
# Import command and star packs
2019-11-15 19:47:32 +00:00
packs: typing.List[str] = list(pack)
packs.append("royalnet.backpack") # backpack is always imported
2019-09-28 16:04:35 +00:00
enabled_commands = []
enabled_page_stars = []
enabled_exception_stars = []
2019-11-19 15:49:34 +00:00
enabled_events = []
2019-10-17 13:33:23 +00:00
for pack in packs:
2019-09-28 16:04:35 +00:00
imported = importlib.import_module(pack)
try:
2019-10-17 18:01:25 +00:00
imported_commands = imported.available_commands
2019-09-28 16:04:35 +00:00
except AttributeError:
raise click.ClickException(f"{pack} isn't a Royalnet Pack as it is missing available_commands.")
try:
imported_page_stars = imported.available_page_stars
except AttributeError:
raise click.ClickException(f"{pack} isn't a Royalnet Pack as it is missing available_page_stars.")
try:
imported_exception_stars = imported.available_exception_stars
except AttributeError:
raise click.ClickException(f"{pack} isn't a Royalnet Pack as it is missing available_exception_stars.")
2019-11-19 15:49:34 +00:00
try:
imported_events = imported.available_events
except AttributeError:
raise click.ClickException(f"{pack} isn't a Royalnet Pack as it is missing available_events.")
2019-09-28 16:04:35 +00:00
enabled_commands = [*enabled_commands, *imported_commands]
enabled_page_stars = [*enabled_page_stars, *imported_page_stars]
enabled_exception_stars = [*enabled_exception_stars, *imported_exception_stars]
2019-11-19 15:49:34 +00:00
enabled_events = [*enabled_events, *imported_events]
2019-09-28 16:04:35 +00:00
telegram_process: typing.Optional[multiprocessing.Process] = None
if interfaces["telegram"]:
2019-11-19 15:49:34 +00:00
if alchemy_url is not None:
telegram_db_config = r.serf.AlchemyConfig(database_url=alchemy_url,
master_table=r.backpack.tables.User,
identity_table=r.backpack.tables.Telegram,
identity_column="tg_id")
else:
telegram_db_config = None
2019-11-15 19:47:32 +00:00
telegram_serf_kwargs = {
'alchemy_config': telegram_db_config,
'commands': enabled_commands,
2019-11-19 15:49:34 +00:00
'events': enabled_events,
'herald_config': herald_config.copy(name="telegram"),
2019-11-20 00:55:04 +00:00
'secrets_name': secrets_name,
'log_level': log_level,
2019-11-15 19:47:32 +00:00
}
telegram_process = multiprocessing.Process(name="Telegram Serf",
target=r.serf.telegram.TelegramSerf.run_process,
kwargs=telegram_serf_kwargs,
2019-09-28 16:04:35 +00:00
daemon=True)
telegram_process.start()
discord_process: typing.Optional[multiprocessing.Process] = None
if interfaces["discord"]:
2019-11-19 15:49:34 +00:00
if alchemy_url is not None:
discord_db_config = r.serf.AlchemyConfig(database_url=alchemy_url,
master_table=r.backpack.tables.User,
identity_table=r.backpack.tables.Discord,
identity_column="discord_id")
else:
discord_db_config = None
2019-11-15 19:47:32 +00:00
discord_serf_kwargs = {
'alchemy_config': discord_db_config,
'commands': enabled_commands,
2019-11-19 15:49:34 +00:00
'events': enabled_events,
'herald_config': herald_config.copy(name="discord"),
2019-11-20 00:55:04 +00:00
'secrets_name': secrets_name,
'log_level': log_level,
2019-11-15 19:47:32 +00:00
}
discord_process = multiprocessing.Process(name="Discord Serf",
target=r.serf.discord.DiscordSerf.run_process,
kwargs=discord_serf_kwargs,
2019-09-28 16:04:35 +00:00
daemon=True)
discord_process.start()
2019-11-15 19:47:32 +00:00
constellation_process: typing.Optional[multiprocessing.Process] = None
if interfaces["constellation"]:
2019-11-05 14:16:29 +00:00
# Create the Constellation
2019-11-15 19:47:32 +00:00
constellation_kwargs = {
'address': "127.0.0.1",
'port': constellation_port,
'secrets_name': secrets_name,
'database_uri': alchemy_url,
'page_stars': enabled_page_stars,
'exc_stars': enabled_exception_stars,
2019-11-20 00:55:04 +00:00
'log_level': log_level,
2019-11-15 19:47:32 +00:00
}
constellation_process = multiprocessing.Process(name="Constellation",
target=r.constellation.Constellation.run_process,
kwargs=constellation_kwargs,
daemon=True)
constellation_process.start()
2019-11-05 10:30:06 +00:00
2019-11-15 19:47:32 +00:00
click.echo("Royalnet is now running! You can stop its execution by pressing Ctrl+C at any time.")
if herald_process is not None:
herald_process.join()
2019-09-28 16:04:35 +00:00
if telegram_process is not None:
telegram_process.join()
if discord_process is not None:
discord_process.join()
2019-11-15 19:47:32 +00:00
if constellation_process is not None:
constellation_process.join()
2019-09-28 16:04:35 +00:00
if __name__ == "__main__":
run()