annotate sat/plugins/plugin_xep_0198.py @ 3080:16925f494820

plugin XEP-0045: don't fail on `item-not-found` with MAM: Some servers don't store permanently the whole history of MUC with MAM. As a result, an "item-not-found" stanza error can be received when message id used as reference doesn't exist anymore on the server. When this case happens, the history is retrieved in the same way as for a newly joined room (i.e. last 50 messages are requested).
author Goffi <goffi@goffi.org>
date Thu, 05 Dec 2019 23:05:16 +0100
parents ab2696e34d29
children 87b8808ac49d
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
1 #!/usr/bin/env python3
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
2 # -*- coding: utf-8 -*-
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
3
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
4 # SàT plugin for managing raw XML log
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
5 # Copyright (C) 2011 Jérôme Poisson (goffi@goffi.org)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
6
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
7 # This program is free software: you can redistribute it and/or modify
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
8 # it under the terms of the GNU Affero General Public License as published by
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
9 # the Free Software Foundation, either version 3 of the License, or
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
10 # (at your option) any later version.
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
11
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
12 # This program is distributed in the hope that it will be useful,
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
15 # GNU Affero General Public License for more details.
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
16
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
17 # You should have received a copy of the GNU Affero General Public License
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
19
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
20 from sat.core.i18n import _
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
21 from sat.core.constants import Const as C
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
22 from sat.core import exceptions
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
23 from sat.core.log import getLogger
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
24 from twisted.words.protocols.jabber import client as jabber_client
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
25 from twisted.words.protocols.jabber import xmlstream
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
26 from twisted.words.xish import domish
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
27 from twisted.internet import defer
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
28 from twisted.internet import task, reactor
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
29 from functools import partial
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
30 from wokkel import disco, iwokkel
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
31 from zope.interface import implementer
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
32 import collections
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
33 import time
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
34
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
35 log = getLogger(__name__)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
36
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
37 PLUGIN_INFO = {
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
38 C.PI_NAME: "Stream Management",
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
39 C.PI_IMPORT_NAME: "XEP-0198",
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
40 C.PI_TYPE: "XEP",
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
41 C.PI_MODES: C.PLUG_MODE_BOTH,
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
42 C.PI_PROTOCOLS: ["XEP-0198"],
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
43 C.PI_DEPENDENCIES: [],
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
44 C.PI_RECOMMENDATIONS: ["XEP-0045", "XEP-0313"],
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
45 C.PI_MAIN: "XEP_0198",
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
46 C.PI_HANDLER: "yes",
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
47 C.PI_DESCRIPTION: _("""Implementation of Stream Management"""),
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
48 }
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
49
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
50 NS_SM = "urn:xmpp:sm:3"
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
51 SM_ENABLED = '/enabled[@xmlns="' + NS_SM + '"]'
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
52 SM_RESUMED = '/resumed[@xmlns="' + NS_SM + '"]'
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
53 SM_FAILED = '/failed[@xmlns="' + NS_SM + '"]'
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
54 SM_R_REQUEST = '/r[@xmlns="' + NS_SM + '"]'
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
55 SM_A_REQUEST = '/a[@xmlns="' + NS_SM + '"]'
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
56 SM_H_REQUEST = '/h[@xmlns="' + NS_SM + '"]'
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
57 # Max number of stanza to send before requesting ack
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
58 MAX_STANZA_ACK_R = 5
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
59 # Max number of seconds before requesting ack
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
60 MAX_DELAY_ACK_R = 30
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
61 MAX_COUNTER = 2**32
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
62 RESUME_MAX = 5*60
2725
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
63 # if we don't have an answer to ACK REQUEST after this delay, connection is aborted
2729
edd230651138 plugin XEP-0198: rised ACK_TIMEOUT + set req_time to None when timing out to be ready after resuming
Goffi <goffi@goffi.org>
parents: 2727
diff changeset
64 ACK_TIMEOUT = 35
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
65
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
66
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
67 class ProfileSessionData(object):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
68 out_counter = 0
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
69 in_counter = 0
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
70 session_id = None
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
71 location = None
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
72 session_max = None
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
73 # True when an ack answer is expected
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
74 ack_requested = False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
75 last_ack_r = 0
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
76 disconnected_time = None
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
77
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
78 def __init__(self, callback, **kw):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
79 self.buffer = collections.deque()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
80 self.buffer_idx = 0
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
81 self._enabled = False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
82 self.timer = None
2725
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
83 # time used when doing a ack request
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
84 # when it times out, connection is aborted
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
85 self.req_timer = None
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
86 self.callback_data = (callback, kw)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
87
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
88 @property
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
89 def enabled(self):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
90 return self._enabled
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
91
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
92 @enabled.setter
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
93 def enabled(self, enabled):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
94 if enabled:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
95 if self._enabled:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
96 raise exceptions.InternalError(
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
97 "Stream Management can't be enabled twice")
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
98 self._enabled = True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
99 callback, kw = self.callback_data
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
100 self.timer = task.LoopingCall(callback, **kw)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
101 self.timer.start(MAX_DELAY_ACK_R, now=False)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
102 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
103 self._enabled = False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
104 if self.timer is not None:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
105 self.timer.stop()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
106 self.timer = None
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
107
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
108 @property
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
109 def resume_enabled(self):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
110 return self.session_id is not None
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
111
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
112 def reset(self):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
113 self.enabled = False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
114 self.buffer.clear()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
115 self.buffer_idx = 0
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
116 self.in_counter = self.out_counter = 0
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
117 self.session_id = self.location = None
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
118 self.ack_requested = False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
119 self.last_ack_r = 0
2865
9213c6dff48d plugin XEP-0198: reset req_timer on session.reset():
Goffi <goffi@goffi.org>
parents: 2796
diff changeset
120 if self.req_timer is not None:
9213c6dff48d plugin XEP-0198: reset req_timer on session.reset():
Goffi <goffi@goffi.org>
parents: 2796
diff changeset
121 if self.req_timer.active():
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
122 log.error("req_timer has been called/cancelled but not reset")
2865
9213c6dff48d plugin XEP-0198: reset req_timer on session.reset():
Goffi <goffi@goffi.org>
parents: 2796
diff changeset
123 else:
9213c6dff48d plugin XEP-0198: reset req_timer on session.reset():
Goffi <goffi@goffi.org>
parents: 2796
diff changeset
124 self.req_timer.cancel()
9213c6dff48d plugin XEP-0198: reset req_timer on session.reset():
Goffi <goffi@goffi.org>
parents: 2796
diff changeset
125 self.req_timer = None
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
126
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
127 def getBufferCopy(self):
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
128 return list(self.buffer)
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
129
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
130
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
131 class XEP_0198(object):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
132 # FIXME: location is not handled yet
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
133
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
134 def __init__(self, host):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
135 log.info(_("Plugin Stream Management initialization"))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
136 self.host = host
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
137 host.registerNamespace('sm', NS_SM)
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
138 host.trigger.add("stream_hooks", self.addHooks)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
139 host.trigger.add("xml_init", self._XMLInitTrigger)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
140 host.trigger.add("disconnecting", self._disconnectingTrigger)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
141 host.trigger.add("disconnected", self._disconnectedTrigger)
2727
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
142 try:
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
143 self._ack_timeout = int(host.memory.getConfig("", "ack_timeout", ACK_TIMEOUT))
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
144 except ValueError:
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
145 log.error(_("Invalid ack_timeout value, please check your configuration"))
2727
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
146 self._ack_timeout = ACK_TIMEOUT
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
147 if not self._ack_timeout:
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
148 log.info(_("Ack timeout disabled"))
2727
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
149 else:
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
150 log.info(_("Ack timeout set to {timeout}s").format(
2727
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
151 timeout=self._ack_timeout))
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
152
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
153 def profileConnecting(self, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
154 client._xep_0198_session = ProfileSessionData(callback=self.checkAcks,
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
155 client=client)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
156
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
157 def getHandler(self, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
158 return XEP_0198_handler(self)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
159
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
160 def addHooks(self, client, receive_hooks, send_hooks):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
161 """Add hooks to handle in/out stanzas counters"""
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
162 receive_hooks.append(partial(self.onReceive, client=client))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
163 send_hooks.append(partial(self.onSend, client=client))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
164 return True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
165
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
166 def _XMLInitTrigger(self, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
167 """Enable or resume a stream mangement"""
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
168 if not (NS_SM, 'sm') in client.xmlstream.features:
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
169 log.warning(_(
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
170 "Your server doesn't support stream management ({namespace}), this is "
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
171 "used to improve connection problems detection (like network outages). "
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
172 "Please ask your server administrator to enable this feature.".format(
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
173 namespace=NS_SM)))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
174 return True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
175 session = client._xep_0198_session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
176
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
177 # a disconnect timer from a previous disconnection may still be active
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
178 try:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
179 disconnect_timer = session.disconnect_timer
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
180 except AttributeError:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
181 pass
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
182 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
183 if disconnect_timer.active():
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
184 disconnect_timer.cancel()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
185 del session.disconnect_timer
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
186
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
187 if session.resume_enabled:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
188 # we are resuming a session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
189 resume_elt = domish.Element((NS_SM, 'resume'))
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
190 resume_elt['h'] = str(session.in_counter)
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
191 resume_elt['previd'] = session.session_id
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
192 client.send(resume_elt)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
193 session.resuming = True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
194 # session.enabled will be set on <resumed/> reception
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
195 return False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
196 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
197 # we start a new session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
198 assert session.out_counter == 0
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
199 enable_elt = domish.Element((NS_SM, 'enable'))
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
200 enable_elt['resume'] = 'true'
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
201 client.send(enable_elt)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
202 session.enabled = True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
203 return True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
204
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
205 def _disconnectingTrigger(self, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
206 session = client._xep_0198_session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
207 if session.enabled:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
208 self.sendAck(client)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
209 # This is a requested disconnection, so we can reset the session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
210 # to disable resuming and close normally the stream
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
211 session.reset()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
212 return True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
213
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
214 def _disconnectedTrigger(self, client, reason):
2796
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
215 if client.is_component:
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
216 return True
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
217 session = client._xep_0198_session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
218 session.enabled = False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
219 if session.resume_enabled:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
220 session.disconnected_time = time.time()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
221 session.disconnect_timer = reactor.callLater(session.session_max,
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
222 client.disconnectProfile,
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
223 reason)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
224 # disconnectProfile must not be called at this point
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
225 # because session can be resumed
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
226 return False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
227 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
228 return True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
229
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
230 def checkAcks(self, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
231 """Request ack if needed"""
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
232 session = client._xep_0198_session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
233 # log.debug("checkAcks (in_counter={}, out_counter={}, buf len={}, buf idx={})"
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
234 # .format(session.in_counter, session.out_counter, len(session.buffer),
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
235 # session.buffer_idx))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
236 if session.ack_requested or not session.buffer:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
237 return
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
238 if (session.out_counter - session.buffer_idx >= MAX_STANZA_ACK_R
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
239 or time.time() - session.last_ack_r >= MAX_DELAY_ACK_R):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
240 self.requestAck(client)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
241 session.ack_requested = True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
242 session.last_ack_r = time.time()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
243
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
244 def updateBuffer(self, session, server_acked):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
245 """Update buffer and buffer_index"""
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
246 if server_acked > session.buffer_idx:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
247 diff = server_acked - session.buffer_idx
3019
c9f03b1eb64d plugin XEP-0198: catch and log an error if buffer is unexpectedly empty
Goffi <goffi@goffi.org>
parents: 3011
diff changeset
248 try:
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
249 for i in range(diff):
3019
c9f03b1eb64d plugin XEP-0198: catch and log an error if buffer is unexpectedly empty
Goffi <goffi@goffi.org>
parents: 3011
diff changeset
250 session.buffer.pop()
c9f03b1eb64d plugin XEP-0198: catch and log an error if buffer is unexpectedly empty
Goffi <goffi@goffi.org>
parents: 3011
diff changeset
251 except IndexError:
c9f03b1eb64d plugin XEP-0198: catch and log an error if buffer is unexpectedly empty
Goffi <goffi@goffi.org>
parents: 3011
diff changeset
252 log.error(
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
253 "error while cleaning buffer, invalid index (buffer is empty):\n"
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
254 "diff = {diff}\n"
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
255 "server_acked = {server_acked}\n"
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
256 "buffer_idx = {buffer_id}".format(
3019
c9f03b1eb64d plugin XEP-0198: catch and log an error if buffer is unexpectedly empty
Goffi <goffi@goffi.org>
parents: 3011
diff changeset
257 diff=diff, server_acked=server_acked,
c9f03b1eb64d plugin XEP-0198: catch and log an error if buffer is unexpectedly empty
Goffi <goffi@goffi.org>
parents: 3011
diff changeset
258 buffer_id=session.buffer_idx))
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
259 session.buffer_idx += diff
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
260
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
261 def replayBuffer(self, client, buffer_, discard_results=False):
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
262 """Resend all stanza in buffer
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
263
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
264 @param buffer_(collection.deque, list): buffer to replay
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
265 the buffer will be cleared by this method
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
266 @param discard_results(bool): if True, don't replay IQ result stanzas
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
267 """
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
268 while True:
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
269 try:
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
270 stanza = buffer_.pop()
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
271 except IndexError:
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
272 break
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
273 else:
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
274 if ((discard_results
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
275 and stanza.name == 'iq'
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
276 and stanza.getAttribute('type') == 'result')):
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
277 continue
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
278 client.send(stanza)
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
279
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
280 def sendAck(self, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
281 """Send an answer element with current IN counter"""
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
282 a_elt = domish.Element((NS_SM, 'a'))
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
283 a_elt['h'] = str(client._xep_0198_session.in_counter)
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
284 client.send(a_elt)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
285
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
286 def requestAck(self, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
287 """Send a request element"""
2725
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
288 session = client._xep_0198_session
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
289 r_elt = domish.Element((NS_SM, 'r'))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
290 client.send(r_elt)
2725
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
291 if session.req_timer is not None:
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
292 raise exceptions.InternalError("req_timer should not be set")
2727
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
293 if self._ack_timeout:
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
294 session.req_timer = reactor.callLater(self._ack_timeout, self.onAckTimeOut,
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
295 client)
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
296
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
297 def _connectionFailed(self, failure_, connector):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
298 normal_host, normal_port = connector.normal_location
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
299 del connector.normal_location
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
300 log.warning(_(
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
301 "Connection failed using location given by server (host: {host}, port: "
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
302 "{port}), switching to normal host and port (host: {normal_host}, port: "
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
303 "{normal_port})".format(host=connector.host, port=connector.port,
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
304 normal_host=normal_host, normal_port=normal_port)))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
305 connector.host, connector.port = normal_host, normal_port
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
306 connector.connectionFailed = connector.connectionFailed_ori
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
307 del connector.connectionFailed_ori
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
308 return connector.connectionFailed(failure_)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
309
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
310 def onEnabled(self, enabled_elt, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
311 session = client._xep_0198_session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
312 session.in_counter = 0
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
313
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
314 # we check that resuming is possible and that we have a session id
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
315 resume = C.bool(enabled_elt.getAttribute('resume'))
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
316 session_id = enabled_elt.getAttribute('id')
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
317 if not session_id:
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
318 log.warning(_('Incorrect <enabled/> element received, no "id" attribute'))
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
319 if not resume or not session_id:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
320 log.warning(_(
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
321 "You're server doesn't support session resuming with stream management, "
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
322 "please contact your server administrator to enable it"))
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
323 return
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
324
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
325 session.session_id = session_id
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
326
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
327 # XXX: we disable resource binding, which must not be done
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
328 # when we resume the session.
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
329 client.factory.authenticator.res_binding = False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
330
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
331 # location, in case server want resuming session to be elsewhere
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
332 try:
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
333 location = enabled_elt['location']
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
334 except KeyError:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
335 pass
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
336 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
337 # TODO: handle IPv6 here (in brackets, cf. XEP)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
338 try:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
339 domain, port = location.split(':', 1)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
340 port = int(port)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
341 except ValueError:
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
342 log.warning(_("Invalid location received: {location}")
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
343 .format(location=location))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
344 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
345 session.location = (domain, port)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
346 # we monkey patch connector to use the new location
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
347 connector = client.xmlstream.transport.connector
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
348 connector.normal_location = connector.host, connector.port
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
349 connector.host = domain
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
350 connector.port = port
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
351 connector.connectionFailed_ori = connector.connectionFailed
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
352 connector.connectionFailed = partial(self._connectionFailed,
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
353 connector=connector)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
354
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
355 # resuming time
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
356 try:
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
357 max_s = int(enabled_elt['max'])
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
358 except (ValueError, KeyError) as e:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
359 if isinstance(e, ValueError):
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
360 log.warning(_('Invalid "max" attribute'))
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
361 max_s = RESUME_MAX
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
362 log.info(_("Using default session max value ({max_s} s).".format(
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
363 max_s=max_s)))
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
364 log.info(_("Stream Management enabled"))
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
365 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
366 log.info(_(
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
367 "Stream Management enabled, with a resumption time of {res_m} min"
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
368 .format(res_m = max_s/60)))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
369 session.session_max = max_s
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
370
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
371 def onResumed(self, enabled_elt, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
372 session = client._xep_0198_session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
373 assert not session.enabled
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
374 del session.resuming
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
375 server_acked = int(enabled_elt['h'])
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
376 self.updateBuffer(session, server_acked)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
377 resend_count = len(session.buffer)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
378 # we resend all stanza which have not been received properly
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
379 self.replayBuffer(client, session.buffer)
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
380 # now we can continue the session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
381 session.enabled = True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
382 d_time = time.time() - session.disconnected_time
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
383 log.info(_("Stream session resumed (disconnected for {d_time} s, {count} "
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
384 "stanza(s) resent)").format(d_time=int(d_time), count=resend_count))
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
385
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
386 def onFailed(self, failed_elt, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
387 session = client._xep_0198_session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
388 condition_elt = failed_elt.firstChildElement()
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
389 buffer_ = session.getBufferCopy()
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
390 session.reset()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
391
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
392 try:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
393 del session.resuming
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
394 except AttributeError:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
395 # stream management can't be started at all
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
396 msg = _("Can't use stream management")
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
397 if condition_elt is None:
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
398 log.error(msg + '.')
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
399 else:
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
400 log.error(_("{msg}: {reason}").format(
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
401 msg=msg, reason=condition_elt.name))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
402 else:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
403 # only stream resumption failed, we can try full session init
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
404 # XXX: we try to start full session init from this point, with many
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
405 # variables/attributes already initialised with a potentially different
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
406 # jid. This is experimental and may not be safe. It may be more
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
407 # secured to abord the connection and restart everything with a fresh
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
408 # client.
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
409 msg = _("stream resumption not possible, restarting full session")
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
410
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
411 if condition_elt is None:
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
412 log.warning('{msg}.'.format(msg=msg))
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
413 else:
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
414 log.warning("{msg}: {reason}".format(
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
415 msg=msg, reason=condition_elt.name))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
416 # stream resumption failed, but we still can do normal stream management
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
417 # we restore attributes as if the session was new, and init stream
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
418 # we keep everything initialized, and only do binding, roster request
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
419 # and initial presence sending.
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
420 if client.conn_deferred.called:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
421 client.conn_deferred = defer.Deferred()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
422 else:
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
423 log.error("conn_deferred should be called at this point")
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
424 plg_0045 = self.host.plugins.get('XEP-0045')
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
425 plg_0313 = self.host.plugins.get('XEP-0313')
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
426
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
427 # FIXME: we should call all loaded plugins with generic callbacks
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
428 # (e.g. prepareResume and resume), so a hot resuming can be done
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
429 # properly for all plugins.
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
430
3008
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
431 if plg_0045 is not None:
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
432 # we have to remove joined rooms
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
433 muc_join_args = plg_0045.popRooms(client)
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
434 # we need to recreate roster
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
435 client.handlers.remove(client.roster)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
436 client.roster = client.roster.__class__(self.host)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
437 client.roster.setHandlerParent(client)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
438 # bind init is not done when resuming is possible, so we have to do it now
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
439 bind_init = jabber_client.BindInitializer(client.xmlstream)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
440 bind_init.required = True
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
441 d = bind_init.start()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
442 # we set the jid, which may have changed
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
443 d.addCallback(lambda __: setattr(client.factory.authenticator, "jid", client.jid))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
444 # we call the trigger who will send the <enable/> element
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
445 d.addCallback(lambda __: self._XMLInitTrigger(client))
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
446 # then we have to re-request the roster, as changes may have occured
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
447 d.addCallback(lambda __: client.roster.requestRoster())
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
448 # we add got_roster to be sure to have roster before sending initial presence
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
449 d.addCallback(lambda __: client.roster.got_roster)
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
450 if plg_0313 is not None:
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
451 # we retrieve one2one MAM archives
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
452 d.addCallback(lambda __: plg_0313.resume(client))
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
453 # initial presence must be sent manually
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
454 d.addCallback(lambda __: client.presence.available())
3008
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
455 if plg_0045 is not None:
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
456 # we re-join MUC rooms
3008
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
457 muc_d_list = defer.DeferredList(
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
458 [plg_0045.join(*args) for args in muc_join_args])
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
459 d.addCallback(lambda __: muc_d_list)
3011
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
460 # at the end we replay the buffer, as those stanzas have probably not
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
461 # been received
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
462 d.addCallback(lambda __: self.replayBuffer(client, buffer_,
93da7c6f8e0c plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection:
Goffi <goffi@goffi.org>
parents: 3008
diff changeset
463 discard_results=True))
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
464
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
465 def onReceive(self, element, client):
2796
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
466 if not client.is_component:
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
467 session = client._xep_0198_session
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
468 if session.enabled and element.name.lower() in C.STANZA_NAMES:
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
469 session.in_counter += 1 % MAX_COUNTER
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
470
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
471 def onSend(self, obj, client):
2796
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
472 if not client.is_component:
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
473 session = client._xep_0198_session
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
474 if (session.enabled
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
475 and domish.IElement.providedBy(obj)
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
476 and obj.name.lower() in C.STANZA_NAMES):
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
477 session.out_counter += 1 % MAX_COUNTER
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
478 session.buffer.appendleft(obj)
fdc53c8a5439 plugin XEP-0198: don't use hooks on components
Goffi <goffi@goffi.org>
parents: 2795
diff changeset
479 self.checkAcks(client)
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
480
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
481 def onAckRequest(self, r_elt, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
482 self.sendAck(client)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
483
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
484 def onAckAnswer(self, a_elt, client):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
485 session = client._xep_0198_session
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
486 session.ack_requested = False
2727
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
487 if self._ack_timeout:
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
488 if session.req_timer is None:
3008
c8c68a3b0a79 plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done:
Goffi <goffi@goffi.org>
parents: 2865
diff changeset
489 log.error("req_timer should be set")
2727
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
490 else:
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
491 session.req_timer.cancel()
59ac9284dee8 plugin XEP-0198: allow to customise/disable ack_timeout:
Goffi <goffi@goffi.org>
parents: 2725
diff changeset
492 session.req_timer = None
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
493 try:
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
494 server_acked = int(a_elt['h'])
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
495 except ValueError:
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
496 log.warning(_("Server returned invalid ack element, disabling stream "
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
497 "management: {xml}").format(xml=a_elt))
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
498 session.enabled = False
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
499 return
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
500
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
501 if server_acked > session.out_counter:
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
502 log.error(_("Server acked more stanzas than we have sent, disabling stream "
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
503 "management."))
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
504 session.reset()
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
505 return
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
506
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
507 self.updateBuffer(session, server_acked)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
508 self.checkAcks(client)
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
509
2725
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
510 def onAckTimeOut(self, client):
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
511 """Called when a requested ACK has not been received in time"""
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
512 log.info(_("Ack was not received in time, aborting connection"))
3020
af9d71303605 plugin XEP-0198: don't crash if transport is None in onAckTimeOut
Goffi <goffi@goffi.org>
parents: 3019
diff changeset
513 transport = client.xmlstream.transport
af9d71303605 plugin XEP-0198: don't crash if transport is None in onAckTimeOut
Goffi <goffi@goffi.org>
parents: 3019
diff changeset
514 if transport is None:
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
515 log.warning("transport was already removed")
3020
af9d71303605 plugin XEP-0198: don't crash if transport is None in onAckTimeOut
Goffi <goffi@goffi.org>
parents: 3019
diff changeset
516 else:
af9d71303605 plugin XEP-0198: don't crash if transport is None in onAckTimeOut
Goffi <goffi@goffi.org>
parents: 3019
diff changeset
517 transport.abortConnection()
2795
25639611c303 plugin XEP-0198: fixed typo resulting in a crash on resume
Goffi <goffi@goffi.org>
parents: 2729
diff changeset
518 client._xep_0198_session.req_timer = None
2725
d0466af33483 plugin XEP-0198: abort connection if ack is not received after a timeout:
Goffi <goffi@goffi.org>
parents: 2691
diff changeset
519
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
520
3028
ab2696e34d29 Python 3 port:
Goffi <goffi@goffi.org>
parents: 3020
diff changeset
521 @implementer(iwokkel.IDisco)
2691
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
522 class XEP_0198_handler(xmlstream.XMPPHandler):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
523
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
524 def __init__(self, plugin_parent):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
525 self.plugin_parent = plugin_parent
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
526 self.host = plugin_parent.host
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
527
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
528 def connectionInitialized(self):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
529 self.xmlstream.addObserver(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
530 SM_ENABLED, self.plugin_parent.onEnabled, client=self.parent
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
531 )
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
532 self.xmlstream.addObserver(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
533 SM_RESUMED, self.plugin_parent.onResumed, client=self.parent
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
534 )
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
535 self.xmlstream.addObserver(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
536 SM_FAILED, self.plugin_parent.onFailed, client=self.parent
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
537 )
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
538 self.xmlstream.addObserver(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
539 SM_R_REQUEST, self.plugin_parent.onAckRequest, client=self.parent
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
540 )
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
541 self.xmlstream.addObserver(
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
542 SM_A_REQUEST, self.plugin_parent.onAckAnswer, client=self.parent
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
543 )
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
544
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
545 def getDiscoInfo(self, requestor, target, nodeIdentifier=""):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
546 return [disco.DiscoFeature(NS_SM)]
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
547
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
548 def getDiscoItems(self, requestor, target, nodeIdentifier=""):
1ecceac3df96 plugin XEP-0198: Stream Management implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
549 return []