comparison orpg/networking/meta_server_lib.py @ 90:d1aff41c031b alpha

Traipse Alpha 'OpenRPG' {090919-00} Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc''s main goal is to offer more advanced features and enhance the productivity of the user. Update Summary: 00: Adds menu changes to draw attention to important updates, errors, or other events. (image info coming soon) Traipse URL is not included in the repos tab and is set as default. 01: Fixes Copy for Windows and Linux (finally!!) users. Fixes incomplete update to Grid and List nodes. Fixes incomplete update to Chat Commands. 02: Fixes problems with Remote Image Upload. Fixes Drop and Drag of Minis to Map. CherryPy can now use any image in the webfiles/ folder and sub-folders. CherryPy can now Drop and Drag Minis to the Map. 03: Minor changes to Update Manager's GUI. Expert recommendation warning added to Revision Update. Step down compatibility with open_rpg & component added to orpgCore. 19-00: Better backwards compatibility in orpgCore. Using majority of 'Grumpy' network folder to correct server lag.
author sirebral
date Sat, 19 Sep 2009 06:45:21 -0500
parents 449a8900f9ac
children 65c1604e7949
comparison
equal deleted inserted replaced
89:b84e0799fed2 90:d1aff41c031b
32 META_DEBUG = 0 32 META_DEBUG = 0
33 33
34 __version__ = "$Id: meta_server_lib.py,v 1.40 2007/04/04 01:18:42 digitalxero Exp $" 34 __version__ = "$Id: meta_server_lib.py,v 1.40 2007/04/04 01:18:42 digitalxero Exp $"
35 35
36 from orpg.orpg_version import PROTOCOL_VERSION 36 from orpg.orpg_version import PROTOCOL_VERSION
37 from orpg.orpgCore import component 37 from orpg.orpg_xml import xml
38 from orpg.tools.validate import validate 38 import orpg.dirpath
39 from orpg.dirpath import dir_struct 39 import orpg.tools.validate
40 import urllib 40 import urllib
41 import orpg.minidom 41 import orpg.minidom
42 from threading import * 42 from threading import *
43 import time 43 import time
44 import sys 44 import sys
67 file.close() 67 file.close()
68 68
69 # Remove any leading or trailing data. This can happen on some satellite connections 69 # Remove any leading or trailing data. This can happen on some satellite connections
70 p = re.compile('(<servers>.*?</servers>)',re.DOTALL|re.IGNORECASE) 70 p = re.compile('(<servers>.*?</servers>)',re.DOTALL|re.IGNORECASE)
71 mo = p.search(data) 71 mo = p.search(data)
72 if mo: data = mo.group(0) 72 if mo:
73 data = mo.group(0)
73 74
74 if META_DEBUG: 75 if META_DEBUG:
75 print 76 print
76 print "Got this string from the Meta at " + path + ":" 77 print "Got this string from the Meta at " + path + ":"
77 print "===============================================" 78 print "==============================================="
78 print data 79 print data
79 print 80 print
80 # build dom 81 # build dom
81 xml = component.get('xml')
82 xml_dom = xml.parseXml(data) 82 xml_dom = xml.parseXml(data)
83 xml_dom = xml_dom._get_documentElement() 83 xml_dom = xml_dom._get_documentElement()
84 return xml_dom 84 return xml_dom
85 85
86 def post_server_data( name, realHostName=None): 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 ##
87 if realHostName: 92 if realHostName:
88 data = urllib.urlencode( {"server_data[name]":name, 93 data = urllib.urlencode( {"server_data[name]":name,
89 "server_data[version]":PROTOCOL_VERSION, 94 "server_data[version]":PROTOCOL_VERSION,
90 "act":"new", 95 "act":"new",
91 "REMOTE_ADDR": realHostName } ) 96 "REMOTE_ADDR": realHostName } )
94 #print "Letting meta server decide the hostname to list..." 99 #print "Letting meta server decide the hostname to list..."
95 data = urllib.urlencode( {"server_data[name]":name, 100 data = urllib.urlencode( {"server_data[name]":name,
96 "server_data[version]":PROTOCOL_VERSION, 101 "server_data[version]":PROTOCOL_VERSION,
97 "act":"new"} ) 102 "act":"new"} )
98 103
99 #xml_dom = get_server_dom( data , "http://openrpg.sf.net/openrpg_servers.php")#Sourceforge still? 104 xml_dom = get_server_dom( data , "http://openrpg.sf.net/openrpg_servers.php")
100 path = component.get('settings').get_setting('MetaServerBaseURL') #getMetaServerBaseURL()
101 xml_dom = get_server_dom(data, path)
102 ret_val = int( xml_dom.getAttribute( "id" ) ) 105 ret_val = int( xml_dom.getAttribute( "id" ) )
103 return ret_val 106 return ret_val
104 107
105 def post_failed_connection(id,meta=None,address=None,port=None): 108 def post_failed_connection(id,meta=None,address=None,port=None):
106 # For now, turning this off. This needs to be re-vamped for 109 # For now, turning this off. This needs to be re-vamped for
107 # handling multiple Metas. 110 # handling multiple Metas.
108 return 0 111 return 0
109 #data = urllib.urlencode({"id":id,"act":"failed"}); 112 # data = urllib.urlencode({"id":id,"act":"failed"});
110 #xml_dom = get_server_dom(data) 113 # xml_dom = get_server_dom(data)
111 #ret_val = int(xml_dom.getAttribute("return")) 114 # ret_val = int(xml_dom.getAttribute("return"))
112 #return ret_val 115 # return ret_val
113 116
114 def remove_server(id): 117 def remove_server(id):
115 data = urllib.urlencode({"id":id,"act":"del"}); 118 data = urllib.urlencode({"id":id,"act":"del"});
116 xml_dom = get_server_dom(data) 119 xml_dom = get_server_dom(data)
117 ret_val = int(xml_dom.getAttribute("return")) 120 ret_val = int(xml_dom.getAttribute("return"))
120 123
121 def byStartAttribute(first,second): 124 def byStartAttribute(first,second):
122 # This function is used to easily sort a list of nodes 125 # This function is used to easily sort a list of nodes
123 # by their start time 126 # by their start time
124 127
125 if first.hasAttribute("start"): first_start = int(first.getAttribute("start")) 128 if first.hasAttribute("start"):
126 else: first_start = 0 129 first_start = int(first.getAttribute("start"))
127 130 else:
128 if second.hasAttribute("start"): second_start = int(second.getAttribute("start")) 131 first_start = 0
129 else: second_start = 0 132
133 if second.hasAttribute("start"):
134 second_start = int(second.getAttribute("start"))
135 else:
136 second_start = 0
130 137
131 # Return the result of the cmp function on the two strings 138 # Return the result of the cmp function on the two strings
132 return cmp(first_start,second_start) 139 return cmp(first_start,second_start)
133 140
134 def byNameAttribute(first,second): 141 def byNameAttribute(first,second):
135 # This function is used to easily sort a list of nodes 142 # This function is used to easily sort a list of nodes
136 # by their name attribute 143 # by their name attribute
137 144
138 # Ensure there is something to sort with for each 145 # Ensure there is something to sort with for each
139 146
140 if first.hasAttribute("name"): first_name = str(first.getAttribute("name")).lower() 147 if first.hasAttribute("name"):
141 else: first_name = "" 148 first_name = str(first.getAttribute("name")).lower()
142 149 else:
143 if second.hasAttribute("name"): second_name = str(second.getAttribute("name")).lower() 150 first_name = ""
144 else: second_name = "" 151
152 if second.hasAttribute("name"):
153 second_name = str(second.getAttribute("name")).lower()
154 else:
155 second_name = ""
145 156
146 # Return the result of the cmp function on the two strings 157 # Return the result of the cmp function on the two strings
158
147 return cmp(first_name,second_name) 159 return cmp(first_name,second_name)
148 160
149 161
150 def get_server_list(versions = None,sort_by="start"): 162 def get_server_list(versions = None,sort_by="start"):
151 data = urllib.urlencode({"version":PROTOCOL_VERSION,"ports":"%"}) 163 data = urllib.urlencode({"version":PROTOCOL_VERSION,"ports":"%"})
157 169
158 return_hash = {} # this will end up with an amalgamated list of servers 170 return_hash = {} # this will end up with an amalgamated list of servers
159 171
160 for meta in all_metas: # check all of the metas 172 for meta in all_metas: # check all of the metas
161 173
162 #get the server's xml from the current meta 174 # get the server's xml from the current meta
163 bad_meta = 0 175 bad_meta = 0
164 #print "Getting server list from " + meta + "..." 176 #print "Getting server list from " + meta + "..."
165 try: xml_dom = get_server_dom(data=data,path=meta) 177 try:
178 xml_dom = get_server_dom(data=data,path=meta)
166 except: 179 except:
167 #print "Trouble getting servers from " + meta + "..." 180 #print "Trouble getting servers from " + meta + "..."
168 bad_meta = 1 181 bad_meta = 1
169 182
170 if bad_meta: 183 if bad_meta:
183 # metas in the list. If a match is found, then use the new values. 196 # metas in the list. If a match is found, then use the new values.
184 for n in node_list: 197 for n in node_list:
185 198
186 # set them from current node 199 # set them from current node
187 200
188 if not n.hasAttribute('name'): n.setAttribute('name','NO_NAME_GIVEN') 201 if not n.hasAttribute('name'):
202 n.setAttribute('name','NO_NAME_GIVEN')
189 name = n.getAttribute('name') 203 name = n.getAttribute('name')
190 if not n.hasAttribute('num_users'): n.setAttribute('num_users','N/A') 204 if not n.hasAttribute('num_users'):
205 n.setAttribute('num_users','N/A')
191 num_users = n.getAttribute('num_users') 206 num_users = n.getAttribute('num_users')
192 if not n.hasAttribute('address'): n.setAttribute('address','NO_ADDRESS_GIVEN') 207 if not n.hasAttribute('address'):
208 n.setAttribute('address','NO_ADDRESS_GIVEN')
193 address = n.getAttribute('address') 209 address = n.getAttribute('address')
194 if not n.hasAttribute('port'): n.setAttribute('port','6774') 210 if not n.hasAttribute('port'):
211 n.setAttribute('port','6774')
195 port = n.getAttribute('port') 212 port = n.getAttribute('port')
196 n.setAttribute('meta',meta) 213 n.setAttribute('meta',meta)
197 end_point = str(address) + ":" + str(port) 214 end_point = str(address) + ":" + str(port)
198 if return_hash.has_key(end_point): 215 if return_hash.has_key(end_point):
199 if META_DEBUG: print "Replacing duplicate server entry at " + end_point 216 if META_DEBUG: print "Replacing duplicate server entry at " + end_point
209 return_list = return_hash.values() 226 return_list = return_hash.values()
210 227
211 # sort them by their name attribute. Uses byNameAttribute() 228 # sort them by their name attribute. Uses byNameAttribute()
212 # defined above as a comparison function 229 # defined above as a comparison function
213 230
214 if sort_by == "start": return_list.sort(byStartAttribute) 231 if sort_by == "start":
215 elif sort_by == "name": return_list.sort(byNameAttribute) 232 return_list.sort(byStartAttribute)
233 elif sort_by == "name":
234 return_list.sort(byNameAttribute)
216 235
217 # Add each node to the DOM 236 # Add each node to the DOM
218 for n in return_list: return_dom.appendChild(n) 237 for n in return_list:
238 return_dom.appendChild(n)
219 return return_dom 239 return return_dom
220 240
221 ## List Format: 241 ## List Format:
222 ## <servers> 242 ## <servers>
223 ## <server address=? id=? name=? failed_count=? > 243 ## <server address=? id=? name=? failed_count=? >
235 if META_DEBUG: print " Authoritive Meta: "+str(authoritative) 255 if META_DEBUG: print " Authoritive Meta: "+str(authoritative)
236 metas = metaservers[0].getElementsByTagName("meta") # get the list of metas 256 metas = metaservers[0].getElementsByTagName("meta") # get the list of metas
237 if META_DEBUG: print " Meta List ("+str(len(metas))+" servers)" 257 if META_DEBUG: print " Meta List ("+str(len(metas))+" servers)"
238 try: 258 try:
239 metacache_lock.acquire() 259 metacache_lock.acquire()
240 ini = open(dir_struct["user"]+"metaservers.cache","w") 260 ini = open(orpg.dirpath.dir_struct["user"]+"metaservers.cache","w")
241 for meta in metas: 261 for meta in metas:
242 if META_DEBUG: print " Writing: "+str(meta.getAttribute('path')) 262 if META_DEBUG: print " Writing: "+str(meta.getAttribute('path'))
243 ini.write(str(meta.getAttribute('path')) + " " + str(meta.getAttribute('versions')) + "\n") 263 ini.write(str(meta.getAttribute('path')) + " " + str(meta.getAttribute('versions')) + "\n")
244 ini.close() 264 ini.close()
245 finally: 265 finally:
251 def getRawMetaList(): 271 def getRawMetaList():
252 try: 272 try:
253 try: 273 try:
254 metacache_lock.acquire() 274 metacache_lock.acquire()
255 # Read in the metas 275 # Read in the metas
256 validate.config_file("metaservers.cache","metaservers.cache") 276 orpg.tools.validate.Validate().config_file("metaservers.cache","metaservers.cache")
257 ini = open(dir_struct["user"]+"metaservers.cache","r") 277 ini = open(orpg.dirpath.dir_struct["user"]+"metaservers.cache","r")
258 metas = ini.readlines() 278 metas = ini.readlines()
259 ini.close() 279 ini.close()
260 return metas 280 return metas
261 finally: 281 finally:
262 metacache_lock.release() 282 metacache_lock.release()
264 if META_DEBUG: traceback.print_exc() 284 if META_DEBUG: traceback.print_exc()
265 print "Meta Server Lib: getRawMetaList(): " + str(e) 285 print "Meta Server Lib: getRawMetaList(): " + str(e)
266 return [] 286 return []
267 287
268 def getMetaServers(versions = None, pick_random=0): 288 def getMetaServers(versions = None, pick_random=0):
269 """ 289 # get meta server URLs as a list
270 get meta server URLs as a list 290
271 291 # versions is a list of acceptable version numbers.
272 versions is a list of acceptable version numbers. 292 # A False truth value will use getMetaServerBaseURL()
273 A False truth value will use getMetaServerBaseURL() 293
274 294 # set a default if we have weird reading problems
275 set a default if we have weird reading problems 295 # default_url = "http://www.openrpg.com/openrpg_servers.php"
276 default_url = "http://www.openrpg.com/openrpg_servers.php"
277 """
278 296
279 meta_names = [] 297 meta_names = []
280 298
281 if(versions): # If versions are supplied, then look in metaservers.conf 299 if(versions): # If versions are supplied, then look in metaservers.conf
282 try: 300 try:
283 """ 301 # read in the metas from file
284 read in the metas from file 302 # format of file is one meta entry per line
285 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
286 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
287 handle. Generally, this will be either a 1 for the original Meta format, or 305 # 2 for the new one.
288 2 for the new one.
289 """
290 306
291 # Read in the metas 307 # Read in the metas
292 metas = getRawMetaList() 308 metas = getRawMetaList()
293 #print str(metas) 309 #print str(metas)
294 310
297 for meta in metas: 313 for meta in metas:
298 314
299 # split the line on whitespace 315 # split the line on whitespace
300 # obviously, your meta servers urls shouldn't contain whitespace. duh. 316 # obviously, your meta servers urls shouldn't contain whitespace. duh.
301 words = meta.split() 317 words = meta.split()
318
302 success = 0 # init success flag for version check 319 success = 0 # init success flag for version check
320
303 for version in versions: # run through each allowed version from caller 321 for version in versions: # run through each allowed version from caller
304 if version in words[1:]: # if the allowed version token was found 322 if version in words[1:]: # if the allowed version token was found
305 success += 1 # then increment the success indicator 323 success += 1 # then increment the success indicator
324
306 if success: # if the meta entry is acceptable to the caller 325 if success: # if the meta entry is acceptable to the caller
307 meta_names.append(words[0]) # add the entry 326 meta_names.append(words[0]) # add the entry
308 if META_DEBUG: print "adding metaserver " + meta 327 if META_DEBUG: print "adding metaserver " + meta
309 328
310 # at this point, we should have at least one name from the cache. If not ... 329 # at this point, we should have at least one name from the cache. If not ...
311 if not meta_names: 330 if not meta_names:
312 default_meta = getMetaServerBaseURL() # grab the meta from ini.xml 331 default_meta = getMetaServerBaseURL() # grab the meta from ini.xml
313 meta_names.append(default_meta) # add it to the return list 332 meta_names.append(default_meta) # add it to the return list
314 # print "Warning!!\nNo valid metaservers cached." 333 # print "Warning!!\nNo valid metaservers cached."
315 # print "Using meta from MetaServerBaseURL: " + default_meta + "\n" 334 # print "Using meta from MetaServerBaseURL: " + default_meta + "\n"
316 # if we have more than one and want a random one 335 # if we have more than one and want a random one
317 elif pick_random: 336 elif pick_random:
318 if META_DEBUG: print "choosing random meta from: " + str(meta_names) 337 if META_DEBUG: print "choosing random meta from: " + str(meta_names)
319 i = int(random.uniform(0,len(meta_names))) 338 i = int(random.uniform(0,len(meta_names)))
320 #meta = meta_names[i] 339 #meta = meta_names[i]
336 355
337 def getMetaServerBaseURL(): 356 def getMetaServerBaseURL():
338 # get meta server URL 357 # get meta server URL
339 url = "http://www.openrpg.com/openrpg_servers.php" 358 url = "http://www.openrpg.com/openrpg_servers.php"
340 try: 359 try:
341 component.get('validate').config_file("settings.xml","default_settings.xml") 360 orpg.tools.validate.Validate().config_file("settings.xml","default_settings.xml")
342 ini = open(dir_struct["user"]+"settings.xml","r") 361 ini = open(orpg.dirpath.dir_struct["user"]+"settings.xml","r")
343 txt = ini.read() 362 txt = ini.read()
344 xml = component.get('xml')
345 tree = xml.parseXml(txt)._get_documentElement() 363 tree = xml.parseXml(txt)._get_documentElement()
346 ini.close() 364 ini.close()
347 node_list = tree.getElementsByTagName("MetaServerBaseURL") 365 node_list = tree.getElementsByTagName("MetaServerBaseURL")
348 if node_list: 366 if node_list:
349 url = node_list[0].getAttribute("value") 367 url = node_list[0].getAttribute("value")
350 368
351 # allow tree to be collected 369 # allow tree to be collected
352 try: tree.unlink() 370 try:
353 except: pass 371 tree.unlink()
372 except:
373 pass
354 374
355 except Exception,e: 375 except Exception,e:
356 print e 376 print e
357 #print "using meta server URI: " + url 377 # print "using meta server URI: " + url
358 return url 378 return url
359 379
360 """ 380 #######################################################################################
361 Beginning of Class registerThread 381 # Beginning of Class registerThread
362 382 #
363 A Class to Manage Registration with the Meta2 383 # A Class to Manage Registration with the Meta2
364 Create an instance and call it's start() method 384 # Create an instance and call it's start() method
365 if you want to be (and stay) registered. This class 385 # if you want to be (and stay) registered. This class
366 will take care of registering and re-registering as 386 # will take care of registering and re-registering as
367 often as necessary to stay in the Meta list. 387 # often as necessary to stay in the Meta list.
368 388 #
369 You may call register() yourself if you wish to change your 389 # You may call register() yourself if you wish to change your
370 server's name. It will immediately update the Meta. There 390 # server's name. It will immediately update the Meta. There
371 is no need to unregister first. 391 # is no need to unregister first.
372 392 #
373 Call unregister() when you no longer want to be registered. 393 # Call unregister() when you no longer want to be registered.
374 This will result in the registerThread dying after 394 # This will result in the registerThread dying after
375 attempting to immediately remove itself from the Meta. 395 # attempting to immediately remove itself from the Meta.
376 396 #
377 If you need to become registered again after that, you 397 # If you need to become registered again after that, you
378 must create a new instance of class registerThread. Don't 398 # must create a new instance of class registerThread. Don't
379 just try to call register() on the old, dead thread class. 399 # just try to call register() on the old, dead thread class.
380 """ 400
381 401
382 class registerThread(Thread): 402 class registerThread(Thread):
383 """ 403 # Originally, I wrote this as a sub-class of wxThread, but
384 Originally, I wrote this as a sub-class of wxThread, but 404 # A) I couldn't get it to import right
385 A) I couldn't get it to import right 405 # B) I realized that I want this to be used in a server,
386 B) I realized that I want this to be used in a server, 406 # which I don't want needing wxWindows to run!
387 which I don't want needing wxWindows to run! 407 #
388 408 # Because of this fact, there are some methods from wxThread
389 Because of this fact, there are some methods from wxThread 409 # that I implemented to minimize changes to the code I had
390 that I implemented to minimize changes to the code I had 410 # just written, i.e. TestDeleteStatus() and Delete()
391 just written, i.e. TestDeleteStatus() and Delete()
392 """
393 411
394 def __init__(self,name=None,realHostName=None,num_users = "Hmmm",MetaPath=None,port=6774,register_callback=None): 412 def __init__(self,name=None,realHostName=None,num_users = "Hmmm",MetaPath=None,port=6774,register_callback=None):
395 413
396 Thread.__init__(self,name="registerThread") 414 Thread.__init__(self,name="registerThread")
397 self.rlock = RLock() # Re-entrant lock used to make this class thread safe 415 self.rlock = RLock() # Re-entrant lock used to make this class thread safe
409 # indicates a new registration. 427 # indicates a new registration.
410 self.interval = 0 # interval returned from Meta. Is how often to 428 self.interval = 0 # interval returned from Meta. Is how often to
411 # re-register, in minutes. 429 # re-register, in minutes.
412 self.destroy = 0 # Used to flag that this thread should die 430 self.destroy = 0 # Used to flag that this thread should die
413 self.port = str(port) 431 self.port = str(port)
414 self.register_callback = register_callback # set a method to call to report result of register 432 self.register_callback = register_callback # set a method to call to report result of register
415 """ 433 # This thread will communicate with one and only one
416 This thread will communicate with one and only one 434 # Meta. If the Meta in ini.xml is changed after
417 Meta. If the Meta in ini.xml is changed after 435 # instantiation, then this instance must be
418 instantiation, then this instance must be 436 # unregistered and a new instance instantiated.
419 unregistered and a new instance instantiated. 437 #
420 438 # Also, if MetaPath is specified, then use that. Makes
421 Also, if MetaPath is specified, then use that. Makes 439 # it easier to have multiple registerThreads going to keep the server registered
422 it easier to have multiple registerThreads going to keep the server registered 440 # on multiple (compatible) Metas.
423 on multiple (compatible) Metas.
424 """
425 441
426 if MetaPath == None: 442 if MetaPath == None:
427 self.path = getMetaServerBaseURL() # Do this if no Meta specified 443 self.path = getMetaServerBaseURL() # Do this if no Meta specified
428 else: 444 else:
429 self.path = MetaPath 445 self.path = MetaPath
444 self.die_event.set() 460 self.die_event.set()
445 finally: 461 finally:
446 self.rlock.release() 462 self.rlock.release()
447 463
448 def run(self): 464 def run(self):
449 """ 465 # This method gets called by Thread implementation
450 This method gets called by Thread implementation 466 # when self.start() is called to begin the thread's
451 when self.start() is called to begin the thread's 467 # execution
452 execution 468 #
453 469 # We will basically enter a loop that continually
454 We will basically enter a loop that continually 470 # re-registers this server and sleeps Interval
455 re-registers this server and sleeps Interval 471 # minutes until the thread is ordered to die in place
456 minutes until the thread is ordered to die in place
457 """
458 while(not self.TestDeleteStatus()): # Loop while until told to die 472 while(not self.TestDeleteStatus()): # Loop while until told to die
459 # Otherwise, call thread safe register(). 473 # Otherwise, call thread safe register().
460 self.register(self.name, self.realHostName, self.num_users) 474 self.register(self.name, self.realHostName, self.num_users)
461 if META_DEBUG: print "Sent Registration Data" 475 if META_DEBUG: print "Sent Registration Data"
476
462 # register() will end up setting the state variables 477 # register() will end up setting the state variables
463 # for us, including self.interval. 478 # for us, including self.interval.
464 try: 479 try:
465 self.rlock.acquire() # Serialize access to this state information 480 self.rlock.acquire() # Serialize access to this state information
466 481
479 # If we get past the while loop, it's because we've been asked to die, 494 # If we get past the while loop, it's because we've been asked to die,
480 # so just let run() end. Once this occurs, the thread is dead and 495 # so just let run() end. Once this occurs, the thread is dead and
481 # calls to Thread.isAlive() return False. 496 # calls to Thread.isAlive() return False.
482 497
483 def unregister(self): 498 def unregister(self):
484 """ 499 # This method can (I hope) be called from both within the thread
485 This method can (I hope) be called from both within the thread 500 # and from other threads. It will attempt to unregister this
486 and from other threads. It will attempt to unregister this 501 # server from the Meta database
487 server from the Meta database 502 # When this is either accomplished or has been tried hard enough
488 When this is either accomplished or has been tried hard enough 503 # (after which it just makes sense to let the Meta remove the
489 (after which it just makes sense to let the Meta remove the 504 # entry itself when we don't re-register using this id),
490 entry itself when we don't re-register using this id), 505 # this method will either cause the thread to immediately die
491 this method will either cause the thread to immediately die 506 # (if called from this thread's context) or set the Destroy flag
492 (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
493 (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
494 the code in Entry() to exit() when the thread wakes up and 509 # checks TestDeleteStatus().
495 checks TestDeleteStatus(). 510 # lock the critical section. The unlock will
496 lock the critical section. The unlock will 511 # automatically occur at the end of the function in the finally clause
497 automatically occur at the end of the function in the finally clause
498 """
499 try: 512 try:
500 self.rlock.acquire() 513 self.rlock.acquire()
501 if not self.isAlive(): # check to see if this thread is dead 514 if not self.isAlive(): # check to see if this thread is dead
502 return 1 # If so, return an error result 515 return 1 # If so, return an error result
503 # Do the actual unregistering here 516 # Do the actual unregistering here
516 # No special handling is required. If the de-registration worked we're done. If 529 # No special handling is required. If the de-registration worked we're done. If
517 # not, then it's because we've already been removed or have a bad cookie. Either 530 # not, then it's because we've already been removed or have a bad cookie. Either
518 # way, we can't do anything else, so die. 531 # way, we can't do anything else, so die.
519 self.Delete() # This will cause the registerThread to die in register() 532 self.Delete() # This will cause the registerThread to die in register()
520 # prep xml_dom for garbage collection 533 # prep xml_dom for garbage collection
521 try: xml_dom.unlink() 534 try:
522 except: pass 535 xml_dom.unlink()
536 except:
537 pass
523 return 0 538 return 0
524 finally: self.rlock.release() 539 finally:
540 self.rlock.release()
525 541
526 def register(self, name=None, realHostName=None, num_users=None): 542 def register(self, name=None, realHostName=None, num_users=None):
527 """ 543 # Designed to handle the registration, both new and
528 Designed to handle the registration, both new and 544 # repeated.
529 repeated. 545 #
530 546 # It is intended to be called once every interval
531 It is intended to be called once every interval 547 # (or interval - delta) minutes.
532 (or interval - delta) minutes. 548
533 549 # lock the critical section. The unlock will
534 lock the critical section. The unlock will 550 # automatically occur at the end of the function in the finally clause
535 automatically occur at the end of the function in the finally clause
536 """
537 try: 551 try:
538 self.rlock.acquire() 552 self.rlock.acquire()
539 if not self.isAlive(): # check to see if this thread is dead 553 if not self.isAlive(): # check to see if this thread is dead
540 return 1 # If so, return an error result 554 return 1 # If so, return an error result
541 555
542 # Set the server's attibutes, if specified. 556 # Set the server's attibutes, if specified.
543 if name: self.name = name 557 if name:
544 if num_users != None: self.num_users = num_users 558 self.name = name
545 if realHostName: self.realHostName = realHostName 559 if num_users != None:
560 self.num_users = num_users
561 if realHostName:
562 self.realHostName = realHostName
546 # build POST data 563 # build POST data
547 if self.realHostName: 564 if self.realHostName:
548 data = urllib.urlencode( {"server_data[id]":self.id, 565 data = urllib.urlencode( {"server_data[id]":self.id,
549 "server_data[cookie]":self.cookie, 566 "server_data[cookie]":self.cookie,
550 "server_data[name]":self.name, 567 "server_data[name]":self.name,
567 except: 584 except:
568 if META_DEBUG: print "Problem talking to server. Setting interval for retry ..." 585 if META_DEBUG: print "Problem talking to server. Setting interval for retry ..."
569 if META_DEBUG: print data 586 if META_DEBUG: print data
570 if META_DEBUG: print 587 if META_DEBUG: print
571 self.interval = 0 588 self.interval = 0
572 """ 589 # If we are in the registerThread thread, then setting interval to 0
573 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())
574 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
575 If we are in the main thread, then setting interval to 0 will do one 592 # of two things:
576 of two things: 593 # 1) Do the same as if we were in the registerThread
577 1) Do the same as if we were in the registerThread 594 # 2) Cause the next, normally scheduled register() call to use the values
578 2) Cause the next, normally scheduled register() call to use the values 595 # provided in this call.
579 provided in this call. 596 #
580 597 # Which case occurs depends on where the registerThread thread is when
581 Which case occurs depends on where the registerThread thread is when 598 # the main thread calls register().
582 the main thread calls register().
583 """
584 return 0 # indicates that it was okay to call, not that no errors occurred 599 return 0 # indicates that it was okay to call, not that no errors occurred
585
586 # If there is a DOM returned .... 600 # If there is a DOM returned ....
587 if xml_dom: 601 if xml_dom:
588 # If there's an error, echo it to the console 602 # If there's an error, echo it to the console
589 if xml_dom.hasAttribute("errmsg"): 603 if xml_dom.hasAttribute("errmsg"):
590 print "Error durring registration: " + xml_dom.getAttribute("errmsg") 604 print "Error durring registration: " + xml_dom.getAttribute("errmsg")
591 if META_DEBUG: print data 605 if META_DEBUG: print data
592 if META_DEBUG: print 606 if META_DEBUG: print
593 """ 607 # No special handling is required. If the registration worked, id, cookie, and interval
594 No special handling is required. If the registration worked, id, cookie, and interval 608 # can be stored and used for the next time.
595 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
596 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
597 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
598 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
599 us on an error anyway, we just store them and the next registration will 613 # automatically be set up as a new one.
600 automatically be set up as a new one. 614 #
601 615 # Unless the server calls register() itself in the meantime. Of course, that's okay
602 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
603 too, because a success on THAT register() call will set up the next one to use 617 # the issued id and cookie.
604 the issued id and cookie. 618 #
605 619 # The interval is stored unconditionally for similar reasons. If there's an error,
606 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
607 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.
608 to 6 seconds for the next retry. 622 # Is it wrong to have a method where there's more comments than code? :)
609 Is it wrong to have a method where there's more comments than code? :)
610 """
611 try: 623 try:
612 self.interval = int(xml_dom.getAttribute("interval")) 624 self.interval = int(xml_dom.getAttribute("interval"))
613 self.id = xml_dom.getAttribute("id") 625 self.id = xml_dom.getAttribute("id")
614 self.cookie = xml_dom.getAttribute("cookie") 626 self.cookie = xml_dom.getAttribute("cookie")
615 if not xml_dom.hasAttribute("errmsg"): 627 if not xml_dom.hasAttribute("errmsg"):