mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-27 13:34:28 +00:00
Start moving some stuff around
This commit is contained in:
parent
22b8cdf97f
commit
e1c3270527
43 changed files with 125 additions and 188 deletions
|
@ -1,3 +1,4 @@
|
||||||
from . import audio, bots, commands, database, network, utils, error, web, version
|
from . import audio, bots, database, network, utils, error, web, version
|
||||||
|
from royalnet import commands
|
||||||
|
|
||||||
__all__ = ["audio", "bots", "commands", "database", "network", "utils", "error", "web", "version"]
|
__all__ = ["audio", "bots", "commands", "database", "network", "utils", "error", "web", "version"]
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import discord
|
import discord
|
||||||
import asyncio
|
|
||||||
import typing
|
import typing
|
||||||
import logging as _logging
|
import logging as _logging
|
||||||
from .generic import GenericBot
|
from .generic import GenericBot
|
||||||
from ..commands import NullCommand
|
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
|
||||||
|
|
|
@ -3,7 +3,7 @@ import typing
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from ..utils import Command, NetworkHandler, Call
|
from ..utils import Command, NetworkHandler, Call
|
||||||
from ..commands import NullCommand
|
from royalnet.commands import NullCommand
|
||||||
from ..network import RoyalnetLink, Request, Response, ResponseError, RoyalnetConfig
|
from ..network import RoyalnetLink, Request, Response, ResponseError, RoyalnetConfig
|
||||||
from ..database import Alchemy, DatabaseConfig, relationshiplinkchain
|
from ..database import Alchemy, DatabaseConfig, relationshiplinkchain
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import telegram
|
import telegram
|
||||||
import telegram.utils.request
|
import telegram.utils.request
|
||||||
import asyncio
|
|
||||||
import typing
|
import typing
|
||||||
import logging as _logging
|
import logging as _logging
|
||||||
from .generic import GenericBot
|
from .generic import GenericBot
|
||||||
from ..commands import NullCommand
|
from royalnet.commands import NullCommand
|
||||||
from ..utils import asyncify, Call, Command, 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
|
||||||
|
|
|
@ -1,39 +1,4 @@
|
||||||
"""Commands that can be used in bots.
|
from .commandinterface import CommandInterface
|
||||||
|
from .command import Command
|
||||||
|
|
||||||
These probably won't suit your needs, as they are tailored for the bots of the Royal Games gaming community, but they may be useful to develop new ones."""
|
__all__ = ["CommandInterface", "Command"]
|
||||||
|
|
||||||
from .null import NullCommand
|
|
||||||
from .ping import PingCommand
|
|
||||||
from .ship import ShipCommand
|
|
||||||
from .smecds import SmecdsCommand
|
|
||||||
from .ciaoruozi import CiaoruoziCommand
|
|
||||||
from .color import ColorCommand
|
|
||||||
from .sync import SyncCommand
|
|
||||||
from .diario import DiarioCommand
|
|
||||||
from .rage import RageCommand
|
|
||||||
from .dateparser import DateparserCommand
|
|
||||||
from .author import AuthorCommand
|
|
||||||
from .reminder import ReminderCommand
|
|
||||||
from .kvactive import KvactiveCommand
|
|
||||||
from .kv import KvCommand
|
|
||||||
from .kvroll import KvrollCommand
|
|
||||||
from .videoinfo import VideoinfoCommand
|
|
||||||
from .summon import SummonCommand
|
|
||||||
from .play import PlayCommand
|
|
||||||
from .skip import SkipCommand
|
|
||||||
from .playmode import PlaymodeCommand
|
|
||||||
from .videochannel import VideochannelCommand
|
|
||||||
from .missing import MissingCommand
|
|
||||||
from .cv import CvCommand
|
|
||||||
from .pause import PauseCommand
|
|
||||||
from .queue import QueueCommand
|
|
||||||
from .royalnetprofile import RoyalnetprofileCommand
|
|
||||||
from .id import IdCommand
|
|
||||||
from .dlmusic import DlmusicCommand
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["NullCommand", "PingCommand", "ShipCommand", "SmecdsCommand", "CiaoruoziCommand", "ColorCommand",
|
|
||||||
"SyncCommand", "DiarioCommand", "RageCommand", "DateparserCommand", "AuthorCommand", "ReminderCommand",
|
|
||||||
"KvactiveCommand", "KvCommand", "KvrollCommand", "VideoinfoCommand", "SummonCommand", "PlayCommand",
|
|
||||||
"SkipCommand", "PlaymodeCommand", "VideochannelCommand", "MissingCommand", "CvCommand", "PauseCommand",
|
|
||||||
"QueueCommand", "RoyalnetprofileCommand", "IdCommand", "DlmusicCommand"]
|
|
||||||
|
|
28
royalnet/commands/command.py
Normal file
28
royalnet/commands/command.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import typing
|
||||||
|
from ..error import UnsupportedError
|
||||||
|
from .commandinterface import CommandInterface
|
||||||
|
|
||||||
|
|
||||||
|
class Command:
|
||||||
|
name: str = NotImplemented
|
||||||
|
"""The main name of the command.
|
||||||
|
To have ``/example`` on Telegram, the name should be ``example``."""
|
||||||
|
|
||||||
|
description: str = NotImplemented
|
||||||
|
"""A small description of the command, to be displayed when the command is being autocompleted."""
|
||||||
|
|
||||||
|
syntax: str = NotImplemented
|
||||||
|
"""The syntax of the command, to be displayed when a :py:exc:`royalnet.error.InvalidInputError` is raised,
|
||||||
|
in the format ``(required_arg) [optional_arg]``."""
|
||||||
|
|
||||||
|
require_alchemy_tables: typing.Set = set()
|
||||||
|
"""A set of :py:class:`royalnet.database` tables that must exist for this command to work."""
|
||||||
|
|
||||||
|
def __init__(self, interface: CommandInterface):
|
||||||
|
self.interface = interface
|
||||||
|
|
||||||
|
async def common(self) -> None:
|
||||||
|
raise UnsupportedError(f"Command {self.name} can't be called on {self.interface.name}.")
|
||||||
|
|
||||||
|
def __getattr__(self, item) -> typing.Callable:
|
||||||
|
return self.common
|
44
royalnet/commands/commandinterface.py
Normal file
44
royalnet/commands/commandinterface.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import typing
|
||||||
|
if typing.TYPE_CHECKING:
|
||||||
|
from ..database import Alchemy
|
||||||
|
from ..bots import GenericBot
|
||||||
|
|
||||||
|
|
||||||
|
class CommandInterface:
|
||||||
|
name: str = NotImplemented
|
||||||
|
prefix: str = NotImplemented
|
||||||
|
alchemy: "Alchemy" = NotImplemented
|
||||||
|
bot: "GenericBot" = NotImplemented
|
||||||
|
|
||||||
|
def __init__(self, alias: str):
|
||||||
|
self.session = self.alchemy.Session()
|
||||||
|
|
||||||
|
async def reply(self, text: str) -> None:
|
||||||
|
"""Send a text message to the channel where the call was made.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
text: The text to be sent, possibly formatted in the weird undescribed markup that I'm using."""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
async def net_request(self, message, destination: str) -> dict:
|
||||||
|
"""Send data through a :py:class:`royalnet.network.RoyalnetLink` and wait for a :py:class:`royalnet.network.Reply`.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
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."""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
async def get_author(self, error_if_none: bool = False):
|
||||||
|
"""Try to find the identifier of the user that sent the message.
|
||||||
|
That probably means, the database row identifying the user.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
error_if_none: Raise a :py:exc:`royalnet.error.UnregisteredError` if this is True and the call has no author.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:py:exc:`royalnet.error.UnregisteredError` if ``error_if_none`` is set to True and no author is found."""
|
||||||
|
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()
|
40
royalnet/commands/royalgames/__init__.py
Normal file
40
royalnet/commands/royalgames/__init__.py
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
"""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
|
||||||
|
may be useful to develop new ones."""
|
||||||
|
|
||||||
|
from .null import NullCommand
|
||||||
|
from .ping import PingCommand
|
||||||
|
from .ship import ShipCommand
|
||||||
|
from .smecds import SmecdsCommand
|
||||||
|
from .ciaoruozi import CiaoruoziCommand
|
||||||
|
from .color import ColorCommand
|
||||||
|
from .sync import SyncCommand
|
||||||
|
from .diario import DiarioCommand
|
||||||
|
from .rage import RageCommand
|
||||||
|
from .dateparser import DateparserCommand
|
||||||
|
from .author import AuthorCommand
|
||||||
|
from .reminder import ReminderCommand
|
||||||
|
from .kvactive import KvactiveCommand
|
||||||
|
from .kv import KvCommand
|
||||||
|
from .kvroll import KvrollCommand
|
||||||
|
from .videoinfo import VideoinfoCommand
|
||||||
|
from .summon import SummonCommand
|
||||||
|
from .play import PlayCommand
|
||||||
|
from .skip import SkipCommand
|
||||||
|
from .playmode import PlaymodeCommand
|
||||||
|
from .videochannel import VideochannelCommand
|
||||||
|
from .missing import MissingCommand
|
||||||
|
from .cv import CvCommand
|
||||||
|
from .pause import PauseCommand
|
||||||
|
from .queue import QueueCommand
|
||||||
|
from .royalnetprofile import RoyalnetprofileCommand
|
||||||
|
from .id import IdCommand
|
||||||
|
from .dlmusic import DlmusicCommand
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["NullCommand", "PingCommand", "ShipCommand", "SmecdsCommand", "CiaoruoziCommand", "ColorCommand",
|
||||||
|
"SyncCommand", "DiarioCommand", "RageCommand", "DateparserCommand", "AuthorCommand", "ReminderCommand",
|
||||||
|
"KvactiveCommand", "KvCommand", "KvrollCommand", "VideoinfoCommand", "SummonCommand", "PlayCommand",
|
||||||
|
"SkipCommand", "PlaymodeCommand", "VideochannelCommand", "MissingCommand", "CvCommand", "PauseCommand",
|
||||||
|
"QueueCommand", "RoyalnetprofileCommand", "IdCommand", "DlmusicCommand"]
|
|
@ -6,8 +6,8 @@ import logging
|
||||||
from royalnet.bots import DiscordBot, DiscordConfig, TelegramBot, TelegramConfig
|
from royalnet.bots import DiscordBot, DiscordConfig, TelegramBot, TelegramConfig
|
||||||
from royalnet.commands import *
|
from royalnet.commands import *
|
||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
from royalnet.commands.debug_create import DebugCreateCommand
|
from royalnet.commands import DebugCreateCommand
|
||||||
from royalnet.commands.error_handler import ErrorHandlerCommand
|
from royalnet.commands import ErrorHandlerCommand
|
||||||
from royalnet.network import RoyalnetServer, RoyalnetConfig
|
from royalnet.network import RoyalnetServer, RoyalnetConfig
|
||||||
from royalnet.database import DatabaseConfig
|
from royalnet.database import DatabaseConfig
|
||||||
from royalnet.database.tables import Royal, Telegram, Discord
|
from royalnet.database.tables import Royal, Telegram, Discord
|
||||||
|
|
|
@ -6,11 +6,9 @@ import logging
|
||||||
from royalnet.bots import DiscordBot, DiscordConfig, TelegramBot, TelegramConfig
|
from royalnet.bots import DiscordBot, DiscordConfig, TelegramBot, TelegramConfig
|
||||||
from royalnet.commands import *
|
from royalnet.commands import *
|
||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
from royalnet.commands.debug_create import DebugCreateCommand
|
from royalnet.commands import DebugCreateCommand
|
||||||
from royalnet.commands.error_handler import ErrorHandlerCommand
|
from royalnet.commands import ErrorHandlerCommand
|
||||||
from royalnet.network import RoyalnetServer, RoyalnetConfig
|
from royalnet.network import RoyalnetServer, RoyalnetConfig
|
||||||
from royalnet.database import DatabaseConfig
|
|
||||||
from royalnet.database.tables import Royal, Telegram, Discord
|
|
||||||
|
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
from .asyncify import asyncify
|
from .asyncify import asyncify
|
||||||
from .escaping import telegram_escape, discord_escape
|
from .escaping import telegram_escape, discord_escape
|
||||||
from .call import Call
|
|
||||||
from .command import Command
|
|
||||||
from .commandargs import CommandArgs
|
from .commandargs import CommandArgs
|
||||||
from .safeformat import safeformat
|
from .safeformat import safeformat
|
||||||
from .classdictjanitor import cdj
|
from .classdictjanitor import cdj
|
||||||
|
@ -11,6 +9,6 @@ from .sleepuntil import sleep_until
|
||||||
from .networkhandler import NetworkHandler
|
from .networkhandler import NetworkHandler
|
||||||
from .formatters import andformat, plusformat, fileformat, ytdldateformat, numberemojiformat
|
from .formatters import andformat, plusformat, fileformat, ytdldateformat, numberemojiformat
|
||||||
|
|
||||||
__all__ = ["asyncify", "Call", "Command", "safeformat", "cdj", "sleep_until", "plusformat", "CommandArgs",
|
__all__ = ["asyncify", "safeformat", "cdj", "sleep_until", "plusformat", "CommandArgs",
|
||||||
"NetworkHandler", "andformat", "plusformat", "fileformat", "ytdldateformat", "numberemojiformat",
|
"NetworkHandler", "andformat", "plusformat", "fileformat", "ytdldateformat", "numberemojiformat",
|
||||||
"telegram_escape", "discord_escape"]
|
"telegram_escape", "discord_escape"]
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
import typing
|
|
||||||
import asyncio
|
|
||||||
from .command import Command
|
|
||||||
from .commandargs import CommandArgs
|
|
||||||
if typing.TYPE_CHECKING:
|
|
||||||
from ..database import Alchemy
|
|
||||||
|
|
||||||
|
|
||||||
class Call:
|
|
||||||
"""A command call. An abstract class, sub-bots should create a new call class from this.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
interface_name: The name of the interface that is calling the command. For example, ``telegram``, or ``discord``.
|
|
||||||
interface_obj: The main object of the interface that is calling the command. For example, the :py:class:`royalnet.bots.TelegramBot` object.
|
|
||||||
interface_prefix: The command prefix used by the interface. For example, ``/``, or ``!``.
|
|
||||||
alchemy: The :py:class:`royalnet.database.Alchemy` object associated to this interface. May be None if the interface is not connected to any database."""
|
|
||||||
|
|
||||||
# These parameters / methods should be overridden
|
|
||||||
interface_name = NotImplemented
|
|
||||||
interface_obj = NotImplemented
|
|
||||||
interface_prefix = NotImplemented
|
|
||||||
alchemy: "Alchemy" = NotImplemented
|
|
||||||
|
|
||||||
async def reply(self, text: str) -> None:
|
|
||||||
"""Send a text message to the channel where the call was made.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
text: The text to be sent, possibly formatted in the weird undescribed markup that I'm using."""
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
async def net_request(self, message, destination: str) -> dict:
|
|
||||||
"""Send data through a :py:class:`royalnet.network.RoyalnetLink` and wait for a :py:class:`royalnet.network.Reply`.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
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."""
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
async def get_author(self, error_if_none=False):
|
|
||||||
"""Try to find the universal identifier of the user that sent the message.
|
|
||||||
That probably means, the database row identifying the user.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
error_if_none: Raise a :py:exc:`royalnet.error.UnregisteredError` if this is True and the call has no author.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
:py:exc:`royalnet.error.UnregisteredError` if ``error_if_none`` is set to True and no author is found."""
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
# These parameters / methods should be left alone
|
|
||||||
def __init__(self,
|
|
||||||
channel,
|
|
||||||
command: typing.Type[Command],
|
|
||||||
command_args: typing.List[str] = None,
|
|
||||||
loop: asyncio.AbstractEventLoop = None,
|
|
||||||
**kwargs):
|
|
||||||
"""Create the call.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
channel: The channel object this call was sent in.
|
|
||||||
command: The command to be called.
|
|
||||||
command_args: The arguments to be passed to the command
|
|
||||||
kwargs: Additional optional keyword arguments that may be passed to the command, possibly specific to the bot.
|
|
||||||
"""
|
|
||||||
if command_args is None:
|
|
||||||
command_args = []
|
|
||||||
if loop is None:
|
|
||||||
self.loop = asyncio.get_event_loop()
|
|
||||||
else:
|
|
||||||
self.loop = loop
|
|
||||||
self.channel = channel
|
|
||||||
self.command = command
|
|
||||||
self.args = CommandArgs(command_args)
|
|
||||||
self.kwargs = kwargs
|
|
||||||
self.session = None
|
|
||||||
|
|
||||||
async def _session_init(self):
|
|
||||||
"""If the command requires database access, create a :py:class:`royalnet.database.Alchemy` session for this call, otherwise, do nothing."""
|
|
||||||
if not self.command.require_alchemy_tables:
|
|
||||||
return
|
|
||||||
self.session = await self.loop.run_in_executor(None, self.alchemy.Session)
|
|
||||||
|
|
||||||
async def session_end(self):
|
|
||||||
"""Close the previously created :py:class:`royalnet.database.Alchemy` session for this call (if it was created)."""
|
|
||||||
if not self.session:
|
|
||||||
return
|
|
||||||
self.session.close()
|
|
||||||
|
|
||||||
async def run(self):
|
|
||||||
"""Execute the called command, and return the command result."""
|
|
||||||
await self._session_init()
|
|
||||||
try:
|
|
||||||
coroutine = getattr(self.command, self.interface_name)
|
|
||||||
except AttributeError:
|
|
||||||
coroutine = self.command.common
|
|
||||||
try:
|
|
||||||
result = await coroutine(self)
|
|
||||||
finally:
|
|
||||||
await self.session_end()
|
|
||||||
return result
|
|
|
@ -1,35 +0,0 @@
|
||||||
import typing
|
|
||||||
from ..error import UnsupportedError
|
|
||||||
if typing.TYPE_CHECKING:
|
|
||||||
from .call import Call
|
|
||||||
from ..utils import NetworkHandler
|
|
||||||
|
|
||||||
|
|
||||||
class Command:
|
|
||||||
"""The base class from which all commands should inherit."""
|
|
||||||
|
|
||||||
command_name: typing.Optional[str] = NotImplemented
|
|
||||||
"""The name of the command. To have ``/example`` on Telegram, the name should be ``example``. If the name is None or empty, the command won't be registered."""
|
|
||||||
|
|
||||||
command_description: str = NotImplemented
|
|
||||||
"""A small description of the command, to be displayed when the command is being autocompleted."""
|
|
||||||
|
|
||||||
command_syntax: str = NotImplemented
|
|
||||||
"""The syntax of the command, to be displayed when a :py:exc:`royalnet.error.InvalidInputError` is raised, in the format ``(required_arg) [optional_arg]``."""
|
|
||||||
|
|
||||||
require_alchemy_tables: typing.Set = set()
|
|
||||||
"""A set of :py:class:`royalnet.database` tables, that must exist for this command to work."""
|
|
||||||
|
|
||||||
network_handlers: typing.List[typing.Type["NetworkHandler"]] = []
|
|
||||||
"""A set of :py:class:`royalnet.utils.NetworkHandler`s that must exist for this command to work."""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
async def common(cls, call: "Call"):
|
|
||||||
raise UnsupportedError()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def network_handler_dict(cls):
|
|
||||||
d = {}
|
|
||||||
for network_handler in cls.network_handlers:
|
|
||||||
d[network_handler.message_type] = network_handler
|
|
||||||
return d
|
|
Loading…
Reference in a new issue