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