core: Roster cache refactoring: cache is now managed by client's SatRosterProtocol instance.
This commit is contained in:
parent
26f59a523e
commit
972b4c2555
3 changed files with 73 additions and 66 deletions
|
|
@ -123,7 +123,7 @@ class SAT(service.Service):
|
|||
self.bridge.register("connect", self.connect)
|
||||
self.bridge.register("asyncConnect", self.asyncConnect)
|
||||
self.bridge.register("disconnect", self.disconnect)
|
||||
self.bridge.register("getContacts", self.memory.getContacts)
|
||||
self.bridge.register("getContacts", self.getContacts)
|
||||
self.bridge.register("getLastResource", self.memory.getLastResource)
|
||||
self.bridge.register("getPresenceStatus", self.memory.getPresenceStatus)
|
||||
self.bridge.register("getWaitingSub", self.memory.getWaitingSub)
|
||||
|
|
@ -270,6 +270,18 @@ class SAT(service.Service):
|
|||
if disconnected_cb:
|
||||
disconnected_cb(profile)
|
||||
|
||||
def getContacts(self, profile_key):
|
||||
client = self.getClient(profile_key)
|
||||
if not client:
|
||||
error(_('Asking contacts for a non-existant profile'))
|
||||
return []
|
||||
ret = []
|
||||
for item in client.roster.getItems(): #we get all item for client's roster
|
||||
#and convert them to expected format
|
||||
attr = client.roster.getAttributes(item)
|
||||
ret.append([item.jid.userhost(), attr, item.groups])
|
||||
return ret
|
||||
|
||||
def purgeClient(self, profile):
|
||||
"""Remove reference to a profile client and purge cache
|
||||
the garbage collector can then free the memory"""
|
||||
|
|
|
|||
|
|
@ -120,7 +120,9 @@ class SatRosterProtocol(xmppim.RosterClientProtocol):
|
|||
def __init__(self, host):
|
||||
xmppim.RosterClientProtocol.__init__(self)
|
||||
self.host = host
|
||||
self._groups=set()
|
||||
#XXX: the two following dicts keep a local copy of the roster
|
||||
self._groups = {} #map from groups to bare jids: key=group value=set of bare jids
|
||||
self._jids = {} #map from bare jids to RosterItem: key=jid value=RosterItem
|
||||
|
||||
def rosterCb(self, roster):
|
||||
for raw_jid, item in roster.iteritems():
|
||||
|
|
@ -157,6 +159,18 @@ class SatRosterProtocol(xmppim.RosterClientProtocol):
|
|||
for group in roster_item.groups:
|
||||
item.addElement('group', content=group)
|
||||
return iq.send()
|
||||
|
||||
def getAttributes(self, item):
|
||||
"""Return dictionary of attributes as used in bridge from a RosterItem
|
||||
@param item: RosterItem
|
||||
@return: dictionary of attributes"""
|
||||
item_attr = {'to': str(item.subscriptionTo),
|
||||
'from': str(item.subscriptionFrom),
|
||||
'ask': str(item.ask)
|
||||
}
|
||||
if item.name:
|
||||
item_attr['name'] = item.name
|
||||
return item_attr
|
||||
|
||||
def onRosterSet(self, item):
|
||||
"""Called when a new/update roster item is received"""
|
||||
|
|
@ -167,26 +181,53 @@ class SatRosterProtocol(xmppim.RosterClientProtocol):
|
|||
#may change in the future
|
||||
self.removeItem(item.jid)
|
||||
return
|
||||
item_attr = {'to': str(item.subscriptionTo),
|
||||
'from': str(item.subscriptionFrom),
|
||||
'ask': str(item.ask)
|
||||
}
|
||||
if item.name:
|
||||
item_attr['name'] = item.name
|
||||
info (_("new contact in roster list: %s"), item.jid.full())
|
||||
self.host.memory.addContact(item.jid, item_attr, item.groups, self.parent.profile)
|
||||
self.host.bridge.newContact(item.jid.full(), item_attr, item.groups, self.parent.profile)
|
||||
self._groups.update(item.groups)
|
||||
#self.host.memory.addContact(item.jid, item_attr, item.groups, self.parent.profile)
|
||||
|
||||
bare_jid = item.jid.userhost()
|
||||
self._jids[bare_jid] = item
|
||||
for group in item.groups:
|
||||
self._groups.get(group,set()).add(bare_jid)
|
||||
self.host.bridge.newContact(item.jid.full(), self.getAttributes(item), item.groups, self.parent.profile)
|
||||
|
||||
def onRosterRemove(self, entity):
|
||||
"""Called when a roster removal event is received"""
|
||||
print _("removing %s from roster list") % entity.full()
|
||||
self.host.memory.delContact(entity, self.parent.profile)
|
||||
bare_jid = entity.userhost()
|
||||
|
||||
#we first remove item from local cache (self._groups and self._jids)
|
||||
try:
|
||||
item = self._jids.pop(bare_jid)
|
||||
except KeyError:
|
||||
log.warning("Received a roster remove event for an item not in cache")
|
||||
return
|
||||
for group in item.groups:
|
||||
try:
|
||||
jids_set = self._groups[group]
|
||||
jids_set.remove(bare_jid)
|
||||
if not jids_set:
|
||||
del self._groups[group]
|
||||
except KeyError:
|
||||
log.warning("there is not cache for the group [%(groups)s] of the removed roster item [%(jid)s]" %
|
||||
{"group": group, "jid": bare_jid})
|
||||
|
||||
#then we send the bridge signal
|
||||
self.host.bridge.contactDeleted(entity.userhost(), self.parent.profile)
|
||||
|
||||
def getGroups(self):
|
||||
"""Return a set of groups"""
|
||||
return self._groups
|
||||
"""Return a list of groups"""
|
||||
return self._groups.keys()
|
||||
|
||||
def getItem(self, jid):
|
||||
"""Return RosterItem for a given jid
|
||||
@param jid: jid of the contact
|
||||
@return: RosterItem or None if contact is not in cache"""
|
||||
return self._jids.get(jid.userhost(), None)
|
||||
|
||||
def getItems(self):
|
||||
"""Return all items of the roster"""
|
||||
return self._jids
|
||||
|
||||
|
||||
class SatPresenceProtocol(xmppim.PresenceClientProtocol):
|
||||
|
||||
|
|
@ -243,8 +284,8 @@ class SatPresenceProtocol(xmppim.PresenceClientProtocol):
|
|||
def subscribed(self, entity):
|
||||
xmppim.PresenceClientProtocol.subscribed(self, entity)
|
||||
self.host.memory.delWaitingSub(entity.userhost(), self.parent.profile)
|
||||
contact = self.host.memory.getContact(entity, self.parent.profile)
|
||||
if not contact or contact[0]['to'] == 'False': #we automatically subscribe to 'to' presence
|
||||
item = self.parent.roster.getItem(entity)
|
||||
if not item or not item.subscriptionTo: #we automatically subscribe to 'to' presence
|
||||
debug(_('sending automatic "from" subscription request'))
|
||||
self.subscribe(entity)
|
||||
|
||||
|
|
@ -262,8 +303,8 @@ class SatPresenceProtocol(xmppim.PresenceClientProtocol):
|
|||
|
||||
def subscribeReceived(self, entity):
|
||||
debug (_("subscription request from [%s]") % entity.userhost())
|
||||
contact = self.host.memory.getContact(entity, self.parent.profile)
|
||||
if contact and contact[0]['to'] == 'True':
|
||||
item = self.parent.roster.getItem(entity)
|
||||
if item and item.subscriptionTo:
|
||||
#We automatically accept subscription if we are already subscribed to contact presence
|
||||
debug(_('sending automatic subscription acceptance'))
|
||||
self.subscribed(entity)
|
||||
|
|
@ -273,8 +314,8 @@ class SatPresenceProtocol(xmppim.PresenceClientProtocol):
|
|||
|
||||
def unsubscribeReceived(self, entity):
|
||||
debug (_("unsubscription asked for [%s]") % entity.userhost())
|
||||
contact = self.host.memory.getContact(entity, self.parent.profile)
|
||||
if contact and contact[0]['from'] == 'True': #we automatically remove contact
|
||||
item = self.parent.roster.getItem(entity)
|
||||
if item and item.subscriptionFrom: #we automatically remove contact
|
||||
debug(_('automatic contact deletion'))
|
||||
self.host.delContact(entity.userhost(), self.parent.profile)
|
||||
self.host.bridge.subscribe('unsubscribe', entity.userhost(), self.parent.profile)
|
||||
|
|
|
|||
|
|
@ -491,7 +491,6 @@ class Memory:
|
|||
info (_("Memory manager init"))
|
||||
self.initialized = defer.Deferred()
|
||||
self.host = host
|
||||
self.contacts={}
|
||||
self.presenceStatus={}
|
||||
self.lastResource={} #tmp, will be refactored with bdd integration
|
||||
self.subscriptions={}
|
||||
|
|
@ -655,51 +654,6 @@ class Memory:
|
|||
assert(self.server_features.has_key(profile))
|
||||
return feature in self.server_features[profile]
|
||||
|
||||
|
||||
def addContact(self, contact_jid, attributes, groups, profile_key):
|
||||
debug("Memory addContact: %s",contact_jid.userhost())
|
||||
profile = self.getProfileName(profile_key)
|
||||
if not profile:
|
||||
error (_('Trying to add a contact to a non-existant profile'))
|
||||
return
|
||||
assert(isinstance(attributes,dict))
|
||||
assert(isinstance(groups,set))
|
||||
if not self.contacts.has_key(profile):
|
||||
self.contacts[profile] = {}
|
||||
self.contacts[profile][contact_jid.userhost()]=[attributes, groups]
|
||||
|
||||
def delContact(self, contact_jid, profile_key):
|
||||
debug("Memory delContact: %s",contact_jid.userhost())
|
||||
profile = self.getProfileName(profile_key)
|
||||
if not profile:
|
||||
error (_('Trying to delete a contact for a non-existant profile'))
|
||||
return
|
||||
if self.contacts.has_key(profile) and self.contacts[profile].has_key(contact_jid.userhost()):
|
||||
del self.contacts[profile][contact_jid.userhost()]
|
||||
|
||||
def getContact(self, contact_jid, profile_key):
|
||||
profile = self.getProfileName(profile_key)
|
||||
if not profile:
|
||||
error(_('Asking a contact for a non-existant profile'))
|
||||
return None
|
||||
if self.contacts.has_key(profile) and self.contacts[profile].has_key(contact_jid.userhost()):
|
||||
return self.contacts[profile][contact_jid.userhost()]
|
||||
|
||||
def getContacts(self, profile_key):
|
||||
"""Return list of contacts for given profile
|
||||
@param profile_key: profile key
|
||||
@return list of [contact, attr, groups]"""
|
||||
profile = self.getProfileName(profile_key)
|
||||
if not profile:
|
||||
error(_('Asking contacts for a non-existant profile'))
|
||||
return []
|
||||
ret=[]
|
||||
if self.contacts.has_key(profile):
|
||||
for contact in self.contacts[profile]:
|
||||
attr, groups = self.contacts[profile][contact]
|
||||
ret.append([contact, attr, groups ])
|
||||
return ret
|
||||
|
||||
def getLastResource(self, contact, profile_key):
|
||||
"""Return the last resource used by a contact
|
||||
@param contact: contact jid (unicode)
|
||||
|
|
|
|||
Loading…
Reference in a new issue