mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-23 19:44:20 +00:00
Working discord bot implementation! :O
This commit is contained in:
parent
c907422156
commit
49382b9bc1
14 changed files with 197 additions and 52 deletions
|
@ -18,6 +18,7 @@ tg_bot = TelegramBot(os.environ["TG_AK"], "localhost:1234", "sas", commands, os.
|
||||||
ds_bot = DiscordBot(os.environ["DS_AK"], "localhost:1234", "sas", commands, os.environ["DB_PATH"], Royal, Discord, "discord_id", error_command=ErrorHandlerCommand)
|
ds_bot = DiscordBot(os.environ["DS_AK"], "localhost:1234", "sas", commands, os.environ["DB_PATH"], Royal, Discord, "discord_id", error_command=ErrorHandlerCommand)
|
||||||
loop.create_task(master.run())
|
loop.create_task(master.run())
|
||||||
loop.create_task(tg_bot.run())
|
loop.create_task(tg_bot.run())
|
||||||
|
loop.create_task(ds_bot.run())
|
||||||
print("Commands enabled:")
|
print("Commands enabled:")
|
||||||
print(tg_bot.generate_botfather_command_string())
|
print(tg_bot.generate_botfather_command_string())
|
||||||
print("Starting loop...")
|
print("Starting loop...")
|
||||||
|
|
|
@ -2,6 +2,7 @@ import discord
|
||||||
import asyncio
|
import asyncio
|
||||||
import typing
|
import typing
|
||||||
import logging as _logging
|
import logging as _logging
|
||||||
|
import sys
|
||||||
from ..commands import NullCommand
|
from ..commands import NullCommand
|
||||||
from ..utils import asyncify, Call, Command, UnregisteredError
|
from ..utils import asyncify, Call, Command, UnregisteredError
|
||||||
from ..network import RoyalnetLink, Message
|
from ..network import RoyalnetLink, Message
|
||||||
|
@ -16,10 +17,6 @@ async def todo(message: Message):
|
||||||
|
|
||||||
|
|
||||||
class DiscordBot:
|
class DiscordBot:
|
||||||
# noinspection PyMethodParameters
|
|
||||||
class DiscordClient(discord.Client):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
token: str,
|
token: str,
|
||||||
master_server_uri: str,
|
master_server_uri: str,
|
||||||
|
@ -32,13 +29,14 @@ 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
|
||||||
self.bot = self.DiscordClient()
|
self.missing_command = missing_command
|
||||||
|
self.error_command = error_command
|
||||||
self.network: RoyalnetLink = RoyalnetLink(master_server_uri, master_server_secret, "discord", todo)
|
self.network: RoyalnetLink = RoyalnetLink(master_server_uri, master_server_secret, "discord", todo)
|
||||||
# Generate commands
|
# Generate commands
|
||||||
self.commands = {}
|
self.commands = {}
|
||||||
required_tables = set()
|
required_tables = set()
|
||||||
for command in commands:
|
for command in commands:
|
||||||
self.commands[f"/{command.command_name}"] = command
|
self.commands[f"!{command.command_name}"] = command
|
||||||
required_tables = required_tables.union(command.require_alchemy_tables)
|
required_tables = required_tables.union(command.require_alchemy_tables)
|
||||||
# Generate the Alchemy database
|
# Generate the Alchemy database
|
||||||
self.alchemy = Alchemy(database_uri, required_tables)
|
self.alchemy = Alchemy(database_uri, required_tables)
|
||||||
|
@ -51,6 +49,7 @@ class DiscordBot:
|
||||||
class DiscordCall(Call):
|
class DiscordCall(Call):
|
||||||
interface_name = "discord"
|
interface_name = "discord"
|
||||||
interface_obj = self
|
interface_obj = self
|
||||||
|
interface_prefix = "!"
|
||||||
alchemy = self.alchemy
|
alchemy = self.alchemy
|
||||||
|
|
||||||
async def reply(call, text: str):
|
async def reply(call, text: str):
|
||||||
|
@ -85,6 +84,37 @@ class DiscordBot:
|
||||||
|
|
||||||
self.DiscordCall = DiscordCall
|
self.DiscordCall = DiscordCall
|
||||||
|
|
||||||
|
# noinspection PyMethodParameters
|
||||||
|
class DiscordClient(discord.Client):
|
||||||
|
async def on_message(cli, message: discord.Message):
|
||||||
|
text = message.content
|
||||||
|
# Skip non-text messages
|
||||||
|
if not text:
|
||||||
|
return
|
||||||
|
# Find and clean parameters
|
||||||
|
command_text, *parameters = text.split(" ")
|
||||||
|
# Find the function
|
||||||
|
try:
|
||||||
|
selected_command = self.commands[command_text]
|
||||||
|
except KeyError:
|
||||||
|
# Skip inexistent commands
|
||||||
|
selected_command = self.missing_command
|
||||||
|
# Call the command
|
||||||
|
try:
|
||||||
|
return await self.DiscordCall(message.channel, selected_command, parameters, log,
|
||||||
|
message=message).run()
|
||||||
|
except Exception as exc:
|
||||||
|
try:
|
||||||
|
return await self.DiscordCall(message.channel, self.error_command, parameters, log,
|
||||||
|
message=message,
|
||||||
|
exception_info=sys.exc_info(),
|
||||||
|
previous_command=selected_command).run()
|
||||||
|
except Exception as exc2:
|
||||||
|
log.error(f"Exception in error handler command: {exc2}")
|
||||||
|
|
||||||
|
self.DiscordClient = DiscordClient
|
||||||
|
self.bot = self.DiscordClient()
|
||||||
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
await self.bot.login(self.token)
|
await self.bot.login(self.token)
|
||||||
await self.bot.connect()
|
await self.bot.connect()
|
||||||
|
|
|
@ -51,6 +51,7 @@ class TelegramBot:
|
||||||
class TelegramCall(Call):
|
class TelegramCall(Call):
|
||||||
interface_name = "telegram"
|
interface_name = "telegram"
|
||||||
interface_obj = self
|
interface_obj = self
|
||||||
|
interface_prefix = "/"
|
||||||
alchemy = self.alchemy
|
alchemy = self.alchemy
|
||||||
|
|
||||||
async def reply(call, text: str):
|
async def reply(call, text: str):
|
||||||
|
|
|
@ -11,10 +11,6 @@ class ErrorHandlerCommand(Command):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def common(cls, call: Call):
|
async def common(cls, call: Call):
|
||||||
raise UnsupportedError()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
async def telegram(cls, call: Call):
|
|
||||||
try:
|
try:
|
||||||
e_type, e_value, e_tb = call.kwargs["exception_info"]
|
e_type, e_value, e_tb = call.kwargs["exception_info"]
|
||||||
except InvalidInputError:
|
except InvalidInputError:
|
||||||
|
@ -22,7 +18,7 @@ class ErrorHandlerCommand(Command):
|
||||||
return
|
return
|
||||||
if e_type == InvalidInputError:
|
if e_type == InvalidInputError:
|
||||||
command = call.kwargs["previous_command"]
|
command = call.kwargs["previous_command"]
|
||||||
await call.reply(f"⚠️ Sintassi non valida.\nSintassi corretta: [c]/{command.command_name} {command.command_syntax}[/c]")
|
await call.reply(f"⚠️ Sintassi non valida.\nSintassi corretta: [c]{call.interface_prefix}{command.command_name} {command.command_syntax}[/c]")
|
||||||
return
|
return
|
||||||
if e_type == UnregisteredError:
|
if e_type == UnregisteredError:
|
||||||
await call.reply("⚠️ Devi essere registrato a Royalnet per usare questo comando!")
|
await call.reply("⚠️ Devi essere registrato a Royalnet per usare questo comando!")
|
||||||
|
|
|
@ -26,7 +26,7 @@ class Alchemy:
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# Actually the intended result
|
# Actually the intended result
|
||||||
# TODO: here is the problem!
|
# TODO: here is the problem!
|
||||||
self.__setattr__(name, type(name, (self.Base,), cdj(table)))
|
self.__setattr__(name, type(name, (self.Base, table), {}))
|
||||||
else:
|
else:
|
||||||
raise NameError(f"{name} is a reserved name and can't be used as a table name")
|
raise NameError(f"{name} is a reserved name and can't be used as a table name")
|
||||||
self.Base.metadata.create_all()
|
self.Base.metadata.create_all()
|
||||||
|
|
|
@ -3,16 +3,29 @@ from sqlalchemy import Column, \
|
||||||
Integer, \
|
Integer, \
|
||||||
ForeignKey
|
ForeignKey
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
|
from .royals import Royal
|
||||||
|
from .keygroup import Keygroup
|
||||||
|
|
||||||
|
|
||||||
class ActiveKvGroup:
|
class ActiveKvGroup:
|
||||||
__tablename__ = "activekvgroups"
|
__tablename__ = "activekvgroups"
|
||||||
|
|
||||||
royal_id = Column(Integer, ForeignKey("royals.uid"), primary_key=True)
|
@declared_attr
|
||||||
group_name = Column(String, ForeignKey("keygroups.group_name"), nullable=False)
|
def royal_id(self):
|
||||||
|
return Column(Integer, ForeignKey("royals.uid"), primary_key=True)
|
||||||
|
|
||||||
royal = relationship("Royal", backref="active_kv_group")
|
@declared_attr
|
||||||
group = relationship("Keygroup", backref="users_with_this_active")
|
def group_name(self):
|
||||||
|
return Column(String, ForeignKey("keygroups.group_name"), nullable=False)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def royal(self):
|
||||||
|
return relationship("Royal", backref="active_kv_group")
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def group(self):
|
||||||
|
return relationship("Keygroup", backref="users_with_this_active")
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<ActiveKvGroup royal={self.royal} group={self.group_name}>"
|
return f"<ActiveKvGroup royal={self.royal} group={self.group_name}>"
|
||||||
|
|
|
@ -3,16 +3,24 @@ from sqlalchemy import Column, \
|
||||||
String, \
|
String, \
|
||||||
ForeignKey
|
ForeignKey
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
from .royals import Royal
|
from .royals import Royal
|
||||||
|
|
||||||
|
|
||||||
class Alias:
|
class Alias:
|
||||||
__tablename__ = "aliases"
|
__tablename__ = "aliases"
|
||||||
|
|
||||||
royal_id = Column(Integer, ForeignKey("royals.uid"))
|
@declared_attr
|
||||||
alias = Column(String, primary_key=True)
|
def royal_id(self):
|
||||||
|
return Column(Integer, ForeignKey("royals.uid"))
|
||||||
|
|
||||||
royal = relationship("Royal", backref="aliases")
|
@declared_attr
|
||||||
|
def alias(self):
|
||||||
|
return Column(String, primary_key=True)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def royal(self):
|
||||||
|
return relationship("Royal", backref="aliases")
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Alias {str(self)}>"
|
return f"<Alias {str(self)}>"
|
||||||
|
|
|
@ -7,24 +7,56 @@ from sqlalchemy import Column, \
|
||||||
ForeignKey, \
|
ForeignKey, \
|
||||||
String
|
String
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
from .royals import Royal
|
from .royals import Royal
|
||||||
|
|
||||||
|
|
||||||
class Diario:
|
class Diario:
|
||||||
__tablename__ = "diario"
|
__tablename__ = "diario"
|
||||||
|
|
||||||
diario_id = Column(Integer, primary_key=True)
|
@declared_attr
|
||||||
creator_id = Column(Integer, ForeignKey("royals.uid"), nullable=False)
|
def diario_id(self):
|
||||||
quoted_account_id = Column(Integer, ForeignKey("royals.uid"))
|
return Column(Integer, primary_key=True)
|
||||||
quoted = Column(String)
|
|
||||||
text = Column(Text)
|
|
||||||
context = Column(Text)
|
|
||||||
timestamp = Column(DateTime, nullable=False)
|
|
||||||
media_url = Column(String)
|
|
||||||
spoiler = Column(Boolean, default=False)
|
|
||||||
|
|
||||||
creator = relationship("Royal", foreign_keys=creator_id, backref="diario_created")
|
@declared_attr
|
||||||
quoted_account = relationship("Royal", foreign_keys=quoted_account_id, backref="diario_quoted")
|
def creator_id(self):
|
||||||
|
return Column(Integer, ForeignKey("royals.uid"), nullable=False)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def quoted_account_id(self):
|
||||||
|
return Column(Integer, ForeignKey("royals.uid"))
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def quoted(self):
|
||||||
|
return Column(String)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def text(self):
|
||||||
|
return Column(Text)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def context(self):
|
||||||
|
return Column(Text)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def timestamp(self):
|
||||||
|
return Column(DateTime, nullable=False)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def media_url(self):
|
||||||
|
return Column(String)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def spoiler(self):
|
||||||
|
return Column(Boolean, default=False)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def creator(self):
|
||||||
|
return relationship("Royal", 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")
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Diario diario_id={self.diario_id} creator_id={self.creator_id} quoted_account_id={self.quoted_account_id} quoted={self.quoted} text={self.text} context={self.context} timestamp={self.timestamp} media_url={self.media_url} spoiler={self.spoiler}>"
|
return f"<Diario diario_id={self.diario_id} creator_id={self.creator_id} quoted_account_id={self.quoted_account_id} quoted={self.quoted} text={self.text} context={self.context} timestamp={self.timestamp} media_url={self.media_url} spoiler={self.spoiler}>"
|
||||||
|
|
|
@ -4,19 +4,36 @@ from sqlalchemy import Column, \
|
||||||
BigInteger, \
|
BigInteger, \
|
||||||
ForeignKey
|
ForeignKey
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
from .royals import Royal
|
from .royals import Royal
|
||||||
|
|
||||||
|
|
||||||
class Discord:
|
class Discord:
|
||||||
__tablename__ = "discord"
|
__tablename__ = "discord"
|
||||||
|
|
||||||
royal_id = Column(Integer, ForeignKey("royals.uid"))
|
@declared_attr
|
||||||
discord_id = Column(BigInteger, primary_key=True)
|
def royal_id(self):
|
||||||
username = Column(String)
|
return Column(Integer, ForeignKey("royals.uid"))
|
||||||
discriminator = Column(String)
|
|
||||||
avatar_hash = Column(String)
|
|
||||||
|
|
||||||
royal = relationship("Royal", backref="discord")
|
@declared_attr
|
||||||
|
def discord_id(self):
|
||||||
|
return Column(BigInteger, primary_key=True)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def username(self):
|
||||||
|
return Column(String)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def discriminator(self):
|
||||||
|
return Column(String)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def avatar_hash(self):
|
||||||
|
return Column(String)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def royal(self):
|
||||||
|
return relationship("Royal", backref="discord")
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Discord {str(self)}>"
|
return f"<Discord {str(self)}>"
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
from sqlalchemy import Column, \
|
from sqlalchemy import Column, \
|
||||||
String, \
|
String, \
|
||||||
ForeignKey
|
ForeignKey
|
||||||
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
|
|
||||||
|
|
||||||
class Keygroup:
|
class Keygroup:
|
||||||
__tablename__ = "keygroups"
|
__tablename__ = "keygroups"
|
||||||
|
|
||||||
group_name = Column(String, ForeignKey("keygroups.group_name"), primary_key=True)
|
@declared_attr
|
||||||
|
def group_name(self):
|
||||||
|
return Column(String, ForeignKey("keygroups.group_name"), primary_key=True)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Keygroup {self.group_name}>"
|
return f"<Keygroup {self.group_name}>"
|
||||||
|
|
|
@ -2,17 +2,28 @@ from sqlalchemy import Column, \
|
||||||
String, \
|
String, \
|
||||||
ForeignKey
|
ForeignKey
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
from .keygroup import Keygroup
|
from .keygroup import Keygroup
|
||||||
|
|
||||||
|
|
||||||
class Keyvalue:
|
class Keyvalue:
|
||||||
__tablename__ = "keyvalues"
|
__tablename__ = "keyvalues"
|
||||||
|
|
||||||
group_name = Column(String, ForeignKey("keygroups.group_name"), primary_key=True)
|
@declared_attr
|
||||||
key = Column(String, primary_key=True)
|
def group_name(self):
|
||||||
value = Column(String, nullable=False)
|
return Column(String, ForeignKey("keygroups.group_name"), primary_key=True)
|
||||||
|
|
||||||
group = relationship("Keygroup")
|
@declared_attr
|
||||||
|
def key(self):
|
||||||
|
return Column(String, primary_key=True)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def value(self):
|
||||||
|
return Column(String, nullable=False)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def group(self):
|
||||||
|
return relationship("Keygroup")
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Keyvalue group={self.group_name} key={self.key} value={self.value}>"
|
return f"<Keyvalue group={self.group_name} key={self.key} value={self.value}>"
|
||||||
|
|
|
@ -2,16 +2,31 @@ from sqlalchemy import Column, \
|
||||||
Integer, \
|
Integer, \
|
||||||
String, \
|
String, \
|
||||||
LargeBinary
|
LargeBinary
|
||||||
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
|
|
||||||
|
|
||||||
class Royal:
|
class Royal:
|
||||||
__tablename__ = "royals"
|
__tablename__ = "royals"
|
||||||
|
|
||||||
uid = Column(Integer, unique=True, primary_key=True)
|
@declared_attr
|
||||||
username = Column(String, unique=True, nullable=False)
|
def uid(self):
|
||||||
password = Column(LargeBinary)
|
return Column(Integer, unique=True, primary_key=True)
|
||||||
role = Column(String, nullable=False)
|
|
||||||
avatar = Column(LargeBinary)
|
@declared_attr
|
||||||
|
def username(self):
|
||||||
|
return Column(String, unique=True, nullable=False)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def password(self):
|
||||||
|
return Column(LargeBinary)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def role(self):
|
||||||
|
return Column(String, nullable=False)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def avatar(self):
|
||||||
|
return Column(LargeBinary)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Royal {self.username}>"
|
return f"<Royal {self.username}>"
|
||||||
|
|
|
@ -5,19 +5,36 @@ from sqlalchemy import Column, \
|
||||||
LargeBinary, \
|
LargeBinary, \
|
||||||
ForeignKey
|
ForeignKey
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
from .royals import Royal
|
from .royals import Royal
|
||||||
|
|
||||||
|
|
||||||
class Telegram:
|
class Telegram:
|
||||||
__tablename__ = "telegram"
|
__tablename__ = "telegram"
|
||||||
|
|
||||||
royal_id = Column(Integer, ForeignKey("royals.uid"))
|
@declared_attr
|
||||||
tg_id = Column(BigInteger, primary_key=True)
|
def royal_id(self):
|
||||||
first_name = Column(String)
|
return Column(Integer, ForeignKey("royals.uid"))
|
||||||
last_name = Column(String)
|
|
||||||
username = Column(String)
|
|
||||||
|
|
||||||
royal = relationship("Royal", backref="telegram")
|
@declared_attr
|
||||||
|
def tg_id(self):
|
||||||
|
return Column(BigInteger, primary_key=True)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def first_name(self):
|
||||||
|
return Column(String)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def last_name(self):
|
||||||
|
return Column(String)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def username(self):
|
||||||
|
return Column(String)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def royal(self):
|
||||||
|
return relationship("Royal", backref="telegram")
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Telegram {str(self)}>"
|
return f"<Telegram {str(self)}>"
|
||||||
|
|
|
@ -20,6 +20,7 @@ class Call:
|
||||||
# These parameters / methods should be overridden
|
# These parameters / methods should be overridden
|
||||||
interface_name = NotImplemented
|
interface_name = NotImplemented
|
||||||
interface_obj = NotImplemented
|
interface_obj = NotImplemented
|
||||||
|
interface_prefix = NotImplemented
|
||||||
alchemy: "Alchemy" = NotImplemented
|
alchemy: "Alchemy" = NotImplemented
|
||||||
|
|
||||||
async def reply(self, text: str):
|
async def reply(self, text: str):
|
||||||
|
|
Loading…
Reference in a new issue