mirror of
https://github.com/osmarks/autobotrobot
synced 2024-06-26 06:53:15 +00:00
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.
146 lines
5.9 KiB
Python
146 lines
5.9 KiB
Python
import discord
|
|
import toml
|
|
import logging
|
|
import discord.ext.commands as commands
|
|
import discord.ext.tasks as tasks
|
|
import re
|
|
import asyncio
|
|
import json
|
|
import traceback
|
|
import random
|
|
import collections
|
|
import prometheus_client
|
|
import prometheus_async.aio
|
|
import typing
|
|
import sys
|
|
|
|
import tio
|
|
import db
|
|
import util
|
|
import eventbus
|
|
import irc_link
|
|
import achievement
|
|
|
|
config = util.config
|
|
|
|
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(asctime)s %(message)s", datefmt="%H:%M:%S %d/%m/%Y")
|
|
|
|
#intents = discord.Intents.default()
|
|
#intents.members = True
|
|
|
|
bot = commands.Bot(command_prefix=config["prefix"], description="AutoBotRobot, the most useless bot in the known universe." + util.config.get("description_suffix", ""),
|
|
case_insensitive=True, allowed_mentions=discord.AllowedMentions(everyone=False, users=True, roles=True))
|
|
bot._skip_check = lambda x, y: False
|
|
|
|
messages = prometheus_client.Counter("abr_messages", "Messages seen/handled by bot")
|
|
command_invocations = prometheus_client.Counter("abr_command_invocations", "Total commands invoked (includes failed)")
|
|
@bot.event
|
|
async def on_message(message):
|
|
messages.inc()
|
|
words = message.content.split(" ")
|
|
if len(words) == 10 and message.author.id == 435756251205468160:
|
|
await message.channel.send(util.unlyric(message.content))
|
|
else:
|
|
if message.author == bot.user or message.author.discriminator == "0000": return
|
|
ctx = await bot.get_context(message)
|
|
if not ctx.valid: return
|
|
command_invocations.inc()
|
|
await bot.invoke(ctx)
|
|
|
|
command_errors = prometheus_client.Counter("abr_errors", "Count of errors encountered in executing commands.")
|
|
@bot.event
|
|
async def on_command_error(ctx, err):
|
|
if isinstance(err, (commands.CommandNotFound, commands.CheckFailure)): return
|
|
if isinstance(err, commands.CommandInvokeError) and isinstance(err.original, ValueError): return await ctx.send(embed=util.error_embed(str(err.original)))
|
|
if isinstance(err, commands.MissingRequiredArgument): return await ctx.send(embed=util.error_embed(str(err)))
|
|
try:
|
|
command_errors.inc()
|
|
trace = re.sub("\n\n+", "\n", "\n".join(traceback.format_exception(err, err, err.__traceback__)))
|
|
logging.error("command error occured (in %s)", ctx.invoked_with, exc_info=err)
|
|
await ctx.send(embed=util.error_embed(util.gen_codeblock(trace), title="Internal error"))
|
|
await achievement.achieve(ctx.bot, ctx.message, "error")
|
|
except Exception as e: print("meta-error:", e)
|
|
|
|
@bot.check
|
|
async def andrew_bad(ctx):
|
|
return ctx.message.author.id != 543131534685765673
|
|
|
|
@bot.event
|
|
async def on_ready():
|
|
logging.info("Connected as " + bot.user.name)
|
|
await bot.change_presence(status=discord.Status.online,
|
|
activity=discord.Activity(name=f"{bot.command_prefix}help", type=discord.ActivityType.listening))
|
|
|
|
webhooks = {}
|
|
|
|
async def initial_load_webhooks(db):
|
|
for row in await db.execute_fetchall("SELECT * FROM discord_webhooks"):
|
|
webhooks[row["channel_id"]] = row["webhook"]
|
|
|
|
@bot.listen("on_message")
|
|
async def send_to_bridge(msg):
|
|
if msg.author == bot.user or msg.author.discriminator == "0000": return
|
|
if msg.content == "": return
|
|
channel_id = msg.channel.id
|
|
msg = eventbus.Message(eventbus.AuthorInfo(msg.author.name, msg.author.id, str(msg.author.avatar_url), msg.author.bot), msg.content, ("discord", channel_id), msg.id)
|
|
await eventbus.push(msg)
|
|
|
|
async def on_bridge_message(channel_id, msg):
|
|
channel = bot.get_channel(channel_id)
|
|
if channel:
|
|
webhook = webhooks.get(channel_id)
|
|
if webhook:
|
|
wh_obj = discord.Webhook.from_url(webhook, adapter=discord.AsyncWebhookAdapter(bot.http._HTTPClient__session))
|
|
await wh_obj.send(
|
|
content=msg.message, username=msg.author.name, avatar_url=msg.author.avatar_url,
|
|
allowed_mentions=discord.AllowedMentions(everyone=False, roles=False, users=False))
|
|
else:
|
|
text = f"<{msg.author.name}> {msg.message}"
|
|
await channel.send(text[:2000], allowed_mentions=discord.AllowedMentions(everyone=False, roles=False, users=False))
|
|
else:
|
|
logging.warning("channel %d not found", channel_id)
|
|
|
|
eventbus.add_listener("discord", on_bridge_message)
|
|
|
|
visible_users = prometheus_client.Gauge("abr_visible_users", "Users the bot can see")
|
|
def get_visible_users():
|
|
return len(bot.users)
|
|
visible_users.set_function(get_visible_users)
|
|
|
|
heavserver_members = prometheus_client.Gauge("abr_heavserver_members", "Current member count of heavserver")
|
|
heavserver_bots = prometheus_client.Gauge("abr_heavserver_bots", "Current bot count of heavserver")
|
|
def get_heavserver_members():
|
|
if not bot.get_guild(util.config["heavserver"]["id"]): return 0
|
|
return len(bot.get_guild(util.config["heavserver"]["id"]).members)
|
|
def get_heavserver_bots():
|
|
if not bot.get_guild(util.config["heavserver"]["id"]): return 0
|
|
return len([ None for member in bot.get_guild(util.config["heavserver"]["id"]).members if member.bot ])
|
|
heavserver_members.set_function(get_heavserver_members)
|
|
heavserver_bots.set_function(get_heavserver_bots)
|
|
|
|
guild_count = prometheus_client.Gauge("abr_guilds", "Guilds the bot is in")
|
|
def get_guild_count():
|
|
return len(bot.guilds)
|
|
guild_count.set_function(get_guild_count)
|
|
|
|
async def run_bot():
|
|
bot.database = await db.init(config["database"])
|
|
await eventbus.initial_load(bot.database)
|
|
await initial_load_webhooks(bot.database)
|
|
await irc_link.initialize()
|
|
for ext in util.extensions:
|
|
logging.info("loaded %s", ext)
|
|
bot.load_extension(ext)
|
|
await bot.start(config["token"])
|
|
|
|
if __name__ == '__main__':
|
|
loop = asyncio.get_event_loop()
|
|
loop.create_task(prometheus_async.aio.web.start_http_server(port=config["metrics_port"]))
|
|
try:
|
|
loop.run_until_complete(run_bot())
|
|
except KeyboardInterrupt:
|
|
loop.run_until_complete(bot.logout())
|
|
sys.exit(0)
|
|
finally:
|
|
loop.close()
|