Refactor ping code into own module

This commit is contained in:
Philipp Hörist 2018-06-24 23:22:49 +02:00
parent 81d9e1bcf2
commit 7b957a2876
8 changed files with 155 additions and 120 deletions

View File

@ -1230,14 +1230,16 @@ class ChatControl(ChatControlBase):
return
self.update_ui()
def _nec_ping_reply(self, obj):
if obj.control:
if obj.control != self:
return
else:
if self.contact != obj.contact:
return
self.print_conversation(_('Pong! (%s s.)') % obj.seconds, 'status')
def _nec_ping(self, obj):
if self.contact != obj.contact:
return
if obj.name == 'ping-sent':
self.print_conversation(_('Ping?'), 'status')
elif obj.name == 'ping-reply':
self.print_conversation(
_('Pong! (%s s.)') % obj.seconds, 'status')
elif obj.name == 'ping-error':
self.print_conversation(_('Error.'), 'status')
def show_avatar(self):
if not app.config.get('show_avatar_in_chat'):

View File

@ -193,16 +193,6 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
if self.parent_win:
self.parent_win.redraw_tab(self)
def _nec_ping_sent(self, obj):
if self.contact != obj.contact:
return
self.print_conversation(_('Ping?'), 'status')
def _nec_ping_error(self, obj):
if self.contact != obj.contact:
return
self.print_conversation(_('Error.'), 'status')
def status_url_clicked(self, widget, url):
helpers.launch_browser_mailer('url', url)
@ -381,11 +371,11 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
app.ged.register_event_handler('our-show', ged.GUI1,
self._nec_our_status)
app.ged.register_event_handler('ping-sent', ged.GUI1,
self._nec_ping_sent)
self._nec_ping)
app.ged.register_event_handler('ping-reply', ged.GUI1,
self._nec_ping_reply)
self._nec_ping)
app.ged.register_event_handler('ping-error', ged.GUI1,
self._nec_ping_error)
self._nec_ping)
# This is basically a very nasty hack to surpass the inability
# to properly use the super, because of the old code.

View File

@ -178,7 +178,7 @@ class StandardCommonChatCommands(CommandContainer):
def ping(self):
if self.account == app.ZEROCONF_ACC_NAME:
raise CommandError(_('Command is not supported for zeroconf accounts'))
app.connections[self.account].sendPing(self.contact)
app.connections[self.account].get_module('Ping').send_ping(self.contact)
@command
@doc(_("Send DTMF sequence through an open audio session"))
@ -391,5 +391,5 @@ class StandardGroupChatCommands(CommandContainer):
if self.account == app.ZEROCONF_ACC_NAME:
raise CommandError(_('Command is not supported for zeroconf accounts'))
gc_c = app.contacts.get_gc_contact(self.account, self.room_jid, nick)
app.connections[self.account].sendPing(gc_c, self)
app.connections[self.account].get_module('Ping').send_ping(gc_c)

View File

@ -65,6 +65,7 @@ from gajim.common import i18n
from gajim.common import idle
from gajim.common.modules.entity_time import EntityTime
from gajim.common.modules.software_version import SoftwareVersion
from gajim.common.modules.ping import Ping
from gajim.common.connection_handlers import *
from gajim.common.contacts import GC_Contact
from gajim.gtkgui_helpers import get_action
@ -661,6 +662,7 @@ class Connection(CommonConnection, ConnectionHandlers):
self.register_module('EntityTime', EntityTime, self)
self.register_module('SoftwareVersion', SoftwareVersion, self)
self.register_module('Ping', Ping, self)
app.ged.register_event_handler('privacy-list-received', ged.CORE,
self._nec_privacy_list_received)
@ -1527,45 +1529,6 @@ class Connection(CommonConnection, ConnectionHandlers):
if self.connection:
self.connection.send(' ')
def _on_xmpp_ping_answer(self, iq_obj):
self.awaiting_xmpp_ping_id = None
def sendPing(self, pingTo=None, control=None):
"""
Send XMPP Ping (XEP-0199) request. If pingTo is not set, ping is sent to
server to detect connection failure at application level
If control is set, display result there
"""
if not app.account_is_connected(self.name):
return
id_ = self.connection.getAnID()
if pingTo:
to = pingTo.get_full_jid()
app.nec.push_incoming_event(PingSentEvent(None, conn=self,
contact=pingTo))
else:
to = app.config.get_per('accounts', self.name, 'hostname')
self.awaiting_xmpp_ping_id = id_
iq = nbxmpp.Iq('get', to=to)
iq.addChild(name='ping', namespace=nbxmpp.NS_PING)
iq.setID(id_)
def _on_response(resp):
timePong = time.time()
if not nbxmpp.isResultNode(resp):
app.nec.push_incoming_event(PingErrorEvent(None, conn=self,
contact=pingTo))
return
timeDiff = round(timePong - timePing, 2)
app.nec.push_incoming_event(PingReplyEvent(None, conn=self,
contact=pingTo, seconds=timeDiff, control=control))
if pingTo:
timePing = time.time()
self.connection.SendAndCallForResponse(iq, _on_response)
else:
self.connection.SendAndCallForResponse(iq, self._on_xmpp_ping_answer)
app.idlequeue.set_alarm(self.check_pingalive, app.config.get_per(
'accounts', self.name, 'time_for_ping_alive_answer'))
def get_active_default_lists(self):
if not app.account_is_connected(self.name):
return
@ -1832,8 +1795,10 @@ class Connection(CommonConnection, ConnectionHandlers):
self.connection = con
if not app.account_is_connected(self.name):
return
self.connection.set_send_timeout(self.keepalives, self.send_keepalive)
self.connection.set_send_timeout2(self.pingalives, self.sendPing)
self.connection.set_send_timeout2(
self.pingalives, self.get_module('Ping').send_keepalive_ping)
self.connection.onreceive(None)
self.privacy_rules_requested = False
@ -2963,15 +2928,6 @@ class Connection(CommonConnection, ConnectionHandlers):
self.connection.send(message)
def check_pingalive(self):
if not app.config.get_per('accounts', self.name, 'active'):
# Account may have been disabled
return
if self.awaiting_xmpp_ping_id:
# We haven't got the pong in time, disco and reconnect
log.warning("No reply received for keepalive ping. Reconnecting.")
self.disconnectedReconnCB()
def _reconnect_alarm(self):
if not app.config.get_per('accounts', self.name, 'active'):
# Account may have been disabled

View File

@ -1328,8 +1328,7 @@ ConnectionHTTPUpload):
self.disco_items_ids = []
# IDs of disco#info requests
self.disco_info_ids = []
# ID of urn:xmpp:ping requests
self.awaiting_xmpp_ping_id = None
self.continue_connect_info = None
self.privacy_default_list = None
@ -1363,8 +1362,6 @@ ConnectionHTTPUpload):
self._nec_roster_received)
app.ged.register_event_handler('iq-error-received', ged.CORE,
self._nec_iq_error_received)
app.ged.register_event_handler('ping-received', ged.CORE,
self._nec_ping_received)
app.ged.register_event_handler('subscribe-presence-received',
ged.CORE, self._nec_subscribe_presence_received)
app.ged.register_event_handler('subscribed-presence-received',
@ -1404,8 +1401,6 @@ ConnectionHTTPUpload):
self._nec_roster_received)
app.ged.remove_event_handler('iq-error-received', ged.CORE,
self._nec_iq_error_received)
app.ged.remove_event_handler('ping-received', ged.CORE,
self._nec_ping_received)
app.ged.remove_event_handler('subscribe-presence-received',
ged.CORE, self._nec_subscribe_presence_received)
app.ged.remove_event_handler('subscribed-presence-received',
@ -1902,23 +1897,6 @@ ConnectionHTTPUpload):
app.nec.push_incoming_event(MucAdminReceivedEvent(None, conn=self,
stanza=iq_obj))
def _IqPingCB(self, con, iq_obj):
log.debug('IqPingCB')
app.nec.push_incoming_event(PingReceivedEvent(None, conn=self,
stanza=iq_obj))
raise nbxmpp.NodeProcessed
def _nec_ping_received(self, obj):
if obj.conn.name != self.name:
return
if not self.connection or self.connected < 2:
return
iq_obj = obj.stanza.buildReply('result')
q = iq_obj.getTag('ping')
if q:
iq_obj.delChild(q)
self.connection.send(iq_obj)
def _PrivacySetCB(self, con, iq_obj):
"""
Privacy lists (XEP 016)
@ -2196,7 +2174,6 @@ ConnectionHTTPUpload):
nbxmpp.NS_DISCO_INFO)
con.RegisterHandler('iq', self._DiscoverItemsGetCB, 'get',
nbxmpp.NS_DISCO_ITEMS)
con.RegisterHandler('iq', self._IqPingCB, 'get', nbxmpp.NS_PING)
con.RegisterHandler('iq', self._SearchCB, 'result', nbxmpp.NS_SEARCH)
con.RegisterHandler('iq', self._PrivacySetCB, 'set', nbxmpp.NS_PRIVACY)
con.RegisterHandler('iq', self._ArchiveCB, ns=nbxmpp.NS_MAM_1)

View File

@ -573,10 +573,6 @@ class IqErrorReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
self.errcode = self.stanza.getErrorCode()
return True
class PingReceivedEvent(nec.NetworkIncomingEvent):
name = 'ping-received'
base_network_events = []
class StreamReceivedEvent(nec.NetworkIncomingEvent):
name = 'stream-received'
base_network_events = []
@ -1970,18 +1966,6 @@ class ConnectionLostEvent(nec.NetworkIncomingEvent):
show='offline'))
return True
class PingSentEvent(nec.NetworkIncomingEvent):
name = 'ping-sent'
base_network_events = []
class PingReplyEvent(nec.NetworkIncomingEvent):
name = 'ping-reply'
base_network_events = []
class PingErrorEvent(nec.NetworkIncomingEvent):
name = 'ping-error'
base_network_events = []
class CapsPresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent,
PresenceHelperEvent):
name = 'caps-presence-received'

View File

@ -0,0 +1,122 @@
# This file is part of Gajim.
#
# Gajim is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation; version 3 only.
#
# Gajim is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
# XEP-0199: XMPP Ping
import logging
import time
import nbxmpp
from gajim.common import app
from gajim.common.nec import NetworkIncomingEvent
log = logging.getLogger('gajim.c.m.ping')
class Ping:
def __init__(self, con):
self._con = con
self._account = con.name
self._alarm_time = None
self.handlers = [
('iq', self._answer_request, 'get', nbxmpp.NS_PING),
]
def _get_ping_iq(self, to):
iq = nbxmpp.Iq('get', to=to)
iq.addChild(name='ping', namespace=nbxmpp.NS_PING)
return iq
def send_keepalive_ping(self):
if not app.account_is_connected(self._account):
return
to = app.config.get_per('accounts', self._account, 'hostname')
self._con.connection.SendAndCallForResponse(self._get_ping_iq(to),
self._keepalive_received)
log.info('Send keepalive')
seconds = app.config.get_per('accounts', self._account,
'time_for_ping_alive_answer')
self._alarm_time = app.idlequeue.set_alarm(self._reconnect, seconds)
def _keepalive_received(self, stanza):
log.info('Received keepalive')
app.idlequeue.remove_alarm(self._reconnect, self._alarm_time)
def _reconnect(self):
if not app.config.get_per('accounts', self._account, 'active'):
# Account may have been disabled
return
# We haven't got the pong in time, disco and reconnect
log.warning('No reply received for keepalive ping. Reconnecting...')
self._con.disconnectedReconnCB()
def send_ping(self, contact):
if not app.account_is_connected(self._account):
return
to = contact.get_full_jid()
iq = self._get_ping_iq(to)
log.info('Send ping to %s', to)
self._con.connection.SendAndCallForResponse(
iq, self._pong_received, {'ping_time': time.time(),
'contact': contact})
app.nec.push_incoming_event(
PingSentEvent(None, conn=self._con, contact=contact))
def _pong_received(self, con, stanza, ping_time, contact):
if not nbxmpp.isResultNode(stanza):
log.info('Error: %s', stanza.getError())
app.nec.push_incoming_event(
PingErrorEvent(None, conn=self._con, contact=contact))
return
diff = round(time.time() - ping_time, 2)
log.info('Received pong from %s after %s seconds',
stanza.getFrom(), diff)
app.nec.push_incoming_event(
PingReplyEvent(None, conn=self._con,
contact=contact,
seconds=diff))
def _answer_request(self, con, stanza):
iq = stanza.buildReply('result')
q = iq.getTag('ping')
if q is not None:
iq.delChild(q)
self._con.connection.send(iq)
log.info('Send pong to %s', stanza.getFrom())
raise nbxmpp.NodeProcessed
class PingSentEvent(NetworkIncomingEvent):
name = 'ping-sent'
base_network_events = []
class PingReplyEvent(NetworkIncomingEvent):
name = 'ping-reply'
base_network_events = []
class PingErrorEvent(NetworkIncomingEvent):
name = 'ping-error'
base_network_events = []

View File

@ -1572,14 +1572,18 @@ class GroupchatControl(ChatControlBase):
obj.xhtml, self.session, msg_log_id=obj.msg_log_id,
encrypted=obj.encrypted, displaymarking=obj.displaymarking)
def _nec_ping_reply(self, obj):
if obj.control:
if obj.control != self:
return
else:
if self.contact != obj.contact:
return
self.print_conversation(_('Pong! (%s s.)') % obj.seconds)
def _nec_ping(self, obj):
if self.contact.jid != obj.contact.room_jid:
return
nick = obj.contact.get_shown_name()
if obj.name == 'ping-sent':
self.print_conversation(_('Ping? (%s)') % nick)
elif obj.name == 'ping-reply':
self.print_conversation(
_('Pong! (%s %s s.)') % (nick, obj.seconds))
elif obj.name == 'ping-error':
self.print_conversation(_('Error.'))
def got_connected(self):
# Make autorejoin stop.