Mercurial > traipse_dev
comparison orpg/networking/meta_server_lib.py @ 0:4385a7d0efd1 grumpy-goblin
Deleted and repushed it with the 'grumpy-goblin' branch. I forgot a y
author | sirebral |
---|---|
date | Tue, 14 Jul 2009 16:41:58 -0500 |
parents | |
children | c54768cffbd4 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4385a7d0efd1 |
---|---|
1 #!/usr/bin/python2.1 | |
2 # Copyright (C) 2000-2001 The OpenRPG Project | |
3 # | |
4 # openrpg-dev@lists.sourceforge.net | |
5 # | |
6 # This program is free software; you can redistribute it and/or modify | |
7 # it under the terms of the GNU General Public License as published by | |
8 # the Free Software Foundation; either version 2 of the License, or | |
9 # (at your option) any later version. | |
10 # | |
11 # This program is distributed in the hope that it will be useful, | |
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 # GNU General Public License for more details. | |
15 # | |
16 # You should have received a copy of the GNU General Public License | |
17 # along with this program; if not, write to the Free Software | |
18 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 # -- | |
20 # | |
21 # File: meta_server_lib.py | |
22 # Author: Chris Davis | |
23 # Maintainer: | |
24 # Version: | |
25 # $Id: meta_server_lib.py,v 1.40 2007/04/04 01:18:42 digitalxero Exp $ | |
26 # | |
27 # Description: A collection of functions to communicate with the meta server. | |
28 # | |
29 | |
30 | |
31 #added debug flag for meta messages to cut console server spam --Snowdog | |
32 META_DEBUG = 0 | |
33 | |
34 __version__ = "$Id: meta_server_lib.py,v 1.40 2007/04/04 01:18:42 digitalxero Exp $" | |
35 | |
36 from orpg.orpg_version import PROTOCOL_VERSION | |
37 from orpg.orpg_xml import * | |
38 import orpg.dirpath | |
39 import orpg.tools.validate | |
40 import urllib | |
41 import orpg.minidom | |
42 from threading import * | |
43 import time | |
44 import sys | |
45 import random | |
46 import traceback | |
47 import re | |
48 | |
49 metacache_lock = RLock() | |
50 | |
51 def get_server_dom(data=None,path=None): | |
52 # post data at server and get the resulting DOM | |
53 | |
54 if path == None: | |
55 # get meta server URI | |
56 path = getMetaServerBaseURL() | |
57 | |
58 # POST the data | |
59 if META_DEBUG: | |
60 print | |
61 print "Sending the following POST info to Meta at " + path + ":" | |
62 print "==========================================" | |
63 print data | |
64 print | |
65 file = urllib.urlopen(path, data) | |
66 data = file.read() | |
67 file.close() | |
68 | |
69 # Remove any leading or trailing data. This can happen on some satellite connections | |
70 p = re.compile('(<servers>.*?</servers>)',re.DOTALL|re.IGNORECASE) | |
71 mo = p.search(data) | |
72 if mo: | |
73 data = mo.group(0) | |
74 | |
75 if META_DEBUG: | |
76 print | |
77 print "Got this string from the Meta at " + path + ":" | |
78 print "===============================================" | |
79 print data | |
80 print | |
81 # build dom | |
82 xml_dom = parseXml(data) | |
83 xml_dom = xml_dom._get_documentElement() | |
84 return xml_dom | |
85 | |
86 def post_server_data( name, realHostName=None): | |
87 # build POST data | |
88 ## data = urllib.urlencode( {"server_data[name]":name, | |
89 ## "server_data[version]":PROTOCOL_VERSION, | |
90 ## "act":"new"} ) | |
91 ## | |
92 if realHostName: | |
93 data = urllib.urlencode( {"server_data[name]":name, | |
94 "server_data[version]":PROTOCOL_VERSION, | |
95 "act":"new", | |
96 "REMOTE_ADDR": realHostName } ) | |
97 | |
98 else: | |
99 #print "Letting meta server decide the hostname to list..." | |
100 data = urllib.urlencode( {"server_data[name]":name, | |
101 "server_data[version]":PROTOCOL_VERSION, | |
102 "act":"new"} ) | |
103 | |
104 xml_dom = get_server_dom( data , "http://openrpg.sf.net/openrpg_servers.php") | |
105 ret_val = int( xml_dom.getAttribute( "id" ) ) | |
106 return ret_val | |
107 | |
108 def post_failed_connection(id,meta=None,address=None,port=None): | |
109 # For now, turning this off. This needs to be re-vamped for | |
110 # handling multiple Metas. | |
111 return 0 | |
112 # data = urllib.urlencode({"id":id,"act":"failed"}); | |
113 # xml_dom = get_server_dom(data) | |
114 # ret_val = int(xml_dom.getAttribute("return")) | |
115 # return ret_val | |
116 | |
117 def remove_server(id): | |
118 data = urllib.urlencode({"id":id,"act":"del"}); | |
119 xml_dom = get_server_dom(data) | |
120 ret_val = int(xml_dom.getAttribute("return")) | |
121 return ret_val | |
122 | |
123 | |
124 def byStartAttribute(first,second): | |
125 # This function is used to easily sort a list of nodes | |
126 # by their start time | |
127 | |
128 if first.hasAttribute("start"): | |
129 first_start = int(first.getAttribute("start")) | |
130 else: | |
131 first_start = 0 | |
132 | |
133 if second.hasAttribute("start"): | |
134 second_start = int(second.getAttribute("start")) | |
135 else: | |
136 second_start = 0 | |
137 | |
138 # Return the result of the cmp function on the two strings | |
139 return cmp(first_start,second_start) | |
140 | |
141 def byNameAttribute(first,second): | |
142 # This function is used to easily sort a list of nodes | |
143 # by their name attribute | |
144 | |
145 # Ensure there is something to sort with for each | |
146 | |
147 if first.hasAttribute("name"): | |
148 first_name = str(first.getAttribute("name")).lower() | |
149 else: | |
150 first_name = "" | |
151 | |
152 if second.hasAttribute("name"): | |
153 second_name = str(second.getAttribute("name")).lower() | |
154 else: | |
155 second_name = "" | |
156 | |
157 # Return the result of the cmp function on the two strings | |
158 | |
159 return cmp(first_name,second_name) | |
160 | |
161 | |
162 def get_server_list(versions = None,sort_by="start"): | |
163 data = urllib.urlencode({"version":PROTOCOL_VERSION,"ports":"%"}) | |
164 all_metas = getMetaServers(versions,1) # get the list of metas | |
165 base_meta = getMetaServerBaseURL() | |
166 | |
167 #all_metas.reverse() # The last one checked will take precedence, so reverse the order | |
168 # so that the top one on the actual list is checked last | |
169 | |
170 return_hash = {} # this will end up with an amalgamated list of servers | |
171 | |
172 for meta in all_metas: # check all of the metas | |
173 | |
174 # get the server's xml from the current meta | |
175 bad_meta = 0 | |
176 #print "Getting server list from " + meta + "..." | |
177 try: | |
178 xml_dom = get_server_dom(data=data,path=meta) | |
179 except: | |
180 #print "Trouble getting servers from " + meta + "..." | |
181 bad_meta = 1 | |
182 | |
183 if bad_meta: | |
184 continue | |
185 | |
186 if base_meta == meta: | |
187 #print "This is our base meta: " + meta | |
188 updateMetaCache(xml_dom) | |
189 | |
190 node_list = xml_dom.getElementsByTagName('server') | |
191 | |
192 if len(node_list): # if there are entries in the node list | |
193 # otherwise, just loop to next meta | |
194 | |
195 # for each node found, we're going to check the nodes from prior | |
196 # metas in the list. If a match is found, then use the new values. | |
197 for n in node_list: | |
198 | |
199 # set them from current node | |
200 | |
201 if not n.hasAttribute('name'): | |
202 n.setAttribute('name','NO_NAME_GIVEN') | |
203 name = n.getAttribute('name') | |
204 if not n.hasAttribute('num_users'): | |
205 n.setAttribute('num_users','N/A') | |
206 num_users = n.getAttribute('num_users') | |
207 if not n.hasAttribute('address'): | |
208 n.setAttribute('address','NO_ADDRESS_GIVEN') | |
209 address = n.getAttribute('address') | |
210 if not n.hasAttribute('port'): | |
211 n.setAttribute('port','6774') | |
212 port = n.getAttribute('port') | |
213 n.setAttribute('meta',meta) | |
214 end_point = str(address) + ":" + str(port) | |
215 if return_hash.has_key(end_point): | |
216 if META_DEBUG: print "Replacing duplicate server entry at " + end_point | |
217 return_hash[end_point] = n | |
218 | |
219 # At this point, we have an amalgamated list of servers | |
220 # Now, we have to construct a new DOM to pass back. | |
221 | |
222 # Create a servers element | |
223 return_dom = orpg.minidom.Element("servers") | |
224 | |
225 # get the nodes stored in return_hash | |
226 return_list = return_hash.values() | |
227 | |
228 # sort them by their name attribute. Uses byNameAttribute() | |
229 # defined above as a comparison function | |
230 | |
231 if sort_by == "start": | |
232 return_list.sort(byStartAttribute) | |
233 elif sort_by == "name": | |
234 return_list.sort(byNameAttribute) | |
235 | |
236 # Add each node to the DOM | |
237 for n in return_list: | |
238 return_dom.appendChild(n) | |
239 return return_dom | |
240 | |
241 ## List Format: | |
242 ## <servers> | |
243 ## <server address=? id=? name=? failed_count=? > | |
244 ## </servers> | |
245 | |
246 def updateMetaCache(xml_dom): | |
247 try: | |
248 if META_DEBUG: print "Updating Meta Server Cache" | |
249 metaservers = xml_dom.getElementsByTagName( 'metaservers' ) # pull out the metaservers bit | |
250 if len(metaservers) == 0: | |
251 cmetalist = getRawMetaList() | |
252 xml_dom = get_server_dom(cmetalist[0]) | |
253 metaservers = xml_dom.getElementsByTagName( 'metaservers' ) | |
254 authoritative = metaservers[0].getAttribute('auth') | |
255 if META_DEBUG: print " Authoritive Meta: "+str(authoritative) | |
256 metas = metaservers[0].getElementsByTagName("meta") # get the list of metas | |
257 if META_DEBUG: print " Meta List ("+str(len(metas))+" servers)" | |
258 try: | |
259 metacache_lock.acquire() | |
260 ini = open(orpg.dirpath.dir_struct["user"]+"metaservers.cache","w") | |
261 for meta in metas: | |
262 if META_DEBUG: print " Writing: "+str(meta.getAttribute('path')) | |
263 ini.write(str(meta.getAttribute('path')) + " " + str(meta.getAttribute('versions')) + "\n") | |
264 ini.close() | |
265 finally: | |
266 metacache_lock.release() | |
267 except Exception, e: | |
268 if META_DEBUG: traceback.print_exc() | |
269 print "Meta Server Lib: UpdateMetaCache(): " + str(e) | |
270 | |
271 def getRawMetaList(): | |
272 try: | |
273 try: | |
274 metacache_lock.acquire() | |
275 # Read in the metas | |
276 orpg.tools.validate.Validate().config_file("metaservers.cache","metaservers.cache") | |
277 ini = open(orpg.dirpath.dir_struct["user"]+"metaservers.cache","r") | |
278 metas = ini.readlines() | |
279 ini.close() | |
280 return metas | |
281 finally: | |
282 metacache_lock.release() | |
283 except Exception, e: | |
284 if META_DEBUG: traceback.print_exc() | |
285 print "Meta Server Lib: getRawMetaList(): " + str(e) | |
286 return [] | |
287 | |
288 def getMetaServers(versions = None, pick_random=0): | |
289 # get meta server URLs as a list | |
290 | |
291 # versions is a list of acceptable version numbers. | |
292 # A False truth value will use getMetaServerBaseURL() | |
293 | |
294 # set a default if we have weird reading problems | |
295 # default_url = "http://www.openrpg.com/openrpg_servers.php" | |
296 | |
297 meta_names = [] | |
298 | |
299 if(versions): # If versions are supplied, then look in metaservers.conf | |
300 try: | |
301 # read in the metas from file | |
302 # format of file is one meta entry per line | |
303 # each entry will be the meta url, followed by one or more version numbers that it | |
304 # handle. Generally, this will be either a 1 for the original Meta format, or | |
305 # 2 for the new one. | |
306 | |
307 # Read in the metas | |
308 metas = getRawMetaList() | |
309 #print str(metas) | |
310 | |
311 # go through each one to check if it should be returned, based on the | |
312 # version numbers allowed. | |
313 for meta in metas: | |
314 | |
315 # split the line on whitespace | |
316 # obviously, your meta servers urls shouldn't contain whitespace. duh. | |
317 words = meta.split() | |
318 | |
319 success = 0 # init success flag for version check | |
320 | |
321 for version in versions: # run through each allowed version from caller | |
322 if version in words[1:]: # if the allowed version token was found | |
323 success += 1 # then increment the success indicator | |
324 | |
325 if success: # if the meta entry is acceptable to the caller | |
326 meta_names.append(words[0]) # add the entry | |
327 if META_DEBUG: print "adding metaserver " + meta | |
328 | |
329 # at this point, we should have at least one name from the cache. If not ... | |
330 if not meta_names: | |
331 default_meta = getMetaServerBaseURL() # grab the meta from ini.xml | |
332 meta_names.append(default_meta) # add it to the return list | |
333 # print "Warning!!\nNo valid metaservers cached." | |
334 # print "Using meta from MetaServerBaseURL: " + default_meta + "\n" | |
335 # if we have more than one and want a random one | |
336 elif pick_random: | |
337 if META_DEBUG: print "choosing random meta from: " + str(meta_names) | |
338 i = int(random.uniform(0,len(meta_names))) | |
339 #meta = meta_names[i] | |
340 meta_names = [meta_names[i]] | |
341 if META_DEBUG: print "using: " + str(meta_names) | |
342 else: | |
343 if META_DEBUG: print "using all metas: " + str(meta_names) | |
344 return meta_names | |
345 except Exception,e: | |
346 print e | |
347 #print "using default meta server URI: " + default_url | |
348 metas = [] | |
349 #metas.append(default_url) | |
350 return metas # return an empty list | |
351 else: # otherwise, use MetaServerBaseURL() | |
352 url = getMetaServerBaseURL() | |
353 meta_names.append(url) | |
354 return meta_names | |
355 | |
356 def getMetaServerBaseURL(): | |
357 # get meta server URL | |
358 url = "http://www.openrpg.com/openrpg_servers.php" | |
359 try: | |
360 orpg.tools.validate.Validate().config_file("settings.xml","default_settings.xml") | |
361 ini = open(orpg.dirpath.dir_struct["user"]+"settings.xml","r") | |
362 txt = ini.read() | |
363 tree = parseXml(txt)._get_documentElement() | |
364 ini.close() | |
365 node_list = tree.getElementsByTagName("MetaServerBaseURL") | |
366 if node_list: | |
367 url = node_list[0].getAttribute("value") | |
368 | |
369 # allow tree to be collected | |
370 try: | |
371 tree.unlink() | |
372 except: | |
373 pass | |
374 | |
375 except Exception,e: | |
376 print e | |
377 # print "using meta server URI: " + url | |
378 return url | |
379 | |
380 ####################################################################################### | |
381 # Beginning of Class registerThread | |
382 # | |
383 # A Class to Manage Registration with the Meta2 | |
384 # Create an instance and call it's start() method | |
385 # if you want to be (and stay) registered. This class | |
386 # will take care of registering and re-registering as | |
387 # often as necessary to stay in the Meta list. | |
388 # | |
389 # You may call register() yourself if you wish to change your | |
390 # server's name. It will immediately update the Meta. There | |
391 # is no need to unregister first. | |
392 # | |
393 # Call unregister() when you no longer want to be registered. | |
394 # This will result in the registerThread dying after | |
395 # attempting to immediately remove itself from the Meta. | |
396 # | |
397 # If you need to become registered again after that, you | |
398 # must create a new instance of class registerThread. Don't | |
399 # just try to call register() on the old, dead thread class. | |
400 | |
401 | |
402 class registerThread(Thread): | |
403 # Originally, I wrote this as a sub-class of wxThread, but | |
404 # A) I couldn't get it to import right | |
405 # B) I realized that I want this to be used in a server, | |
406 # which I don't want needing wxWindows to run! | |
407 # | |
408 # Because of this fact, there are some methods from wxThread | |
409 # that I implemented to minimize changes to the code I had | |
410 # just written, i.e. TestDeleteStatus() and Delete() | |
411 | |
412 def __init__(self,name=None,realHostName=None,num_users = "Hmmm",MetaPath=None,port=6774,register_callback=None): | |
413 | |
414 Thread.__init__(self,name="registerThread") | |
415 self.rlock = RLock() # Re-entrant lock used to make this class thread safe | |
416 self.die_event = Event() # The main loop in run() will wait with timeout on this | |
417 if name: | |
418 self.name = name # Name that the server want's displayed on the Meta | |
419 else: | |
420 self.name = "Unnamed server" # But use this if for some crazy reason no name is | |
421 # passed to the constructor | |
422 self.num_users = num_users # the number of users currently on this server | |
423 self.realHostName = realHostName # Name to advertise for connection | |
424 self.id = "0" # id returned from Meta. Defaults to "0", which | |
425 # indicates a new registration. | |
426 self.cookie = "0" # cookie returned from Meta. Defaults to "0",which | |
427 # indicates a new registration. | |
428 self.interval = 0 # interval returned from Meta. Is how often to | |
429 # re-register, in minutes. | |
430 self.destroy = 0 # Used to flag that this thread should die | |
431 self.port = str(port) | |
432 self.register_callback = register_callback # set a method to call to report result of register | |
433 # This thread will communicate with one and only one | |
434 # Meta. If the Meta in ini.xml is changed after | |
435 # instantiation, then this instance must be | |
436 # unregistered and a new instance instantiated. | |
437 # | |
438 # Also, if MetaPath is specified, then use that. Makes | |
439 # it easier to have multiple registerThreads going to keep the server registered | |
440 # on multiple (compatible) Metas. | |
441 | |
442 if MetaPath == None: | |
443 self.path = getMetaServerBaseURL() # Do this if no Meta specified | |
444 else: | |
445 self.path = MetaPath | |
446 | |
447 def getIdAndCookie(self): | |
448 return self.id, self.cookie | |
449 | |
450 def TestDeleteStatus(self): | |
451 try: | |
452 self.rlock.acquire() | |
453 return self.die_event.isSet() | |
454 finally: | |
455 self.rlock.release() | |
456 | |
457 def Delete(self): | |
458 try: | |
459 self.rlock.acquire() | |
460 self.die_event.set() | |
461 finally: | |
462 self.rlock.release() | |
463 | |
464 def run(self): | |
465 # This method gets called by Thread implementation | |
466 # when self.start() is called to begin the thread's | |
467 # execution | |
468 # | |
469 # We will basically enter a loop that continually | |
470 # re-registers this server and sleeps Interval | |
471 # minutes until the thread is ordered to die in place | |
472 while(not self.TestDeleteStatus()): # Loop while until told to die | |
473 # Otherwise, call thread safe register(). | |
474 self.register(self.name, self.realHostName, self.num_users) | |
475 if META_DEBUG: print "Sent Registration Data" | |
476 | |
477 # register() will end up setting the state variables | |
478 # for us, including self.interval. | |
479 try: | |
480 self.rlock.acquire() # Serialize access to this state information | |
481 | |
482 if self.interval >= 3: # If the number of minutes is one or greater | |
483 self.interval -= 1 # wake up with 30 seconds left to re-register | |
484 else: | |
485 self.interval = .5 # Otherwise, we probably experienced some kind | |
486 # of error from the Meta in register(). Sleep | |
487 # for 6 seconds and start from scratch. | |
488 | |
489 finally: # no matter what, release the lock | |
490 self.rlock.release() | |
491 # Wait interval minutes for a command to die | |
492 die_signal = self.die_event.wait(self.interval*60) | |
493 | |
494 # If we get past the while loop, it's because we've been asked to die, | |
495 # so just let run() end. Once this occurs, the thread is dead and | |
496 # calls to Thread.isAlive() return False. | |
497 | |
498 def unregister(self): | |
499 # This method can (I hope) be called from both within the thread | |
500 # and from other threads. It will attempt to unregister this | |
501 # server from the Meta database | |
502 # When this is either accomplished or has been tried hard enough | |
503 # (after which it just makes sense to let the Meta remove the | |
504 # entry itself when we don't re-register using this id), | |
505 # this method will either cause the thread to immediately die | |
506 # (if called from this thread's context) or set the Destroy flag | |
507 # (if called from the main thread), a positive test for which will cause | |
508 # the code in Entry() to exit() when the thread wakes up and | |
509 # checks TestDeleteStatus(). | |
510 # lock the critical section. The unlock will | |
511 # automatically occur at the end of the function in the finally clause | |
512 try: | |
513 self.rlock.acquire() | |
514 if not self.isAlive(): # check to see if this thread is dead | |
515 return 1 # If so, return an error result | |
516 # Do the actual unregistering here | |
517 data = urllib.urlencode( {"server_data[id]":self.id, | |
518 "server_data[cookie]":self.cookie, | |
519 "server_data[version]":PROTOCOL_VERSION, | |
520 "act":"unregister"} ) | |
521 try: | |
522 xml_dom = get_server_dom(data=data, path=self.path) # this POSTS the request and returns the result | |
523 if xml_dom.hasAttribute("errmsg"): | |
524 print "Error durring unregistration: " + xml_dom.getAttribute("errmsg") | |
525 except: | |
526 if META_DEBUG: print "Problem talking to Meta. Will go ahead and die, letting Meta remove us." | |
527 # If there's an error, echo it to the console | |
528 | |
529 # No special handling is required. If the de-registration worked we're done. If | |
530 # not, then it's because we've already been removed or have a bad cookie. Either | |
531 # way, we can't do anything else, so die. | |
532 self.Delete() # This will cause the registerThread to die in register() | |
533 # prep xml_dom for garbage collection | |
534 try: | |
535 xml_dom.unlink() | |
536 except: | |
537 pass | |
538 return 0 | |
539 finally: | |
540 self.rlock.release() | |
541 | |
542 def register(self, name=None, realHostName=None, num_users=None): | |
543 # Designed to handle the registration, both new and | |
544 # repeated. | |
545 # | |
546 # It is intended to be called once every interval | |
547 # (or interval - delta) minutes. | |
548 | |
549 # lock the critical section. The unlock will | |
550 # automatically occur at the end of the function in the finally clause | |
551 try: | |
552 self.rlock.acquire() | |
553 if not self.isAlive(): # check to see if this thread is dead | |
554 return 1 # If so, return an error result | |
555 | |
556 # Set the server's attibutes, if specified. | |
557 if name: | |
558 self.name = name | |
559 if num_users != None: | |
560 self.num_users = num_users | |
561 if realHostName: | |
562 self.realHostName = realHostName | |
563 # build POST data | |
564 if self.realHostName: | |
565 data = urllib.urlencode( {"server_data[id]":self.id, | |
566 "server_data[cookie]":self.cookie, | |
567 "server_data[name]":self.name, | |
568 "server_data[port]":self.port, | |
569 "server_data[version]":PROTOCOL_VERSION, | |
570 "server_data[num_users]":self.num_users, | |
571 "act":"register", | |
572 "server_data[address]": self.realHostName } ) | |
573 else: | |
574 if META_DEBUG: print "Letting meta server decide the hostname to list..." | |
575 data = urllib.urlencode( {"server_data[id]":self.id, | |
576 "server_data[cookie]":self.cookie, | |
577 "server_data[name]":self.name, | |
578 "server_data[port]":self.port, | |
579 "server_data[version]":PROTOCOL_VERSION, | |
580 "server_data[num_users]":self.num_users, | |
581 "act":"register"} ) | |
582 try: | |
583 xml_dom = get_server_dom(data=data,path=self.path) # this POSTS the request and returns the result | |
584 except: | |
585 if META_DEBUG: print "Problem talking to server. Setting interval for retry ..." | |
586 if META_DEBUG: print data | |
587 if META_DEBUG: print | |
588 self.interval = 0 | |
589 # If we are in the registerThread thread, then setting interval to 0 | |
590 # will end up causing a retry in about 6 seconds (see self.run()) | |
591 # If we are in the main thread, then setting interval to 0 will do one | |
592 # of two things: | |
593 # 1) Do the same as if we were in the registerThread | |
594 # 2) Cause the next, normally scheduled register() call to use the values | |
595 # provided in this call. | |
596 # | |
597 # Which case occurs depends on where the registerThread thread is when | |
598 # the main thread calls register(). | |
599 return 0 # indicates that it was okay to call, not that no errors occurred | |
600 # If there is a DOM returned .... | |
601 if xml_dom: | |
602 # If there's an error, echo it to the console | |
603 if xml_dom.hasAttribute("errmsg"): | |
604 print "Error durring registration: " + xml_dom.getAttribute("errmsg") | |
605 if META_DEBUG: print data | |
606 if META_DEBUG: print | |
607 # No special handling is required. If the registration worked, id, cookie, and interval | |
608 # can be stored and used for the next time. | |
609 # If an error occurred, then the Meta will delete us and we need to re-register as | |
610 # a new server. The way to indicate this is with a "0" id and "0" cookie sent to | |
611 # the server during the next registration. Since that's what the server returns to | |
612 # us on an error anyway, we just store them and the next registration will | |
613 # automatically be set up as a new one. | |
614 # | |
615 # Unless the server calls register() itself in the meantime. Of course, that's okay | |
616 # too, because a success on THAT register() call will set up the next one to use | |
617 # the issued id and cookie. | |
618 # | |
619 # The interval is stored unconditionally for similar reasons. If there's an error, | |
620 # the interval will be less than 1, and the main thread's while loop will reset it | |
621 # to 6 seconds for the next retry. | |
622 # Is it wrong to have a method where there's more comments than code? :) | |
623 try: | |
624 self.interval = int(xml_dom.getAttribute("interval")) | |
625 self.id = xml_dom.getAttribute("id") | |
626 self.cookie = xml_dom.getAttribute("cookie") | |
627 if not xml_dom.hasAttribute("errmsg"): | |
628 updateMetaCache(xml_dom) | |
629 except: | |
630 if META_DEBUG: print | |
631 if META_DEBUG: print "OOPS! Is the Meta okay? It should be returning an id, cookie, and interval." | |
632 if META_DEBUG: print "Check to see what it really returned.\n" | |
633 # Let xml_dom get garbage collected | |
634 try: | |
635 xml_dom.unlink() | |
636 except: | |
637 pass | |
638 else: # else if no DOM is returned from get_server_dom() | |
639 print "Error - no DOM constructed from Meta message!" | |
640 return 0 # Let caller know it was okay to call us | |
641 finally: | |
642 self.rlock.release() | |
643 # End of class registerThread | |
644 ################################################################################ |