Switch to asyncio and slixmpp

This commit is contained in:
Alexei Sorokin 2017-06-04 15:32:26 +03:00
parent b702c1af45
commit aa67de2acc
3 changed files with 47 additions and 56 deletions

View File

@ -1,10 +1,10 @@
# hybridbot # hybridbot
Hybridbot is a bot that relays messages from a IRC channel to an XMPP MUC and vice versa. First of all, you need to install sleekxmpp and irc. Hybridbot is a bot that relays messages from a IRC channel to an XMPP MUC and vice versa. First of all, you need to install slixmpp and irc.
su -c "pip install sleekxmpp irc" su -c "pip3 install slixmpp irc"
# or # or
su -c "pip install -r requirements.txt" su -c "pip3 install -r requirements.txt"
It's configuration is simple, you have to create a config file per relay, as this example (remember to change the values): It's configuration is simple, you have to create a config file per relay, as this example (remember to change the values):
@ -32,10 +32,10 @@ The option "owner" is a string that will be printed when issuing the ".help" com
To execute it, just do: To execute it, just do:
python hybridbot.py myconfig.ini python3 hybridbot.py myconfig.ini
Or if the config file is named "config.ini", just do: Or if the config file is named "config.ini", just do:
python hybridbot.py python3 hybridbot.py
And on the MUC or the IRC channel, you can issue two commands, ".help" and ".users". And on the MUC or the IRC channel, you can issue two commands, ".help" and ".users".

View File

@ -1,23 +1,19 @@
#!/usr/bin/env python #!/usr/bin/env python3
# -*- coding: utf-8 -*-
import asyncio
import re import re
import signal import signal
import sys import sys
import time import time
import sleekxmpp import slixmpp
if sys.version_info.major >= 3: from configparser import SafeConfigParser
from configparser import SafeConfigParser
else:
from ConfigParser import SafeConfigParser
from threading import Thread
from irc.bot import SingleServerIRCBot from irc.bot import SingleServerIRCBot
class IRCBot: class IRCBot:
def __init__(self, opts, inter): def __init__(self, opts, inter):
self.client = SingleServerIRCBot([(opts['server'], opts['port'])], self.client = SingleServerIRCBot([(opts['server'], opts['port'])],
opts['nick'], opts['nick']) opts['nick'], opts['nick'])
self.conn = self.client.connection self.conn = self.client.connection
self.opts = opts self.opts = opts
self.nick = opts['nick'] self.nick = opts['nick']
@ -68,7 +64,7 @@ class IRCBot:
if nick not in self.inter.get_irc_users(): if nick not in self.inter.get_irc_users():
self.inter.append_irc_user(nick) self.inter.append_irc_user(nick)
except Exception as e: except Exception as e:
sys.stderr.write(str(e) + '\n') print(str(e), file=sys.stderr)
def on_namreply(self, conn, event): def on_namreply(self, conn, event):
for nick in event.arguments[2].split(): for nick in event.arguments[2].split():
@ -101,19 +97,16 @@ class IRCBot:
self.conn.privmsg(self.chan, prefix + r) self.conn.privmsg(self.chan, prefix + r)
except Exception as e: except Exception as e:
sys.stderr.write(str(e) + '\n') print(str(e), file=sys.stderr)
def start(self): def run(self):
self.register_handlers() self.register_handlers()
self.client.start() self.client.start()
class XMPPBot: class XMPPBot:
def __init__(self, opts, inter): def __init__(self, opts, inter):
if sys.version_info.major < 3: self.client = slixmpp.ClientXMPP(opts['jid'], opts['passwd'])
sleekxmpp.util.misc_ops.setdefaultencoding('utf-8')
self.client = sleekxmpp.ClientXMPP(opts['jid'], opts['passwd'])
self.opts = opts self.opts = opts
self.nick = opts['nick'] self.nick = opts['nick']
self.pure_nick = self.nick self.pure_nick = self.nick
@ -121,6 +114,8 @@ class XMPPBot:
self.inter = inter self.inter = inter
def register_handlers(self): def register_handlers(self):
self.client.add_event_handler('failed_all_auth',
self.on_failed_all_auth)
self.client.add_event_handler('session_start', self.on_session_start) self.client.add_event_handler('session_start', self.on_session_start)
self.client.add_event_handler('session_end', self.on_session_end) self.client.add_event_handler('session_end', self.on_session_end)
self.client.add_event_handler('groupchat_message', self.on_message) self.client.add_event_handler('groupchat_message', self.on_message)
@ -128,22 +123,24 @@ class XMPPBot:
self.on_presence) self.on_presence)
def connect(self): def connect(self):
if not self.client.connect(): self.client.connect()
# sys.stderr.write('could not connect!\n')
sys.stderr.write('Could not connect to server, or password ' +
'mismatch!\n')
sys.exit(1)
# sys.stderr.write('connected with %s\n'%con)
def join_muc(self): def join_muc(self):
muc_plugin = self.client.plugin['xep_0045'] muc_plugin = self.client.plugin['xep_0045']
muc_plugin.joinMUC(self.muc, self.nick) muc_plugin.join_muc(self.muc, self.nick)
def on_failed_all_auth(event):
# print('could not connect!', file=sys.stderr)
print('Could not connect to the server, or password mismatch!',
file=sys.stderr)
sys.exit(1)
def on_session_start(self, event): def on_session_start(self, event):
# print('connected with %s' %con, file=sys.stderr)
print('Connected to XMPP') print('Connected to XMPP')
self.client.get_roster()
self.client.send_presence() self.client.send_presence()
self.client.get_roster()
self.join_muc() self.join_muc()
def on_session_end(self, event): def on_session_end(self, event):
@ -165,7 +162,7 @@ class XMPPBot:
if not typ: if not typ:
typ = event['type'] typ = event['type']
if not nick: if not nick:
nick = muc_plugin.getNick(self.muc, event['from']) nick = muc_plugin.get_nick(self.muc, event['from'])
if typ == 'error': if typ == 'error':
if event['error']['code'] == '409': if event['error']['code'] == '409':
@ -187,7 +184,7 @@ class XMPPBot:
self.inter.append_xmpp_user(nick) self.inter.append_xmpp_user(nick)
except Exception as e: except Exception as e:
sys.stderr.write(str(e) + '\n') print(str(e), file=sys.stderr)
def send_message(self, msg, prefix=''): def send_message(self, msg, prefix=''):
try: try:
@ -197,18 +194,19 @@ class XMPPBot:
mtype='groupchat') mtype='groupchat')
except Exception as e: except Exception as e:
sys.stderr.write(str(e) + '\n') print(str(e), file=sys.stderr)
def start(self): @asyncio.coroutine
def run(self):
self.client.register_plugin('xep_0045') # XMPP MUC. self.client.register_plugin('xep_0045') # XMPP MUC.
self.client.register_plugin('xep_0199') # XMPP Ping. self.client.register_plugin('xep_0199') # XMPP Ping.
self.register_handlers() self.register_handlers()
self.connect() self.connect()
self.client.process(block=True)
class Intermedia: class Intermedia:
def __init__(self, shared_opts, irc_chan, xmpp_muc): def __init__(self, loop, shared_opts, irc_chan, xmpp_muc):
self.loop = loop
self.irc_chan = irc_chan self.irc_chan = irc_chan
self.xmpp_muc = xmpp_muc self.xmpp_muc = xmpp_muc
self.ircbot = None self.ircbot = None
@ -229,7 +227,7 @@ class Intermedia:
def to_xmpp(self, msg, prefix=''): def to_xmpp(self, msg, prefix=''):
if self.xmppbot: if self.xmppbot:
self.xmppbot.send_message(msg, prefix) loop.call_soon_threadsafe(self.xmppbot.send_message, msg, prefix)
def relay_message(self, from_net, nick, body): def relay_message(self, from_net, nick, body):
if not self.ircbot or not self.xmppbot: if not self.ircbot or not self.xmppbot:
@ -292,7 +290,7 @@ class Intermedia:
prefix=nick_prefix) prefix=nick_prefix)
except Exception as e: except Exception as e:
sys.stderr.write(str(e) + '\n') print(str(e), file=sys.stderr)
def get_irc_users(self): def get_irc_users(self):
return self.irc_users return self.irc_users
@ -324,7 +322,8 @@ if __name__ == '__main__':
config.read('config.ini') config.read('config.ini')
if not config.sections(): if not config.sections():
sys.stderr.write('Error: Configuration file does not exist or is empty.\n') print('Error: Configuration file does not exist or is empty.',
file=sys.stderr)
sys.exit(1) sys.exit(1)
shared_opts['prefix'] = config.get('Shared', 'prefix') shared_opts['prefix'] = config.get('Shared', 'prefix')
@ -341,22 +340,14 @@ if __name__ == '__main__':
xmpp_opts['nick'] = config.get('XMPP', 'nick') xmpp_opts['nick'] = config.get('XMPP', 'nick')
signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGINT, signal.SIG_DFL)
loop = asyncio.get_event_loop()
while True: inter = Intermedia(loop, shared_opts, irc_opts['chan'], xmpp_opts['muc'])
inter = Intermedia(shared_opts, irc_opts['chan'], xmpp_opts['muc']) ircbot = IRCBot(irc_opts, inter)
ircbot = IRCBot(irc_opts, inter) xmppbot = XMPPBot(xmpp_opts, inter)
xmppbot = XMPPBot(xmpp_opts, inter) inter.set_bots(ircbot, xmppbot)
inter.set_bots(ircbot, xmppbot)
irc_thread = Thread(target=ircbot.start, args=()) asyncio.async(xmppbot.run())
xmpp_thread = Thread(target=xmppbot.start, args=()) asyncio.async(loop.run_in_executor(None, ircbot.run))
loop.run_forever()
irc_thread.daemon = True loop.close()
xmpp_thread.daemon = True
irc_thread.start()
time.sleep(1)
xmpp_thread.start()
irc_thread.join()
xmpp_thread.join()

View File

@ -1,2 +1,2 @@
sleekxmpp>=1.2.0 slixmpp
irc>=5.0.1 irc>=5.0.1