1
0
mirror of https://github.com/osmarks/autobotrobot synced 2024-06-26 06:53:15 +00:00
autobotrobot/src/debug.py
osmarks d8344d9759 Unified bridge system
ABR can now bridge to IRC, because of course.
It can also bridge Discord to Discord.
Bridging works transitively because I have a fairly elegant (if I do say so myself) way of handling it:
links are internally point-to-point, and when something is sent in a channel with links configured the bot traverses the graph of links to work out where to send to.
It is planned to expose a private websocket API to synchronize with other servers providing virtual channels.
This system is now used for telephone calls.
There may be issues in certain situations due to the lack of (meaningful) transaction support in aiosqlite.
The telephone command has been extended with (un)link commands, currently only for me as they can link anywhere.
2021-02-25 17:48:06 +00:00

81 lines
3.2 KiB
Python

import asyncio
import traceback
import re
from discord.ext import commands
import util
import eventbus
def setup(bot):
@bot.group(help="Debug/random messing around utilities. Owner-only.")
@commands.check(util.admin_check)
async def magic(ctx):
if ctx.invoked_subcommand == None:
return await ctx.send("Invalid magic command.")
@magic.command(rest_is_raw=True, brief="Execute Python.")
async def py(ctx, *, code):
"Executes Python. You may supply a codeblock. Comments in the form #timeout:([0-9]+) will be used as a timeout specifier. React with :x: to stop, probably."
timeout = 5.0
timeout_match = re.search("#timeout:([0-9]+)", code, re.IGNORECASE)
if timeout_match:
timeout = int(timeout_match.group(1))
if timeout == 0: timeout = None
code = util.extract_codeblock(code)
try:
loc = {
**locals(),
"bot": bot,
"ctx": ctx,
"db": bot.database,
"util": util,
"eventbus": eventbus
}
def check(re, u): return str(re.emoji) == "" and u == ctx.author
result = None
async def run():
nonlocal result
result = await util.async_exec(code, loc, globals())
halt_task = asyncio.create_task(bot.wait_for("reaction_add", check=check))
exec_task = asyncio.create_task(run())
done, pending = await asyncio.wait((exec_task, halt_task), timeout=timeout, return_when=asyncio.FIRST_COMPLETED)
for task in done: task.result() # get exceptions
for task in pending: task.cancel()
if result != None:
if isinstance(result, str):
await ctx.send(result[:2000])
else:
await ctx.send(util.gen_codeblock(repr(result)))
except (TimeoutError, asyncio.CancelledError):
await ctx.send(embed=util.error_embed("Timed out."))
except BaseException as e:
await ctx.send(embed=util.error_embed(util.gen_codeblock(traceback.format_exc())))
@magic.command(rest_is_raw=True, help="Execute SQL code against the database.")
async def sql(ctx, *, code):
"Executes SQL (and commits). You may use a codeblock, similarly to with py."
code = util.extract_codeblock(code)
try:
csr = bot.database.execute(code)
out = ""
async with csr as cursor:
async for row in cursor:
out += " ".join(map(repr, row)) + "\n"
await ctx.send(util.gen_codeblock(out))
await bot.database.commit()
except Exception as e:
await ctx.send(embed=util.error_embed(util.gen_codeblock(traceback.format_exc())))
@magic.command(help="Reload configuration file.")
async def reload_config(ctx):
util.load_config()
ctx.send("Done!")
@magic.command(help="Reload extensions (all or the specified one).")
async def reload_ext(ctx, ext="all"):
if ext == "all":
for ext in util.extensions: bot.reload_extension(ext)
else: bot.reload_extension(ext)
await ctx.send("Done!")