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

Do some more stuff

This commit is contained in:
Steffo 2019-04-16 19:02:21 +02:00
parent 90f566107f
commit 3e27e3b183
4 changed files with 97 additions and 63 deletions

View file

@ -4,11 +4,9 @@ import typing
import logging as _logging import logging as _logging
import sys import sys
from ..commands import NullCommand from ..commands import NullCommand
from ..commands.summon import SummonMessage
from ..commands.play import PlayMessage
from ..utils import asyncify, Call, Command from ..utils import asyncify, Call, Command
from royalnet.error import UnregisteredError from ..error import UnregisteredError, NoneFoundError, TooManyFoundError
from ..network import RoyalnetLink, Message, RequestSuccessful, RequestError from ..network import RoyalnetLink, Message, RequestSuccessful
from ..database import Alchemy, relationshiplinkchain from ..database import Alchemy, relationshiplinkchain
from ..audio import RoyalAudioFile from ..audio import RoyalAudioFile
@ -20,6 +18,19 @@ if not discord.opus.is_loaded():
log.error("Opus is not loaded. Weird behaviour might emerge.") log.error("Opus is not loaded. Weird behaviour might emerge.")
class PlayMessage(Message):
def __init__(self, url: str, channel_identifier: typing.Optional[typing.Union[int, str]] = None):
self.url: str = url
self.channel_identifier: typing.Optional[typing.Union[int, str]] = channel_identifier
class SummonMessage(Message):
def __init__(self, channel_identifier: typing.Union[int, str],
guild_identifier: typing.Optional[typing.Union[int, str]]):
self.channel_identifier = channel_identifier
self.guild_identifier = guild_identifier
class DiscordBot: class DiscordBot:
def __init__(self, def __init__(self,
token: str, token: str,
@ -33,9 +44,9 @@ class DiscordBot:
missing_command: typing.Type[Command] = NullCommand, missing_command: typing.Type[Command] = NullCommand,
error_command: typing.Type[Command] = NullCommand): error_command: typing.Type[Command] = NullCommand):
self.token = token self.token = token
# Generate commands
self.missing_command = missing_command self.missing_command = missing_command
self.error_command = error_command self.error_command = error_command
# Generate commands
self.commands = {} self.commands = {}
required_tables = set() required_tables = set()
for command in commands: for command in commands:
@ -47,8 +58,9 @@ class DiscordBot:
self.identity_table = self.alchemy.__getattribute__(identity_table.__name__) self.identity_table = self.alchemy.__getattribute__(identity_table.__name__)
self.identity_column = self.identity_table.__getattribute__(self.identity_table, identity_column_name) self.identity_column = self.identity_table.__getattribute__(self.identity_table, identity_column_name)
self.identity_chain = relationshiplinkchain(self.master_table, self.identity_table) self.identity_chain = relationshiplinkchain(self.master_table, self.identity_table)
# Connect to Royalnet
self.network: RoyalnetLink = RoyalnetLink(master_server_uri, master_server_secret, "discord", self.network_handler) self.network: RoyalnetLink = RoyalnetLink(master_server_uri, master_server_secret, "discord",
self.network_handler)
loop.create_task(self.network.run()) loop.create_task(self.network.run())
# noinspection PyMethodParameters # noinspection PyMethodParameters
@ -60,16 +72,16 @@ class DiscordBot:
async def reply(call, text: str): async def reply(call, text: str):
escaped_text = text.replace("*", "\\*") \ escaped_text = text.replace("*", "\\*") \
.replace("_", "\\_") \ .replace("_", "\\_") \
.replace("`", "\\`") \ .replace("`", "\\`") \
.replace("[b]", "**") \ .replace("[b]", "**") \
.replace("[/b]", "**") \ .replace("[/b]", "**") \
.replace("[i]", "_") \ .replace("[i]", "_") \
.replace("[/i]", "_") \ .replace("[/i]", "_") \
.replace("[u]", "__") \ .replace("[u]", "__") \
.replace("[/u]", "__") \ .replace("[/u]", "__") \
.replace("[c]", "`") \ .replace("[c]", "`") \
.replace("[/c]", "`") .replace("[/c]", "`")
await call.channel.send(escaped_text) await call.channel.send(escaped_text)
async def net_request(call, message: Message, destination: str): async def net_request(call, message: Message, destination: str):
@ -98,6 +110,7 @@ class DiscordBot:
await channel.connect() await channel.connect()
except discord.errors.ClientException: except discord.errors.ClientException:
# Move to the selected channel, instead of connecting # Move to the selected channel, instead of connecting
# noinspection PyUnusedLocal
for voice_client in self.bot.voice_clients: for voice_client in self.bot.voice_clients:
voice_client: discord.VoiceClient voice_client: discord.VoiceClient
if voice_client.guild != channel.guild: if voice_client.guild != channel.guild:
@ -133,38 +146,71 @@ class DiscordBot:
self.DiscordClient = DiscordClient self.DiscordClient = DiscordClient
self.bot = self.DiscordClient() self.bot = self.DiscordClient()
def find_guild(self, identifier: typing.Union[str, int]):
"""Find the Guild with the specified identifier. Names are case-insensitive."""
if isinstance(identifier, str):
all_guilds: typing.List[discord.Guild] = self.bot.guilds
matching_channels: typing.List[discord.Guild] = []
for guild in all_guilds:
if guild.name.lower() == identifier.lower():
matching_channels.append(guild)
if len(matching_channels) == 0:
raise NoneFoundError("No channels were found")
elif len(matching_channels) > 1:
raise TooManyFoundError("Too many channels were found")
return matching_channels[0]
elif isinstance(identifier, int):
return self.bot.get_guild(identifier)
raise TypeError("Invalid identifier type, should be str or int")
def find_channel(self, identifier: typing.Union[str, int], guild: typing.Optional[discord.Guild] = None):
"""Find the GuildChannel with the specified identifier. Names are case-insensitive."""
if isinstance(identifier, str):
if guild is not None:
all_channels = guild.channels
else:
all_channels: typing.List[discord.abc.GuildChannel] = self.bot.get_all_channels()
matching_channels: typing.List[discord.abc.GuildChannel] = []
for channel in all_channels:
if not (isinstance(channel, discord.TextChannel)
or isinstance(channel, discord.VoiceChannel)
or isinstance(channel, discord.CategoryChannel)):
continue
if channel.name.lower() == identifier.lower():
matching_channels.append(channel)
if len(matching_channels) == 0:
raise NoneFoundError("No channels were found")
elif len(matching_channels) > 1:
raise TooManyFoundError("Too many channels were found")
return matching_channels[0]
elif isinstance(identifier, int):
channel: typing.List[discord.abc.GuildChannel] = self.bot.get_channel(identifier)
if ((isinstance(channel, discord.TextChannel)
or isinstance(channel, discord.VoiceChannel)
or isinstance(channel, discord.CategoryChannel))
and guild):
assert channel.guild == guild
return channel
raise TypeError("Invalid identifier type, should be str or int")
async def network_handler(self, message: Message) -> Message: async def network_handler(self, message: Message) -> Message:
"""Handle a Royalnet request."""
if isinstance(message, SummonMessage): if isinstance(message, SummonMessage):
return await self.nh_summon(message) return await self.nh_summon(message)
elif isinstance(message, PlayMessage): elif isinstance(message, PlayMessage):
return await self.nh_play(message) return await self.nh_play(message)
async def nh_summon(self, message: SummonMessage): async def nh_summon(self, message: SummonMessage):
channels: typing.List[discord.abc.GuildChannel] = self.bot.get_all_channels() """Handle a summon Royalnet request. That is, join a voice channel, or move to a different one if that is not possible."""
matching_channels: typing.List[discord.VoiceChannel] = [] channel = self.find_channel(message.channel_identifier)
for channel in channels: if not isinstance(channel, discord.VoiceChannel):
if isinstance(channel, discord.VoiceChannel): raise NoneFoundError("Channel is not a voice channel")
if channel.name == message.channel_name: loop.create_task(self.bot.vc_connect_or_move(channel))
matching_channels.append(channel)
if len(matching_channels) == 0:
return RequestError("No channels with a matching name found")
elif len(matching_channels) > 1:
return RequestError("Multiple channels with a matching name found")
matching_channel = matching_channels[0]
await self.bot.vc_connect_or_move(matching_channel)
return RequestSuccessful() return RequestSuccessful()
async def nh_play(self, message: PlayMessage): async def nh_play(self, message: PlayMessage):
# TODO: actually do what's intended to do """Handle a play Royalnet request. That is, add audio to a PlayMode."""
# Download the audio raise
file = await asyncify(RoyalAudioFile.create_from_url, message.url)
# Get the audio source
audio_source = file[0].as_audio_source()
# Play the audio source
for voice_client in self.bot.voice_clients:
voice_client: discord.VoiceClient
voice_client.play(audio_source)
return RequestError()
async def run(self): async def run(self):
await self.bot.login(self.token) await self.bot.login(self.token)

View file

@ -1,11 +1,7 @@
import typing import typing
from ..utils import Command, Call from ..utils import Command, Call
from ..network import Message, RequestSuccessful, RequestError from ..network import Message, RequestSuccessful, RequestError
from ..bots.discord import PlayMessage
class PlayMessage(Message):
def __init__(self, url: str):
self.url: str = url
class PlayCommand(Command): class PlayCommand(Command):
@ -17,10 +13,5 @@ class PlayCommand(Command):
async def common(cls, call: Call): async def common(cls, call: Call):
url: str = call.args[0] url: str = call.args[0]
response: typing.Union[RequestSuccessful, RequestError] = await call.net_request(PlayMessage(url), "discord") response: typing.Union[RequestSuccessful, RequestError] = await call.net_request(PlayMessage(url), "discord")
if isinstance(response, RequestSuccessful): response.raise_on_error()
await call.reply(f"✅ Richiesta la riproduzione di [c]{url}[/c].") await call.reply(f"✅ Richiesta la riproduzione di [c]{url}[/c].")
return
elif isinstance(response, RequestError):
await call.reply(f"⚠️ Si è verificato un'errore nella richiesta di riproduzione:\n[c]{response.reason}[/c]")
return
raise TypeError(f"Received unexpected response in the PlayCommand: {response.__class__.__name__}")

View file

@ -2,11 +2,7 @@ import typing
import discord import discord
from ..utils import Command, Call from ..utils import Command, Call
from ..network import Message, RequestSuccessful, RequestError from ..network import Message, RequestSuccessful, RequestError
from ..bots.discord import SummonMessage
class SummonMessage(Message):
def __init__(self, channel_name: str):
self.channel_name: str = channel_name
class SummonCommand(Command): class SummonCommand(Command):
@ -19,13 +15,8 @@ class SummonCommand(Command):
async def common(cls, call: Call): async def common(cls, call: Call):
channel_name: str = call.args[0].lstrip("#") channel_name: str = call.args[0].lstrip("#")
response: typing.Union[RequestSuccessful, RequestError] = await call.net_request(SummonMessage(channel_name), "discord") response: typing.Union[RequestSuccessful, RequestError] = await call.net_request(SummonMessage(channel_name), "discord")
if isinstance(response, RequestError): response.raise_on_error()
await call.reply(f"⚠️ Si è verificato un'errore nella richiesta di connessione:\n[c]{response.exc}[/c]") await call.reply(f"✅ Mi sono connesso in [c]#{channel_name}[/c].")
return
elif isinstance(response, RequestSuccessful):
await call.reply(f"✅ Mi sono connesso in [c]#{channel_name}[/c].")
return
raise TypeError(f"Received unexpected response type while summoning the bot: {response.__class__.__name__}")
@classmethod @classmethod
async def discord(cls, call: Call): async def discord(cls, call: Call):

View file

@ -2,6 +2,9 @@ class Message:
def __repr__(self): def __repr__(self):
return f"<{self.__class__.__name__}>" return f"<{self.__class__.__name__}>"
def raise_on_error(self):
pass
class IdentifySuccessfulMessage(Message): class IdentifySuccessfulMessage(Message):
pass pass
@ -32,3 +35,6 @@ class RequestSuccessful(Message):
class RequestError(Message): class RequestError(Message):
def __init__(self, exc: Exception): def __init__(self, exc: Exception):
self.exc = exc self.exc = exc
def raise_on_error(self):
raise self.exc