Mercurial > libervia-backend
comparison sat/core/xmpp.py @ 2885:e9016bfd8cb2
core (xmpp): advanced handling of connection termination
factory's clientConnectionFailed and clientConnectionLost methods are monkey patched to allow client to tune termination:
- a warning when connection is lost in an unclean way
- connector is saved to allow to disable automatic reconnection and retry manually later
- new triggers connection_failed and connection_lost allow plugins to tune connection termination workflow
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 06 Apr 2019 18:51:20 +0200 |
parents | 368a60f05d0e |
children | b06cb71079fa |
comparison
equal
deleted
inserted
replaced
2884:368a60f05d0e | 2885:e9016bfd8cb2 |
---|---|
15 # GNU Affero General Public License for more details. | 15 # GNU Affero General Public License for more details. |
16 | 16 |
17 # You should have received a copy of the GNU Affero General Public License | 17 # You should have received a copy of the GNU Affero General Public License |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 from functools import partial | |
20 from sat.core.i18n import _ | 21 from sat.core.i18n import _ |
21 from sat.core.constants import Const as C | 22 from sat.core.constants import Const as C |
22 from sat.memory import cache | 23 from sat.memory import cache |
23 from twisted.internet import defer | 24 from twisted.internet import defer, error as internet_error |
24 from twisted.words.protocols.jabber.xmlstream import XMPPHandler | 25 from twisted.words.protocols.jabber.xmlstream import XMPPHandler |
25 from twisted.words.protocols.jabber import xmlstream | 26 from twisted.words.protocols.jabber import xmlstream |
26 from twisted.words.protocols.jabber import error | 27 from twisted.words.protocols.jabber import error |
27 from twisted.words.protocols.jabber import jid | 28 from twisted.words.protocols.jabber import jid |
28 from twisted.words.xish import domish | 29 from twisted.words.xish import domish |
51 class SatXMPPEntity(object): | 52 class SatXMPPEntity(object): |
52 """Common code for Client and Component""" | 53 """Common code for Client and Component""" |
53 | 54 |
54 def __init__(self, host_app, profile, max_retries): | 55 def __init__(self, host_app, profile, max_retries): |
55 factory = self.factory | 56 factory = self.factory |
57 | |
58 # we monkey patch clientConnectionLost to handle networkEnabled/networkDisabled | |
59 # and to allow plugins to tune reconnection mechanism | |
60 clientConnectionFailed_ori = factory.clientConnectionFailed | |
61 clientConnectionLost_ori = factory.clientConnectionLost | |
62 factory.clientConnectionFailed = partial( | |
63 self.connectionTerminated, term_type=u"failed", cb=clientConnectionFailed_ori) | |
64 factory.clientConnectionLost = partial( | |
65 self.connectionTerminated, term_type=u"lost", cb=clientConnectionLost_ori) | |
66 | |
56 factory.maxRetries = max_retries | 67 factory.maxRetries = max_retries |
57 factory.maxDelay = 30 | 68 factory.maxDelay = 30 |
58 # when self._connected_d is None, we are not connected | 69 # when self._connected_d is None, we are not connected |
59 # else, it's a deferred which fire on disconnection | 70 # else, it's a deferred which fire on disconnection |
60 self._connected_d = None | 71 self._connected_d = None |
272 except: | 283 except: |
273 # we already chained an errback, no need to raise an exception | 284 # we already chained an errback, no need to raise an exception |
274 pass | 285 pass |
275 | 286 |
276 ## connection ## | 287 ## connection ## |
288 | |
289 def connectionTerminated(self, connector, reason, term_type, cb): | |
290 """Display disconnection reason, and call factory method | |
291 | |
292 This method is monkey patched to factory, allowing plugins to handle finely | |
293 reconnection with the triggers. | |
294 @param connector(twisted.internet.base.BaseConnector): current connector | |
295 @param reason(failure.Failure): why connection has been terminated | |
296 @param term_type(unicode): on of 'failed' or 'lost' | |
297 @param cb(callable): original factory method | |
298 | |
299 @trigger connection_failed(connector, reason): connection can't be established | |
300 @trigger connection_lost(connector, reason): connection was available but it not | |
301 anymore | |
302 """ | |
303 # we save connector because it may be deleted when connection will be dropped | |
304 # if reconnection is disabled | |
305 self._saved_connector = connector | |
306 if reason is not None and not isinstance(reason.value, | |
307 internet_error.ConnectionDone): | |
308 try: | |
309 reason_str = unicode(reason.value) | |
310 except Exception: | |
311 # FIXME: workaround for Android were p4a strips docstrings | |
312 # while Twisted use docstring in __str__ | |
313 # TODO: create a ticket upstream, Twisted should work when optimization | |
314 # is used | |
315 reason_str = unicode(reason.value.__class__) | |
316 log.warning(u"Connection {term_type}: {reason}".format( | |
317 term_type = term_type, | |
318 reason=reason_str)) | |
319 if not self.host_app.trigger.point(u"connection_" + term_type, connector, reason): | |
320 return | |
321 return cb(connector, reason) | |
277 | 322 |
278 def _connected(self, xs): | 323 def _connected(self, xs): |
279 send_hooks = [] | 324 send_hooks = [] |
280 receive_hooks = [] | 325 receive_hooks = [] |
281 self.host_app.trigger.point( | 326 self.host_app.trigger.point( |