1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-23 11:34:18 +00:00

5.0a59: beeg update

This commit is contained in:
Steffo 2019-09-28 18:04:35 +02:00
parent b1ee018254
commit 9b1c8704bd
50 changed files with 384 additions and 259 deletions

View file

@ -6,16 +6,10 @@ It has a lot of submodules, many of which may be used in other bots.
[Documentation available here](https://royal-games.github.io/royalnet/html/index.html).
## Installation for the Royal Games community
## Quick install
With `python3.7` and `pip` installed, run:
```bash
pip install royalnet
pip install websockets --upgrade
export TG_AK="Telegram API Key"
export DS_AK="Discord API Key"
export DB_PATH="sqlalchemy database path to postgresql"
export MASTER_KEY="A secret password to connect to the network"
python3.7 -m royalnet.royalgames -OO
```
pip3.7 install royalnet
python3.7 -m royalnet.configurator
python3.7 -m royalnet -c (YOUR_COMMAND_PACK)
```

View file

@ -1,4 +1,4 @@
bcrypt
bcrypt>=3.1.7
python-telegram-bot>=11.1.0
websockets>=7.0
pytest>=4.3.1
@ -20,3 +20,5 @@ mcstatus>=2.2.1
sortedcontainers>=2.1.0
sentry-sdk>=0.11.1
click>=7.0
keyring>=19.2.0
urllib3>=1.25.6

134
royalnet/__main__.py Normal file
View file

@ -0,0 +1,134 @@
import click
import typing
import importlib
import royalnet as r
import multiprocessing
import keyring
@click.command()
@click.option("--telegram/--no-telegram", default=None,
help="Enable/disable the Telegram module.")
@click.option("--discord/--no-discord", default=None,
help="Enable/disable the Discord module.")
@click.option("-d", "--database", type=str, default=None,
help="The PostgreSQL database path.")
@click.option("-c", "--command-packs", type=str, multiple=True, default=[],
help="The names of the command pack modules that should be imported.")
@click.option("-n", "--network-address", type=str, default=None,
help="The Network server URL to connect to.")
@click.option("--local-network-server/--no-local-network-server", default=True,
help="Locally run a Network server, bind it to port 44444.")
@click.option("-s", "--secrets-name", type=str, default="__default__",
help="The name in the keyring that the secrets are stored with.")
def run(telegram: typing.Optional[bool],
discord: typing.Optional[bool],
database: typing.Optional[str],
command_packs: typing.List[str],
network_address: typing.Optional[str],
local_network_server: bool,
secrets_name: str):
# Get the network password
network_password = keyring.get_password(f"Royalnet/{secrets_name}", "network")
# Get the sentry dsn
sentry_dsn = keyring.get_password(f"Royalnet/{secrets_name}", "sentry")
# Enable / Disable interfaces
interfaces = {
"telegram": telegram,
"discord": discord
}
# 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
server_process: typing.Optional[multiprocessing.Process] = None
# Start the network server
if local_network_server:
server_process = multiprocessing.Process(name="Network Server",
target=r.network.NetworkServer("0.0.0.0",
44444,
network_password).run_blocking(),
daemon=True)
server_process.start()
network_address = "ws://127.0.0.1:44444/"
# Create a Royalnet configuration
network_config: typing.Optional[r.network.NetworkConfig] = None
if network_address is not None:
network_config = r.network.NetworkConfig(network_address, network_password)
# Create a Alchemy configuration
telegram_db_config: typing.Optional[r.database.DatabaseConfig] = None
discord_db_config: typing.Optional[r.database.DatabaseConfig] = None
if database is not None:
telegram_db_config = r.database.DatabaseConfig(database,
r.database.tables.User,
r.database.tables.Telegram,
"tg_id")
discord_db_config = r.database.DatabaseConfig(database,
r.database.tables.User,
r.database.tables.Discord,
"discord_id")
# Import command packs
if not command_packs:
raise click.ClickException("No command packs were specified.")
enabled_commands = []
for pack in command_packs:
imported = importlib.import_module(pack)
try:
imported_commands = imported.commands
except AttributeError:
raise click.ClickException(f"{pack} isn't a Royalnet command pack.")
enabled_commands = [*enabled_commands, *imported_commands]
telegram_process: typing.Optional[multiprocessing.Process] = None
if interfaces["telegram"]:
telegram_bot = r.bots.TelegramBot(network_config=network_config,
database_config=telegram_db_config,
sentry_dsn=sentry_dsn,
commands=enabled_commands,
secrets_name=secrets_name)
telegram_process = multiprocessing.Process(name="Telegram Interface",
target=telegram_bot.run_blocking,
daemon=True)
telegram_process.start()
discord_process: typing.Optional[multiprocessing.Process] = None
if interfaces["discord"]:
discord_bot = r.bots.DiscordBot(network_config=network_config,
database_config=discord_db_config,
sentry_dsn=sentry_dsn,
commands=enabled_commands,
secrets_name=secrets_name)
discord_process = multiprocessing.Process(name="Discord Interface",
target=discord_bot.run_blocking,
daemon=True)
discord_process.start()
click.echo("Royalnet processes have been started. You can force-quit by pressing Ctrl+C.")
if server_process is not None:
server_process.join()
if telegram_process is not None:
telegram_process.join()
if discord_process is not None:
discord_process.join()
if __name__ == "__main__":
run()

View file

@ -24,7 +24,7 @@ class YtdlDiscord:
ffmpeg.input(self.ytdl_file.filename)
.output(destination_filename, format="s16le", ac=2, ar="48000")
.overwrite_output()
.run(quiet=True)
.run_async(quiet=True)
)
self.pcm_filename = destination_filename

View file

@ -24,7 +24,7 @@ class YtdlMp3:
ffmpeg.input(self.ytdl_file.filename)
.output(destination_filename, format="mp3")
.overwrite_output()
.run()
.run_async()
)
self.mp3_filename = destination_filename

View file

@ -1,7 +1,7 @@
"""Various bot interfaces, and a generic class to create new ones."""
from .generic import GenericBot
from .telegram import TelegramBot, TelegramConfig
from .discord import DiscordBot, DiscordConfig
from .telegram import TelegramBot
from .discord import DiscordBot
__all__ = ["TelegramBot", "TelegramConfig", "DiscordBot", "DiscordConfig", "GenericBot"]
__all__ = ["TelegramBot", "DiscordBot", "GenericBot"]

View file

@ -1,12 +1,9 @@
import discord
import typing
import sentry_sdk
import logging as _logging
from .generic import GenericBot
from ..utils import *
from ..error import *
from ..network import *
from ..database import *
from ..audio import *
from ..commands import *
@ -17,12 +14,6 @@ if not discord.opus.is_loaded():
log.error("Opus is not loaded. Weird behaviour might emerge.")
class DiscordConfig:
"""The specific configuration to be used for :py:class:`royalnet.bots.DiscordBot`."""
def __init__(self, token: str):
self.token = token
class DiscordBot(GenericBot):
"""A bot that connects to `Discord <https://discordapp.com/>`_."""
interface_name = "discord"
@ -204,24 +195,19 @@ class DiscordBot(GenericBot):
self._Client = self._bot_factory()
self.client = self._Client()
def __init__(self, *,
discord_config: DiscordConfig,
royalnet_config: typing.Optional[RoyalnetConfig] = None,
database_config: typing.Optional[DatabaseConfig] = None,
sentry_dsn: typing.Optional[str] = None,
commands: typing.List[typing.Type[Command]] = None):
super().__init__(royalnet_config=royalnet_config,
database_config=database_config,
sentry_dsn=sentry_dsn,
commands=commands)
self._discord_config = discord_config
def _initialize(self):
super()._initialize()
self._init_client()
self._init_voice()
async def run(self):
"""Login to Discord, then run the bot."""
if not self.initialized:
self._initialize()
log.debug("Getting Discord secret")
token = self.get_secret("discord")
log.info(f"Logging in to Discord")
await self.client.login(self._discord_config.token)
await self.client.login(token)
log.info(f"Connecting to Discord")
await self.client.connect()
# TODO: how to stop?

View file

@ -1,8 +1,8 @@
import sys
import typing
import asyncio
import logging
import sentry_sdk
import keyring
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
from sentry_sdk.integrations.aiohttp import AioHttpIntegration
from sentry_sdk.integrations.logging import LoggingIntegration
@ -21,7 +21,7 @@ class GenericBot:
:py:class:`royalnet.bots.TelegramBot` and :py:class:`royalnet.bots.DiscordBot`. """
interface_name = NotImplemented
def _init_commands(self, commands: typing.List[typing.Type[Command]]) -> None:
def _init_commands(self) -> None:
"""Generate the ``commands`` dictionary required to handle incoming messages, and the ``network_handlers``
dictionary required to handle incoming requests. """
log.debug(f"Now binding commands")
@ -29,13 +29,13 @@ class GenericBot:
self._Data = self._data_factory()
self.commands = {}
self.network_handlers: typing.Dict[str, typing.Type[NetworkHandler]] = {}
for SelectedCommand in commands:
for SelectedCommand in self.uninitialized_commands:
log.debug(f"Binding {SelectedCommand.name}...")
interface = self._Interface()
try:
self.commands[f"{interface.prefix}{SelectedCommand.name}"] = SelectedCommand(interface)
except Exception as e:
log.error(f"{e} during the initialization of {SelectedCommand.name}, skipping...")
log.error(f"{e.__class__.__name__} during the initialization of {SelectedCommand.name}, skipping...")
log.debug(f"Successfully bound commands")
def _interface_factory(self) -> typing.Type[CommandInterface]:
@ -71,15 +71,17 @@ class GenericBot:
def _data_factory(self) -> typing.Type[CommandData]:
raise NotImplementedError()
def _init_royalnet(self, royalnet_config: RoyalnetConfig):
"""Create a :py:class:`royalnet.network.RoyalnetLink`, and run it as a :py:class:`asyncio.Task`."""
self.network: RoyalnetLink = RoyalnetLink(royalnet_config.master_uri, royalnet_config.master_secret,
self.interface_name, self._network_handler)
log.debug(f"Running RoyalnetLink {self.network}")
self.loop.create_task(self.network.run())
def _init_network(self):
"""Create a :py:class:`royalnet.network.NetworkLink`, and run it as a :py:class:`asyncio.Task`."""
if self.uninitialized_network_config is not None:
self.network: NetworkLink = NetworkLink(self.uninitialized_network_config.master_uri,
self.uninitialized_network_config.master_secret,
self.interface_name, self._network_handler)
log.debug(f"Running NetworkLink {self.network}")
self.loop.create_task(self.network.run())
async def _network_handler(self, request_dict: dict) -> dict:
"""Handle a single :py:class:`dict` received from the :py:class:`royalnet.network.RoyalnetLink`.
"""Handle a single :py:class:`dict` received from the :py:class:`royalnet.network.NetworkLink`.
Returns:
Another :py:class:`dict`, formatted as a :py:class:`royalnet.network.Response`."""
@ -91,7 +93,7 @@ class GenericBot:
return ResponseError("invalid_request",
f"The Request that you sent was invalid. Check extra_info to see what you sent.",
extra_info={"you_sent": request_dict}).to_dict()
log.debug(f"Received {request} from the RoyalnetLink")
log.debug(f"Received {request} from the NetworkLink")
try:
network_handler = self.network_handlers[request.handler]
except KeyError:
@ -115,59 +117,79 @@ class GenericBot:
"str": str(exc)
}).to_dict()
def _init_database(self, commands: typing.List[typing.Type[Command]], database_config: DatabaseConfig):
def _init_database(self):
"""Create an :py:class:`royalnet.database.Alchemy` with the tables required by the commands. Then,
find the chain that links the ``master_table`` to the ``identity_table``. """
log.debug(f"Initializing database")
required_tables = {database_config.master_table, database_config.identity_table}
for command in commands:
required_tables = required_tables.union(command.require_alchemy_tables)
log.debug(f"Found {len(required_tables)} required tables")
self.alchemy = Alchemy(database_config.database_uri, required_tables)
self.master_table = self.alchemy.__getattribute__(database_config.master_table.__name__)
self.identity_table = self.alchemy.__getattribute__(database_config.identity_table.__name__)
self.identity_column = self.identity_table.__getattribute__(self.identity_table,
database_config.identity_column_name)
self.identity_chain = relationshiplinkchain(self.master_table, self.identity_table)
log.debug(f"Identity chain is {self.identity_chain}")
if self.uninitialized_database_config:
log.debug(f"Initializing database")
required_tables = {self.uninitialized_database_config.master_table, self.uninitialized_database_config.identity_table}
for command in self.uninitialized_commands:
required_tables = required_tables.union(command.require_alchemy_tables)
log.debug(f"Found {len(required_tables)} required tables")
self.alchemy = Alchemy(self.uninitialized_database_config.database_uri, required_tables)
self.master_table = self.alchemy.__getattribute__(self.uninitialized_database_config.master_table.__name__)
self.identity_table = self.alchemy.__getattribute__(self.uninitialized_database_config.identity_table.__name__)
self.identity_column = self.identity_table.__getattribute__(self.identity_table,
self.uninitialized_database_config.identity_column_name)
self.identity_chain = relationshiplinkchain(self.master_table, self.identity_table)
log.debug(f"Identity chain is {self.identity_chain}")
else:
log.debug(f"Database is not enabled, setting everything to None")
self.alchemy = None
self.master_table = None
self.identity_table = None
self.identity_column = None
def _init_sentry(self):
if self.uninitialized_sentry_dsn:
log.debug("Sentry integration enabled")
self.sentry = sentry_sdk.init(self.uninitialized_sentry_dsn,
integrations=[AioHttpIntegration(),
SqlalchemyIntegration(),
LoggingIntegration(event_level=None)])
else:
log.debug("Sentry integration disabled")
def _init_loop(self):
if self.uninitialized_loop is None:
self.loop = asyncio.get_event_loop()
else:
self.loop = self.uninitialized_loop
def __init__(self, *,
royalnet_config: typing.Optional[RoyalnetConfig] = None,
network_config: typing.Optional[NetworkConfig] = None,
database_config: typing.Optional[DatabaseConfig] = None,
commands: typing.List[typing.Type[Command]] = None,
sentry_dsn: typing.Optional[str] = None,
loop: asyncio.AbstractEventLoop = None):
if loop is None:
self.loop = asyncio.get_event_loop()
else:
self.loop = loop
if sentry_dsn:
log.debug("Sentry integration enabled")
self.sentry = sentry_sdk.init(sentry_dsn, integrations=[AioHttpIntegration(),
SqlalchemyIntegration(),
LoggingIntegration(event_level=None)])
else:
log.debug("Sentry integration disabled")
try:
if database_config is None:
self.alchemy = None
self.master_table = None
self.identity_table = None
self.identity_column = None
else:
self._init_database(commands=commands, database_config=database_config)
if commands is None:
commands = []
self._init_commands(commands)
if royalnet_config is None:
self.network = None
else:
self._init_royalnet(royalnet_config=royalnet_config)
except Exception as e:
sentry_sdk.capture_exception(e)
log.error(f"{e.__class__.__name__} while initializing Royalnet: {' | '.join(e.args)}")
raise
loop: asyncio.AbstractEventLoop = None,
secrets_name: str = "__default__"):
self.initialized = False
self.uninitialized_network_config = network_config
self.uninitialized_database_config = database_config
self.uninitialized_commands = commands
self.uninitialized_sentry_dsn = sentry_dsn
self.uninitialized_loop = loop
self.secrets_name = secrets_name
async def run(self):
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 _initialize(self):
if not self.initialized:
self._init_sentry()
self._init_loop()
self._init_database()
self._init_commands()
self._init_network()
self.initialized = True
def run(self):
"""A blocking coroutine that should make the bot start listening to commands and requests."""
raise NotImplementedError()
def run_blocking(self):
self._initialize()
self.loop.run_until_complete(self.run())

View file

@ -1,6 +1,5 @@
import telegram
import telegram.utils.request
import typing
import uuid
import urllib3
import asyncio
@ -9,20 +8,12 @@ import logging as _logging
from .generic import GenericBot
from ..utils import *
from ..error import *
from ..network import *
from ..database import *
from ..commands import *
log = _logging.getLogger(__name__)
class TelegramConfig:
"""The specific configuration to be used for :py:class:`royalnet.database.TelegramBot`."""
def __init__(self, token: str):
self.token: str = token
class TelegramBot(GenericBot):
"""A bot that connects to `Telegram <https://telegram.org/>`_."""
interface_name = "telegram"
@ -30,8 +21,9 @@ class TelegramBot(GenericBot):
def _init_client(self):
"""Create the :py:class:`telegram.Bot`, and set the starting offset."""
# https://github.com/python-telegram-bot/python-telegram-bot/issues/341
request = telegram.utils.request.Request(20, read_timeout=15)
self.client = telegram.Bot(self._telegram_config.token, request=request)
request = telegram.utils.request.Request(5, read_timeout=30)
token = self.get_secret("telegram")
self.client = telegram.Bot(token, request=request)
self._offset: int = -100
def _interface_factory(self) -> typing.Type[CommandInterface]:
@ -109,19 +101,6 @@ class TelegramBot(GenericBot):
return TelegramData
def __init__(self, *,
telegram_config: TelegramConfig,
royalnet_config: typing.Optional[RoyalnetConfig] = None,
database_config: typing.Optional[DatabaseConfig] = None,
sentry_dsn: typing.Optional[str] = None,
commands: typing.List[typing.Type[Command]] = None):
super().__init__(royalnet_config=royalnet_config,
database_config=database_config,
sentry_dsn=sentry_dsn,
commands=commands)
self._telegram_config = telegram_config
self._init_client()
@staticmethod
async def safe_api_call(f: typing.Callable, *args, **kwargs) -> typing.Optional:
while True:
@ -225,7 +204,13 @@ class TelegramBot(GenericBot):
else:
await self.safe_api_call(query.answer, text=response)
def _initialize(self):
super()._initialize()
self._init_client()
async def run(self):
if not self.initialized:
self._initialize()
while True:
# Get the latest 100 updates
last_updates: typing.List[telegram.Update] = await self.safe_api_call(self.client.get_updates,

View file

@ -28,7 +28,7 @@ class CommandInterface:
raise UnsupportedError()
async def net_request(self, message, destination: str) -> dict:
"""Send data through a :py:class:`royalnet.network.RoyalnetLink` and wait for a
"""Send data through a :py:class:`royalnet.network.NetworkLink` and wait for a
:py:class:`royalnet.network.Reply`.
Parameters:

View file

@ -1,6 +1,6 @@
"""Commands that can be used in bots.
These probably won't suit your needs, as they are tailored for the bots of the Royal Games gaming community, but they
These probably won't suit your needs, as they are tailored for the bots of the User Games gaming community, but they
may be useful to develop new ones."""
from .ciaoruozi import CiaoruoziCommand

View file

@ -8,7 +8,7 @@ from ..commanddata import CommandData
class CiaoruoziCommand(Command):
name: str = "ciaoruozi"
description: str = "Saluta Ruozi, un leggendario essere che una volta era in Royal Games."
description: str = "Saluta Ruozi, un leggendario essere che una volta era in User Games."
syntax: str = ""

View file

@ -2,26 +2,21 @@ import typing
import re
import datetime
import telegram
import os
import aiohttp
from ..command import Command
from ..commandargs import CommandArgs
from ..commanddata import CommandData
from ...database.tables import Royal, Diario, Alias
from ...database.tables import User, Diario, Alias
from ...utils import asyncify
from ...error import *
async def to_imgur(photosizes: typing.List[telegram.PhotoSize], caption="") -> str:
async def to_imgur(imgur_api_key, photosizes: typing.List[telegram.PhotoSize], caption="") -> str:
# Select the largest photo
largest_photo = sorted(photosizes, key=lambda p: p.width * p.height)[-1]
# Get the photo url
photo_file: telegram.File = await asyncify(largest_photo.get_file)
# Forward the url to imgur, as an upload
try:
imgur_api_key = os.environ["IMGUR_CLIENT_ID"]
except KeyError:
raise InvalidConfigError("Missing IMGUR_CLIENT_ID envvar, can't upload images to imgur.")
async with aiohttp.request("post", "https://api.imgur.com/3/upload", data={
"image": photo_file.file_path,
"type": "URL",
@ -43,7 +38,7 @@ class DiarioCommand(Command):
syntax = "[!] \"(testo)\" --[autore], [contesto]"
require_alchemy_tables = {Royal, Diario, Alias}
require_alchemy_tables = {User, Diario, Alias}
async def run(self, args: CommandArgs, data: CommandData) -> None:
if self.interface.name == "telegram":
@ -74,7 +69,8 @@ class DiarioCommand(Command):
if photosizes:
# Text is a caption
text = reply.caption
media_url = await to_imgur(photosizes, text if text is not None else "")
media_url = await to_imgur(self.interface.bot.get_secret("imgur"),
photosizes, text if text is not None else "")
else:
media_url = None
# Ensure there is a text or an image
@ -101,7 +97,8 @@ class DiarioCommand(Command):
# Check if there's an image associated with the reply
photosizes: typing.Optional[typing.List[telegram.PhotoSize]] = message.photo
if photosizes:
media_url = await to_imgur(photosizes, raw_text if raw_text is not None else "")
media_url = await to_imgur(self.interface.bot.get_secret("imgur"),
photosizes, raw_text if raw_text is not None else "")
else:
media_url = None
# Parse the text, if it exists

View file

@ -1,6 +1,5 @@
import datetime
import dateparser
import os
import telegram
import asyncio
import re
@ -98,7 +97,7 @@ class MmCommand(Command):
try:
await self.interface.bot.safe_api_call(client.edit_message_text,
text=telegram_escape(self._main_text(mmevent)),
chat_id=os.environ["MM_CHANNEL_ID"],
chat_id=-1001224004974,
message_id=mmevent.message_id,
parse_mode="HTML",
disable_web_page_preview=True,
@ -384,7 +383,7 @@ class MmCommand(Command):
await asyncify(self.interface.session.commit)
message: telegram.Message = await self.interface.bot.safe_api_call(client.send_message,
chat_id=os.environ["MM_CHANNEL_ID"],
chat_id=-1001224004974,
text=telegram_escape(self._main_text(mmevent)),
parse_mode="HTML",
disable_webpage_preview=True,

27
royalnet/configurator.py Normal file
View file

@ -0,0 +1,27 @@
import click
import keyring
@click.command()
def run():
click.echo("Welcome to the Royalnet configuration creator!")
secrets_name = click.prompt("Desired secrets name", default="__default__")
network = click.prompt("Network password", default="")
if network:
keyring.set_password(f"Royalnet/{secrets_name}", "network", network)
telegram = click.prompt("Telegram Bot API token", default="")
if telegram:
keyring.set_password(f"Royalnet/{secrets_name}", "telegram", telegram)
discord = click.prompt("Discord Bot API token", default="")
if discord:
keyring.set_password(f"Royalnet/{secrets_name}", "discord", discord)
imgur = click.prompt("Imgur API token", default="")
if imgur:
keyring.set_password(f"Royalnet/{secrets_name}", "imgur", imgur)
sentry = click.prompt("Sentry DSN", default="")
if sentry:
keyring.set_password(f"Royalnet/{secrets_name}", "sentry", sentry)
if __name__ == "__main__":
run()

View file

@ -3,5 +3,6 @@
from .alchemy import Alchemy
from .relationshiplinkchain import relationshiplinkchain
from .databaseconfig import DatabaseConfig
from . import tables
__all__ = ["Alchemy", "relationshiplinkchain", "DatabaseConfig"]
__all__ = ["Alchemy", "relationshiplinkchain", "DatabaseConfig", "tables"]

View file

@ -1,4 +1,4 @@
from .royals import Royal
from .royals import User
from .telegram import Telegram
from .diario import Diario
from .aliases import Alias
@ -17,6 +17,6 @@ from .mmdecisions import MMDecision
from .mmevents import MMEvent
from .mmresponse import MMResponse
__all__ = ["Royal", "Telegram", "Diario", "Alias", "ActiveKvGroup", "Keyvalue", "Keygroup", "Discord", "WikiPage",
__all__ = ["User", "Telegram", "Diario", "Alias", "ActiveKvGroup", "Keyvalue", "Keygroup", "Discord", "WikiPage",
"WikiRevision", "Medal", "MedalAward", "Bio", "Reminder", "TriviaScore", "MMDecision", "MMEvent",
"MMResponse"]

View file

@ -5,7 +5,7 @@ from sqlalchemy import Column, \
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declared_attr
# noinspection PyUnresolvedReferences
from .royals import Royal
from .royals import User
# noinspection PyUnresolvedReferences
from .keygroups import Keygroup
@ -15,7 +15,7 @@ class ActiveKvGroup:
@declared_attr
def royal_id(self):
return Column(Integer, ForeignKey("royals.uid"), primary_key=True)
return Column(Integer, ForeignKey("users.uid"), primary_key=True)
@declared_attr
def group_name(self):
@ -23,7 +23,7 @@ class ActiveKvGroup:
@declared_attr
def royal(self):
return relationship("Royal", backref="active_kv_group")
return relationship("User", backref="active_kv_group")
@declared_attr
def group(self):

View file

@ -5,7 +5,7 @@ from sqlalchemy import Column, \
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declared_attr
# noinspection PyUnresolvedReferences
from .royals import Royal
from .royals import User
class Alias:
@ -13,7 +13,7 @@ class Alias:
@declared_attr
def royal_id(self):
return Column(Integer, ForeignKey("royals.uid"))
return Column(Integer, ForeignKey("users.uid"))
@declared_attr
def alias(self):
@ -21,7 +21,7 @@ class Alias:
@declared_attr
def royal(self):
return relationship("Royal", backref="aliases")
return relationship("User", backref="aliases")
def __repr__(self):
return f"<Alias {str(self)}>"

View file

@ -4,7 +4,7 @@ from sqlalchemy import Column, \
ForeignKey
from sqlalchemy.orm import relationship, backref
from sqlalchemy.ext.declarative import declared_attr
from .royals import Royal
from .royals import User
class Bio:
@ -12,11 +12,11 @@ class Bio:
@declared_attr
def royal_id(self):
return Column(Integer, ForeignKey("royals.uid"), primary_key=True)
return Column(Integer, ForeignKey("users.uid"), primary_key=True)
@declared_attr
def royal(self):
return relationship("Royal", backref=backref("bio", uselist=False))
return relationship("User", backref=backref("bio", uselist=False))
@declared_attr
def contents(self):

View file

@ -9,7 +9,7 @@ from sqlalchemy import Column, \
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declared_attr
# noinspection PyUnresolvedReferences
from .royals import Royal
from .royals import User
class Diario:
@ -21,11 +21,11 @@ class Diario:
@declared_attr
def creator_id(self):
return Column(Integer, ForeignKey("royals.uid"))
return Column(Integer, ForeignKey("users.uid"))
@declared_attr
def quoted_account_id(self):
return Column(Integer, ForeignKey("royals.uid"))
return Column(Integer, ForeignKey("users.uid"))
@declared_attr
def quoted(self):
@ -53,11 +53,11 @@ class Diario:
@declared_attr
def creator(self):
return relationship("Royal", foreign_keys=self.creator_id, backref="diario_created")
return relationship("User", foreign_keys=self.creator_id, backref="diario_created")
@declared_attr
def quoted_account(self):
return relationship("Royal", foreign_keys=self.quoted_account_id, backref="diario_quoted")
return relationship("User", foreign_keys=self.quoted_account_id, backref="diario_quoted")
def __repr__(self):
return f"<Diario diario_id={self.diario_id}" \

View file

@ -6,7 +6,7 @@ from sqlalchemy import Column, \
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declared_attr
# noinspection PyUnresolvedReferences
from .royals import Royal
from .royals import User
class Discord:
@ -14,7 +14,7 @@ class Discord:
@declared_attr
def royal_id(self):
return Column(Integer, ForeignKey("royals.uid"))
return Column(Integer, ForeignKey("users.uid"))
@declared_attr
def discord_id(self):
@ -34,7 +34,7 @@ class Discord:
@declared_attr
def royal(self):
return relationship("Royal", backref="discord")
return relationship("User", backref="discord")
def __repr__(self):
return f"<Discord {str(self)}>"

View file

@ -4,7 +4,7 @@ from sqlalchemy import Column, \
ForeignKey
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.orm import relationship
from .royals import Royal
from .royals import User
from .medals import Medal
@ -25,7 +25,7 @@ class MedalAward:
@declared_attr
def royal_id(self):
return Column(Integer, ForeignKey("royal.uid"), nullable=False)
return Column(Integer, ForeignKey("users.uid"), nullable=False)
@declared_attr
def medal(self):
@ -33,7 +33,7 @@ class MedalAward:
@declared_attr
def royal(self):
return relationship("Royal", backref="medals_received")
return relationship("User", backref="medals_received")
def __repr__(self):
return f"<MedalAward of {self.medal} to {self.royal} on {self.date}>"

View file

@ -4,7 +4,7 @@ from sqlalchemy import Column, \
ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declared_attr
from .royals import Royal
from .royals import User
from .mmevents import MMEvent
@ -13,11 +13,11 @@ class MMDecision:
@declared_attr
def royal_id(self):
return Column(Integer, ForeignKey("royals.uid"), primary_key=True)
return Column(Integer, ForeignKey("users.uid"), primary_key=True)
@declared_attr
def royal(self):
return relationship("Royal", backref="mmdecisions_taken")
return relationship("User", backref="mmdecisions_taken")
@declared_attr
def mmevent_id(self):

View file

@ -9,7 +9,7 @@ from sqlalchemy import Column, \
BigInteger
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declared_attr
from .royals import Royal
from .royals import User
if typing.TYPE_CHECKING:
from .mmdecisions import MMDecision
from .mmresponse import MMResponse
@ -20,11 +20,11 @@ class MMEvent:
@declared_attr
def creator_id(self):
return Column(Integer, ForeignKey("royals.uid"), nullable=False)
return Column(Integer, ForeignKey("users.uid"), nullable=False)
@declared_attr
def creator(self):
return relationship("Royal", backref="mmevents_created")
return relationship("User", backref="mmevents_created")
@declared_attr
def mmid(self):

View file

@ -4,7 +4,7 @@ from sqlalchemy import Column, \
ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declared_attr
from .royals import Royal
from .royals import User
from .mmevents import MMEvent
@ -13,11 +13,11 @@ class MMResponse:
@declared_attr
def royal_id(self):
return Column(Integer, ForeignKey("royals.uid"), primary_key=True)
return Column(Integer, ForeignKey("users.uid"), primary_key=True)
@declared_attr
def royal(self):
return relationship("Royal", backref="mmresponses_given")
return relationship("User", backref="mmresponses_given")
@declared_attr
def mmevent_id(self):

View file

@ -7,7 +7,7 @@ from sqlalchemy import Column, \
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declared_attr
# noinspection PyUnresolvedReferences
from .royals import Royal
from .royals import User
class Reminder:
@ -19,11 +19,11 @@ class Reminder:
@declared_attr
def creator_id(self):
return Column(Integer, ForeignKey("royals.uid"))
return Column(Integer, ForeignKey("users.uid"))
@declared_attr
def creator(self):
return relationship("Royal", backref="reminders_created")
return relationship("User", backref="reminders_created")
@declared_attr
def interface_name(self):

View file

@ -5,8 +5,8 @@ from sqlalchemy import Column, \
from sqlalchemy.ext.declarative import declared_attr
class Royal:
__tablename__ = "royals"
class User:
__tablename__ = "users"
@declared_attr
def uid(self):
@ -29,7 +29,7 @@ class Royal:
return Column(LargeBinary)
def __repr__(self):
return f"<Royal {self.username}>"
return f"<User {self.username}>"
def __str__(self):
return f"[c]royalnet:{self.username}[/c]"
return self.username

View file

@ -6,7 +6,7 @@ from sqlalchemy import Column, \
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declared_attr
# noinspection PyUnresolvedReferences
from .royals import Royal
from .royals import User
class Telegram:
@ -14,7 +14,7 @@ class Telegram:
@declared_attr
def royal_id(self):
return Column(Integer, ForeignKey("royals.uid"))
return Column(Integer, ForeignKey("users.uid"))
@declared_attr
def tg_id(self):
@ -34,7 +34,7 @@ class Telegram:
@declared_attr
def royal(self):
return relationship("Royal", backref="telegram")
return relationship("User", backref="telegram")
def __repr__(self):
return f"<Telegram {str(self)}>"

View file

@ -3,7 +3,7 @@ from sqlalchemy import Column, \
ForeignKey
from sqlalchemy.orm import relationship, backref
from sqlalchemy.ext.declarative import declared_attr
from .royals import Royal
from .royals import User
class TriviaScore:
@ -11,11 +11,11 @@ class TriviaScore:
@declared_attr
def royal_id(self):
return Column(Integer, ForeignKey("royals.uid"), primary_key=True)
return Column(Integer, ForeignKey("users.uid"), primary_key=True)
@declared_attr
def royal(self):
return relationship("Royal", backref=backref("trivia_score", uselist=False))
return relationship("User", backref=backref("trivia_score", uselist=False))
@declared_attr
def correct_answers(self):

View file

@ -9,7 +9,7 @@ from sqlalchemy.ext.declarative import declared_attr
# noinspection PyUnresolvedReferences
from .wikipages import WikiPage
# noinspection PyUnresolvedReferences
from .royals import Royal
from .royals import User
class WikiRevision:
@ -33,11 +33,11 @@ class WikiRevision:
@declared_attr
def author_id(self):
return Column(Integer, ForeignKey("royals.uid"), nullable=False)
return Column(Integer, ForeignKey("users.uid"), nullable=False)
@declared_attr
def author(self):
return relationship("Royal", foreign_keys=self.author_id, backref="wiki_contributions")
return relationship("User", foreign_keys=self.author_id, backref="wiki_contributions")
@declared_attr
def timestamp(self):

View file

@ -2,17 +2,17 @@
from .request import Request
from .response import Response, ResponseSuccess, ResponseError
from .package import Package
from .royalnetlink import RoyalnetLink, NetworkError, NotConnectedError, NotIdentifiedError, ConnectionClosedError
from .royalnetserver import RoyalnetServer
from .royalnetconfig import RoyalnetConfig
from .networklink import NetworkLink, NetworkError, NotConnectedError, NotIdentifiedError, ConnectionClosedError
from .networkserver import NetworkServer
from .networkconfig import NetworkConfig
__all__ = ["RoyalnetLink",
__all__ = ["NetworkLink",
"NetworkError",
"NotConnectedError",
"NotIdentifiedError",
"Package",
"RoyalnetServer",
"RoyalnetConfig",
"NetworkServer",
"NetworkConfig",
"ConnectionClosedError",
"Request",
"Response",

View file

@ -1,4 +1,4 @@
class RoyalnetConfig:
class NetworkConfig:
def __init__(self,
master_uri: str,
master_secret: str):

View file

@ -13,19 +13,19 @@ log = _logging.getLogger(__name__)
class NotConnectedError(Exception):
"""The :py:class:`royalnet.network.RoyalnetLink` is not connected to a :py:class:`royalnet.network.RoyalnetServer`."""
"""The :py:class:`royalnet.network.NetworkLink` is not connected to a :py:class:`royalnet.network.NetworkServer`."""
class NotIdentifiedError(Exception):
"""The :py:class:`royalnet.network.RoyalnetLink` has not identified yet to a :py:class:`royalnet.network.RoyalnetServer`."""
"""The :py:class:`royalnet.network.NetworkLink` has not identified yet to a :py:class:`royalnet.network.NetworkServer`."""
class ConnectionClosedError(Exception):
"""The :py:class:`royalnet.network.RoyalnetLink`'s connection was closed unexpectedly. The link can't be used anymore."""
"""The :py:class:`royalnet.network.NetworkLink`'s connection was closed unexpectedly. The link can't be used anymore."""
class InvalidServerResponseError(Exception):
"""The :py:class:`royalnet.network.RoyalnetServer` sent invalid data to the :py:class:`royalnet.network.RoyalnetLink`."""
"""The :py:class:`royalnet.network.NetworkServer` sent invalid data to the :py:class:`royalnet.network.NetworkLink`."""
class NetworkError(Exception):
@ -69,7 +69,7 @@ def requires_identification(func):
return new_func
class RoyalnetLink:
class NetworkLink:
def __init__(self, master_uri: str, secret: str, link_type: str, request_handler, *,
loop: asyncio.AbstractEventLoop = None):
if ":" in link_type:
@ -90,7 +90,7 @@ class RoyalnetLink:
self.identify_event: asyncio.Event = asyncio.Event(loop=self._loop)
async def connect(self):
"""Connect to the :py:class:`royalnet.network.RoyalnetServer` at ``self.master_uri``."""
"""Connect to the :py:class:`royalnet.network.NetworkServer` at ``self.master_uri``."""
log.info(f"Connecting to {self.master_uri}...")
self.websocket = await websockets.connect(self.master_uri, loop=self._loop)
self.connect_event.set()
@ -98,7 +98,7 @@ class RoyalnetLink:
@requires_connection
async def receive(self) -> Package:
"""Recieve a :py:class:`Package` from the :py:class:`royalnet.network.RoyalnetServer`.
"""Recieve a :py:class:`Package` from the :py:class:`royalnet.network.NetworkServer`.
Raises:
:py:exc:`royalnet.network.royalnetlink.ConnectionClosedError` if the connection closes."""
@ -113,7 +113,7 @@ class RoyalnetLink:
# What to do now? Let's just reraise.
raise ConnectionClosedError()
if self.identify_event.is_set() and package.destination != self.nid:
raise InvalidServerResponseError("Package is not addressed to this RoyalnetLink.")
raise InvalidServerResponseError("Package is not addressed to this NetworkLink.")
log.debug(f"Received package: {package}")
return package

View file

@ -12,7 +12,7 @@ log = _logging.getLogger(__name__)
class ConnectedClient:
"""The :py:class:`royalnet.network.RoyalnetServer`-side representation of a connected :py:class:`royalnet.network.RoyalnetLink`."""
"""The :py:class:`royalnet.network.NetworkServer`-side representation of a connected :py:class:`royalnet.network.NetworkLink`."""
def __init__(self, socket: websockets.WebSocketServerProtocol):
self.socket: websockets.WebSocketServerProtocol = socket
self.nid: typing.Optional[str] = None
@ -30,11 +30,11 @@ class ConnectedClient:
destination=self.nid))
async def send(self, package: Package):
"""Send a :py:class:`royalnet.network.Package` to the :py:class:`royalnet.network.RoyalnetLink`."""
"""Send a :py:class:`royalnet.network.Package` to the :py:class:`royalnet.network.NetworkLink`."""
await self.socket.send(package.to_json_bytes())
class RoyalnetServer:
class NetworkServer:
def __init__(self, address: str, port: int, required_secret: str, *, loop: asyncio.AbstractEventLoop = None):
self.address: str = address
self.port: int = port
@ -131,9 +131,12 @@ class RoyalnetServer:
async def serve(self):
await websockets.serve(self.listener, host=self.address, port=self.port)
async def start(self):
async def run(self):
log.debug(f"Starting main server loop for <server> on ws://{self.address}:{self.port}")
# noinspection PyAsyncCall
self._loop.create_task(self.serve())
# Just to be sure it has started on Linux
await asyncio.sleep(0.5)
def run_blocking(self):
self._loop.run_until_complete(self.run())

View file

@ -4,7 +4,7 @@ import typing
class Package:
"""A Royalnet package, the data type with which a :py:class:`royalnet.network.RoyalnetLink` communicates with a :py:class:`royalnet.network.RoyalnetServer` or another link.
"""A Royalnet package, the data type with which a :py:class:`royalnet.network.NetworkLink` communicates with a :py:class:`royalnet.network.NetworkServer` or another link.
Contains info about the source and the destination."""
def __init__(self,

View file

@ -1,5 +1,5 @@
class Request:
"""A request sent from a :py:class:`royalnet.network.RoyalnetLink` to another.
"""A request sent from a :py:class:`royalnet.network.NetworkLink` to another.
It contains the name of the requested handler, in addition to the data."""

View file

@ -1,26 +0,0 @@
import click
import typing
import royalnet as r
@click.command()
@click.option("--telegram/--no-telegram", default=None,
help="Enable/disable the Telegram module.")
@click.option("--discord/--no-discord", default=None,
help="Enable/disable the Discord module.")
@click.option("--database", type=str, default=None,
help="The PostgreSQL database path.")
@click.option("--commands", type=str, multiple=True, default=[],
help="The names of the command pack modules that should be imported.")
@click.option("--network", type=str, default=None,
help="The Royalnet master server uri and password, separated by a pipe.")
def run(telegram: typing.Optional[bool],
discord: typing.Optional[bool],
database: typing.Optional[str],
commands: typing.List[str],
network: typing.Optional[str]):
...
if __name__ == "__main__":
run()

View file

@ -4,11 +4,11 @@ import datetime
import difflib
import uuid
from royalnet.database import Alchemy
from royalnet.database.tables import Royal, WikiPage, WikiRevision
from royalnet.database.tables import User, WikiPage, WikiRevision
if __name__ == "__main__":
alchemy = Alchemy(os.environ["DB_PATH"], {Royal, WikiPage, WikiRevision})
alchemy = Alchemy(os.environ["DB_PATH"], {User, WikiPage, WikiRevision})
with open(r"data.txt") as file, alchemy.session_cm() as session:
for line in file.readlines():
match = re.match("^([^\t]+)\t([^\t]+)\t([tf])$", line)

View file

@ -1 +1 @@
semantic = "5.0a58"
semantic = "5.0a59"

View file

@ -1,15 +1,15 @@
"""A Royal Games Diario viewer :py:class:`royalnet.web.Royalprint`."""
"""A User Games Diario viewer :py:class:`royalnet.web.Royalprint`."""
import flask as f
import os
from ...royalprint import Royalprint
from ...shortcuts import error
from ....database.tables import Royal, Diario
from ....database.tables import User, Diario
tmpl_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
rp = Royalprint("diarioview", __name__, url_prefix="/diario", template_folder=tmpl_dir,
required_tables={Royal, Diario})
required_tables={User, Diario})
@rp.route("/", defaults={"page": 1})

View file

@ -1,4 +1,4 @@
"""Homepage :py:class:`royalnet.web.Royalprint` of the Royal Games website."""
"""Homepage :py:class:`royalnet.web.Royalprint` of the User Games website."""
import flask as f
import os
from ...royalprint import Royalprint

View file

@ -5,11 +5,11 @@ import datetime
import bcrypt
from ...royalprint import Royalprint
from ...shortcuts import error
from ....database.tables import Royal
from ....database.tables import User
tmpl_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
rp = Royalprint("login", __name__, url_prefix="/login/password", required_tables={Royal},
rp = Royalprint("login", __name__, url_prefix="/login/password", required_tables={User},
template_folder=tmpl_dir)

View file

@ -4,11 +4,11 @@ import os
import bcrypt
from ...royalprint import Royalprint
from ...shortcuts import error
from ....database.tables import Royal, Alias
from ....database.tables import User, Alias
tmpl_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
rp = Royalprint("newaccount", __name__, url_prefix="/newaccount", required_tables={Royal, Alias},
rp = Royalprint("newaccount", __name__, url_prefix="/newaccount", required_tables={User, Alias},
template_folder=tmpl_dir)

View file

@ -11,7 +11,7 @@ from ....utils.wikirender import prepare_page_markdown, RenderError
# Maybe some of these tables are optional...
tmpl_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
rp = Royalprint("profile", __name__, url_prefix="/profile", template_folder=tmpl_dir,
required_tables={Royal, ActiveKvGroup, Alias, Diario, Discord, Keygroup, Keyvalue, Telegram, WikiPage,
required_tables={User, ActiveKvGroup, Alias, Diario, Discord, Keygroup, Keyvalue, Telegram, WikiPage,
WikiRevision, Bio, TriviaScore})

View file

@ -6,11 +6,11 @@ import datetime
import os
from ...royalprint import Royalprint
from ...shortcuts import error
from ....database.tables import Royal, Telegram
from ....database.tables import User, Telegram
tmpl_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
rp = Royalprint("tglogin", __name__, url_prefix="/login/telegram", required_tables={Royal, Telegram},
rp = Royalprint("tglogin", __name__, url_prefix="/login/telegram", required_tables={User, Telegram},
template_folder=tmpl_dir)
@ -38,7 +38,7 @@ def tglogin_done():
return error(400, "L'autenticazione è fallita: l'hash ricevuto non coincide con quello calcolato.")
tg_user = alchemy_session.query(alchemy.Telegram).filter(alchemy.Telegram.tg_id == f.request.args["id"]).one_or_none()
if tg_user is None:
return error(404, "L'account Telegram con cui hai fatto il login non è connesso a nessun account Royal Games. Se sei un membro Royal Games, assicurati di aver syncato con il bot il tuo account di Telegram!")
return error(404, "L'account Telegram con cui hai fatto il login non è connesso a nessun account User Games. Se sei un membro User Games, assicurati di aver syncato con il bot il tuo account di Telegram!")
royal_user = tg_user.royal
f.session["royal"] = {
"uid": royal_user.uid,

View file

@ -1,4 +1,4 @@
"""A Royal Games Wiki viewer :py:class:`royalnet.web.Royalprint`. Doesn't support any kind of edit."""
"""A User Games Wiki viewer :py:class:`royalnet.web.Royalprint`. Doesn't support any kind of edit."""
import flask as f
import uuid
import os
@ -6,12 +6,12 @@ import datetime
import difflib
from ...royalprint import Royalprint
from ...shortcuts import error, from_urluuid
from ....database.tables import Royal, WikiPage, WikiRevision
from ....database.tables import User, WikiPage, WikiRevision
tmpl_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
rp = Royalprint("wikiedit", __name__, url_prefix="/wiki/edit", template_folder=tmpl_dir,
required_tables={Royal, WikiPage, WikiRevision})
required_tables={User, WikiPage, WikiRevision})
@rp.route("/newpage", methods=["GET", "POST"])

View file

@ -1,16 +1,16 @@
"""A Royal Games Wiki viewer :py:class:`royalnet.web.Royalprint`. Doesn't support any kind of edit."""
"""A User Games Wiki viewer :py:class:`royalnet.web.Royalprint`. Doesn't support any kind of edit."""
import flask as f
import os
from ...royalprint import Royalprint
from ...shortcuts import error, from_urluuid
from ....database.tables import Royal, WikiPage, WikiRevision
from ....database.tables import User, WikiPage, WikiRevision
from ....utils.wikirender import prepare_page_markdown, RenderError
tmpl_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
rp = Royalprint("wikiview", __name__, url_prefix="/wiki/view", template_folder=tmpl_dir,
required_tables={Royal, WikiPage, WikiRevision})
required_tables={User, WikiPage, WikiRevision})
def prepare_page(page):

View file

@ -9,7 +9,7 @@ setuptools.setup(
version=royalnet.version.semantic,
author="Stefano Pigozzi",
author_email="ste.pigozzi@gmail.com",
description="The great bot network of the Royal Games community",
description="The great bot network of the User Games community",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/royal-games/royalnet",
@ -31,7 +31,8 @@ setuptools.setup(
"mcstatus>=2.2.1",
"sortedcontainers>=2.1.0",
"sentry-sdk>=0.11.1",
"click>=7.0"],
"click>=7.0",
"keyring>=19.2.0"],
python_requires=">=3.7",
classifiers=[
"Development Status :: 3 - Alpha",

View file

@ -2,7 +2,7 @@ import pytest
import uuid
import asyncio
import logging
from royalnet.network import Package, RoyalnetLink, RoyalnetServer, ConnectionClosedError, Request
from royalnet.network import Package, NetworkLink, NetworkServer, ConnectionClosedError, Request
log = logging.root
@ -41,16 +41,16 @@ def test_request_creation():
def test_links(async_loop: asyncio.AbstractEventLoop):
address, port = "127.0.0.1", 1235
master = RoyalnetServer(address, port, "test")
master = NetworkServer(address, port, "test")
async_loop.run_until_complete(master.start())
# Test invalid secret
wrong_secret_link = RoyalnetLink("ws://127.0.0.1:1235", "invalid", "test", echo_request_handler, loop=async_loop)
wrong_secret_link = NetworkLink("ws://127.0.0.1:1235", "invalid", "test", echo_request_handler, loop=async_loop)
with pytest.raises(ConnectionClosedError):
async_loop.run_until_complete(wrong_secret_link.run())
# Test regular connection
link1 = RoyalnetLink("ws://127.0.0.1:1235", "test", "one", echo_request_handler, loop=async_loop)
link1 = NetworkLink("ws://127.0.0.1:1235", "test", "one", echo_request_handler, loop=async_loop)
async_loop.create_task(link1.run())
link2 = RoyalnetLink("ws://127.0.0.1:1235", "test", "two", echo_request_handler, loop=async_loop)
link2 = NetworkLink("ws://127.0.0.1:1235", "test", "two", echo_request_handler, loop=async_loop)
async_loop.create_task(link2.run())
message = {"ciao": "ciao"}
response = async_loop.run_until_complete(link1.request(message, "two"))