Mercurial > traipse_dev
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"): |