applied the except and raise fixers to the master branch to close the gap with py3
[nepi.git] / src / nepi / resources / omf / omf6_api.py
1 #
2 #    NEPI, a framework to manage network experiments
3 #    Copyright (C) 2013 INRIA
4 #
5 #    This program is free software: you can redistribute it and/or modify
6 #    it under the terms of the GNU General Public License version 2 as
7 #    published by the Free Software Foundation;
8 #
9 #    This program is distributed in the hope that it will be useful,
10 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 #    GNU General Public License for more details.
13 #
14 #    You should have received a copy of the GNU General Public License
15 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 #
17 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
18 #         Julien Tribino <julien.tribino@inria.fr>
19
20 import ssl
21 import sys
22 import time
23
24 from nepi.util.timefuncs import tsformat 
25 import os
26
27 from nepi.util.logger import Logger
28
29 from nepi.resources.omf.omf_client import OMFClient
30 from nepi.resources.omf.messages_6 import MessageHandler
31
32 class OMF6API(Logger):
33     """
34     .. class:: Class Args :
35       
36         :param server: Xmpp Server
37         :type server: str
38         :param user: Xmpp User
39         :type user: str
40         :param port: Xmpp Port
41         :type port: str
42         :param password: Xmpp password
43         :type password: str
44         :param xmpp_root: Root of the Xmpp Topic Architecture
45         :type xmpp_root: str
46
47     .. note::
48
49        This class is the implementation of an OMF 5.4 API. 
50        Since the version 5.4.1, the Topic Architecture start with OMF_5.4 
51        instead of OMF used for OMF5.3
52
53     """
54     def __init__(self, server, user = "nepi", port="5222", password="1234",
55             exp_id = None):
56         """
57         :param server: Xmpp Server
58         :type server: str
59         :param user: Xmpp User
60         :type user: str
61         :param port: Xmpp Port
62         :type port: str
63         :param password: Xmpp password
64         :type password: str
65         :param xmpp_root: Root of the Xmpp Topic Architecture
66         :type xmpp_root: str
67
68         """
69         super(OMF6API, self).__init__("OMF6API")
70         self._exp_id = exp_id
71         self._user = user # name of the machine that run Nepi
72         self._server = server # name of the xmpp server
73         self._port = port # port of the xmpp server
74         self._password = password # password to connect to xmpp
75         self._jid = "%s-%s@%s" % (self._user, self._exp_id, self._server)
76         self._src = "xmpp://" + self._jid
77         
78         self._topics = []
79
80         # OMF xmpp client
81         self._client = None
82
83         # message handler
84         self._message = None
85
86         if sys.version_info < (3, 0):
87             reload(sys)
88             sys.setdefaultencoding('utf8')
89
90         # instantiate the xmpp client
91         self._init_client()
92
93         # register nepi topic
94         self._enroll_nepi()
95
96
97     def _init_client(self):
98         """ Initialize XMPP Client
99
100         """
101         xmpp = OMFClient(self._jid, self._password)
102         # PROTOCOL_SSLv3 required for compatibility with OpenFire
103         xmpp.ssl_version = ssl.PROTOCOL_SSLv3
104
105         if xmpp.connect((self._server, self._port)):
106             xmpp.process(block=False)
107             self.check_ready(xmpp)
108             self._client = xmpp
109             self._message = MessageHandler()
110         else:
111             msg = "Unable to connect to the XMPP server."
112             self.error(msg)
113             raise RuntimeError(msg)
114
115     def check_ready(self, xmpp):
116         delay = 1.0
117         for i in xrange(15):
118             if xmpp.ready:
119                 break
120             else:
121                 time.sleep(delay)
122                 delay = delay * 1.5
123         else:
124             msg = "XMPP Client is not ready after long time"
125             self.error(msg)
126             raise RuntimeError(msg)
127
128     @property
129     def _nepi_topic(self):
130         """ Return the name of the session topic
131
132         """
133         msg = "nepi-" + self._exp_id
134         self.debug(msg)
135         return msg
136
137     def _enroll_nepi(self):
138         """ Create and Subscribe to the session Topic
139
140         """
141         nepi_topic = self._nepi_topic
142         self._client.create(nepi_topic)
143         self._client.subscribe(nepi_topic)
144
145
146     def create_and_enroll_topic(self, topic):
147         """ Create and Subscribe to the session topic and the resources
148             corresponding to the hostname
149
150         :param hostname: Full hrn of the node
151         :type hostname: str
152
153         """
154         if topic in self._topics:
155             return 
156
157         self._topics.append(topic)
158
159         self._client.create(topic)
160         self._client.subscribe(topic)
161
162
163     def enroll_topic(self, topic):
164         """ Create and Subscribe to the session topic and the resources
165             corresponding to the hostname
166
167         """
168         if topic in self._topics:
169             return 
170
171         self._topics.append(topic)
172         self._client.subscribe(topic)
173
174
175     def frcp_inform(self, topic, cid, itype):
176         """ Publish an inform message
177
178         """
179         msg_id = os.urandom(16).encode('hex')
180         timestamp = tsformat()
181         payload = self._message.inform_function(msg_id, self._src, timestamp, props = props ,guards = guards) 
182         
183         self._client.publish(payload, xmpp_node)
184
185     def frcp_configure(self, topic, props = None, guards = None ):
186         """ Publish a configure message
187
188         """
189         msg_id = os.urandom(16).encode('hex')
190         timestamp = tsformat()
191         payload = self._message.configure_function(msg_id, self._src, timestamp ,props = props ,guards = guards) 
192         self._client.publish(payload, topic)
193
194     
195     def frcp_create(self, msg_id, topic, rtype, props = None, guards = None ):
196         """ Publish a create message
197
198         """
199         timestamp = tsformat()
200         payload = self._message.create_function(msg_id, self._src, rtype, timestamp , props = props ,guards = guards) 
201         self._client.publish(payload, topic)
202
203
204     def frcp_request(self, topic, props = None, guards = None ):
205         """ Execute command on the node
206
207         """
208         msg_id = os.urandom(16).encode('hex')
209         timestamp = tsformat()
210         payload = self._message.request_function(msg_id, self._src, timestamp, props = props ,guards = guards) 
211         self._client.publish(payload, xmpp_node)
212
213     def frcp_release(self, msg_id, parent, child, res_id = None, props = None, guards = None ):
214         """ Publish a release message
215
216         """
217         timestamp = tsformat()
218         payload = self._message.release_function(msg_id, self._src, timestamp, res_id = res_id, props = props ,guards = guards) 
219         self._client.publish(payload, parent)
220
221         if child in self._topics:
222             self._topics.remove(child)
223
224         self._client.unsubscribe(child)
225         #self._client.delete(child)
226
227     def check_mailbox(self, itype, attr):
228         """ Check the mail box
229
230         :param itype: type of mail
231         :type itype: str
232         :param attr: value wanted
233         :type attr: str
234
235         """
236         return self._client.check_mailbox(itype, attr)
237
238     def unenroll_topic(self, topic):
239         """ Create and Subscribe to the session topic and the resources
240             corresponding to the hostname
241
242         """
243         if topic in self._topics:
244             self._topics.remove(topic)
245         self._client.unsubscribe(topic)
246
247     def disconnect(self) :
248         """ Delete the session and logger topics. Then disconnect 
249
250         """
251         # To receive the last messages
252         time.sleep(2)
253
254         self._client.delete(self._nepi_topic)
255        
256         # Wait the send queue to be empty before disconnect
257         self._client.disconnect(wait=True)
258         msg = " Disconnected from XMPP Server"
259         self.debug(msg)
260