2021-02-25 17:48:06 +00:00
import eventbus
import asyncio
import irc . client_aio
import random
import util
import logging
import hashlib
2021-03-25 17:56:29 +00:00
import discord . ext . commands as commands
2021-04-18 11:39:49 +00:00
from jaraco . stream import buffer
2021-02-25 17:48:06 +00:00
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 )
2021-03-25 17:56:29 +00:00
def render_formatting ( message ) :
out = " "
for seg in message :
if isinstance ( seg , str ) :
out + = seg . replace ( " \n " , " " )
else :
kind = seg [ " type " ]
2021-10-06 19:53:42 +00:00
# TODO: check if user exists on both ends, and possibly drop if so
2021-03-25 17:56:29 +00:00
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 ' ] } "
2021-10-06 13:58:04 +00:00
elif kind == " role_mention " :
out + = f " @ { random_color ( seg [ ' id ' ] ) } { seg [ ' name ' ] } { color_code ( ' ' ) } "
2021-03-25 17:56:29 +00:00
else : logging . warn ( " Unrecognized message seg %s " , kind )
return out . strip ( )
2021-03-08 10:25:11 +00:00
global_conn = None
2021-03-25 17:56:29 +00:00
unlisten = None
2021-03-08 10:25:11 +00:00
2021-02-25 17:48:06 +00:00
async def initialize ( ) :
2021-03-08 10:25:11 +00:00
logging . info ( " Initializing IRC link " )
2021-02-25 17:48:06 +00:00
joined = set ( )
loop = asyncio . get_event_loop ( )
2021-04-18 11:39:49 +00:00
irc . client . ServerConnection . buffer_class = buffer . LenientDecodingLineBuffer # should not crash in the face of invalid UTF-8
2021-02-25 17:48:06 +00:00
reactor = irc . client_aio . AioReactor ( loop = loop )
conn = await reactor . server ( ) . connect ( util . config [ " irc " ] [ " server " ] , util . config [ " irc " ] [ " port " ] , util . config [ " irc " ] [ " nick " ] )
2021-03-08 10:25:11 +00:00
global global_conn
global_conn = conn
2021-02-25 17:48:06 +00:00
def inuse ( conn , event ) :
conn . nick ( scramble ( conn . get_nickname ( ) ) )
def pubmsg ( conn , event ) :
2021-07-28 19:30:37 +00:00
msg = eventbus . Message ( eventbus . AuthorInfo ( event . source . nick , str ( event . source ) , None ) , [ " " . join ( event . arguments ) ] , ( util . config [ " irc " ] [ " name " ] , event . target ) , util . random_id ( ) , [ ] )
2021-02-25 17:48:06 +00:00
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 )
2021-10-06 14:16:25 +00:00
# if its a reply
2021-10-06 19:53:42 +00:00
dmsg = discord . fetch_message ( msg . id )
if dmsg . reference . message_id :
conn . privmessage ( channel_name , f " Replying to @ { random_color ( dmsg . reference . cached_message . author . id ) } { dmsg . reference . cached_message . author . name } { color_code ( ' ' ) } : " )
2021-03-06 22:25:31 +00:00
# ping fix - zero width space embedded in messages
2021-03-25 17:56:29 +00:00
line = f " < { random_color ( msg . author . id ) } { msg . author . name [ 0 ] } \u200B { msg . author . name [ 1 : ] } { color_code ( ' ' ) } > " + render_formatting ( msg . message ) [ : 400 ]
2021-02-25 17:48:06 +00:00
conn . privmsg ( channel_name , line )
2021-07-28 19:30:37 +00:00
for at in msg . attachments :
conn . privmsg ( channel_name , f " -> { at . filename } : { at . proxy_url } " )
2021-02-25 17:48:06 +00:00
else :
logging . warning ( " IRC channel %s not allowed " , channel_name )
def connect ( conn , event ) :
for channel in util . config [ " irc " ] [ " channels " ] :
2021-05-12 16:32:52 +00:00
conn . join ( channel , key = util . config [ " irc " ] [ " channel_keys " ] . get ( channel , " " ) )
2021-03-25 17:56:29 +00:00
logging . info ( " Connected to %s on IRC " , channel )
2021-02-25 17:48:06 +00:00
joined . add ( channel )
# TODO: do better thing
conn . add_global_handler ( " welcome " , connect )
2021-03-25 17:56:29 +00:00
conn . add_global_handler ( " disconnect " , lambda conn , event : logging . warn ( " Disconnected from IRC " ) )
2021-02-25 17:48:06 +00:00
conn . add_global_handler ( " nicknameinuse " , inuse )
conn . add_global_handler ( " pubmsg " , pubmsg )
2021-03-25 17:56:29 +00:00
global unlisten
unlisten = eventbus . add_listener ( util . config [ " irc " ] [ " name " ] , on_bridge_message )
2021-03-08 10:25:11 +00:00
def setup ( bot ) :
asyncio . create_task ( initialize ( ) )
def teardown ( bot ) :
2021-03-25 17:56:29 +00:00
if global_conn : global_conn . disconnect ( )
2021-05-12 16:32:52 +00:00
if unlisten : unlisten ( )