comparison bridge.py @ 24:4e1f27ea527b

First hack at locks for thread safety. Some other minor changes. Signed-off-by: Charly COSTE <changaco@changaco.net>
author Charly COSTE <changaco@changaco.net>
date Thu, 20 Aug 2009 21:52:52 +0200
parents e2bd4de698e5
children 984e1e5c5e51
comparison
equal deleted inserted replaced
23:abdb7a2b6c6d 24:4e1f27ea527b
20 del muc 20 del muc
21 from participant import * 21 from participant import *
22 from encoding import * 22 from encoding import *
23 import traceback 23 import traceback
24 import re 24 import re
25 import threading
25 26
26 27
27 class NoSuchParticipantException(Exception): pass 28 class NoSuchParticipantException(Exception): pass
28 29
29 30
33 _info = 1 34 _info = 1
34 _notice = 2 35 _notice = 2
35 _warning = 3 36 _warning = 3
36 _error = 4 37 _error = 4
37 _nothing = 5 38 _nothing = 5
39 _modes = ['normal', 'limited', 'minimal']
38 40
39 41
40 def __init__(self, owner_bot, xmpp_room_jid, irc_room, irc_server, mode, say_level, irc_port=6667): 42 def __init__(self, owner_bot, xmpp_room_jid, irc_room, irc_server, mode, say_level, irc_port=6667):
41 """Create a new bridge.""" 43 """Create a new bridge."""
42 self.bot = owner_bot 44 self.bot = owner_bot
46 if hasattr(self.__class__, '_'+say_level): 48 if hasattr(self.__class__, '_'+say_level):
47 self.say_level = getattr(self.__class__, '_'+say_level) 49 self.say_level = getattr(self.__class__, '_'+say_level)
48 else: 50 else:
49 raise Exception('[Error] "'+say_level+'" is not a correct value for a bridge\'s "say_level" attribute') 51 raise Exception('[Error] "'+say_level+'" is not a correct value for a bridge\'s "say_level" attribute')
50 self.participants = [] 52 self.participants = []
51 if mode not in ['normal', 'limited', 'minimal']: 53 if mode not in self.__class__._modes:
52 raise Exception('[Error] "'+mode+'" is not a correct value for a bridge\'s "mode" attribute') 54 raise Exception('[Error] "'+mode+'" is not a correct value for a bridge\'s "mode" attribute')
53 self.mode = mode 55 self.mode = mode
56
57 self.lock = threading.Lock()
54 58
55 # Join XMPP room 59 # Join XMPP room
56 try: 60 try:
57 self.xmpp_room = xmpp.muc(xmpp_room_jid) 61 self.xmpp_room = xmpp.muc(xmpp_room_jid)
58 self.xmpp_room.join(self.bot.xmpp_c, self.bot.nickname, callback=self._xmpp_join_callback) 62 self.xmpp_room.join(self.bot.xmpp_c, self.bot.nickname, callback=self._xmpp_join_callback)
65 self.irc_connection = self.bot.irc.server(irc_server, irc_port, self.bot.nickname) 69 self.irc_connection = self.bot.irc.server(irc_server, irc_port, self.bot.nickname)
66 self.irc_connection.connect(nick_callback=self._irc_nick_callback) 70 self.irc_connection.connect(nick_callback=self._irc_nick_callback)
67 except: 71 except:
68 self.bot.error('[Error] joining IRC room failed') 72 self.bot.error('[Error] joining IRC room failed')
69 raise 73 raise
70 self.bot.error('[Notice] bridge "'+str(self)+'" is running in '+self.mode+' mode') 74
75 self.bot.error('[Notice] bridge "'+str(self)+'" is running in '+self.mode+' mode and a say_level of "'+say_level+'"')
71 76
72 77
73 def _irc_nick_callback(self, error, arguments=[]): 78 def _irc_nick_callback(self, error, arguments=[]):
74 if error == None: 79 if error == None:
75 self.irc_connection.join(self.irc_room) 80 self.irc_connection.join(self.irc_room)
133 return p 138 return p
134 139
135 140
136 def getParticipant(self, nickname): 141 def getParticipant(self, nickname):
137 """Returns a participant object if there is a participant using nickname in the bridge. Raises a NoSuchParticipantException otherwise.""" 142 """Returns a participant object if there is a participant using nickname in the bridge. Raises a NoSuchParticipantException otherwise."""
143 self.lock.acquire()
138 for participant_ in self.participants: 144 for participant_ in self.participants:
139 if participant_.nickname == nickname: 145 if participant_.nickname == nickname:
146 self.lock.release()
140 return participant_ 147 return participant_
148 self.lock.release()
141 raise NoSuchParticipantException('there is no participant using the nickname "'+nickname+'" in this bridge') 149 raise NoSuchParticipantException('there is no participant using the nickname "'+nickname+'" in this bridge')
142 150
143 151
144 def get_participants_nicknames_list(self, protocols=['irc', 'xmpp']): 152 def get_participants_nicknames_list(self, protocols=['irc', 'xmpp']):
145 """Returns a list of the nicknames of the bridge's participants that are connected on the XMPP side.""" 153 """Returns a list of the nicknames of the bridge's participants that are connected on the XMPP side."""
154 self.lock.acquire()
146 participants_nicknames = [] 155 participants_nicknames = []
147 for p in self.participants: 156 for p in self.participants:
148 if p.protocol in protocols: 157 if p.protocol in protocols:
149 participants_nicknames.append('"'+p.nickname+'"') 158 participants_nicknames.append('"'+p.nickname+'"')
159 self.lock.release()
150 return participants_nicknames 160 return participants_nicknames
151 161
152 162
153 def removeParticipant(self, left_protocol, nickname, leave_message): 163 def removeParticipant(self, left_protocol, nickname, leave_message):
154 """Remove the participant using nickname from the bridge. Raises a NoSuchParticipantException if nickname is not used in the bridge.""" 164 """Remove the participant using nickname from the bridge. Raises a NoSuchParticipantException if nickname is not used in the bridge."""
182 192
183 if was_on_both == True: 193 if was_on_both == True:
184 self.bot.error('===> Debug: "'+nickname+'" was on both sides of bridge "'+str(self)+'" but left '+left_protocol, debug=True) 194 self.bot.error('===> Debug: "'+nickname+'" was on both sides of bridge "'+str(self)+'" but left '+left_protocol, debug=True)
185 195
186 elif was_on_both == False: 196 elif was_on_both == False:
197 self.lock.acquire()
187 self.bot.error('===> Debug: removing participant "'+nickname+'" from bridge "'+str(self)+'"', debug=True) 198 self.bot.error('===> Debug: removing participant "'+nickname+'" from bridge "'+str(self)+'"', debug=True)
188 self.participants.remove(p) 199 self.participants.remove(p)
189 p.leave(leave_message) 200 p.leave(leave_message)
190 del p 201 del p
191 i = 0 202 i = 0
192 for p in self.participants: 203 for p in self.participants:
193 if p.protocol == 'xmpp': 204 if p.protocol == 'xmpp':
194 i += 1 205 i += 1
206 self.lock.release()
195 if left_protocol == 'xmpp': 207 if left_protocol == 'xmpp':
196 if self.irc_connections_limit != -1 and self.irc_connections_limit > i: 208 if self.irc_connections_limit != -1 and self.irc_connections_limit > i:
197 self.switchFromLimitedToNormalMode() 209 self.switchFromLimitedToNormalMode()
198 if self.mode != 'normal' and self.say_participants_list == True: 210 if self.mode != 'normal':
199 xmpp_participants_nicknames = self.get_participants_nicknames_list(protocols=['xmpp']) 211 xmpp_participants_nicknames = self.get_participants_nicknames_list(protocols=['xmpp'])
200 self.say('[Info] Participants on XMPP: '+' '.join(xmpp_participants_nicknames), on_xmpp=False) 212 self.say('[Info] Participants on XMPP: '+' '.join(xmpp_participants_nicknames), on_xmpp=False)
201 elif left_protocol == 'irc': 213 elif left_protocol == 'irc':
202 if self.mode == 'minimal' and self.say_participants_list == True: 214 if self.mode == 'minimal':
203 irc_participants_nicknames = self.get_participants_nicknames_list(protocols=['irc']) 215 irc_participants_nicknames = self.get_participants_nicknames_list(protocols=['irc'])
204 self.say('[Info] Participants on IRC: '+' '.join(irc_participants_nicknames), on_irc=False) 216 self.say('[Info] Participants on IRC: '+' '.join(irc_participants_nicknames), on_irc=False)
205 217
206 else: 218 else:
207 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) 219 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)