diff --git a/sleekxmpp/plugins/xep_0030/disco.py b/sleekxmpp/plugins/xep_0030/disco.py index 78820b45..783eddb3 100644 --- a/sleekxmpp/plugins/xep_0030/disco.py +++ b/sleekxmpp/plugins/xep_0030/disco.py @@ -32,6 +32,21 @@ class xep_0030(base_plugin): Also see . + The XEP-0030 plugin works using a hierarchy of dynamic + node handlers, ranging from global handlers to specific + JID+node handlers. The default set of handlers operate + in a static manner, storing disco information in memory. + However, custom handlers may use any available backend + storage mechanism desired, such as SQLite or Redis. + + Node handler hierarchy: + JID | Node | Level + --------------------- + None | None | Global + Given | None | All nodes for the JID + None | Given | Node on self.xmpp.boundjid + Given | Given | A single node + Stream Handlers: Disco Info -- Any Iq stanze that includes a query with the namespace http://jabber.org/protocol/disco#info. @@ -44,20 +59,33 @@ class xep_0030(base_plugin): disco_info_query -- Received a disco#info Iq query request. disco_items_query -- Received a disco#items Iq query request. + Attributes: + stanza -- A reference to the module containing the stanza classes + provided by this plugin. + static -- Object containing the default set of static node handlers. + xmpp -- The main SleekXMPP object. + Methods: - set_node_handler -- - del_node_handler -- - add_identity -- + set_node_handler -- Assign a handler to a JID/node combination. + del_node_handler -- Remove a handler from a JID/node combination. + get_info -- Retrieve disco#info data, locally or remote. + get_items -- Retrieve disco#items data, locally or remote. + set_identities -- + set_features -- + set_items -- + del_items -- del_identity -- - add_feature -- del_feature -- - add_item -- del_item -- - get_info -- - get_items -- + add_identity -- + add_feature -- + add_item -- """ def plugin_init(self): + """ + Start the XEP-0030 plugin. + """ self.xep = '0030' self.description = 'Service Discovery' self.stanza = sleekxmpp.plugins.xep_0030.stanza @@ -78,14 +106,14 @@ class xep_0030(base_plugin): self.static = StaticDisco(self.xmpp) self._disco_ops = ['get_info', 'set_identities', 'set_features', - 'del_info', 'get_items', 'set_items', 'del_items', + 'get_items', 'set_items', 'del_items', 'add_identity', 'del_identity', 'add_feature', 'del_feature', 'add_item', 'del_item'] - self.handlers = {} + self._handlers = {} for op in self._disco_ops: - self.handlers[op] = {'global': getattr(self.static, op), - 'jid': {}, - 'node': {}} + self._handlers[op] = {'global': getattr(self.static, op), + 'jid': {}, + 'node': {}} def set_node_handler(self, htype, jid=None, node=None, handler=None): """ @@ -112,7 +140,6 @@ class xep_0030(base_plugin): set_identities set_features set_items - del_info del_items del_identity del_feature @@ -133,14 +160,14 @@ class xep_0030(base_plugin): if htype not in self._disco_ops: return if jid is None and node is None: - self.handlers[htype]['global'] = handler + self._handlers[htype]['global'] = handler elif node is None: - self.handlers[htype]['jid'][jid] = handler + self._handlers[htype]['jid'][jid] = handler elif jid is None: jid = self.xmpp.boundjid.full - self.handlers[htype]['node'][(jid, node)] = handler + self._handlers[htype]['node'][(jid, node)] = handler else: - self.handlers[htype]['node'][(jid, node)] = handler + self._handlers[htype]['node'][(jid, node)] = handler def del_node_handler(self, htype, jid, node): """ @@ -263,36 +290,168 @@ class xep_0030(base_plugin): block=kwargs.get('block', None), callback=kwargs.get('callback', None)) - def set_info(self, jid=None, node=None, **kwargs): - self._run_node_handler('set_info', jid, node, kwargs) - - def del_info(self, jid=None, node=None, **kwargs): - self._run_node_handler('del_info', jid, node, kwargs) - def set_items(self, jid=None, node=None, **kwargs): + """ + Set or replace all items for the specified JID/node combination. + + The given items must be in a list or set where each item is a + tuple of the form: (jid, node, name). + + Arguments: + jid -- The JID to modify. + node -- Optional node to modify. + items -- A series of items in tuple format. + """ self._run_node_handler('set_items', jid, node, kwargs) def del_items(self, jid=None, node=None, **kwargs): + """ + Remove all items from the given JID/node combination. + + Arguments: + jid -- The JID to modify. + node -- Optional node to modify. + """ self._run_node_handler('del_items', jid, node, kwargs) - def add_identity(self, jid=None, node=None, **kwargs): - self._run_node_handler('add_identity', jid, node, kwargs) - - def add_feature(self, jid=None, node=None, **kwargs): - self._run_node_handler('add_feature', jid, node, kwargs) - - def del_identity(self, jid=None, node=None, **kwargs): - self._run_node_handler('del_identity', jid, node, kwargs) - - def del_feature(self, jid=None, node=None, **kwargs): - self._run_node_handler('del_feature', jid, node, kwargs) - def add_item(self, jid=None, node=None, **kwargs): + """ + Add a new item element to the given JID/node combination. + + Each item is required to have a JID, but may also specify + a node value to reference non-addressable entities. + + Arguments: + jid -- The JID to modify. + node -- The node to modify. + ijid -- The JID for the item. + inode -- Optional node for the item. + name -- Optional name for the item. + """ self._run_node_handler('add_item', jid, node, kwargs) def del_item(self, jid=None, node=None, **kwargs): + """ + Remove a single item from the given JID/node combination. + + Arguments: + jid -- The JID to modify. + node -- The node to modify. + ijid -- The item's JID. + inode -- The item's node. + """ self._run_node_handler('del_item', jid, node, kwargs) + def add_identity(self, jid=None, node=None, **kwargs): + """ + Add a new identity to the given JID/node combination. + + Each identity must be unique in terms of all four identity + components: category, type, name, and language. + + Multiple, identical category/type pairs are allowed only + if the xml:lang values are different. Likewise, multiple + category/type/xml:lang pairs are allowed so long as the + names are different. A category and type is always required. + + Arguments: + jid -- The JID to modify. + node -- The node to modify. + category -- The identity's category. + itype -- The identity's type. + name -- Optional name for the identity. + lang -- Optional two-letter language code. + """ + self._run_node_handler('add_identity', jid, node, kwargs) + + def add_feature(self, jid=None, node=None, **kwargs): + """ + Add a feature to a JID/node combination. + + Arguments: + jid -- The JID to modify. + node -- The node to modify. + feature -- The namespace of the supported feature. + """ + self._run_node_handler('add_feature', jid, node, kwargs) + + def del_identity(self, jid=None, node=None, **kwargs): + """ + Remove an identity from the given JID/node combination. + + Arguments: + jid -- The JID to modify. + node -- The node to modify. + category -- The identity's category. + itype -- The identity's type value. + name -- Optional, human readable name for the identity. + lang -- Optional, the identity's xml:lang value. + """ + self._run_node_handler('del_identity', jid, node, kwargs) + + def del_feature(self, jid=None, node=None, **kwargs): + """ + Remove a feature from a given JID/node combination. + + Arguments: + jid -- The JID to modify. + node -- The node to modify. + feature -- The feature's namespace. + """ + self._run_node_handler('del_feature', jid, node, kwargs) + + def set_identities(self, jid=None, node=None, **kwargs): + """ + Add or replace all identities for the given JID/node combination. + + The identities must be in a set where each identity is a tuple + of the form: (category, type, lang, name) + + Arguments: + jid -- The JID to modify. + node -- The node to modify. + identities -- A set of identities in tuple form. + lang -- Optional, xml:lang value. + """ + self._run_node_handler('set_identities', jid, node, kwargs) + + def del_identities(self, jid=None, node=None, **kwargs): + """ + Remove all identities for a JID/node combination. + + If a language is specified, only identities using that + language will be removed. + + Arguments: + jid -- The JID to modify. + node -- The node to modify. + lang -- Optional. If given, only remove identities + using this xml:lang value. + """ + self._run_node_handler('del_identities', jid, node, kwargs) + + def set_features(self, jid=None, node=None, **kwargs): + """ + Add or replace the set of supported features + for a JID/node combination. + + Arguments: + jid -- The JID to modify. + node -- The node to modify. + features -- The new set of supported features. + """ + self._run_node_handler('set_features', jid, node, kwargs) + + def del_features(self, jid=None, node=None, **kwargs): + """ + Remove all features from a JID/node combination. + + Arguments: + jid -- The JID to modify. + node -- The node to modify. + """ + self._run_node_handler('del_features', jid, node, kwargs) + def _run_node_handler(self, htype, jid, node, data=None): """ Execute the most specific node handler for the given @@ -309,12 +468,12 @@ class xep_0030(base_plugin): if node is None: node = '' - if self.handlers[htype]['node'].get((jid, node), False): - return self.handlers[htype]['node'][(jid, node)](jid, node, data) - elif self.handlers[htype]['jid'].get(jid, False): - return self.handlers[htype]['jid'][jid](jid, node, data) - elif self.handlers[htype]['global']: - return self.handlers[htype]['global'](jid, node, data) + if self._handlers[htype]['node'].get((jid, node), False): + return self._handlers[htype]['node'][(jid, node)](jid, node, data) + elif self._handlers[htype]['jid'].get(jid, False): + return self._handlers[htype]['jid'][jid](jid, node, data) + elif self._handlers[htype]['global']: + return self._handlers[htype]['global'](jid, node, data) else: return None