84 lines
2.9 KiB
Python
84 lines
2.9 KiB
Python
import eventbus
|
|
import asyncio
|
|
import irc.client_aio
|
|
import random
|
|
import util
|
|
import logging
|
|
import hashlib
|
|
import discord.ext.commands as commands
|
|
|
|
def scramble(text):
|
|
n = list(text)
|
|
random.shuffle(n)
|
|
return "".join(n)
|
|
|
|
def color_code(x):
|
|
return f"\x03{x}"
|
|
def random_color(id): return color_code(hashlib.blake2b(str(id).encode("utf-8")).digest()[0] % 13 + 2)
|
|
|
|
def render_formatting(message):
|
|
out = ""
|
|
for seg in message:
|
|
if isinstance(seg, str):
|
|
out += seg.replace("\n", " ")
|
|
else:
|
|
kind = seg["type"]
|
|
# TODO: check if user exists on both ends, and possibly drop if so
|
|
if kind == "user_mention":
|
|
out += f"@{random_color(seg['id'])}{seg['name']}{color_code('')}"
|
|
elif kind == "channel_mention": # these appear to be clickable across servers/guilds
|
|
out += f"#{seg['name']}"
|
|
else: logging.warn("Unrecognized message seg %s", kind)
|
|
return out.strip()
|
|
|
|
global_conn = None
|
|
unlisten = None
|
|
|
|
async def initialize():
|
|
logging.info("Initializing IRC link")
|
|
|
|
joined = set()
|
|
|
|
loop = asyncio.get_event_loop()
|
|
reactor = irc.client_aio.AioReactor(loop=loop)
|
|
conn = await reactor.server().connect(util.config["irc"]["server"], util.config["irc"]["port"], util.config["irc"]["nick"])
|
|
global global_conn
|
|
global_conn = conn
|
|
|
|
def inuse(conn, event):
|
|
conn.nick(scramble(conn.get_nickname()))
|
|
|
|
def pubmsg(conn, event):
|
|
msg = eventbus.Message(eventbus.AuthorInfo(event.source.nick, str(event.source), None), [" ".join(event.arguments)], (util.config["irc"]["name"], event.target), util.random_id())
|
|
asyncio.create_task(eventbus.push(msg))
|
|
|
|
async def on_bridge_message(channel_name, msg):
|
|
if channel_name in util.config["irc"]["channels"]:
|
|
if channel_name not in joined: conn.join(channel_name)
|
|
# ping fix - zero width space embedded in messages
|
|
line = f"<{random_color(msg.author.id)}{msg.author.name[0]}\u200B{msg.author.name[1:]}{color_code('')}> " + render_formatting(msg.message)[:400]
|
|
conn.privmsg(channel_name, line)
|
|
else:
|
|
logging.warning("IRC channel %s not allowed", channel_name)
|
|
|
|
def connect(conn, event):
|
|
for channel in util.config["irc"]["channels"]:
|
|
conn.join(channel)
|
|
logging.info("Connected to %s on IRC", channel)
|
|
joined.add(channel)
|
|
|
|
# TODO: do better thing
|
|
conn.add_global_handler("welcome", connect)
|
|
conn.add_global_handler("disconnect", lambda conn, event: logging.warn("Disconnected from IRC"))
|
|
conn.add_global_handler("nicknameinuse", inuse)
|
|
conn.add_global_handler("pubmsg", pubmsg)
|
|
|
|
global unlisten
|
|
unlisten = eventbus.add_listener(util.config["irc"]["name"], on_bridge_message)
|
|
|
|
def setup(bot):
|
|
asyncio.create_task(initialize())
|
|
|
|
def teardown(bot):
|
|
if global_conn: global_conn.disconnect()
|
|
if unlisten: unlisten() |