Mercurial > libervia-backend
comparison src/tools/memory.py @ 423:6c20c76abdcc
backend: - bridge async D-Bus method now automatically manage callback and errback, we just have to return a deferred
- getParams, getParamsForCategory and getParamsUI are now asynchronous
primitivus: management of asynchronous getParamsUI
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 07 Nov 2011 00:09:22 +0100 |
parents | acd908528ef7 |
children | e4e9187e3b5b |
comparison
equal
deleted
inserted
replaced
422:5a18c5f08d9b | 423:6c20c76abdcc |
---|---|
84 def loadGenParams(self): | 84 def loadGenParams(self): |
85 """Load general parameters data from storage | 85 """Load general parameters data from storage |
86 @return: deferred triggered once params are loaded""" | 86 @return: deferred triggered once params are loaded""" |
87 return self.storage.loadGenParams(self.params_gen) | 87 return self.storage.loadGenParams(self.params_gen) |
88 | 88 |
89 def loadIndParams(self, profile): | 89 def loadIndParams(self, profile, cache=None): |
90 """Load individual parameters | 90 """Load individual parameters |
91 set self.params cache | 91 set self.params cache or a temporary cache |
92 @param profile: profile to load (*must exist*) | 92 @param profile: profile to load (*must exist*) |
93 @param cache: if not None, will be used to store the value, as a short time cache | |
93 @return: deferred triggered once params are loaded""" | 94 @return: deferred triggered once params are loaded""" |
94 self.params[profile] = {} | 95 if cache == None: |
95 return self.storage.loadIndParams(self.params, profile) | 96 self.params[profile] = {} |
97 return self.storage.loadIndParams(self.params[profile] if cache==None else cache, profile) | |
96 | 98 |
97 def purgeProfile(self, profile): | 99 def purgeProfile(self, profile): |
98 """Remove cache data of a profile | 100 """Remove cache data of a profile |
99 @param profile: %(doc_profile)s""" | 101 @param profile: %(doc_profile)s""" |
100 try: | 102 try: |
127 if not self.host.trigger.point("ProfileCreation", profile): | 129 if not self.host.trigger.point("ProfileCreation", profile): |
128 return False | 130 return False |
129 self.storage.createProfile(profile) | 131 self.storage.createProfile(profile) |
130 return False | 132 return False |
131 | 133 |
132 def asyncCreateProfile(self, profile, callback, errback): | 134 def asyncCreateProfile(self, profile): |
133 """Create a new profile | 135 """Create a new profile |
134 @param profile: name of the profile | 136 @param profile: name of the profile |
135 @param callback: called when the profile actually exists in database and memory | 137 @param callback: called when the profile actually exists in database and memory |
136 @param errback: called with a string constant as parameter: | 138 @param errback: called with a string constant as parameter: |
137 - CONFLICT: the profile already exists | 139 - CONFLICT: the profile already exists |
138 - CANCELED: profile creation canceled | 140 - CANCELED: profile creation canceled |
139 - DATABASE: profile creation in database failed""" | 141 """ |
140 #FIXME: must be asynchronous and call the callback once the profile actually exists | |
141 if self.storage.hasProfile(profile): | 142 if self.storage.hasProfile(profile): |
142 info (_('The profile name already exists')) | 143 info (_('The profile name already exists')) |
143 errback("CONFLICT") | 144 return defer.fail("CONFLICT") |
144 return | |
145 if not self.host.trigger.point("ProfileCreation", profile): | 145 if not self.host.trigger.point("ProfileCreation", profile): |
146 errback("CANCELED") | 146 return defer.fail("CANCEL") |
147 return | 147 return self.storage.createProfile(profile) |
148 d = self.storage.createProfile(profile) | |
149 d.addCallback(lambda ignore: callback()) | |
150 d.addErrback(lambda ignore: errback("DATABASE")) | |
151 | 148 |
152 | 149 |
153 def deleteProfile(self, profile): | 150 def deleteProfile(self, profile): |
154 """Delete an existing profile | 151 """Delete an existing profile |
155 @param profile: name of the profile""" | 152 @param profile: name of the profile""" |
173 if not self.params: | 170 if not self.params: |
174 return "" | 171 return "" |
175 default = self.host.memory.getPrivate('Profile_default') | 172 default = self.host.memory.getPrivate('Profile_default') |
176 if not default or not default in self.params: | 173 if not default or not default in self.params: |
177 info(_('No default profile, returning first one')) #TODO: manage real default profile | 174 info(_('No default profile, returning first one')) #TODO: manage real default profile |
178 default = self.getProfilesList()[0] | 175 default = self.storage.getProfilesList()[0] |
179 self.host.memory.setPrivate('Profile_default', default) | 176 self.host.memory.setPrivate('Profile_default', default) |
180 return default #FIXME: temporary, must use real default value, and fallback to first one if it doesn't exists | 177 return default #FIXME: temporary, must use real default value, and fallback to first one if it doesn't exists |
181 if not self.storage.hasProfile(profile_key): | 178 if not self.storage.hasProfile(profile_key): |
182 info (_('Trying to access an unknown profile')) | 179 info (_('Trying to access an unknown profile')) |
183 return "" | 180 return "" |
272 value = self.__getParam(profile, category, name) | 269 value = self.__getParam(profile, category, name) |
273 return value if value!=None else node[1].getAttribute(attr) | 270 return value if value!=None else node[1].getAttribute(attr) |
274 else: | 271 else: |
275 return node[1].getAttribute(attr) | 272 return node[1].getAttribute(attr) |
276 | 273 |
277 def asyncGetParamA(self, name, category, attr="value", profile_key="@DEFAULT@", callback=None, errback=None): | 274 def asyncGetParamA(self, name, category, attr="value", profile_key="@DEFAULT@"): |
278 """Helper method to get a specific attribute | 275 """Helper method to get a specific attribute |
279 @param name: name of the parameter | 276 @param name: name of the parameter |
280 @param category: category of the parameter | 277 @param category: category of the parameter |
281 @param attr: name of the attribute (default: "value") | 278 @param attr: name of the attribute (default: "value") |
282 @param profile: owner of the param (@ALL@ for everyone) | 279 @param profile: owner of the param (@ALL@ for everyone)""" |
283 @param callback: called when the profile is connected | |
284 @param errback: called is the connection fail""" | |
285 node = self.__getParamNode(name, category) | 280 node = self.__getParamNode(name, category) |
286 if not node: | 281 if not node: |
287 error(_("Requested param [%(name)s] in category [%(category)s] doesn't exist !") % {'name':name, 'category':category}) | 282 error(_("Requested param [%(name)s] in category [%(category)s] doesn't exist !") % {'name':name, 'category':category}) |
288 return None | 283 return None |
289 | 284 |
290 if node[0] == 'general': | 285 if node[0] == 'general': |
291 value = self.__getParam(None, category, name, 'general') | 286 value = self.__getParam(None, category, name, 'general') |
292 callback(value if value!=None else node[1].getAttribute(attr)) | 287 return defer.succeed(value if value!=None else node[1].getAttribute(attr)) |
293 return | |
294 | 288 |
295 assert(node[0] == 'individual') | 289 assert(node[0] == 'individual') |
296 | 290 |
297 profile = self.getProfileName(profile_key) | 291 profile = self.getProfileName(profile_key) |
298 if not profile: | 292 if not profile: |
299 error(_('Requesting a param for a non-existant profile')) | 293 error(_('Requesting a param for a non-existant profile')) |
300 errback() | 294 return defer.fail() |
301 return | |
302 | 295 |
303 if attr != "value": | 296 if attr != "value": |
304 callback(node[1].getAttribute(attr)) | 297 return defer.succeed(node[1].getAttribute(attr)) |
305 return | |
306 default = node[1].getAttribute(attr) | 298 default = node[1].getAttribute(attr) |
307 try: | 299 try: |
308 value = self.__getParam(profile, category, name) | 300 value = self.__getParam(profile, category, name) |
309 callback(value if value!=None else default) | 301 return defer.succeed(value if value!=None else default) |
310 except ProfileNotInCacheError: | 302 except ProfileNotInCacheError: |
311 #We have to ask data to the storage manager | 303 #We have to ask data to the storage manager |
312 d = self.storage.getIndParam(category, name, profile) | 304 d = self.storage.getIndParam(category, name, profile) |
313 d.addCallback(lambda value: callback(value if value!=None else default)) | 305 return d.addCallback(lambda value: value if value!=None else default) |
314 d.addErrback(lambda x:errback()) | 306 |
315 | 307 def __getParam(self, profile, category, name, type='individual', cache=None): |
316 def __getParam(self, profile, category, name, type='individual'): | |
317 """Return the param, or None if it doesn't exist | 308 """Return the param, or None if it doesn't exist |
318 @param profile: the profile name (not profile key, i.e. name and not something like @DEFAULT@) | 309 @param profile: the profile name (not profile key, i.e. name and not something like @DEFAULT@) |
319 @param category: param category | 310 @param category: param category |
320 @param name: param name | 311 @param name: param name |
312 @param type: "general" or "individual" | |
313 @param cache: temporary cache, to use when profile is not logged | |
314 @return: param value or None if it doesn't exist | |
321 """ | 315 """ |
322 if type == 'general': | 316 if type == 'general': |
323 if self.params_gen.has_key((category, name)): | 317 if self.params_gen.has_key((category, name)): |
324 return self.params_gen[(category, name)] | 318 return self.params_gen[(category, name)] |
325 return None #This general param has the default value | 319 return None #This general param has the default value |
326 assert (type == 'individual') | 320 assert (type == 'individual') |
327 if not self.params.has_key(profile): | 321 if self.params.has_key(profile): |
322 cache = self.params[profile] # if profile is in main cache, we use it, | |
323 # ignoring the temporary cache | |
324 elif cache == None: #else we use the temporary cache if it exists, or raise an exception | |
328 raise ProfileNotInCacheError | 325 raise ProfileNotInCacheError |
329 if not self.params[profile].has_key((category, name)): | 326 if not cache.has_key((category, name)): |
330 return None | 327 return None |
331 return self.params[profile][(category, name)] | 328 return cache[(category, name)] |
332 | 329 |
333 def __constructProfileXml(self, profile): | 330 def __constructProfileXml(self, profile): |
334 """Construct xml for asked profile, filling values when needed | 331 """Construct xml for asked profile, filling values when needed |
335 /!\ as noticed in doc, don't forget to unlink the minidom.Document | 332 /!\ as noticed in doc, don't forget to unlink the minidom.Document |
336 @param profile: profile name (not key !) | 333 @param profile: profile name (not key !) |
337 @return: minidom.Document of the profile xml (cf warning above) | 334 @return: a deferred that fire a minidom.Document of the profile xml (cf warning above) |
338 """ | 335 """ |
339 #TODO: asynchronous equivalent | 336 def constructProfile(ignore,profile_cache): |
340 prof_xml = minidom.parseString('<params/>') | 337 prof_xml = minidom.parseString('<params/>') |
341 cache = {} | 338 cache = {} |
342 | 339 |
343 for type_node in self.dom.documentElement.childNodes: | 340 for type_node in self.dom.documentElement.childNodes: |
344 if type_node.nodeName == 'general' or type_node.nodeName == 'individual': #we use all params, general and individual | 341 if type_node.nodeName == 'general' or type_node.nodeName == 'individual': #we use all params, general and individual |
345 for cat_node in type_node.childNodes: | 342 for cat_node in type_node.childNodes: |
346 if cat_node.nodeName == 'category': | 343 if cat_node.nodeName == 'category': |
347 category = cat_node.getAttribute('name') | 344 category = cat_node.getAttribute('name') |
348 if not cache.has_key(category): | 345 if not cache.has_key(category): |
349 cache[category] = dest_cat = cat_node.cloneNode(True) #we make a copy for the new xml | 346 cache[category] = dest_cat = cat_node.cloneNode(True) #we make a copy for the new xml |
350 new_node = True | 347 new_node = True |
351 else: | 348 else: |
352 dest_cat = cache[category] | 349 dest_cat = cache[category] |
353 new_node = False #It's not a new node, we will merge information | 350 new_node = False #It's not a new node, we will merge information |
354 params = cat_node.getElementsByTagName("param") | 351 params = cat_node.getElementsByTagName("param") |
355 dest_params = {} | 352 dest_params = {} |
356 for node in dest_cat.childNodes: | 353 for node in dest_cat.childNodes: |
357 if node.nodeName != "param": | 354 if node.nodeName != "param": |
358 continue | 355 continue |
359 dest_params[node.getAttribute('name')] = node | 356 dest_params[node.getAttribute('name')] = node |
360 | 357 |
361 for param_node in params: | 358 for param_node in params: |
362 name = param_node.getAttribute('name') | 359 name = param_node.getAttribute('name') |
363 | 360 |
364 if name not in dest_params: | 361 if name not in dest_params: |
365 dest_params[name] = param_node.cloneNode(True) | 362 dest_params[name] = param_node.cloneNode(True) |
366 dest_cat.appendChild(dest_params[name]) | 363 dest_cat.appendChild(dest_params[name]) |
367 | 364 |
368 profile_value = self.__getParam(profile, category, name, type_node.nodeName) | 365 profile_value = self.__getParam(profile, category, name, type_node.nodeName, cache=profile_cache) |
369 if profile_value!=None: #there is a value for this profile, we must change the default | 366 if profile_value!=None: #there is a value for this profile, we must change the default |
370 dest_params[name].setAttribute('value', profile_value) | 367 dest_params[name].setAttribute('value', profile_value) |
371 if new_node: | 368 if new_node: |
372 prof_xml.documentElement.appendChild(dest_cat) | 369 prof_xml.documentElement.appendChild(dest_cat) |
373 return prof_xml | 370 return prof_xml |
374 | 371 |
372 | |
373 if self.params.has_key(profile): | |
374 d = defer.succeed(None) | |
375 profile_cache = self.params[profile] | |
376 else: | |
377 #profile is not in cache, we load values in a short time cache | |
378 profile_cache = {} | |
379 d = self.loadIndParams(profile, profile_cache) | |
380 | |
381 return d.addCallback(constructProfile, profile_cache) | |
375 | 382 |
376 def getParamsUI(self, profile_key): | 383 def getParamsUI(self, profile_key): |
377 """Return a SàT XMLUI for parameters, with given profile""" | 384 """Return a SàT XMLUI for parameters, with given profile""" |
378 #TODO: asynchronous equivalent | |
379 profile = self.getProfileName(profile_key) | 385 profile = self.getProfileName(profile_key) |
380 if not profile: | 386 if not profile: |
381 error(_("Asking params for inexistant profile")) | 387 error(_("Asking params for inexistant profile")) |
382 return "" | 388 return "" |
383 param_xml = self.getParams(profile) | 389 d = self.getParams(profile) |
384 return paramsXml2xmlUI(param_xml) | 390 return d.addCallback(lambda param_xml:paramsXml2xmlUI(param_xml)) |
385 | 391 |
386 def getParams(self, profile_key): | 392 def getParams(self, profile_key): |
387 """Construct xml for asked profile | 393 """Construct xml for asked profile |
388 Take params xml as skeleton""" | 394 Take params xml as skeleton""" |
389 #TODO: asynchronous equivalent | |
390 profile = self.getProfileName(profile_key) | 395 profile = self.getProfileName(profile_key) |
391 if not profile: | 396 if not profile: |
392 error(_("Asking params for inexistant profile")) | 397 error(_("Asking params for inexistant profile")) |
393 return "" | 398 return "" |
394 prof_xml = self.__constructProfileXml(profile) | 399 |
395 return_xml = prof_xml.toxml() | 400 def returnXML(prof_xml): |
396 prof_xml.unlink() | 401 return_xml = prof_xml.toxml() |
397 | 402 prof_xml.unlink() |
398 return return_xml | 403 return return_xml |
404 | |
405 return self.__constructProfileXml(profile).addCallback(returnXML) | |
399 | 406 |
400 def getParamsForCategory(self, category, profile_key): | 407 def getParamsForCategory(self, category, profile_key): |
401 """Return node's xml for selected category""" | 408 """Return node's xml for selected category""" |
402 #TODO: manage category of general type (without existant profile) | 409 #TODO: manage category of general type (without existant profile) |
403 #TODO: asynchronous equivalent | |
404 profile = self.getProfileName(profile_key) | 410 profile = self.getProfileName(profile_key) |
405 if not profile: | 411 if not profile: |
406 error(_("Asking params for inexistant profile")) | 412 error(_("Asking params for inexistant profile")) |
407 return "" | 413 return "" |
408 prof_xml = self.__constructProfileXml(profile) | 414 |
409 | 415 def returnCategoryXml(prof_xml): |
410 for node in prof_xml.getElementsByTagName("category"): | 416 for node in prof_xml.getElementsByTagName("category"): |
411 if node.nodeName == "category" and node.getAttribute("name") == category: | 417 if node.nodeName == "category" and node.getAttribute("name") == category: |
412 result = node.toxml() | 418 result = node.toxml() |
413 prof_xml.unlink() | 419 prof_xml.unlink() |
414 return result | 420 return result |
415 | 421 |
416 prof_xml.unlink() | 422 prof_xml.unlink() |
417 return "<category />" | 423 return "<category />" |
424 | |
425 d = self.__constructProfileXml(profile) | |
426 return d.addCallback(returnCategoryXml) | |
418 | 427 |
419 def __getParamNode(self, name, category, type="@ALL@"): #FIXME: is type useful ? | 428 def __getParamNode(self, name, category, type="@ALL@"): #FIXME: is type useful ? |
420 """Return a node from the param_xml | 429 """Return a node from the param_xml |
421 @param name: name of the node | 430 @param name: name of the node |
422 @param category: category of the node | 431 @param category: category of the node |
461 return | 470 return |
462 | 471 |
463 if node[0] == 'general': | 472 if node[0] == 'general': |
464 self.params_gen[(category, name)] = value | 473 self.params_gen[(category, name)] = value |
465 self.storage.setGenParam(category, name, value) | 474 self.storage.setGenParam(category, name, value) |
466 for profile in self.getProfilesList(): | 475 for profile in self.storage.getProfilesList(): |
467 if self.host.isConnected(profile): | 476 if self.host.isConnected(profile): |
468 self.host.bridge.paramUpdate(name, value, category, profile) | 477 self.host.bridge.paramUpdate(name, value, category, profile) |
469 return | 478 return |
470 | 479 |
471 assert (node[0] == 'individual') | 480 assert (node[0] == 'individual') |
623 """Create a new profile | 632 """Create a new profile |
624 @param name: Profile name | 633 @param name: Profile name |
625 """ | 634 """ |
626 return self.params.createProfile(name) | 635 return self.params.createProfile(name) |
627 | 636 |
628 def asyncCreateProfile(self, name, callback, errback): | 637 def asyncCreateProfile(self, name): |
629 """Create a new profile | 638 """Create a new profile |
630 @param name: Profile name | 639 @param name: Profile name |
631 """ | 640 """ |
632 return self.params.asyncCreateProfile(name, callback, errback) | 641 return self.params.asyncCreateProfile(name) |
633 | 642 |
634 def deleteProfile(self, name): | 643 def deleteProfile(self, name): |
635 """Delete an existing profile | 644 """Delete an existing profile |
636 @param name: Name of the profile""" | 645 @param name: Name of the profile""" |
637 return self.params.deleteProfile(name) | 646 return self.params.deleteProfile(name) |
837 return self.presenceStatus[profile] | 846 return self.presenceStatus[profile] |
838 | 847 |
839 def getParamA(self, name, category, attr="value", profile_key='@DEFAULT@'): | 848 def getParamA(self, name, category, attr="value", profile_key='@DEFAULT@'): |
840 return self.params.getParamA(name, category, attr, profile_key) | 849 return self.params.getParamA(name, category, attr, profile_key) |
841 | 850 |
842 def asyncGetParamA(self, name, category, attr="value", profile_key='@DEFAULT@', callback=None, errback=None): | 851 def asyncGetParamA(self, name, category, attr="value", profile_key='@DEFAULT@'): |
843 return self.params.asyncGetParamA(name, category, attr, profile_key, callback, errback) | 852 return self.params.asyncGetParamA(name, category, attr, profile_key) |
844 | 853 |
845 def getParamsUI(self, profile_key): | 854 def getParamsUI(self, profile_key): |
846 return self.params.getParamsUI(profile_key) | 855 return self.params.getParamsUI(profile_key) |
847 | 856 |
848 def getParams(self, profile_key): | 857 def getParams(self, profile_key): |