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(