comparison bridge.py @ 180:102f895347ff

added a required "importance" argument to Bot.error() Signed-off-by: Charly COSTE <changaco@changaco.net>
author Charly COSTE <changaco@changaco.net>
date Sat, 13 Feb 2010 16:32:28 +0100
parents f6c6708c6c0e
children 60ee2b914616
comparison
equal deleted inserted replaced
179:f6c6708c6c0e 180:102f895347ff
23 import muc 23 import muc
24 xmpp = muc.xmpp 24 xmpp = muc.xmpp
25 del muc 25 del muc
26 26
27 from participant import Participant 27 from participant import Participant
28 import say_levels
28 29
29 30
30 class Bridge: 31 class Bridge:
31 32
32 _all = 0 33 modes = ['bypass', 'normal', 'limited', 'minimal']
33 _info = 1
34 _notice = 2
35 _warning = 3
36 _error = 4
37 _nothing = 5
38 _say_levels = ['all', 'info', 'notice', 'warning', 'error', 'nothing']
39 _modes = ['normal', 'bypass', 'limited', 'minimal']
40
41 34
42 class NoSuchParticipantException(Exception): pass 35 class NoSuchParticipantException(Exception): pass
43 36
44 37
45 def __init__(self, owner_bot, xmpp_room_jid, irc_room, irc_server, mode, say_level, irc_port=6667, irc_connection_interval=None, irc_charsets=None): 38 def __init__(self, owner_bot, xmpp_room_jid, irc_room, irc_server, mode, say_level, irc_port=6667, irc_connection_interval=None, irc_charsets=None):
49 self.irc_port = irc_port 42 self.irc_port = irc_port
50 self.irc_room = irc_room.lower() 43 self.irc_room = irc_room.lower()
51 self.irc_connection_interval = irc_connection_interval 44 self.irc_connection_interval = irc_connection_interval
52 self.irc_charsets = irc_charsets 45 self.irc_charsets = irc_charsets
53 self.xmpp_room_jid = xmpp_room_jid 46 self.xmpp_room_jid = xmpp_room_jid
54 if hasattr(self.__class__, '_'+say_level): 47 self.say_level = say_level
55 self.say_level = getattr(self.__class__, '_'+say_level)
56 else:
57 raise Exception('[Error] "'+say_level+'" is not a correct value for a bridge\'s "say_level" attribute')
58 self.participants = [] 48 self.participants = []
59 if mode not in self.__class__._modes: 49 if mode not in self.__class__.modes:
60 raise Exception('[Error] "'+mode+'" is not a correct value for a bridge\'s "mode" attribute') 50 raise Exception('[Error] "'+mode+'" is not a correct value for a bridge\'s "mode" attribute')
61 self.mode = mode 51 self.mode = mode
62 52
63 self.lock = threading.RLock() 53 self.lock = threading.RLock()
64 54
72 62
73 # Join IRC room 63 # Join IRC room
74 self.irc_connection = self.bot.irc.open_connection(self.irc_server, self.irc_port, self.bot.nickname, delay=self.irc_connection_interval) 64 self.irc_connection = self.bot.irc.open_connection(self.irc_server, self.irc_port, self.bot.nickname, delay=self.irc_connection_interval)
75 self.irc_connection.connect(nick_callback=self._irc_nick_callback, charsets=self.irc_charsets) 65 self.irc_connection.connect(nick_callback=self._irc_nick_callback, charsets=self.irc_charsets)
76 66
77 self.bot.error('[Notice] bridge "'+str(self)+'" is running in '+self.mode+' mode and a say_level of "'+self.__class__._say_levels[self.say_level]+'"') 67 self.bot.error(say_levels.notice, 'bridge "'+str(self)+'" is running in '+self.mode+' mode and a say_level of "'+str(self.say_level)+'"')
78 68
79 69
80 def _join_irc_failed(self): 70 def _join_irc_failed(self):
81 self.bot.error('[Error] failed to connect to the IRC chan of bridge "'+str(self)+'", stopping bridge', send_to_admins=True) 71 self.bot.error(say_levels.error, 'failed to connect to the IRC chan of bridge "'+str(self)+'", stopping bridge', send_to_admins=True)
82 self.stop(message='failed to connect to the IRC chan') 72 self.stop(message='failed to connect to the IRC chan')
83 73
84 74
85 def _irc_nick_callback(self, error, arguments=[]): 75 def _irc_nick_callback(self, error, arguments=[]):
86 if error == None: 76 if error == None:
87 if self.mode == None: 77 if self.mode == None:
88 return 78 return
89 self.irc_connection.join(self.irc_room) 79 self.irc_connection.join(self.irc_room)
90 self.bot.error('===> Debug: successfully connected on IRC side of bridge "'+str(self)+'"', debug=True) 80 self.bot.error(3, 'successfully connected on IRC side of bridge "'+str(self)+'"', debug=True)
91 self.say('[Notice] bridge "'+str(self)+'" is running in '+self.mode+' mode', on_xmpp=False) 81 self.say(say_levels.notice, 'bridge "'+str(self)+'" is running in '+self.mode+' mode', on_xmpp=False)
92 if self.mode not in ['normal', 'bypass']: 82 if self.mode not in ['normal', 'bypass']:
93 self.show_participants_list_on(protocols=['irc']) 83 self.show_participants_list_on(protocols=['irc'])
94 else: 84 else:
95 self.mode = None 85 self.mode = None
96 if self.xmpp_room.connected == True: 86 if self.xmpp_room.connected == True:
97 self.say('[Error] failed to connect to the IRC chan, leaving ...', on_irc=False) 87 self.say(say_levels.error, 'failed to connect to the IRC chan, leaving ...', on_irc=False)
98 try: 88 try:
99 if error == 'nicknameinuse': 89 if error == 'nicknameinuse':
100 raise Exception('[Error] "'+self.bot.nickname+'" is already used in the IRC chan or reserved on the IRC server of bridge "'+str(self)+'"') 90 raise Exception('[Error] "'+self.bot.nickname+'" is already used in the IRC chan or reserved on the IRC server of bridge "'+str(self)+'"')
101 elif error == 'nickcollision': 91 elif error == 'nickcollision':
102 raise Exception('[Error] "'+self.bot.nickname+'" is already used or reserved on the IRC server of bridge "'+str(self)+'"') 92 raise Exception('[Error] "'+self.bot.nickname+'" is already used or reserved on the IRC server of bridge "'+str(self)+'"')
123 if len(errors) == 0: 113 if len(errors) == 0:
124 if hasattr(self, 'reconnecting'): 114 if hasattr(self, 'reconnecting'):
125 del self.reconnecting 115 del self.reconnecting
126 if self.mode == None: 116 if self.mode == None:
127 return 117 return
128 self.bot.error('===> Debug: succesfully connected on XMPP side of bridge "'+str(self)+'"', debug=True) 118 self.bot.error(3, 'succesfully connected on XMPP side of bridge "'+str(self)+'"', debug=True)
129 self.say('[Notice] bridge "'+str(self)+'" is running in '+self.mode+' mode', on_irc=False) 119 self.say(say_levels.notice, 'bridge "'+str(self)+'" is running in '+self.mode+' mode', on_irc=False)
130 else: 120 else:
131 self.mode = None 121 self.mode = None
132 if self.irc_connection.really_connected == True: 122 if self.irc_connection.really_connected == True:
133 self.say('[Error] failed to connect to the XMPP room, leaving ...', on_xmpp=False) 123 self.say(say_levels.error, 'failed to connect to the XMPP room, leaving ...', on_xmpp=False)
134 for error in errors: 124 for error in errors:
135 try: 125 try:
136 raise error 126 raise error
137 except xmpp.muc.RemoteServerNotFound: 127 except xmpp.muc.RemoteServerNotFound:
138 self._RemoteServerNotFound_handler() 128 self._RemoteServerNotFound_handler()
139 except: 129 except:
140 trace = traceback.format_exc() 130 trace = traceback.format_exc()
141 self.bot.error('[Error] failed to connect to the XMPP room of bridge "'+str(self)+'", stopping bridge\n'+trace, send_to_admins=True) 131 self.bot.error(say_levels.error, 'failed to connect to the XMPP room of bridge "'+str(self)+'", stopping bridge\n'+trace, send_to_admins=True)
142 self.stop(message='failed to connect to the XMPP room') 132 self.stop(message='failed to connect to the XMPP room')
143 133
144 134
145 def addParticipant(self, from_protocol, nickname, real_jid=None, irc_id=None): 135 def addParticipant(self, from_protocol, nickname, real_jid=None, irc_id=None):
146 """Add a participant to the bridge.""" 136 """Add a participant to the bridge."""
147 if (from_protocol == 'irc' and nickname == self.bot.nickname) or (from_protocol == 'xmpp' and nickname == self.bot.nickname): 137 if (from_protocol == 'irc' and nickname == self.bot.nickname) or (from_protocol == 'xmpp' and nickname == self.bot.nickname):
148 self.bot.error('===> Debug: not adding self ('+self.bot.nickname+') to bridge "'+str(self)+'"', debug=True) 138 self.bot.error(3, 'not adding self ('+self.bot.nickname+') to bridge "'+str(self)+'"', debug=True)
149 return 139 return
150 try: 140 try:
151 p = self.getParticipant(nickname) 141 p = self.getParticipant(nickname)
152 if p.protocol != from_protocol: 142 if p.protocol != from_protocol:
153 if from_protocol == 'irc' and isinstance(p.irc_connection, ServerConnection) and p.irc_connection.really_connected == True and p.irc_connection.real_nickname == nickname or from_protocol == 'xmpp' and isinstance(p.xmpp_c, xmpp.client.Client) and isinstance(p.muc, xmpp.muc) and p.xmpp_c.nickname == nickname: 143 if from_protocol == 'irc' and isinstance(p.irc_connection, ServerConnection) and p.irc_connection.really_connected == True and p.irc_connection.real_nickname == nickname or from_protocol == 'xmpp' and isinstance(p.xmpp_c, xmpp.client.Client) and isinstance(p.muc, xmpp.muc) and p.xmpp_c.nickname == nickname:
161 151
162 if nickname == 'ChanServ' and from_protocol == 'irc': 152 if nickname == 'ChanServ' and from_protocol == 'irc':
163 return 153 return
164 154
165 self.lock.acquire() 155 self.lock.acquire()
166 self.bot.error('===> Debug: adding participant "'+nickname+'" from "'+from_protocol+'" to bridge "'+str(self)+'"', debug=True) 156 self.bot.error(3, 'adding participant "'+nickname+'" from "'+from_protocol+'" to bridge "'+str(self)+'"', debug=True)
167 try: 157 try:
168 p = Participant(self, from_protocol, nickname, real_jid=real_jid) 158 p = Participant(self, from_protocol, nickname, real_jid=real_jid)
169 except IOError: 159 except IOError:
170 self.bot.error('===> Debug: IOError while adding participant "'+nickname+'" from "'+from_protocol+'" to bridge "'+str(self)+'", reconnectiong ...', debug=True) 160 self.bot.error(3, 'IOError while adding participant "'+nickname+'" from "'+from_protocol+'" to bridge "'+str(self)+'", reconnectiong ...', debug=True)
171 p.xmpp_c.reconnectAndReauth() 161 p.xmpp_c.reconnectAndReauth()
172 except: 162 except:
173 self.bot.error('===> Debug: unknown error while adding participant "'+nickname+'" from "'+from_protocol+'" to bridge "'+str(self)+'"', debug=True) 163 self.bot.error(3, 'unknown error while adding participant "'+nickname+'" from "'+from_protocol+'" to bridge "'+str(self)+'"', debug=True)
174 traceback.print_exc() 164 traceback.print_exc()
175 return 165 return
176 self.participants.append(p) 166 self.participants.append(p)
177 self.lock.release() 167 self.lock.release()
178 if self.mode not in ['normal', 'bypass']: 168 if self.mode not in ['normal', 'bypass']:
247 # From bypass to * 237 # From bypass to *
248 for p in self.participants: 238 for p in self.participants:
249 if p.nickname != p.duplicate_nickname: 239 if p.nickname != p.duplicate_nickname:
250 p.leave('Bridge is switching to '+new_mode+' mode') 240 p.leave('Bridge is switching to '+new_mode+' mode')
251 241
252 self.say('[Notice] Bridge is switching from '+old_mode+' to '+new_mode+' mode.', log=True) 242 self.say(say_levels.notice, 'Bridge is switching from '+old_mode+' to '+new_mode+' mode.', log=True)
253 243
254 244
255 def getParticipant(self, nickname): 245 def getParticipant(self, nickname):
256 """Returns a participant object if there is a participant using nickname in the bridge. Raises a NoSuchParticipantException otherwise.""" 246 """Returns a participant object if there is a participant using nickname in the bridge. Raises a NoSuchParticipantException otherwise."""
257 self.lock.acquire() 247 self.lock.acquire()
326 316
327 else: 317 else:
328 raise Exception('[Internal Error] bad protocol') 318 raise Exception('[Internal Error] bad protocol')
329 319
330 if was_on_both == True: 320 if was_on_both == True:
331 self.bot.error('===> Debug: "'+nickname+'" was on both sides of bridge "'+str(self)+'" but left '+left_protocol, debug=True) 321 self.bot.error(3, '"'+nickname+'" was on both sides of bridge "'+str(self)+'" but left '+left_protocol, debug=True)
332 322
333 elif was_on_both == False: 323 elif was_on_both == False:
334 self.lock.acquire() 324 self.lock.acquire()
335 self.bot.error('===> Debug: removing participant "'+nickname+'" from bridge "'+str(self)+'"', debug=True) 325 self.bot.error(3, 'removing participant "'+nickname+'" from bridge "'+str(self)+'"', debug=True)
336 self.participants.remove(p) 326 self.participants.remove(p)
337 p.leave(leave_message) 327 p.leave(leave_message)
338 del p 328 del p
339 self.lock.release() 329 self.lock.release()
340 if left_protocol == 'xmpp': 330 if left_protocol == 'xmpp':
343 elif left_protocol == 'irc': 333 elif left_protocol == 'irc':
344 if self.mode == 'minimal': 334 if self.mode == 'minimal':
345 self.show_participants_list_on(protocols=['xmpp']) 335 self.show_participants_list_on(protocols=['xmpp'])
346 336
347 else: 337 else:
348 self.bot.error('=> Debug: Bad decision tree, p.protocol='+p.protocol+' left_protocol='+left_protocol+'\np.xmpp_c='+str(p.xmpp_c)+'\np.irc_connection='+str(p.irc_connection), debug=True) 338 self.bot.error(1, 'Bad decision tree, p.protocol='+p.protocol+' left_protocol='+left_protocol+'\np.xmpp_c='+str(p.xmpp_c)+'\np.irc_connection='+str(p.irc_connection), debug=True)
349 339
350 340
351 def restart(self): 341 def restart(self):
352 """Restart the bridge""" 342 """Restart the bridge"""
353 343
354 # Tell admins 344 # Tell admins
355 self.bot.error('Restarting bridge '+str(self), send_to_admins=True) 345 self.bot.error(-1, 'Restarting bridge '+str(self), send_to_admins=True)
356 346
357 # Stop the bridge 347 # Stop the bridge
358 self.stop(message='Restarting bridge') 348 self.stop(message='Restarting bridge')
359 349
360 # Recreate the bridge 350 # Recreate the bridge
361 self.init2() 351 self.init2()
362 352
363 353
364 def say(self, message, on_irc=True, on_xmpp=True, log=False): 354 def say(self, importance, message, on_irc=True, on_xmpp=True, log=False, send_to_admins=False):
365 """Make the bot say something.""" 355 """Make the bot say something."""
366 if message[0] != '[': 356 message = self.bot.format_message(importance, message)
367 raise Exception('[Internal Error] message does not start with "["') 357 if log or send_to_admins:
368 if log: 358 self.bot.error(importance, message+' ('+str(self)+')', send_to_admins=send_to_admins)
369 self.bot.error(message+' ('+str(self)+')') 359 if importance < self.say_level:
370 if self.say_level == self.__class__._nothing:
371 return
372 level = re.findall('^\[(Info|Notice|Warning|Error)\]', message)
373 if len(level) == 0:
374 raise Exception('[Internal Error] unknown message importance "'+re.findall('^\[([^[\]]+)', message)[0]+'"')
375 level = level[0].lower()
376 if getattr(self.__class__, '_'+level) < self.say_level:
377 return 360 return
378 if on_xmpp == True: 361 if on_xmpp == True:
379 self.xmpp_room.say(message) 362 self.xmpp_room.say(message)
380 if on_irc == True: 363 if on_irc == True:
381 self.irc_connection.privmsg(self.irc_room, message) 364 self.irc_connection.privmsg(self.irc_room, message)
382 365
383 366
384 def show_participants_list_on(self, protocols=[]): 367 def show_participants_list_on(self, protocols=[]):
385 if 'irc' in protocols and self.irc_connection.really_connected: 368 if 'irc' in protocols and self.irc_connection.really_connected:
386 xmpp_participants_nicknames = self.get_participants_nicknames_list(protocols=['xmpp']) 369 xmpp_participants_nicknames = self.get_participants_nicknames_list(protocols=['xmpp'])
387 self.say('[Info] Participants on XMPP: '+' '.join(xmpp_participants_nicknames), on_xmpp=False) 370 self.say(say_levels.info, 'Participants on XMPP: '+' '.join(xmpp_participants_nicknames), on_xmpp=False)
388 if 'xmpp' in protocols: 371 if 'xmpp' in protocols:
389 irc_participants_nicknames = self.get_participants_nicknames_list(protocols=['irc']) 372 irc_participants_nicknames = self.get_participants_nicknames_list(protocols=['irc'])
390 self.say('[Info] Participants on IRC: '+' '.join(irc_participants_nicknames), on_irc=False) 373 self.say(say_levels.info, 'Participants on IRC: '+' '.join(irc_participants_nicknames), on_irc=False)
391 374
392 375
393 def stop(self, message='Stopping bridge'): 376 def stop(self, message='Stopping bridge'):
394 """Stop the bridge""" 377 """Stop the bridge"""
395 378