comparison orpg/networking/meta_server_lib.py @ 28:ff154cf3350c ornery-orc

Traipse 'OpenRPG' {100203-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 (Stable) New Features: New Bookmarks Feature New 'boot' command to remote admin New confirmation window for sent nodes Miniatures Layer pop up box allows users to turn off Mini labels, from FlexiRPG New Zoom Mouse plugin added New Images added to Plugin UI Switching to Element Tree New Map efficiency, from FlexiRPG New Status Bar to Update Manager New TrueDebug Class in orpg_log (See documentation for usage) New Portable Mercurial New Tip of the Day, from Core and community New Reference Syntax added for custom PC sheets New Child Reference for gametree New Parent Reference for gametree New Gametree Recursion method, mapping, context sensitivity, and effeciency.. New Features node with bonus nodes and Node Referencing help added New Dieroller structure from Core New DieRoller portability for odd Dice New 7th Sea die roller; ie [7k3] = [7d10.takeHighest(3).open(10)] New 'Mythos' System die roller added New vs. die roller method for WoD; ie [3v3] = [3d10.vs(3)]. Included for Mythos roller also New Warhammer FRPG Die Roller (Special thanks to Puu-san for the support) New EZ_Tree Reference system. Push a button, Traipse the tree, get a reference (Beta!) New Grids act more like Spreadsheets in Use mode, with Auto Calc Fixes: Fix to allow for portability to an OpenSUSE linux OS Fix to mplay_client for Fedora and OpenSUSE Fix to Text based Server Fix to Remote Admin Commands Fix to Pretty Print, from Core Fix to Splitter Nodes not being created Fix to massive amounts of images loading, from Core Fix to Map from gametree not showing to all clients Fix to gametree about menus Fix to Password Manager check on startup Fix to PC Sheets from tool nodes. They now use the tabber_panel Fix to Whiteboard ID to prevent random line or text deleting. Fixes to Server, Remote Server, and Server GUI Fix to Update Manager; cleaner clode for saved repositories Fixes made to Settings Panel and now reactive settings when Ok is pressed Fixes to Alternity roller's attack roll. Uses a simple Tuple instead of a Splice Fix to Use panel of Forms and Tabbers. Now longer enters design mode Fix made Image Fetching. New fetching image and new failed image Fix to whiteboard ID's to prevent non updated clients from ruining the fix. default_manifest.xml renamed to default_upmana.xml
author sirebral
date Wed, 03 Feb 2010 22:16:49 -0600
parents 97265586402b
children 8e77f169f324
comparison
equal deleted inserted replaced
27:51428d30c59e 28:ff154cf3350c
20 # 20 #
21 # File: meta_server_lib.py 21 # File: meta_server_lib.py
22 # Author: Chris Davis 22 # Author: Chris Davis
23 # Maintainer: 23 # Maintainer:
24 # Version: 24 # Version:
25 # $Id: meta_server_lib.py,v 1.40 2007/04/04 01:18:42 digitalxero Exp $ 25 # $Id: meta_server_lib.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
26 # 26 #
27 # Description: A collection of functions to communicate with the meta server. 27 # Description: A collection of functions to communicate with the meta server.
28 # 28 #
29 29
30 30
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.orpgCore import component
38 from orpg.tools.validate import validate 38 from orpg.tools.validate import validate
39 from orpg.dirpath import dir_struct 39 from orpg.dirpath import dir_struct
40 import urllib 40
41 import orpg.minidom 41 import urllib, time, sys, traceback, re
42
42 from threading import * 43 from threading import *
43 import time 44 from random import uniform
44 import sys 45 from urllib import urlopen, urlencode
45 import random 46 from orpg.tools.orpg_log import debug
46 import traceback 47
47 import re 48 from xml.etree.ElementTree import Element, fromstring
48
49 metacache_lock = RLock() 49 metacache_lock = RLock()
50 50
51 def get_server_dom(data=None,path=None): 51 def get_server_dom(data=None,path=None, string=False):
52 # post data at server and get the resulting DOM 52 # post data at server and get the resulting DOM
53
54 if path == None: 53 if path == None:
55 # get meta server URI 54 # get meta server URI
56 path = getMetaServerBaseURL() 55 path = getMetaServerBaseURL()
57 56
58 # POST the data 57 # POST the data
60 print 59 print
61 print "Sending the following POST info to Meta at " + path + ":" 60 print "Sending the following POST info to Meta at " + path + ":"
62 print "==========================================" 61 print "=========================================="
63 print data 62 print data
64 print 63 print
65 file = urllib.urlopen(path, data) 64 file = urlopen(path, data)
66 data = file.read() 65 data = file.read()
67 file.close() 66 file.close()
68 67
69 # Remove any leading or trailing data. This can happen on some satellite connections 68 # Remove any leading or trailing data. This can happen on some satellite connections
70 p = re.compile('(<servers>.*?</servers>)',re.DOTALL|re.IGNORECASE) 69 p = re.compile('(<servers>.*?</servers>)',re.DOTALL|re.IGNORECASE)
76 print "Got this string from the Meta at " + path + ":" 75 print "Got this string from the Meta at " + path + ":"
77 print "===============================================" 76 print "==============================================="
78 print data 77 print data
79 print 78 print
80 # build dom 79 # build dom
81 xml = component.get('xml') 80 etreeEl = data
82 xml_dom = xml.parseXml(data) 81 if not string: return fromstring(etreeEl)
83 xml_dom = xml_dom._get_documentElement() 82 else: return etreeEl
84 return xml_dom 83
85 84 def post_server_data(name, realHostName=None):
86 def post_server_data( name, realHostName=None): 85 if realHostName: data = urlencode({"server_data[name]":name,
87 if realHostName:
88 data = urllib.urlencode( {"server_data[name]":name,
89 "server_data[version]":PROTOCOL_VERSION, 86 "server_data[version]":PROTOCOL_VERSION,
90 "act":"new", 87 "act":"new",
91 "REMOTE_ADDR": realHostName } ) 88 "REMOTE_ADDR": realHostName })
92 89 # print "Letting meta server decide the hostname to list..."
93 else: 90 else: data = urlencode({"server_data[name]":name,
94 #print "Letting meta server decide the hostname to list..."
95 data = urllib.urlencode( {"server_data[name]":name,
96 "server_data[version]":PROTOCOL_VERSION, 91 "server_data[version]":PROTOCOL_VERSION,
97 "act":"new"} ) 92 "act":"new"})
98 93 path = component.get('settings').get('MetaServerBaseURL') #getMetaServerBaseURL()
99 #xml_dom = get_server_dom( data , "http://openrpg.sf.net/openrpg_servers.php")#Sourceforge still? 94 etreeEl = get_server_dom(data, path)
100 path = component.get('settings').get_setting('MetaServerBaseURL') #getMetaServerBaseURL() 95 return int(etreeEl.get('id'))
101 xml_dom = get_server_dom(data, path)
102 ret_val = int( xml_dom.getAttribute( "id" ) )
103 return ret_val
104 96
105 def post_failed_connection(id,meta=None,address=None,port=None): 97 def post_failed_connection(id,meta=None,address=None,port=None):
106 # For now, turning this off. This needs to be re-vamped for 98 # For now, turning this off. This needs to be re-vamped for
107 # handling multiple Metas. 99 # handling multiple Metas.
108 return 0 100 return 0
109 #data = urllib.urlencode({"id":id,"act":"failed"}); 101 #data = urlencode({"id":id,"act":"failed"});
110 #xml_dom = get_server_dom(data) 102 #xml_dom = get_server_dom(data)
111 #ret_val = int(xml_dom.getAttribute("return")) 103 #ret_val = int(xml_dom.getAttribute("return"))
112 #return ret_val 104 #return ret_val
113 105
114 def remove_server(id): 106 def remove_server(id):
115 data = urllib.urlencode({"id":id,"act":"del"}); 107 data = urlencode({"id":id,"act":"del"});
116 xml_dom = get_server_dom(data) 108 etreeEl = get_server_dom(data)
117 ret_val = int(xml_dom.getAttribute("return")) 109 return int(etreeEl.get("return"))
118 return ret_val 110
119 111 def byStartAttribute(first, second):
120 112 # This function is used to easily sort a list of nodes by their start time
121 def byStartAttribute(first,second): 113 # Ensure there is something to sort with for each
122 # This function is used to easily sort a list of nodes 114
123 # by their start time 115 first_start = int(first.get('start')) or 0
124 116 second_start = int(second.get('start')) or 0
125 if first.hasAttribute("start"): first_start = int(first.getAttribute("start"))
126 else: first_start = 0
127
128 if second.hasAttribute("start"): second_start = int(second.getAttribute("start"))
129 else: second_start = 0
130 117
131 # Return the result of the cmp function on the two strings 118 # Return the result of the cmp function on the two strings
132 return cmp(first_start,second_start) 119 return cmp(first_start, second_start)
133 120
134 def byNameAttribute(first,second): 121 def byNameAttribute(first, second):
135 # This function is used to easily sort a list of nodes 122 # This function is used to easily sort a list of nodes by their name attribute
136 # by their name attribute
137
138 # Ensure there is something to sort with for each 123 # Ensure there is something to sort with for each
139 124
140 if first.hasAttribute("name"): first_name = str(first.getAttribute("name")).lower() 125 first_name = first.get('name') or ''
141 else: first_name = "" 126 second_name = second.get('name') or ''
142 127
143 if second.hasAttribute("name"): second_name = str(second.getAttribute("name")).lower()
144 else: second_name = ""
145
146 # Return the result of the cmp function on the two strings 128 # Return the result of the cmp function on the two strings
147 return cmp(first_name,second_name) 129 return cmp(first_name,second_name)
148 130
149 131
150 def get_server_list(versions = None,sort_by="start"): 132 def get_server_list(versions = None, sort_by="start"):
151 data = urllib.urlencode({"version":PROTOCOL_VERSION,"ports":"%"}) 133 data = urlencode({"version":PROTOCOL_VERSION,"ports":"%"})
152 all_metas = getMetaServers(versions,1) # get the list of metas 134 all_metas = getMetaServers(versions, 1) # get the list of metas
153 base_meta = getMetaServerBaseURL() 135 base_meta = getMetaServerBaseURL()
154 136
155 #all_metas.reverse() # The last one checked will take precedence, so reverse the order 137 #all_metas.reverse() # The last one checked will take precedence, so reverse the order
156 # so that the top one on the actual list is checked last 138 # so that the top one on the actual list is checked last
157 139 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 140
159 141 for meta in all_metas: # check all of the metas
160 for meta in all_metas: # check all of the metas
161
162 #get the server's xml from the current meta 142 #get the server's xml from the current meta
163 bad_meta = 0 143 bad_meta = 0
164 #print "Getting server list from " + meta + "..." 144 #print "Getting server list from " + meta + "..."
165 try: xml_dom = get_server_dom(data=data,path=meta) 145 try: xml_dom = get_server_dom(data=data, path=meta)
166 except: 146 except: bad_meta = 1 #print "Trouble getting servers from " + meta + "..."
167 #print "Trouble getting servers from " + meta + "..." 147 if bad_meta: continue
168 bad_meta = 1 148 if base_meta == meta: updateMetaCache(xml_dom) #print "This is our base meta: " + meta
169 149 node_list = xml_dom.findall('server')
170 if bad_meta: 150 if len(node_list): # if there are entries in the node list
171 continue 151 # otherwise, just loop to next meta
172
173 if base_meta == meta:
174 #print "This is our base meta: " + meta
175 updateMetaCache(xml_dom)
176
177 node_list = xml_dom.getElementsByTagName('server')
178
179 if len(node_list): # if there are entries in the node list
180 # otherwise, just loop to next meta
181 152
182 # for each node found, we're going to check the nodes from prior 153 # for each node found, we're going to check the nodes from prior
183 # metas in the list. If a match is found, then use the new values. 154 # metas in the list. If a match is found, then use the new values.
184 for n in node_list: 155 for n in node_list:
185
186 # set them from current node 156 # set them from current node
187 157 if not n.get('name'): n.set('name','NO_NAME_GIVEN')
188 if not n.hasAttribute('name'): n.setAttribute('name','NO_NAME_GIVEN') 158 name = n.get('name')
189 name = n.getAttribute('name') 159 if not n.get('num_users'): n.set('num_users','N/A')
190 if not n.hasAttribute('num_users'): n.setAttribute('num_users','N/A') 160 num_users = n.get('num_users')
191 num_users = n.getAttribute('num_users') 161 if not n.get('address'): n.set('address','NO_ADDRESS_GIVEN')
192 if not n.hasAttribute('address'): n.setAttribute('address','NO_ADDRESS_GIVEN') 162 address = n.get('address')
193 address = n.getAttribute('address') 163 if not n.get('port'): n.set('port','6774')
194 if not n.hasAttribute('port'): n.setAttribute('port','6774') 164 port = n.get('port')
195 port = n.getAttribute('port') 165 n.set('meta',meta)
196 n.setAttribute('meta',meta)
197 end_point = str(address) + ":" + str(port) 166 end_point = str(address) + ":" + str(port)
198 if return_hash.has_key(end_point): 167 if return_hash.has_key(end_point):
199 if META_DEBUG: print "Replacing duplicate server entry at " + end_point 168 if META_DEBUG: print "Replacing duplicate server entry at " + end_point
200 return_hash[end_point] = n 169 return_hash[end_point] = n
201 170
202 # At this point, we have an amalgamated list of servers 171 # At this point, we have an amalgamated list of servers
203 # Now, we have to construct a new DOM to pass back. 172 # Now, we have to construct a new DOM to pass back.
204 173
205 # Create a servers element 174 # Create a servers element
206 return_dom = orpg.minidom.Element("servers") 175 server_list = Element('servers')
207 176
208 # get the nodes stored in return_hash 177 # get the nodes stored in return_hash
209 return_list = return_hash.values() 178 sort_list = return_hash.values()
210 179
211 # sort them by their name attribute. Uses byNameAttribute() 180 # sort them by their name attribute. Uses byNameAttribute()
212 # defined above as a comparison function 181 # defined above as a comparison function
213 182 if sort_by == "start": sort_list.sort(byStartAttribute)
214 if sort_by == "start": return_list.sort(byStartAttribute) 183 elif sort_by == "name": sort_list.sort(byNameAttribute)
215 elif sort_by == "name": return_list.sort(byNameAttribute)
216 184
217 # Add each node to the DOM 185 # Add each node to the DOM
218 for n in return_list: return_dom.appendChild(n) 186 for n in sort_list: server_list.append(n)
219 return return_dom 187 return server_list
220 188
221 ## List Format: 189 ## List Format:
222 ## <servers> 190 ## <servers>
223 ## <server address=? id=? name=? failed_count=? > 191 ## <server address=? id=? name=? failed_count=? >
224 ## </servers> 192 ## </servers>
225 193
226 def updateMetaCache(xml_dom): 194 def updateMetaCache(xml_dom):
227 try: 195 try:
228 if META_DEBUG: print "Updating Meta Server Cache" 196 if META_DEBUG: print "Updating Meta Server Cache"
229 metaservers = xml_dom.getElementsByTagName( 'metaservers' ) # pull out the metaservers bit 197 metaservers = xml_dom.findall('metaservers') # pull out the metaservers bit
230 if len(metaservers) == 0: 198 if len(metaservers) == 0:
231 cmetalist = getRawMetaList() 199 cmetalist = getRawMetaList()
232 xml_dom = get_server_dom(cmetalist[0]) 200 xml_dom = get_server_dom(cmetalist[0])
233 metaservers = xml_dom.getElementsByTagName( 'metaservers' ) 201 metaservers = xml_dom.findall('metaservers')
234 authoritative = metaservers[0].getAttribute('auth') 202 authoritative = metaservers[0].get('auth')
235 if META_DEBUG: print " Authoritive Meta: "+str(authoritative) 203 if META_DEBUG: print " Authoritive Meta: "+str(authoritative)
236 metas = metaservers[0].getElementsByTagName("meta") # get the list of metas 204 metas = metaservers[0].findall("meta") # get the list of metas
237 if META_DEBUG: print " Meta List ("+str(len(metas))+" servers)" 205 if META_DEBUG: print " Meta List ("+str(len(metas))+" servers)"
238 try: 206 try:
239 metacache_lock.acquire() 207 metacache_lock.acquire()
240 ini = open(dir_struct["user"]+"metaservers.cache","w") 208 ini = open(dir_struct["user"]+"metaservers.cache","w")
241 for meta in metas: 209 for meta in metas:
242 if META_DEBUG: print " Writing: "+str(meta.getAttribute('path')) 210 if META_DEBUG: print " Writing: "+str(meta.get('path'))
243 ini.write(str(meta.getAttribute('path')) + " " + str(meta.getAttribute('versions')) + "\n") 211 ini.write(str(meta.get('path')) + " " + str(meta.get('versions')) + "\n")
244 ini.close() 212 ini.close()
245 finally: 213 finally:
246 metacache_lock.release() 214 metacache_lock.release()
247 except Exception, e: 215 except Exception, e:
248 if META_DEBUG: traceback.print_exc() 216 if META_DEBUG: traceback.print_exc()
249 print "Meta Server Lib: UpdateMetaCache(): " + str(e) 217 print "Meta Server Lib: UpdateMetaCache(): " + str(e)
250 218
251 def getRawMetaList(): 219 def getRawMetaList(path=None):
220 ### Alpha ###
221 """This code will allow for a list of metas to be created. Future developement will more integrate the list of metas"""
222 if path != None:
223 metas = []
224 data = urlencode({"version":PROTOCOL_VERSION,"ports":"%"})
225 xml_dom = get_server_dom(data, path)
226 node_list = fromstring(xml_dom).findall('meta_server')
227 if len(node_list):
228 for n in node_list:
229 metas.append(n.get('path'))
230 return metas
252 try: 231 try:
253 try: 232 try:
254 metacache_lock.acquire() 233 metacache_lock.acquire()
255 # Read in the metas 234 # Read in the metas
256 validate.config_file("metaservers.cache","metaservers.cache") 235 validate.config_file("metaservers.cache","metaservers.cache")
266 return [] 245 return []
267 246
268 def getMetaServers(versions = None, pick_random=0): 247 def getMetaServers(versions = None, pick_random=0):
269 """ 248 """
270 get meta server URLs as a list 249 get meta server URLs as a list
271
272 versions is a list of acceptable version numbers. 250 versions is a list of acceptable version numbers.
273 A False truth value will use getMetaServerBaseURL() 251 A False truth value will use getMetaServerBaseURL()
274
275 set a default if we have weird reading problems 252 set a default if we have weird reading problems
276 default_url = "http://www.openrpg.com/openrpg_servers.php" 253 default_url = "http://www.openrpg.com/openrpg_servers.php"
277 """ 254 """
278 255
256 ### Pre Alpha Design ###
257 """ Here is how to handle Multiple Meta servers, and probably the best way to do it. Create an XML file that contains nodes with the various servers. Users will grab that meta data and have the option to connect to multiple meta servers which will allow them to find all the rooms. A check box should be used so if one server faile the users can continue without much lag. When creating a server hosts will need to select a meta to go too. This should be in the final of Ornery Orc."""
279 meta_names = [] 258 meta_names = []
280
281 if(versions): # If versions are supplied, then look in metaservers.conf 259 if(versions): # If versions are supplied, then look in metaservers.conf
282 try: 260 try:
283 """ 261 """
284 read in the metas from file 262 read in the metas from file
285 format of file is one meta entry per line 263 format of file is one meta entry per line
286 each entry will be the meta url, followed by one or more version numbers that it 264 each entry will be the meta url, followed by one or more version numbers that it
287 handle. Generally, this will be either a 1 for the original Meta format, or 265 handle. Generally, this will be either a 1 for the original Meta format, or
288 2 for the new one. 266 2 for the new one.
289 """ 267 """
290
291 # Read in the metas 268 # Read in the metas
269 #Adding a path object will attempt to look for a meta_network.
292 metas = getRawMetaList() 270 metas = getRawMetaList()
293 #print str(metas)
294 271
295 # go through each one to check if it should be returned, based on the 272 # go through each one to check if it should be returned, based on the
296 # version numbers allowed. 273 # version numbers allowed.
297 for meta in metas: 274 for meta in metas:
298
299 # split the line on whitespace 275 # split the line on whitespace
300 # obviously, your meta servers urls shouldn't contain whitespace. duh. 276 # obviously, your meta servers urls shouldn't contain whitespace. duh.
301 words = meta.split() 277 words = meta.split()
302 success = 0 # init success flag for version check 278 success = 0 # init success flag for version check
303 for version in versions: # run through each allowed version from caller 279 for version in versions: # run through each allowed version from caller
314 # print "Warning!!\nNo valid metaservers cached." 290 # print "Warning!!\nNo valid metaservers cached."
315 # print "Using meta from MetaServerBaseURL: " + default_meta + "\n" 291 # print "Using meta from MetaServerBaseURL: " + default_meta + "\n"
316 # if we have more than one and want a random one 292 # if we have more than one and want a random one
317 elif pick_random: 293 elif pick_random:
318 if META_DEBUG: print "choosing random meta from: " + str(meta_names) 294 if META_DEBUG: print "choosing random meta from: " + str(meta_names)
319 i = int(random.uniform(0,len(meta_names))) 295 i = int(uniform(0,len(meta_names)))
320 #meta = meta_names[i] 296 #meta = meta_names[i]
321 meta_names = [meta_names[i]] 297 meta_names = [meta_names[i]]
322 if META_DEBUG: print "using: " + str(meta_names) 298 if META_DEBUG: print "using: " + str(meta_names)
323 else: 299 else:
324 if META_DEBUG: print "using all metas: " + str(meta_names) 300 if META_DEBUG: print "using all metas: " + str(meta_names)
345 tree = xml.parseXml(txt)._get_documentElement() 321 tree = xml.parseXml(txt)._get_documentElement()
346 ini.close() 322 ini.close()
347 node_list = tree.getElementsByTagName("MetaServerBaseURL") 323 node_list = tree.getElementsByTagName("MetaServerBaseURL")
348 if node_list: 324 if node_list:
349 url = node_list[0].getAttribute("value") 325 url = node_list[0].getAttribute("value")
350
351 # allow tree to be collected 326 # allow tree to be collected
352 try: tree.unlink() 327 try: tree.unlink()
353 except: pass 328 except: pass
354 329
355 except Exception,e: 330 except Exception,e:
389 Because of this fact, there are some methods from wxThread 364 Because of this fact, there are some methods from wxThread
390 that I implemented to minimize changes to the code I had 365 that I implemented to minimize changes to the code I had
391 just written, i.e. TestDeleteStatus() and Delete() 366 just written, i.e. TestDeleteStatus() and Delete()
392 """ 367 """
393 368
394 def __init__(self,name=None,realHostName=None,num_users = "Hmmm",MetaPath=None,port=6774,register_callback=None): 369 def __init__(self, name=None, realHostName=None, num_users="0",
395 370 MetaPath=None, port=6774, register_callback=None):
396 Thread.__init__(self,name="registerThread") 371 Thread.__init__(self, name="registerThread")
397 self.rlock = RLock() # Re-entrant lock used to make this class thread safe 372 self.rlock = RLock() # Re-entrant lock used to make this class thread safe
398 self.die_event = Event() # The main loop in run() will wait with timeout on this 373 self.die_event = Event() # The main loop in run() will wait with timeout on this
399 if name: 374 self.name = name or 'Unnamed Server' # Name that the server want's displayed on the Meta
400 self.name = name # Name that the server want's displayed on the Meta 375 # But use Unnamed Server if for some crazy reason
401 else: 376 # no name is passed to the constructor
402 self.name = "Unnamed server" # But use this if for some crazy reason no name is 377 self.num_users = num_users # the number of users currently on this server
403 # passed to the constructor
404 self.num_users = num_users # the number of users currently on this server
405 self.realHostName = realHostName # Name to advertise for connection 378 self.realHostName = realHostName # Name to advertise for connection
406 self.id = "0" # id returned from Meta. Defaults to "0", which 379 self.id = "0" # id returned from Meta. Defaults to "0", which
407 # indicates a new registration. 380 # indicates a new registration.
408 self.cookie = "0" # cookie returned from Meta. Defaults to "0",which 381 self.cookie = "0" # cookie returned from Meta. Defaults to "0", which
409 # indicates a new registration. 382 # indicates a new registration.
410 self.interval = 0 # interval returned from Meta. Is how often to 383 self.interval = 0 # interval returned from Meta. Is how often to
411 # re-register, in minutes. 384 # re-register, in minutes.
412 self.destroy = 0 # Used to flag that this thread should die 385 self.destroy = 0 # Used to flag that this thread should die
413 self.port = str(port) 386 self.port = str(port)
420 393
421 Also, if MetaPath is specified, then use that. Makes 394 Also, if MetaPath is specified, then use that. Makes
422 it easier to have multiple registerThreads going to keep the server registered 395 it easier to have multiple registerThreads going to keep the server registered
423 on multiple (compatible) Metas. 396 on multiple (compatible) Metas.
424 """ 397 """
425 398 if MetaPath == None: self.path = getMetaServerBaseURL() # Do this if no Meta specified
426 if MetaPath == None: 399 else: self.path = MetaPath
427 self.path = getMetaServerBaseURL() # Do this if no Meta specified
428 else:
429 self.path = MetaPath
430 400
431 def getIdAndCookie(self): 401 def getIdAndCookie(self):
432 return self.id, self.cookie 402 return self.id, self.cookie
433 403
434 def TestDeleteStatus(self): 404 def TestDeleteStatus(self):
435 try: 405 try:
436 self.rlock.acquire() 406 self.rlock.acquire()
437 return self.die_event.isSet() 407 return self.die_event.isSet()
438 finally: 408 finally: self.rlock.release()
439 self.rlock.release()
440 409
441 def Delete(self): 410 def Delete(self):
442 try: 411 try:
443 self.rlock.acquire() 412 self.rlock.acquire()
444 self.die_event.set() 413 self.die_event.set()
445 finally: 414 finally: self.rlock.release()
446 self.rlock.release()
447 415
448 def run(self): 416 def run(self):
449 """ 417 """
450 This method gets called by Thread implementation 418 This method gets called by Thread implementation
451 when self.start() is called to begin the thread's 419 when self.start() is called to begin the thread's
453 421
454 We will basically enter a loop that continually 422 We will basically enter a loop that continually
455 re-registers this server and sleeps Interval 423 re-registers this server and sleeps Interval
456 minutes until the thread is ordered to die in place 424 minutes until the thread is ordered to die in place
457 """ 425 """
458 while(not self.TestDeleteStatus()): # Loop while until told to die 426 while(not self.TestDeleteStatus()): # Loop while until told to die
459 # Otherwise, call thread safe register(). 427 # Otherwise, call thread safe register().
460 self.register(self.name, self.realHostName, self.num_users) 428 self.register(self.name, self.realHostName, self.num_users)
461 if META_DEBUG: print "Sent Registration Data" 429 if META_DEBUG: print "Sent Registration Data"
462 # register() will end up setting the state variables 430 # register() will end up setting the state variables
463 # for us, including self.interval. 431 # for us, including self.interval.
464 try: 432 try:
465 self.rlock.acquire() # Serialize access to this state information 433 self.rlock.acquire() # Serialize access to this state information
466 434
467 if self.interval >= 3: # If the number of minutes is one or greater 435 if self.interval >= 3: # If the number of minutes is one or greater
468 self.interval -= 1 # wake up with 30 seconds left to re-register 436 self.interval -= 1 # wake up with 30 seconds left to re-register
469 else: 437 else:
470 self.interval = .5 # Otherwise, we probably experienced some kind 438 self.interval = .5 # Otherwise, we probably experienced some kind
471 # of error from the Meta in register(). Sleep 439 # of error from the Meta in register(). Sleep
472 # for 6 seconds and start from scratch. 440 # for 6 seconds and start from scratch.
473 441
474 finally: # no matter what, release the lock 442 finally: self.rlock.release() # no matter what, release the lock
475 self.rlock.release()
476 # Wait interval minutes for a command to die 443 # Wait interval minutes for a command to die
477 die_signal = self.die_event.wait(self.interval*60) 444 die_signal = self.die_event.wait(self.interval*60)
478 445
479 # If we get past the while loop, it's because we've been asked to die, 446 # 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 447 # so just let run() end. Once this occurs, the thread is dead and
499 try: 466 try:
500 self.rlock.acquire() 467 self.rlock.acquire()
501 if not self.isAlive(): # check to see if this thread is dead 468 if not self.isAlive(): # check to see if this thread is dead
502 return 1 # If so, return an error result 469 return 1 # If so, return an error result
503 # Do the actual unregistering here 470 # Do the actual unregistering here
504 data = urllib.urlencode( {"server_data[id]":self.id, 471 data = urlencode( {"server_data[id]":self.id,
505 "server_data[cookie]":self.cookie, 472 "server_data[cookie]":self.cookie,
506 "server_data[version]":PROTOCOL_VERSION, 473 "server_data[version]":PROTOCOL_VERSION,
507 "act":"unregister"} ) 474 "act":"unregister"} )
508 try: 475 try: # this POSTS the request and returns the result
509 xml_dom = get_server_dom(data=data, path=self.path) # this POSTS the request and returns the result 476 xml_dom = get_server_dom(data=data, path=self.path)
510 if xml_dom.hasAttribute("errmsg"): 477 if xml_dom.get("errmsg"):
511 print "Error durring unregistration: " + xml_dom.getAttribute("errmsg") 478 print "Error durring unregistration: " + xml_dom.get("errmsg")
512 except: 479 except:
513 if META_DEBUG: print "Problem talking to Meta. Will go ahead and die, letting Meta remove us." 480 if META_DEBUG: print "Problem talking to Meta. Will go ahead and die, letting Meta remove us."
514 # If there's an error, echo it to the console 481 # If there's an error, echo it to the console
515 482
516 # No special handling is required. If the de-registration worked we're done. If 483 # No special handling is required. If the de-registration worked we're done. If
543 if name: self.name = name 510 if name: self.name = name
544 if num_users != None: self.num_users = num_users 511 if num_users != None: self.num_users = num_users
545 if realHostName: self.realHostName = realHostName 512 if realHostName: self.realHostName = realHostName
546 # build POST data 513 # build POST data
547 if self.realHostName: 514 if self.realHostName:
548 data = urllib.urlencode( {"server_data[id]":self.id, 515 data = urlencode( {"server_data[id]":self.id,
549 "server_data[cookie]":self.cookie, 516 "server_data[cookie]":self.cookie,
550 "server_data[name]":self.name, 517 "server_data[name]":self.name,
551 "server_data[port]":self.port, 518 "server_data[port]":self.port,
552 "server_data[version]":PROTOCOL_VERSION, 519 "server_data[version]":PROTOCOL_VERSION,
553 "server_data[num_users]":self.num_users, 520 "server_data[num_users]":self.num_users,
554 "act":"register", 521 "act":"register",
555 "server_data[address]": self.realHostName } ) 522 "server_data[address]": self.realHostName } )
556 else: 523 else:
557 if META_DEBUG: print "Letting meta server decide the hostname to list..." 524 if META_DEBUG: print "Letting meta server decide the hostname to list..."
558 data = urllib.urlencode( {"server_data[id]":self.id, 525 data = urlencode( {"server_data[id]":self.id,
559 "server_data[cookie]":self.cookie, 526 "server_data[cookie]":self.cookie,
560 "server_data[name]":self.name, 527 "server_data[name]":self.name,
561 "server_data[port]":self.port, 528 "server_data[port]":self.port,
562 "server_data[version]":PROTOCOL_VERSION, 529 "server_data[version]":PROTOCOL_VERSION,
563 "server_data[num_users]":self.num_users, 530 "server_data[num_users]":self.num_users,
564 "act":"register"} ) 531 "act":"register"} )
565 try: 532 try: # this POSTS the request and returns the result
566 xml_dom = get_server_dom(data=data,path=self.path) # this POSTS the request and returns the result 533 etreeEl = get_server_dom(data=data, path=self.path)
567 except: 534 except:
568 if META_DEBUG: print "Problem talking to server. Setting interval for retry ..." 535 if META_DEBUG: print "Problem talking to server. Setting interval for retry ..."
569 if META_DEBUG: print data 536 if META_DEBUG: print data
570 if META_DEBUG: print 537 if META_DEBUG: print
571 self.interval = 0 538 self.interval = 0
582 the main thread calls register(). 549 the main thread calls register().
583 """ 550 """
584 return 0 # indicates that it was okay to call, not that no errors occurred 551 return 0 # indicates that it was okay to call, not that no errors occurred
585 552
586 # If there is a DOM returned .... 553 # If there is a DOM returned ....
587 if xml_dom: 554 if etreeEl:
588 # If there's an error, echo it to the console 555 # If there's an error, echo it to the console
589 if xml_dom.hasAttribute("errmsg"): 556 if etreeEl.get("errmsg"):
590 print "Error durring registration: " + xml_dom.getAttribute("errmsg") 557 print "Error durring registration: " + etreeEl.get("errmsg")
591 if META_DEBUG: print data 558 if META_DEBUG: print data
592 if META_DEBUG: print 559 if META_DEBUG: print
593 """ 560 """
594 No special handling is required. If the registration worked, id, cookie, and interval 561 No special handling is required. If the registration worked, id, cookie, and interval
595 can be stored and used for the next time. 562 can be stored and used for the next time.
607 the interval will be less than 1, and the main thread's while loop will reset it 574 the interval will be less than 1, and the main thread's while loop will reset it
608 to 6 seconds for the next retry. 575 to 6 seconds for the next retry.
609 Is it wrong to have a method where there's more comments than code? :) 576 Is it wrong to have a method where there's more comments than code? :)
610 """ 577 """
611 try: 578 try:
612 self.interval = int(xml_dom.getAttribute("interval")) 579 self.interval = int(etreeEl.get("interval"))
613 self.id = xml_dom.getAttribute("id") 580 self.id = etreeEl.get("id")
614 self.cookie = xml_dom.getAttribute("cookie") 581 self.cookie = etreeEl.get("cookie")
615 if not xml_dom.hasAttribute("errmsg"): 582 if not etreeEl.get("errmsg"): updateMetaCache(xml_dom)
616 updateMetaCache(xml_dom)
617 except: 583 except:
618 if META_DEBUG: print 584 if META_DEBUG: print
619 if META_DEBUG: print "OOPS! Is the Meta okay? It should be returning an id, cookie, and interval." 585 if META_DEBUG: print "OOPS! Is the Meta okay? It should be returning an id, cookie, and interval."
620 if META_DEBUG: print "Check to see what it really returned.\n" 586 if META_DEBUG: print "Check to see what it really returned.\n"
621 # Let xml_dom get garbage collected 587 # Let xml_dom get garbage collected
622 try: 588 try: xml_dom.unlink()
623 xml_dom.unlink() 589 except: pass
624 except:
625 pass
626 else: # else if no DOM is returned from get_server_dom() 590 else: # else if no DOM is returned from get_server_dom()
627 print "Error - no DOM constructed from Meta message!" 591 print "Error - no DOM constructed from Meta message!"
628 return 0 # Let caller know it was okay to call us 592 return 0 # Let caller know it was okay to call us
629 finally: 593 finally: self.rlock.release()
630 self.rlock.release()
631 # End of class registerThread 594 # End of class registerThread
632 ################################################################################ 595 ################################################################################