mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-23 19:44:20 +00:00
Webserver is working but the db is still missing
This commit is contained in:
parent
c09631786f
commit
884b44302d
16 changed files with 263 additions and 11 deletions
|
@ -40,4 +40,5 @@ yarl==1.3.0
|
|||
youtube-dl==2019.10.16
|
||||
riotwatcher==2.7.1
|
||||
# discord.py is missing as we currently use the git version and we ignore the websockets<7.0 requirement
|
||||
uvicorn==0.10.3
|
||||
starlette==0.12.13
|
||||
|
|
|
@ -5,7 +5,7 @@ import royalnet as r
|
|||
import royalherald as rh
|
||||
import multiprocessing
|
||||
import keyring
|
||||
import starlette
|
||||
import logging
|
||||
|
||||
|
||||
@click.command()
|
||||
|
@ -36,6 +36,14 @@ def run(telegram: typing.Optional[bool],
|
|||
local_network_server: bool,
|
||||
secrets_name: str,
|
||||
verbose: bool):
|
||||
# Setup logging
|
||||
if verbose:
|
||||
core_logger = logging.root
|
||||
core_logger.setLevel(logging.DEBUG)
|
||||
stream_handler = logging.StreamHandler()
|
||||
stream_handler.formatter = logging.Formatter("{asctime}\t{name}\t{levelname}\t{message}", style="{")
|
||||
core_logger.addHandler(stream_handler)
|
||||
core_logger.debug("Logging setup complete.")
|
||||
|
||||
# Get the network password
|
||||
network_password = keyring.get_password(f"Royalnet/{secrets_name}", "network")
|
||||
|
@ -92,17 +100,29 @@ def run(telegram: typing.Optional[bool],
|
|||
r.packs.common.tables.Discord,
|
||||
"discord_id")
|
||||
|
||||
# Import command packs
|
||||
# Import command and star packs
|
||||
packs: typing.List[str] = list(packs)
|
||||
packs.append("royalnet.packs.common") # common pack is always imported
|
||||
enabled_commands = []
|
||||
enabled_page_stars = []
|
||||
enabled_exception_stars = []
|
||||
for pack in packs:
|
||||
imported = importlib.import_module(pack)
|
||||
try:
|
||||
imported_commands = imported.available_commands
|
||||
except AttributeError:
|
||||
raise click.ClickException(f"{pack} isn't a Royalnet Pack.")
|
||||
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.")
|
||||
enabled_commands = [*enabled_commands, *imported_commands]
|
||||
enabled_page_stars = [*enabled_page_stars, *imported_page_stars]
|
||||
enabled_exception_stars = [*enabled_exception_stars, *imported_exception_stars]
|
||||
|
||||
telegram_process: typing.Optional[multiprocessing.Process] = None
|
||||
if interfaces["telegram"]:
|
||||
|
@ -134,8 +154,16 @@ def run(telegram: typing.Optional[bool],
|
|||
daemon=True)
|
||||
discord_process.start()
|
||||
|
||||
webserver_process: typing.Optional[multiprocessing.Process] = None
|
||||
if interfaces["webserver"]:
|
||||
...
|
||||
constellation = r.web.Constellation(page_stars=enabled_page_stars,
|
||||
exc_stars=enabled_exception_stars,
|
||||
secrets_name=secrets_name)
|
||||
webserver_process = multiprocessing.Process(name="Constellation Webserver",
|
||||
target=constellation.run_blocking,
|
||||
args=(verbose,),
|
||||
daemon=True)
|
||||
webserver_process.start()
|
||||
|
||||
click.echo("Royalnet processes have been started. You can force-quit by pressing Ctrl+C.")
|
||||
if server_process is not None:
|
||||
|
@ -144,6 +172,8 @@ def run(telegram: typing.Optional[bool],
|
|||
telegram_process.join()
|
||||
if discord_process is not None:
|
||||
discord_process.join()
|
||||
if webserver_process is not None:
|
||||
webserver_process.join()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -37,6 +37,7 @@ class GenericBot:
|
|||
command = SelectedCommand(interface)
|
||||
except Exception as e:
|
||||
log.error(f"{e.__class__.__qualname__} during the registration of {SelectedCommand.__qualname__}")
|
||||
sentry_sdk.capture_exception(e)
|
||||
continue
|
||||
# Linking the command to the interface
|
||||
interface.command = command
|
||||
|
|
|
@ -1,7 +1,16 @@
|
|||
# This is a template Pack __init__. You can use this without changing anything in other packages too!
|
||||
|
||||
from . import commands, tables
|
||||
from . import commands, tables, stars
|
||||
from .commands import available_commands
|
||||
from .tables import available_tables
|
||||
from .stars import available_page_stars, available_exception_stars
|
||||
|
||||
__all__ = ["commands", "tables", "available_commands", "available_tables"]
|
||||
__all__ = [
|
||||
"commands",
|
||||
"tables",
|
||||
"stars",
|
||||
"available_commands",
|
||||
"available_tables",
|
||||
"available_page_stars",
|
||||
"available_exception_stars",
|
||||
]
|
||||
|
|
16
royalnet/packs/common/stars/__init__.py
Normal file
16
royalnet/packs/common/stars/__init__.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Imports go here!
|
||||
from .version import VersionStar
|
||||
|
||||
|
||||
# Enter the PageStars of your Pack here!
|
||||
available_page_stars = [
|
||||
VersionStar,
|
||||
]
|
||||
|
||||
# Enter the ExceptionStars of your Pack here!
|
||||
available_exception_stars = [
|
||||
|
||||
]
|
||||
|
||||
# Don't change this, it should automatically generate __all__
|
||||
__all__ = [star.__name__ for star in [*available_page_stars, *available_exception_stars]]
|
15
royalnet/packs/common/stars/version.py
Normal file
15
royalnet/packs/common/stars/version.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
import royalnet
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import *
|
||||
from royalnet.web import PageStar
|
||||
|
||||
|
||||
class VersionStar(PageStar):
|
||||
path = "/api/royalnet/version"
|
||||
|
||||
async def page(self, request: Request, **kwargs) -> JSONResponse:
|
||||
return JSONResponse({
|
||||
"version": {
|
||||
"semantic": royalnet.version.semantic
|
||||
}
|
||||
})
|
|
@ -1,6 +1,16 @@
|
|||
# This is a template Pack __init__. You can use this without changing anything in other packages too!
|
||||
|
||||
from . import commands, tables, stars
|
||||
from .commands import available_commands
|
||||
from .tables import available_tables
|
||||
from .stars import available_page_stars, available_exception_stars
|
||||
|
||||
__all__ = ["commands", "tables", "available_commands", "available_tables"]
|
||||
__all__ = [
|
||||
"commands",
|
||||
"tables",
|
||||
"stars",
|
||||
"available_commands",
|
||||
"available_tables",
|
||||
"available_page_stars",
|
||||
"available_exception_stars",
|
||||
]
|
||||
|
|
15
royalnet/packs/royal/stars/__init__.py
Normal file
15
royalnet/packs/royal/stars/__init__.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Imports go here!
|
||||
|
||||
|
||||
# Enter the PageStars of your Pack here!
|
||||
available_page_stars = [
|
||||
|
||||
]
|
||||
|
||||
# Enter the ExceptionStars of your Pack here!
|
||||
available_exception_stars = [
|
||||
|
||||
]
|
||||
|
||||
# Don't change this, it should automatically generate __all__
|
||||
__all__ = [star.__name__ for star in [*available_page_stars, *available_exception_stars]]
|
|
@ -3,7 +3,7 @@ from sqlalchemy import Column, \
|
|||
String
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.ext.declarative import declared_attr
|
||||
from royalnet.web.shortcuts import to_urluuid
|
||||
from royalnet.utils import to_urluuid
|
||||
|
||||
|
||||
class WikiPage:
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
# This is a template Pack __init__. You can use this without changing anything in other packages too!
|
||||
|
||||
from . import commands, tables, stars
|
||||
from .commands import available_commands
|
||||
from .tables import available_tables
|
||||
from .stars import available_page_stars, available_exception_stars
|
||||
|
||||
__all__ = ["commands", "tables", "available_commands", "available_tables"]
|
||||
__all__ = [
|
||||
"commands",
|
||||
"tables",
|
||||
"stars",
|
||||
"available_commands",
|
||||
"available_tables",
|
||||
"available_page_stars",
|
||||
"available_exception_stars",
|
||||
]
|
||||
|
|
15
royalnet/packs/rpg/stars/__init__.py
Normal file
15
royalnet/packs/rpg/stars/__init__.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Imports go here!
|
||||
|
||||
|
||||
# Enter the PageStars of your Pack here!
|
||||
available_page_stars = [
|
||||
|
||||
]
|
||||
|
||||
# Enter the ExceptionStars of your Pack here!
|
||||
available_exception_stars = [
|
||||
|
||||
]
|
||||
|
||||
# Don't change this, it should automatically generate __all__
|
||||
__all__ = [star.__name__ for star in [*available_page_stars, *available_exception_stars]]
|
|
@ -6,6 +6,7 @@ from .safeformat import safeformat
|
|||
from .classdictjanitor import cdj
|
||||
from .sleepuntil import sleep_until
|
||||
from .formatters import andformat, plusformat, fileformat, ytdldateformat, numberemojiformat, splitstring, ordinalformat
|
||||
from .urluuid import to_urluuid, from_urluuid
|
||||
|
||||
__all__ = [
|
||||
"asyncify",
|
||||
|
@ -22,4 +23,6 @@ __all__ = [
|
|||
"discord_escape",
|
||||
"splitstring",
|
||||
"ordinalformat",
|
||||
"to_urluuid",
|
||||
"from_urluuid",
|
||||
]
|
||||
|
|
11
royalnet/utils/urluuid.py
Normal file
11
royalnet/utils/urluuid.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
import uuid as _uuid
|
||||
import base64
|
||||
|
||||
|
||||
def to_urluuid(uuid: _uuid.UUID) -> str:
|
||||
"""Return a base64 url-friendly short UUID."""
|
||||
return str(base64.urlsafe_b64encode(uuid.bytes), encoding="ascii").rstrip("=")
|
||||
|
||||
|
||||
def from_urluuid(b: str) -> _uuid.UUID:
|
||||
return _uuid.UUID(bytes=base64.urlsafe_b64decode(bytes(b + "==", encoding="ascii")))
|
|
@ -0,0 +1,9 @@
|
|||
from .constellation import Constellation
|
||||
from .star import Star, PageStar, ExceptionStar
|
||||
|
||||
__all__ = [
|
||||
"Constellation",
|
||||
"Star",
|
||||
"PageStar",
|
||||
"ExceptionStar",
|
||||
]
|
87
royalnet/web/constellation.py
Normal file
87
royalnet/web/constellation.py
Normal file
|
@ -0,0 +1,87 @@
|
|||
import typing
|
||||
import uvicorn
|
||||
import logging
|
||||
import sentry_sdk
|
||||
import royalnet
|
||||
import keyring
|
||||
from starlette.applications import Starlette
|
||||
from .star import PageStar, ExceptionStar
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Constellation:
|
||||
def __init__(self,
|
||||
secrets_name: str,
|
||||
page_stars: typing.List[typing.Type[PageStar]] = None,
|
||||
exc_stars: typing.List[typing.Type[ExceptionStar]] = None,
|
||||
*,
|
||||
debug: bool = __debug__,):
|
||||
if page_stars is None:
|
||||
page_stars = []
|
||||
|
||||
if exc_stars is None:
|
||||
exc_stars = []
|
||||
|
||||
self.secrets_name: str = secrets_name
|
||||
|
||||
log.info("Creating starlette app...")
|
||||
self.starlette = Starlette(debug=debug)
|
||||
|
||||
log.info("Registering page_stars...")
|
||||
for SelectedPageStar in page_stars:
|
||||
try:
|
||||
page_star_instance = SelectedPageStar(constellation=self)
|
||||
except Exception as e:
|
||||
log.error(f"{e.__class__.__qualname__} during the registration of {SelectedPageStar.__qualname__}")
|
||||
sentry_sdk.capture_exception(e)
|
||||
continue
|
||||
log.info(f"Registering: {page_star_instance.path} -> {page_star_instance.__class__.__name__}")
|
||||
self.starlette.add_route(page_star_instance.path, page_star_instance.page, page_star_instance.methods)
|
||||
|
||||
log.info("Registering exc_stars...")
|
||||
for SelectedExcStar in exc_stars:
|
||||
try:
|
||||
exc_star_instance = SelectedExcStar(constellation=self)
|
||||
except Exception as e:
|
||||
log.error(f"{e.__class__.__qualname__} during the registration of {SelectedExcStar.__qualname__}")
|
||||
sentry_sdk.capture_exception(e)
|
||||
continue
|
||||
log.info(f"Registering: {exc_star_instance.error} -> {exc_star_instance.__class__.__name__}")
|
||||
self.starlette.add_exception_handler(exc_star_instance.error, exc_star_instance.page)
|
||||
|
||||
def _init_sentry(self):
|
||||
sentry_dsn = self.get_secret("sentry")
|
||||
if sentry_dsn:
|
||||
# noinspection PyUnreachableCode
|
||||
if __debug__:
|
||||
release = "DEV"
|
||||
else:
|
||||
release = royalnet.version.semantic
|
||||
log.info(f"Sentry: enabled (Royalnet {release})")
|
||||
self.sentry = sentry_sdk.init(sentry_dsn,
|
||||
integrations=[AioHttpIntegration(),
|
||||
SqlalchemyIntegration(),
|
||||
LoggingIntegration(event_level=None)],
|
||||
release=release)
|
||||
else:
|
||||
log.info("Sentry: disabled")
|
||||
|
||||
def get_secret(self, username: str):
|
||||
return keyring.get_password(f"Royalnet/{self.secrets_name}", username)
|
||||
|
||||
def set_secret(self, username: str, password: str):
|
||||
return keyring.set_password(f"Royalnet/{self.secrets_name}", username, password)
|
||||
|
||||
def run_blocking(self, verbose):
|
||||
if verbose:
|
||||
core_logger = logging.root
|
||||
core_logger.setLevel(logging.DEBUG)
|
||||
stream_handler = logging.StreamHandler()
|
||||
stream_handler.formatter = logging.Formatter("{asctime}\t{name}\t{levelname}\t{message}", style="{")
|
||||
core_logger.addHandler(stream_handler)
|
||||
core_logger.debug("Logging setup complete.")
|
||||
self._init_sentry()
|
||||
log.info("Running constellation server...")
|
||||
uvicorn.run(self.starlette)
|
|
@ -1,5 +1,25 @@
|
|||
import starlette
|
||||
import typing
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import Response
|
||||
if typing.TYPE_CHECKING:
|
||||
from .constellation import Constellation
|
||||
|
||||
|
||||
class Star:
|
||||
...
|
||||
tables: set = {}
|
||||
|
||||
def __init__(self, constellation: "Constellation"):
|
||||
self.constellation: "Constellation" = constellation
|
||||
|
||||
async def page(self, request: Request, **kwargs) -> Response:
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class PageStar(Star):
|
||||
path: str = NotImplemented
|
||||
|
||||
methods: typing.List[str] = ["GET"]
|
||||
|
||||
|
||||
class ExceptionStar(Star):
|
||||
error: typing.Union[typing.Type[Exception], int]
|
||||
|
|
Loading…
Reference in a new issue