comparison src/memory/memory.py @ 944:e1842ebcb2f3

core, plugin XEP-0115: discovery refactoring: - hashing algorithm of XEP-0115 has been including in core - our own hash is still calculated by XEP-0115 and can be regenerated with XEP_0115.recalculateHash - old discovery methods have been removed. Now the following methods are used: - hasFeature: tell if a feature is available for an entity - getDiscoInfos: self explaining - getDiscoItems: self explaining - findServiceEntities: return all available items of an entity which given (category, type) - findFeaturesSet: search for a set of features in entity + entity's items all these methods are asynchronous, and manage cache automatically - XEP-0115 manage in a better way hashes, and now use a trigger for presence instead of monkey patch - new FeatureNotFound exception, when we want to do something which is not available - refactored client initialisation sequence, removed client.initialized Deferred - added constant APP_URL - test_plugin_xep_0033.py has been temporarly deactivated, the time to adapt it - lot of cleaning
author Goffi <goffi@goffi.org>
date Fri, 28 Mar 2014 18:07:22 +0100
parents 71926ec2114d
children fe181994246a
comparison
equal deleted inserted replaced
943:71926ec2114d 944:e1842ebcb2f3
30 from sat.core import exceptions 30 from sat.core import exceptions
31 from sat.core.constants import Const as C 31 from sat.core.constants import Const as C
32 from sat.memory.sqlite import SqliteStorage 32 from sat.memory.sqlite import SqliteStorage
33 from sat.memory.persistent import PersistentDict 33 from sat.memory.persistent import PersistentDict
34 from sat.memory.params import Params 34 from sat.memory.params import Params
35 from sat.memory.disco import Discovery
35 36
36 37
37 class Sessions(object): 38 class Sessions(object):
38 DEFAULT_TIMEOUT = 600 39 DEFAULT_TIMEOUT = 600
39 40
113 self.initialized = defer.Deferred() 114 self.initialized = defer.Deferred()
114 self.host = host 115 self.host = host
115 self._entities_cache = {} # XXX: keep presence/last resource/other data in cache 116 self._entities_cache = {} # XXX: keep presence/last resource/other data in cache
116 # /!\ an entity is not necessarily in roster 117 # /!\ an entity is not necessarily in roster
117 self.subscriptions = {} 118 self.subscriptions = {}
118 self.server_features = {} # used to store discovery's informations 119 self.disco = Discovery(host)
119 self.server_identities = {}
120 self.config = self.parseMainConf() 120 self.config = self.parseMainConf()
121 self.__fixLocalDir() 121 self.__fixLocalDir()
122 database_file = os.path.expanduser(os.path.join(self.getConfig('', 'local_dir'), C.SAVEFILE_DATABASE)) 122 database_file = os.path.expanduser(os.path.join(self.getConfig('', 'local_dir'), C.SAVEFILE_DATABASE))
123 self.storage = SqliteStorage(database_file, host.__version__) 123 self.storage = SqliteStorage(database_file, host.__version__)
124 PersistentDict.storage = self.storage 124 PersistentDict.storage = self.storage
278 278
279 def getHistory(self, from_jid, to_jid, limit=0, between=True, profile=C.PROF_KEY_NONE): 279 def getHistory(self, from_jid, to_jid, limit=0, between=True, profile=C.PROF_KEY_NONE):
280 assert profile != C.PROF_KEY_NONE 280 assert profile != C.PROF_KEY_NONE
281 return self.storage.getHistory(jid.JID(from_jid), jid.JID(to_jid), limit, between, profile) 281 return self.storage.getHistory(jid.JID(from_jid), jid.JID(to_jid), limit, between, profile)
282 282
283 def addServerFeature(self, feature, jid_, profile):
284 """Add a feature discovered from server
285 @param feature: string of the feature
286 @param jid_: the jid of the target server
287 @param profile: which profile asked this server?"""
288 if profile not in self.server_features:
289 self.server_features[profile] = {}
290 features = self.server_features[profile].setdefault(jid_, [])
291 features.append(feature)
292
293 def addServerIdentity(self, category, type_, entity, jid_, profile):
294 """Add an identity discovered from server
295 @param feature: string of the feature
296 @param jid_: the jid of the target server
297 @param profile: which profile asked this server?"""
298 if not profile in self.server_identities:
299 self.server_identities[profile] = {}
300 identities = self.server_identities[profile].setdefault(jid_, {})
301 if (category, type_) not in identities:
302 identities[(category, type_)] = set()
303 identities[(category, type_)].add(entity)
304
305 def getServerServiceEntities(self, category, type_, jid_=None, profile=None):
306 """Return all available entities of a server for the service (category, type_)
307 @param category: identity's category
308 @param type_: identitiy's type
309 @param jid_: the jid of the target server (None for profile's server)
310 @param profile: which profile is asking this server?
311 @return: a set of entities or None if no cached data were found
312 """
313 if jid_ is None:
314 jid_ = self.host.getClientHostJid(profile)
315 if profile in self.server_identities and jid_ in self.server_identities[profile]:
316 return self.server_identities[profile][jid_].get((category, type_), set())
317 else:
318 return None
319
320 def getServerServiceEntity(self, category, type_, jid_=None, profile=None):
321 """Helper method to get first available entity of a server for the service (category, type_)
322 @param category: identity's category
323 @param type_: identitiy's type
324 @param jid_: the jid of the target server (None for profile's server)
325 @param profile: which profile is asking this server?
326 @return: the first found entity or None if no cached data were found
327 """
328 entities = self.getServerServiceEntities(category, type_, jid_, profile)
329 if entities is None:
330 warning(_("Entities (%(category)s/%(type)s) of %(server)s not available, maybe they haven't been asked yet?")
331 % {"category": category, "type": type_, "server": jid_})
332 return None
333 else:
334 return list(entities)[0] if entities else None
335
336 def getAllServerIdentities(self, jid_, profile):
337 """Helper method to get all identities of a server
338 @param jid_: the jid of the target server (None for profile's server)
339 @param profile: which profile is asking this server?
340 @return: a set of entities or None if no cached data were found
341 """
342 if jid_ is None:
343 jid_ = self.host.getClientHostJid(profile)
344 if jid_ not in self.server_identities[profile]:
345 return None
346 entities = set()
347 for set_ in self.server_identities[profile][jid_].values():
348 entities.update(set_)
349 return entities
350
351 def hasServerFeature(self, feature, jid_=None, profile_key=C.PROF_KEY_NONE):
352 """Tell if the specified server has the required feature
353 @param feature: requested feature
354 @param jid_: the jid of the target server (None for profile's server)
355 @param profile_key: %(doc_profile_key)s
356 """
357 profile = self.getProfileName(profile_key)
358 if not profile:
359 error(_('Trying find server feature for a non-existant profile'))
360 return None
361 assert profile in self.server_features
362 if jid_ is None:
363 jid_ = self.host.getClientHostJid(profile)
364 if jid_ in self.server_features[profile]:
365 return feature in self.server_features[profile][jid_]
366 else:
367 warning(_("Features of %s not available, maybe they haven't been asked yet?") % jid_)
368 return None
369
370 def _getLastResource(self, jid_s, profile_key): 283 def _getLastResource(self, jid_s, profile_key):
371 jid_ = jid.JID(jid_s) 284 jid_ = jid.JID(jid_s)
372 return self.getLastResource(jid_, profile_key) or "" 285 return self.getLastResource(jid_, profile_key) or ""
373 286
374 287
482 except KeyError: 395 except KeyError:
483 debug("Key [%s] doesn't exist for [%s] in entities_cache" % (key, entity_jid.full())) 396 debug("Key [%s] doesn't exist for [%s] in entities_cache" % (key, entity_jid.full()))
484 397
485 def getEntityData(self, entity_jid, keys_list, profile_key): 398 def getEntityData(self, entity_jid, keys_list, profile_key):
486 """Get a list of cached values for entity 399 """Get a list of cached values for entity
400
487 @param entity_jid: JID of the entity 401 @param entity_jid: JID of the entity
488 @param keys_list: list of keys to get, empty list for everything 402 @param keys_list (iterable): list of keys to get, empty list for everything
489 @param profile_key: %(doc_profile_key)s 403 @param profile_key: %(doc_profile_key)s
490 @return: dict withs values for each key in keys_list. 404 @return: dict withs values for each key in keys_list.
491 if there is no value of a given key, resulting dict will 405 if there is no value of a given key, resulting dict will
492 have nothing with that key nether 406 have nothing with that key nether
493 @raise: exceptions.UnknownEntityError if entity is not in cache 407 @raise: exceptions.UnknownEntityError if entity is not in cache
502 for key in keys_list: 416 for key in keys_list:
503 if key in entity_data: 417 if key in entity_data:
504 ret[key] = entity_data[key] 418 ret[key] = entity_data[key]
505 return ret 419 return ret
506 420
421 def getEntityDatum(self, entity_jid, key, profile_key):
422 """Get a datum from entity
423
424 @param entity_jid: JID of the entity
425 @param keys: key to get
426 @param profile_key: %(doc_profile_key)s
427 @return: requested value
428
429 @raise: exceptions.UnknownEntityError if entity is not in cache
430 @raise: KeyError if there is no value for this key and this entity
431 """
432 return self.getEntityData(entity_jid, (key,), profile_key)[key]
433
434
507 def delEntityCache(self, entity_jid, delete_all_resources=True, profile_key=C.PROF_KEY_NONE): 435 def delEntityCache(self, entity_jid, delete_all_resources=True, profile_key=C.PROF_KEY_NONE):
508 """Remove cached data for entity 436 """Remove cached data for entity
509 @param entity_jid: JID of the entity to delete 437 @param entity_jid: JID of the entity to delete
510 @param delete_all_resources: if True also delete all known resources form cache 438 @param delete_all_resources: if True also delete all known resources form cache
511 @param profile_key: %(doc_profile_key)s 439 @param profile_key: %(doc_profile_key)s