2 # NEPI, a framework to manage network experiments
3 # Copyright (C) 2013 INRIA
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
19 # Julien Tribino <julien.tribino@inria.fr>
21 from nepi.util.logger import Logger
22 from nepi.resources.omf.omf6_parser import OMF6Parser
25 from sleekxmpp.exceptions import IqError, IqTimeout
26 class BaseOMFClient(sleekxmpp.ClientXMPP):
29 msg = ("SleekXMPP is not installed. Without this library "
30 "you will be not able to use OMF Resources "
31 "if you want to install SleekXmpp: \n"
32 " git clone -b develop git://github.com/fritzy/SleekXMPP.git \n"
34 " sudo python setup.py install\n")
36 logger = Logger("BaseOMFClient")
39 class BaseOMFClient(object):
43 import xml.etree.ElementTree as ET
45 # inherit from BaseXmpp and XMLstream classes
46 class OMFClient(BaseOMFClient, Logger):
48 .. class:: Class Args :
50 :param jid: Jabber Id (= Xmpp Slice + Date)
52 :param password: Jabber Password (= Xmpp Password)
57 This class is an XMPP Client with customized method
61 def __init__(self, jid, password):
64 :param jid: Jabber Id (= Xmpp Slice + Date)
66 :param password: Jabber Password (= Xmpp Password)
71 Logger.__init__(self, "OMFClient")
73 sleekxmpp.ClientXMPP.__init__(self, jid, password)
75 self._registered = False
79 self.register_plugin('xep_0077') # In-band registration
80 self.register_plugin('xep_0030')
81 self.register_plugin('xep_0059')
82 self.register_plugin('xep_0060') # PubSub
84 self.add_event_handler("session_start", self.start)
85 self.add_event_handler("register", self.register)
86 self.add_event_handler("pubsub_publish", self.handle_omf_message)
91 def _init_parser(self):
92 """ Init the parser depending on the OMF Version
95 self._parser = OMF6Parser()
99 """ Check if the client is ready
104 def start(self, event):
105 """ Send presence to the Xmppp Server. This function is called directly by the sleekXmpp library
110 self._server = "pubsub.%s" % self.boundjid.domain
112 def register(self, iq):
113 """ Register to the Xmppp Server. This function is called directly by the sleekXmpp library
117 msg = " %s already registered!" % self.boundjid
123 resp['register']['username'] = self.boundjid.user
124 resp['register']['password'] = self.password
128 msg = " Account created for %s!" % self.boundjid
130 self._registered = True
132 msg = " Could not register account: %s" % e.iq['error']['text']
135 msg = " No response from server."
138 def unregister(self):
139 """ Unregister from the Xmppp Server.
143 self.plugin['xep_0077'].cancel_registration(
144 ifrom=self.boundjid.full)
145 msg = " Account unregistered for %s!" % self.boundjid
148 msg = " Could not unregister account: %s" % e.iq['error']['text']
151 msg = " No response from server."
155 """ Get all the nodes of the Xmppp Server.
159 result = self['xep_0060'].get_nodes(self._server)
160 for item in result['disco_items']['items']:
161 msg = ' - %s' % str(item)
165 error = traceback.format_exc()
166 msg = 'Could not retrieve node list.\ntraceback:\n%s' % error
169 def subscriptions(self):
170 """ Get all the subscriptions of the Xmppp Server.
174 result = self['xep_0060'].get_subscriptions(self._server)
176 for node in result['node']:
177 msg = ' - %s' % str(node)
181 error = traceback.format_exc()
182 msg = ' Could not retrieve subscriptions.\ntraceback:\n%s' % error
185 def create(self, node):
186 """ Create the topic corresponding to the node
188 :param node: Name of the topic, corresponding to the node (ex : omf.plexus.wlab17)
192 msg = " Create Topic : " + node
195 config = self['xep_0004'].makeForm('submit')
196 config.add_field(var='pubsub#node_type', value='leaf')
197 config.add_field(var='pubsub#notify_retract', value='0')
198 config.add_field(var='pubsub#publish_model', value='open')
199 config.add_field(var='pubsub#persist_items', value='1')
200 config.add_field(var='pubsub#max_items', value='1')
201 config.add_field(var='pubsub#title', value=node)
204 self['xep_0060'].create_node(self._server, node, config = config)
206 #error = traceback.format_exc()
207 #msg = ' Could not create topic: %s\ntraceback:\n%s' % (node, error)
208 msg = 'Could not create the topic : '+node+' . Maybe the topic already exists'
211 def delete(self, node):
212 """ Delete the topic corresponding to the node
214 :param node: Name of the topic, corresponding to the node (ex : omf.plexus.wlab17)
218 # To check if the queue are well empty at the end
219 #print " length of the queue : " + str(self.send_queue.qsize())
220 #print " length of the queue : " + str(self.event_queue.qsize())
222 self['xep_0060'].delete_node(self._server, node)
223 msg = ' Deleted node: %s' % node
226 #error = traceback.format_exc()
227 #msg = ' Could not delete topic: %s\ntraceback:\n%s' % (node, error)
228 msg = 'Could not delete the topic : '+node+' . Maybe It is not the owner of the topic'
231 def publish(self, data, node):
232 """ Publish the data to the corresponding topic
234 :param data: Data that will be published
236 :param node: Name of the topic
241 msg = " Publish to Topic : " + node
244 result = self['xep_0060'].publish(self._server,node,payload=data)
245 # id = result['pubsub']['publish']['item']['id']
246 # print('Published at item id: %s' % id)
248 error = traceback.format_exc()
249 msg = ' Could not publish to: %s\ntraceback:\n%s' % (node, error)
255 :param data: data from which the items will be get back
261 result = self['xep_0060'].get_item(self._server, self.boundjid,
263 for item in result['pubsub']['items']['substanzas']:
264 msg = 'Retrieved item %s: %s' % (item['id'], tostring(item['payload']))
267 error = traceback.format_exc()
268 msg = ' Could not retrieve item %s from topic %s\ntraceback:\n%s' \
269 % (data, self.boundjid, error)
272 def retract(self, data):
275 :param data: data from which the item will be retracted
280 result = self['xep_0060'].retract(self._server, self.boundjid, data)
281 msg = ' Retracted item %s from topic %s' % (data, self.boundjid)
284 error = traceback.format_exc()
285 msg = 'Could not retract item %s from topic %s\ntraceback:\n%s' \
286 % (data, self.boundjid, error)
290 """ Purge the information in the server
294 result = self['xep_0060'].purge(self._server, self.boundjid)
295 msg = ' Purged all items from topic %s' % self.boundjid
298 error = traceback.format_exc()
299 msg = ' Could not purge items from topic %s\ntraceback:\n%s' \
300 % (self.boundjid, error)
303 def subscribe(self, node):
304 """ Subscribe to a topic
306 :param node: Name of the topic
311 result = self['xep_0060'].subscribe(self._server, node)
312 msg = ' Subscribed %s to topic %s' \
313 % (self.boundjid.user, node)
317 error = traceback.format_exc()
318 msg = ' Could not subscribe %s to topic %s\ntraceback:\n%s' \
319 % (self.boundjid.bare, node, error)
322 def unsubscribe(self, node):
323 """ Unsubscribe to a topic
325 :param node: Name of the topic
330 result = self['xep_0060'].unsubscribe(self._server, node)
331 msg = ' Unsubscribed %s from topic %s' % (self.boundjid.bare, node)
334 error = traceback.format_exc()
335 msg = ' Could not unsubscribe %s from topic %s\ntraceback:\n%s' \
336 % (self.boundjid.bare, node, error)
339 def check_mailbox(self, itype, attr):
340 """ Check the mail box
342 :param itype: type of mail
344 :param attr: value wanted
348 return self._parser.check_mailbox(itype, attr)
351 def handle_omf_message(self, iq):
352 """ Handle published/received message
354 :param iq: Stanzas that is currently published/received
358 self._parser.handle(iq)