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
This commit is contained in:
Goffi 2019-04-06 18:51:20 +02:00
commit 5b3aa5c60f

View file

@ -17,10 +17,11 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from functools import partial
from sat.core.i18n import _
from sat.core.constants import Const as C
from sat.memory import cache
from twisted.internet import defer
from twisted.internet import defer, error as internet_error
from twisted.words.protocols.jabber.xmlstream import XMPPHandler
from twisted.words.protocols.jabber import xmlstream
from twisted.words.protocols.jabber import error
@ -53,6 +54,16 @@ class SatXMPPEntity(object):
def __init__(self, host_app, profile, max_retries):
factory = self.factory
# we monkey patch clientConnectionLost to handle networkEnabled/networkDisabled
# and to allow plugins to tune reconnection mechanism
clientConnectionFailed_ori = factory.clientConnectionFailed
clientConnectionLost_ori = factory.clientConnectionLost
factory.clientConnectionFailed = partial(
self.connectionTerminated, term_type=u"failed", cb=clientConnectionFailed_ori)
factory.clientConnectionLost = partial(
self.connectionTerminated, term_type=u"lost", cb=clientConnectionLost_ori)
factory.maxRetries = max_retries
factory.maxDelay = 30
# when self._connected_d is None, we are not connected
@ -275,6 +286,40 @@ class SatXMPPEntity(object):
## connection ##
def connectionTerminated(self, connector, reason, term_type, cb):
"""Display disconnection reason, and call factory method
This method is monkey patched to factory, allowing plugins to handle finely
reconnection with the triggers.
@param connector(twisted.internet.base.BaseConnector): current connector
@param reason(failure.Failure): why connection has been terminated
@param term_type(unicode): on of 'failed' or 'lost'
@param cb(callable): original factory method
@trigger connection_failed(connector, reason): connection can't be established
@trigger connection_lost(connector, reason): connection was available but it not
anymore
"""
# we save connector because it may be deleted when connection will be dropped
# if reconnection is disabled
self._saved_connector = connector
if reason is not None and not isinstance(reason.value,
internet_error.ConnectionDone):
try:
reason_str = unicode(reason.value)
except Exception:
# FIXME: workaround for Android were p4a strips docstrings
# while Twisted use docstring in __str__
# TODO: create a ticket upstream, Twisted should work when optimization
# is used
reason_str = unicode(reason.value.__class__)
log.warning(u"Connection {term_type}: {reason}".format(
term_type = term_type,
reason=reason_str))
if not self.host_app.trigger.point(u"connection_" + term_type, connector, reason):
return
return cb(connector, reason)
def _connected(self, xs):
send_hooks = []
receive_hooks = []