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

Maybe this was a bad idea afterall

This commit is contained in:
Steffo 2019-08-18 01:10:01 +03:00
parent e1c3270527
commit d2c1f87798
6 changed files with 59 additions and 50 deletions

View file

@ -2,7 +2,6 @@ import discord
import typing import typing
import logging as _logging import logging as _logging
from .generic import GenericBot from .generic import GenericBot
from royalnet.commands import NullCommand
from ..utils import asyncify, Call, Command, discord_escape from ..utils import asyncify, Call, Command, discord_escape
from ..error import UnregisteredError, NoneFoundError, TooManyFoundError, InvalidConfigError, RoyalnetResponseError from ..error import UnregisteredError, NoneFoundError, TooManyFoundError, InvalidConfigError, RoyalnetResponseError
from ..network import RoyalnetConfig, Request, ResponseSuccess, ResponseError from ..network import RoyalnetConfig, Request, ResponseSuccess, ResponseError
@ -32,7 +31,7 @@ class DiscordBot(GenericBot):
log.debug(f"Creating music_data dict") log.debug(f"Creating music_data dict")
self.music_data: typing.Dict[discord.Guild, playmodes.PlayMode] = {} self.music_data: typing.Dict[discord.Guild, playmodes.PlayMode] = {}
def _call_factory(self) -> typing.Type[Call]: def _interface_factory(self) -> typing.Type[Call]:
log.debug(f"Creating DiscordCall") log.debug(f"Creating DiscordCall")
# noinspection PyMethodParameters # noinspection PyMethodParameters

View file

@ -2,10 +2,11 @@ import sys
import typing import typing
import asyncio import asyncio
import logging import logging
from ..utils import Command, NetworkHandler, Call from ..utils import NetworkHandler
from royalnet.commands import NullCommand from ..network import RoyalnetLink, Request, Response, ResponseSuccess, ResponseError, RoyalnetConfig
from ..network import RoyalnetLink, Request, Response, ResponseError, RoyalnetConfig
from ..database import Alchemy, DatabaseConfig, relationshiplinkchain from ..database import Alchemy, DatabaseConfig, relationshiplinkchain
from ..commands import Command, CommandInterface
from ..error import *
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -28,17 +29,40 @@ class GenericBot:
for command in commands: for command in commands:
lower_command_name = command.command_name.lower() lower_command_name = command.command_name.lower()
self.commands[f"{command_prefix}{lower_command_name}"] = command self.commands[f"{command_prefix}{lower_command_name}"] = command
self.network_handlers = {**self.network_handlers, **command.network_handler_dict()}
self.missing_command: typing.Type[Command] = missing_command self.missing_command: typing.Type[Command] = missing_command
self.error_command: typing.Type[Command] = error_command self.error_command: typing.Type[Command] = error_command
log.debug(f"Successfully generated commands") log.debug(f"Successfully generated commands")
def _call_factory(self) -> typing.Type[Call]: def _interface_factory(self) -> typing.Type[CommandInterface]:
"""Create the TelegramCall class, representing a command call. It should inherit from :py:class:`royalnet.utils.Call`. """Create a :py:class:`royalnet.commands.CommandInterface` type and return it.
Returns: Returns:
The created TelegramCall class.""" The created :py:class:`royalnet.commands.CommandInterface` type."""
raise NotImplementedError()
# noinspection PyAbstractClass,PyMethodParameters
class GenericInterface(CommandInterface):
alchemy = self.alchemy
bot = self
def register_net_handler(ci, message_type: str, network_handler: typing.Callable):
self.network_handlers[message_type] = network_handler
async def net_request(ci, request: Request, destination: str) -> dict:
if self.network is None:
raise InvalidConfigError("Royalnet is not enabled on this bot")
response_dict: dict = await self.network.request(request.to_dict(), destination)
if "type" not in response_dict:
raise RoyalnetResponseError("Response is missing a type")
elif response_dict["type"] == "ResponseSuccess":
response: typing.Union[ResponseSuccess, ResponseError] = ResponseSuccess.from_dict(response_dict)
elif response_dict["type"] == "ResponseError":
response = ResponseError.from_dict(response_dict)
else:
raise RoyalnetResponseError("Response type is unknown")
response.raise_on_error()
return response.data
return GenericInterface
def _init_royalnet(self, royalnet_config: RoyalnetConfig): def _init_royalnet(self, royalnet_config: RoyalnetConfig):
"""Create a :py:class:`royalnet.network.RoyalnetLink`, and run it as a :py:class:`asyncio.Task`.""" """Create a :py:class:`royalnet.network.RoyalnetLink`, and run it as a :py:class:`asyncio.Task`."""
@ -117,7 +141,7 @@ class GenericBot:
if commands is None: if commands is None:
commands = [] commands = []
self._init_commands(command_prefix, commands, missing_command=missing_command, error_command=error_command) self._init_commands(command_prefix, commands, missing_command=missing_command, error_command=error_command)
self._Call = self._call_factory() self._Call = self._interface_factory()
if royalnet_config is None: if royalnet_config is None:
self.network = None self.network = None
else: else:

View file

@ -3,11 +3,11 @@ import telegram.utils.request
import typing import typing
import logging as _logging import logging as _logging
from .generic import GenericBot from .generic import GenericBot
from royalnet.commands import NullCommand from ..utils import asyncify, telegram_escape
from ..utils import asyncify, Call, Command, telegram_escape
from ..error import UnregisteredError, InvalidConfigError, RoyalnetResponseError from ..error import UnregisteredError, InvalidConfigError, RoyalnetResponseError
from ..network import RoyalnetConfig, Request, ResponseSuccess, ResponseError from ..network import RoyalnetConfig, Request, ResponseSuccess, ResponseError
from ..database import DatabaseConfig from ..database import DatabaseConfig
from ..commands import CommandInterface
log = _logging.getLogger(__name__) log = _logging.getLogger(__name__)
@ -21,7 +21,6 @@ class TelegramConfig:
class TelegramBot(GenericBot): class TelegramBot(GenericBot):
"""A bot that connects to `Telegram <https://telegram.org/>`_.""" """A bot that connects to `Telegram <https://telegram.org/>`_."""
interface_name = "telegram"
def _init_client(self): def _init_client(self):
"""Create the :py:class:`telegram.Bot`, and set the starting offset.""" """Create the :py:class:`telegram.Bot`, and set the starting offset."""
@ -30,43 +29,29 @@ class TelegramBot(GenericBot):
self.client = telegram.Bot(self._telegram_config.token, request=request) self.client = telegram.Bot(self._telegram_config.token, request=request)
self._offset: int = -100 self._offset: int = -100
def _call_factory(self) -> typing.Type[Call]: def _interface_factory(self) -> typing.Type[CommandInterface]:
GenericInterface = super()._interface_factory()
# noinspection PyMethodParameters # noinspection PyMethodParameters
class TelegramCall(Call): class TelegramInterface(GenericInterface):
interface_name = self.interface_name name = "telegram"
interface_obj = self prefix = "/"
interface_prefix = "/"
alchemy = self.alchemy alchemy = self.alchemy
async def reply(call, text: str): async def reply(ci, extra: dict, text: str):
await asyncify(call.channel.send_message, telegram_escape(text), await asyncify(ci.channel.send_message, telegram_escape(text),
parse_mode="HTML", parse_mode="HTML",
disable_web_page_preview=True) disable_web_page_preview=True)
async def net_request(call, request: Request, destination: str) -> dict: async def get_author(ci, extra: dict, error_if_none=False):
if self.network is None: update: telegram.Update = extra["update"]
raise InvalidConfigError("Royalnet is not enabled on this bot")
response_dict: dict = await self.network.request(request.to_dict(), destination)
if "type" not in response_dict:
raise RoyalnetResponseError("Response is missing a type")
elif response_dict["type"] == "ResponseSuccess":
response: typing.Union[ResponseSuccess, ResponseError] = ResponseSuccess.from_dict(response_dict)
elif response_dict["type"] == "ResponseError":
response = ResponseError.from_dict(response_dict)
else:
raise RoyalnetResponseError("Response type is unknown")
response.raise_on_error()
return response.data
async def get_author(call, error_if_none=False):
update: telegram.Update = call.kwargs["update"]
user: telegram.User = update.effective_user user: telegram.User = update.effective_user
if user is None: if user is None:
if error_if_none: if error_if_none:
raise UnregisteredError("No author for this message") raise UnregisteredError("No author for this message")
return None return None
query = call.session.query(self.master_table) query = ci.session.query(self.master_table)
for link in self.identity_chain: for link in self.identity_chain:
query = query.join(link.mapper.class_) query = query.join(link.mapper.class_)
query = query.filter(self.identity_column == user.id) query = query.filter(self.identity_column == user.id)

View file

@ -1,6 +1,7 @@
import typing import typing
from ..error import UnsupportedError from ..error import UnsupportedError
from .commandinterface import CommandInterface from .commandinterface import CommandInterface
from .commandargs import CommandArgs
class Command: class Command:
@ -21,8 +22,5 @@ class Command:
def __init__(self, interface: CommandInterface): def __init__(self, interface: CommandInterface):
self.interface = interface self.interface = interface
async def common(self) -> None: async def run(self, args: CommandArgs, **extra) -> None:
raise UnsupportedError(f"Command {self.name} can't be called on {self.interface.name}.") raise UnsupportedError(f"Command {self.name} can't be called on {self.interface.name}.")
def __getattr__(self, item) -> typing.Callable:
return self.common

View file

@ -13,32 +13,35 @@ class CommandInterface:
def __init__(self, alias: str): def __init__(self, alias: str):
self.session = self.alchemy.Session() self.session = self.alchemy.Session()
async def reply(self, text: str) -> None: def register_net_handler(self, message_type: str, network_handler: typing.Callable):
"""Register a new handler for messages received through Royalnet."""
raise NotImplementedError()
async def reply(self, extra: dict, text: str) -> None:
"""Send a text message to the channel where the call was made. """Send a text message to the channel where the call was made.
Parameters: Parameters:
extra: The ``extra`` dict passed to the Command
text: The text to be sent, possibly formatted in the weird undescribed markup that I'm using.""" text: The text to be sent, possibly formatted in the weird undescribed markup that I'm using."""
raise NotImplementedError() raise NotImplementedError()
async def net_request(self, message, destination: str) -> dict: async def net_request(self, extra: dict, message, destination: str) -> dict:
"""Send data through a :py:class:`royalnet.network.RoyalnetLink` and wait for a :py:class:`royalnet.network.Reply`. """Send data through a :py:class:`royalnet.network.RoyalnetLink` and wait for a :py:class:`royalnet.network.Reply`.
Parameters: Parameters:
extra: The ``extra`` dict passed to the Command
message: The data to be sent. Must be :py:mod:`pickle`-able. message: The data to be sent. Must be :py:mod:`pickle`-able.
destination: The destination of the request, either in UUID format or node name.""" destination: The destination of the request, either in UUID format or node name."""
raise NotImplementedError() raise NotImplementedError()
async def get_author(self, error_if_none: bool = False): async def get_author(self, extra: dict, error_if_none: bool = False):
"""Try to find the identifier of the user that sent the message. """Try to find the identifier of the user that sent the message.
That probably means, the database row identifying the user. That probably means, the database row identifying the user.
Parameters: Parameters:
extra: The ``extra`` dict passed to the Command
error_if_none: Raise a :py:exc:`royalnet.error.UnregisteredError` if this is True and the call has no author. error_if_none: Raise a :py:exc:`royalnet.error.UnregisteredError` if this is True and the call has no author.
Raises: Raises:
:py:exc:`royalnet.error.UnregisteredError` if ``error_if_none`` is set to True and no author is found.""" :py:exc:`royalnet.error.UnregisteredError` if ``error_if_none`` is set to True and no author is found."""
raise NotImplementedError() raise NotImplementedError()
def register_net_handler(self, message_type: str, network_handler: typing.Callable):
"""Register a new handler for messages received through Royalnet."""
raise NotImplementedError()