r70964 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r70963‎ | r70964 | r70965 >
Date:15:05, 12 August 2010
Author:daniel
Status:deferred
Tags:
Comment:
xmlrc echo client now working
Modified paths:
  • /trunk/extensions/XMLRC/client/rcclient.ini.sample (modified) (history)
  • /trunk/extensions/XMLRC/client/rcclient.py (modified) (history)

Diff [purge]

Index: trunk/extensions/XMLRC/client/rcclient.ini.sample
@@ -8,6 +8,6 @@
99 password: snoopy64
1010
1111 # If you want to join a group chat, use the lines below
12 -# or use --group and optionally --nick on the command line
 12+# or specify the group's JID on the command line
1313 #group: recentchanges@conference.jabber.yourhost.com
1414 #nick: john
\ No newline at end of file
Index: trunk/extensions/XMLRC/client/rcclient.py
@@ -21,7 +21,7 @@
2222 # along with this program. If not, see <http://www.gnu.org/licenses/>.
2323 ##############################################################################
2424
25 -import sys, os, os.path, traceback, datetime
 25+import sys, os, os.path, traceback, datetime, re
2626 import ConfigParser, optparse
2727 import select, xmpp # using the xmpppy library <http://xmpppy.sourceforge.net/>, GPL
2828
@@ -34,11 +34,12 @@
3535 ##################################################################################
3636 class RecentChange(object):
3737 """ Represence a RecentChanges-Record. Properties of a change can be accessed
38 - using item syntax (e.g. rc['revid']) or attribute syntax (e.g. rc.revid). """
 38+ using item syntax (e.g. rc['revid']) or attribute syntax (e.g. rc.revid).
 39+ Well known attributes are converted to the appropriate type automatically. """
3940
40 - flags = set( ( 'anon', 'bot', 'minor' ) )
41 - numerics = set( ( 'rcid', 'pageid', 'revid', 'old_revid', 'newlen', 'oldlen', 'ns' ) )
42 - times = set( ( 'timestamp' ) )
 41+ flags = set( ( 'anon', 'bot', 'minor', ) )
 42+ numerics = set( ( 'rcid', 'pageid', 'revid', 'old_revid', 'newlen', 'oldlen', 'ns', ) )
 43+ times = set( ( 'timestamp', ) )
4344
4445 def __init__(self, dom):
4546 self.dom = dom
@@ -46,6 +47,9 @@
4748 def get_property(self, prop):
4849 a = self.dom.getAttr(prop)
4950
 51+ if type(prop) == unicode:
 52+ prop = prop.encode("ascii")
 53+
5054 if prop in RecentChange.flags:
5155 if a is None or a is False:
5256 return False
@@ -54,11 +58,24 @@
5559 elif a is None:
5660 a = self.dom.getTag(prop)
5761 # TODO: wrap for conversion. known tags: <tags>, <param>, <block>
58 - elif a in RecentChange.numerics:
59 - a = int( a )
60 - elif a in RecentChange.times:
61 - a = datetime.strptime( a, '%Y-%m-%dT%H:%M:%S%Z' ) # 2010-10-12T08:57:03Z
 62+ elif prop in RecentChange.numerics:
 63+ if a == "":
 64+ a = None
 65+ else:
 66+ a = int( a )
 67+ elif prop in RecentChange.times:
 68+ if a == "":
 69+ a = None
 70+ else:
 71+ # Using ISO 8601: 2010-10-12T08:57:03Z
 72+ # XXX: python apparently does not support time zone offsets (%z) when parsing the date time??
 73+ # a = datetime.datetime.strptime( a, '%Y-%m-%dT%H:%M:%S%z' )
6274
 75+ a = re.sub( r'[A-Z]+$|[-+][0-9]+$', r'', a ) # strip time zone
 76+ a = datetime.datetime.strptime( a, '%Y-%m-%dT%H:%M:%S' ) # naive time. This sucks, but MW should use UTC anyway
 77+ else:
 78+ pass
 79+
6380 return a
6481
6582 def __getitem__(self, prop):
@@ -76,22 +93,32 @@
7794 pass
7895
7996 class RCEcho(RCHandler):
 97+ """ Implementation of RCHandler that will print the RecentChanges-
 98+ record to the shell. """
 99+
80100 props = ( 'rcid', 'timestamp', 'type', 'ns', 'title', 'pageid', 'revid', 'old_revid',
81 - 'user', 'oldlen', 'newlen', 'comment', 'logid', 'logtype', 'logaction' )
 101+ 'user', 'oldlen', 'newlen', 'comment', 'logid', 'logtype', 'logaction',
 102+ 'anon', 'bot', 'minor' )
82103
83104 def process(self, rc):
 105+ print "-----------------------------------------------"
84106 for p in RCEcho.props:
85107 self.print_prop(rc, p)
 108+ print "-----------------------------------------------"
86109
87110 def print_prop(self, rc, prop):
88111 v = rc[prop]
89112 if v is None: v = ''
90113
91 - print "%s: %s" % (prop, v) # XXX: check encoding crap
 114+ print "%s: %s" % (prop, v)
92115
93116 ##################################################################################
94117
95118 class RCClient(object):
 119+ """ XMPP client listeneing for RecentChanges-messages, and passing them
 120+ to any instances of RCHandler that have been registered using
 121+ RCClient.add_handler(). """
 122+
96123 def __init__( self, console_encoding = 'utf-8' ):
97124 self.console_encoding = console_encoding
98125 self.handlers = []
@@ -100,7 +127,7 @@
101128 self.xmpp = None
102129 self.jid = None
103130
104 - self.group = None
 131+ self.room = None
105132 self.nick = None
106133
107134 def warn(self, message):
@@ -120,33 +147,38 @@
121148
122149 self.online = 1
123150
124 - while self.online:
125 - (in_socks , out_socks, err_socks) = select.select(sockets, [], sockets, 1)
 151+ try:
 152+ while self.online:
 153+ (in_socks , out_socks, err_socks) = select.select(sockets, [], sockets, 1)
126154
127 - for sock in in_socks:
128 - try:
129 - self.xmpp.Process(1)
 155+ for sock in in_socks:
 156+ try:
 157+ self.xmpp.Process(1)
130158
131 - if not self.xmpp.isConnected():
132 - self.warn("connection lost, reconnecting...")
133 -
134 - if self.xmpp.reconnectAndReauth():
135 - self.warn("re-connect successful.")
136 - self.on_connect()
 159+ if not self.xmpp.isConnected():
 160+ self.warn("connection lost, reconnecting...")
 161+
 162+ if self.xmpp.reconnectAndReauth():
 163+ self.warn("re-connect successful.")
 164+ self.on_connect()
137165
138 - except Exception, e:
139 - error_type, error_value, trbk = sys.exc_info()
140 - self.warn( "Error while processing! %s" % " ".join( traceback.format_exception( error_type, error_value, trbk ) ) )
141 - # TODO: detect when we should kill the loop because a connection failed
 166+ except Exception, e:
 167+ error_type, error_value, trbk = sys.exc_info()
 168+ self.warn( "Error while processing! %s" % " ".join( traceback.format_exception( error_type, error_value, trbk ) ) )
 169+ # TODO: detect when we should kill the loop because a connection failed
142170
143 - for sock in err_socks:
144 - raise Exception( "Error in socket: %s" % repr(sock) )
 171+ for sock in err_socks:
 172+ raise Exception( "Error in socket: %s" % repr(sock) )
 173+ except KeyboardInterrupt:
 174+ pass
145175
146176 self.info("service loop terminated, disconnecting")
147177
148178 for sock in sockets:
149 - con.close()
 179+ sock.close()
150180
 181+ # TODO: how to leave chat room cleanly ?
 182+
151183 self.info("done.")
152184
153185 def process_message(self, con, message):
@@ -214,18 +246,18 @@
215247 self.xmpp.sendInitPresence(self)
216248 self.roster = self.xmpp.getRoster()
217249
218 - if self.group:
219 - self.join( self.group )
 250+ if self.room:
 251+ self.join( self.room )
220252
221 - def join(self, group, nick = None):
 253+ def join(self, room, nick = None):
222254 if not nick:
223255 nick = self.jid.getNode()
224256
225 - if type( group ) != object:
226 - group = xmpp.protocol.JID( group )
 257+ if type( room ) != object:
 258+ room = xmpp.protocol.JID( room )
227259
228 - # use our own desired nickname as resource part of the group's JID
229 - gjid = group.getStripped() + "/" + nick;
 260+ # use our own desired nickname as resource part of the room's JID
 261+ gjid = room.getStripped() + "/" + nick;
230262
231263 #create presence stanza
232264 join = xmpp.Presence( to= gjid )
@@ -237,7 +269,7 @@
238270
239271 self.info( 'joined room %s' % self.jid.getStripped() )
240272
241 - self.group = group
 273+ self.room = room
242274 self.nick = nick
243275
244276 return True
@@ -246,12 +278,15 @@
247279
248280 if __name__ == '__main__':
249281
 282+ # -- CONFIG & COMMAND LINE ----------------------------------------------------------------------
 283+
250284 # find the location of this script
251285 bindir= os.path.dirname( os.path.realpath( sys.argv[0] ) )
252286 extdir= os.path.dirname( bindir )
253287
254288 # set up command line options........
255289 option_parser = optparse.OptionParser()
 290+ option_parser.set_usage( "usage: %prog [options] [room]" )
256291 option_parser.add_option("--config", dest="config_file",
257292 help="read config from FILE", metavar="FILE")
258293
@@ -261,11 +296,8 @@
262297 option_parser.add_option("--debug", action="store_const", dest="loglevel", const=LOG_DEBUG,
263298 help="print debug messages")
264299
265 - option_parser.add_option("--group", "--muc", dest="group", default=None,
266 - help="join MUC chat group")
267 -
268300 option_parser.add_option("--nick", dest="nick", metavar="NICKNAME", default=None,
269 - help="use NICKNAME in the MUC group")
 301+ help="use NICKNAME in the MUC room")
270302
271303 (options, args) = option_parser.parse_args()
272304
@@ -285,7 +317,7 @@
286318 config = ConfigParser.SafeConfigParser()
287319
288320 config.add_section( 'XMPP' )
289 - config.set( 'XMPP', 'group', '' )
 321+ config.set( 'XMPP', 'room', '' )
290322 config.set( 'XMPP', 'nick', '' )
291323
292324 # read config file........
@@ -296,33 +328,36 @@
297329 jid = config.get( 'XMPP', 'jid' )
298330 password = config.get( 'XMPP', 'password' )
299331
300 - if options.group is None:
301 - group = config.get( 'XMPP', 'group' )
 332+ if len(args) >= 1:
 333+ room = args[0]
302334 else:
303 - group = options.group
 335+ room = config.get( 'XMPP', 'room' )
304336
305337 if options.nick is None:
306338 nick = config.get( 'XMPP', 'nick' )
307339 else:
308340 nick = options.nick
309341
310 - if group == '': group = None
 342+ if room == '': room = None
311343 if nick == '': nick = None
312344
 345+ # -- DO STUFF -----------------------------------------------------------------------------------
 346+
313347 # create rc client instance
314348 client = RCClient( )
315349 client.loglevel = options.loglevel
316350
317 - # -- DO STUFF -----------------------------------------------------------------------------------
 351+ # add an echo handler that prints the RC info to the shell
 352+ client.add_handler( RCEcho() )
318353
319354 # connect................
320 - if not client.connect( jid = jid, password = password ):
 355+ if not client.connect( jid, password ):
321356 sys.exit(1)
322357
323 - if group:
324 - client.join( group, nick )
 358+ if room:
 359+ client.join( room, nick )
325360
326 - # run relay loop................
 361+ # run listener loop................
327362 client.service_loop( )
328363
329364 print "done."

Status & tagging log