Coding standards and documentation improvements in client_nb.py

This commit is contained in:
Stephan Erb 2008-12-24 14:41:26 +00:00
parent 5139e7c8d0
commit 40d802284e
1 changed files with 58 additions and 41 deletions

View File

@ -16,10 +16,13 @@
# $Id: client.py,v 1.52 2006/01/02 19:40:55 normanr Exp $ # $Id: client.py,v 1.52 2006/01/02 19:40:55 normanr Exp $
'''
Client class establishs connection to XMPP Server and handles authentication
'''
import socket import socket
import transports_nb, dispatcher_nb, auth_nb, roster_nb, protocol, bosh import transports_nb, dispatcher_nb, auth_nb, roster_nb, protocol, bosh
from client import * from client import PlugIn
from protocol import NS_TLS from protocol import NS_TLS
@ -37,10 +40,11 @@ class NonBlockingClient:
def __init__(self, domain, idlequeue, caller=None): def __init__(self, domain, idlequeue, caller=None):
''' '''
Caches connection data: Caches connection data:
:param domain: domain - for to: attribute (from account info) :param domain: domain - for to: attribute (from account info)
:param idlequeue: processing idlequeue :param idlequeue: processing idlequeue
:param caller: calling object - it has to implement methods _event_dispatcher :param caller: calling object - it has to implement methods
which is called from dispatcher instance _event_dispatcher which is called from dispatcher instance
''' '''
self.Namespace = protocol.NS_CLIENT self.Namespace = protocol.NS_CLIENT
self.defaultNamespace = self.Namespace self.defaultNamespace = self.Namespace
@ -51,7 +55,8 @@ class NonBlockingClient:
self.Server = domain self.Server = domain
self.xmpp_hostname = None # FQDN hostname to connect to self.xmpp_hostname = None # FQDN hostname to connect to
# caller is who initiated this client, it is ineeded to register the EventDispatcher # caller is who initiated this client, it is in needed to register
# the EventDispatcher
self._caller = caller self._caller = caller
self._owner = self self._owner = self
self._registered_name = None self._registered_name = None
@ -68,10 +73,9 @@ class NonBlockingClient:
def disconnect(self, message=''): def disconnect(self, message=''):
''' '''
Called on disconnection - disconnect callback is picked based on state of the Called on disconnection - disconnect callback is picked based on state
client. of the client.
''' '''
# to avoid recursive calls # to avoid recursive calls
if self.disconnecting: return if self.disconnecting: return
@ -102,8 +106,8 @@ class NonBlockingClient:
log.debug('Client disconnected..') log.debug('Client disconnected..')
if connected == '': if connected == '':
# if we're disconnecting before connection to XMPP sever is opened, we don't # if we're disconnecting before connection to XMPP sever is opened,
# call disconnect handlers but on_connect_failure callback # we don't call disconnect handlers but on_connect_failure callback
if self.proxy: if self.proxy:
# with proxy, we have different failure callback # with proxy, we have different failure callback
log.debug('calling on_proxy_failure cb') log.debug('calling on_proxy_failure cb')
@ -114,9 +118,10 @@ class NonBlockingClient:
else: else:
# we are connected to XMPP server # we are connected to XMPP server
if not stream_started: if not stream_started:
# if error occur before XML stream was opened, e.g. no response on init # if error occur before XML stream was opened, e.g. no response on
# request, we call the on_connect_failure callback because proper # init request, we call the on_connect_failure callback because
# connection is not estabilished yet and it's not a proxy issue # proper connection is not estabilished yet and it's not a proxy
# issue
log.debug('calling on_connect_failure cb') log.debug('calling on_connect_failure cb')
self.on_connect_failure() self.on_connect_failure()
else: else:
@ -126,26 +131,26 @@ class NonBlockingClient:
i() i()
self.disconnecting = False self.disconnecting = False
def connect(self, on_connect, on_connect_failure, hostname=None, port=5222, def connect(self, on_connect, on_connect_failure, hostname=None, port=5222,
on_proxy_failure=None, proxy=None, secure_tuple=(None, None, None)): on_proxy_failure=None, proxy=None, secure_tuple=(None, None, None)):
''' '''
Open XMPP connection (open XML streams in both directions). Open XMPP connection (open XML streams in both directions).
:param on_connect: called after stream is successfully opened :param on_connect: called after stream is successfully opened
:param on_connect_failure: called when error occures during connection :param on_connect_failure: called when error occures during connection
:param hostname: hostname of XMPP server from SRV request :param hostname: hostname of XMPP server from SRV request
:param port: port number of XMPP server :param port: port number of XMPP server
:param on_proxy_failure: called if error occurres during TCP connection to :param on_proxy_failure: called if error occurres during TCP connection to
proxy server or during proxy connecting process proxy server or during proxy connecting process
:param proxy: dictionary with proxy data. It should contain at least values :param proxy: dictionary with proxy data. It should contain at least
for keys 'host' and 'port' - connection details for proxy server and values for keys 'host' and 'port' - connection details for proxy serve
optionally keys 'user' and 'pass' as proxy credentials and optionally keys 'user' and 'pass' as proxy credentials
:param secure_tuple: tuple of (desired connection type, cacerts and mycerts) :param secure_tuple: tuple of (desired connection type, cacerts, mycerts)
connection type can be 'ssl' - TLS estabilished after TCP connection, connection type can be 'ssl' - TLS estabilished after TCP connection,
'tls' - TLS estabilished after negotiation with starttls, or 'plain'. 'tls' - TLS estabilished after negotiation with starttls, or 'plain'.
cacerts, mycerts - see tls_nb.NonBlockingTLS constructor for more details cacerts, mycerts - see tls_nb.NonBlockingTLS constructor for more
details
''' '''
self.on_connect = on_connect self.on_connect = on_connect
self.on_connect_failure=on_connect_failure self.on_connect_failure=on_connect_failure
self.on_proxy_failure = on_proxy_failure self.on_proxy_failure = on_proxy_failure
@ -173,9 +178,9 @@ class NonBlockingClient:
# (DNS request will be done for proxy or BOSH CM hostname) # (DNS request will be done for proxy or BOSH CM hostname)
tcp_host, tcp_port, proxy_user, proxy_pass = \ tcp_host, tcp_port, proxy_user, proxy_pass = \
transports_nb.get_proxy_data_from_dict(proxy) transports_nb.get_proxy_data_from_dict(proxy)
if proxy['type'] == 'bosh': if proxy['type'] == 'bosh':
# Setup BOSH transport
self.socket = bosh.NonBlockingBOSH( self.socket = bosh.NonBlockingBOSH(
on_disconnect = self.disconnect, on_disconnect = self.disconnect,
raise_event = self.raise_event, raise_event = self.raise_event,
@ -187,14 +192,16 @@ class NonBlockingClient:
domain = self.Server, domain = self.Server,
bosh_dict = proxy) bosh_dict = proxy)
self.protocol_type = 'BOSH' self.protocol_type = 'BOSH'
self.wait_for_restart_response = proxy['bosh_wait_for_restart_response'] self.wait_for_restart_response = \
proxy['bosh_wait_for_restart_response']
else: else:
# http proxy
proxy_dict['type'] = proxy['type'] proxy_dict['type'] = proxy['type']
proxy_dict['xmpp_server'] = (self.xmpp_hostname, self.Port) proxy_dict['xmpp_server'] = (self.xmpp_hostname, self.Port)
proxy_dict['credentials'] = (proxy_user, proxy_pass) proxy_dict['credentials'] = (proxy_user, proxy_pass)
if not proxy or proxy['type'] != 'bosh': if not proxy or proxy['type'] != 'bosh':
# Setup ordinary TCP transport
self.socket = transports_nb.NonBlockingTCP( self.socket = transports_nb.NonBlockingTCP(
on_disconnect = self.disconnect, on_disconnect = self.disconnect,
raise_event = self.raise_event, raise_event = self.raise_event,
@ -203,6 +210,7 @@ class NonBlockingClient:
certs = certs, certs = certs,
proxy_dict = proxy_dict) proxy_dict = proxy_dict)
# plug transport into client as self.Connection
self.socket.PlugIn(self) self.socket.PlugIn(self)
self._resolve_hostname( self._resolve_hostname(
@ -222,7 +230,7 @@ class NonBlockingClient:
on_success() on_success()
def _try_next_ip(self, err_message=None): def _try_next_ip(self, err_message=None):
'''iterates over IP addresses from getaddrinfo''' '''Iterates over IP addresses tries to connect to it'''
if err_message: if err_message:
log.debug('While looping over DNS A records: %s' % err_message) log.debug('While looping over DNS A records: %s' % err_message)
if self.ip_addresses == []: if self.ip_addresses == []:
@ -236,10 +244,9 @@ class NonBlockingClient:
on_connect=lambda: self._xmpp_connect(socket_type='plain'), on_connect=lambda: self._xmpp_connect(socket_type='plain'),
on_connect_failure=self._try_next_ip) on_connect_failure=self._try_next_ip)
def incoming_stream_version(self): def incoming_stream_version(self):
''' gets version of xml stream''' ''' gets version of xml stream'''
if self.Dispatcher.Stream._document_attrs.has_key('version'): if 'version' in self.Dispatcher.Stream._document_attrs:
return self.Dispatcher.Stream._document_attrs['version'] return self.Dispatcher.Stream._document_attrs['version']
else: else:
return None return None
@ -255,19 +262,23 @@ class NonBlockingClient:
self.connected = socket_type self.connected = socket_type
self._xmpp_connect_machine() self._xmpp_connect_machine()
def _xmpp_connect_machine(self, mode=None, data=None): def _xmpp_connect_machine(self, mode=None, data=None):
''' '''
Finite automaton taking care of stream opening and features tag Finite automaton taking care of stream opening and features tag
handling. Calls _on_stream_start when stream is started, and disconnect() handling. Calls _on_stream_start when stream is started, and disconnect()
on failure. on failure.
''' '''
log.info('-------------xmpp_connect_machine() >> mode: %s, data: %s...' % (mode,str(data)[:20] )) log.info('-------------xmpp_connect_machine() >> mode: %s, data: %s...' %
(mode, str(data)[:20]))
def on_next_receive(mode): def on_next_receive(mode):
'''
Sets desired on_receive callback on transport based on the state of
connect_machine.
'''
log.info('setting %s on next receive' % mode) log.info('setting %s on next receive' % mode)
if mode is None: if mode is None:
self.onreceive(None) self.onreceive(None) # switch to Dispatcher.ProcessNonBlocking
else: else:
self.onreceive(lambda _data:self._xmpp_connect_machine(mode, _data)) self.onreceive(lambda _data:self._xmpp_connect_machine(mode, _data))
@ -286,7 +297,7 @@ class NonBlockingClient:
if data: if data:
self.Dispatcher.ProcessNonBlocking(data) self.Dispatcher.ProcessNonBlocking(data)
if not hasattr(self, 'Dispatcher') or \ if not hasattr(self, 'Dispatcher') or \
self.Dispatcher.Stream._document_attrs is None: self.Dispatcher.Stream._document_attrs is None:
self._xmpp_connect_machine( self._xmpp_connect_machine(
mode='FAILURE', mode='FAILURE',
data='Error on stream open') data='Error on stream open')
@ -320,7 +331,7 @@ class NonBlockingClient:
def _on_stream_start(self): def _on_stream_start(self):
''' '''
Called after XMPP stream is opened. Called after XMPP stream is opened.
TLS negotiation may follow after esabilishing a stream. TLS negotiation may follow when stream is established.
''' '''
self.stream_started = True self.stream_started = True
self.onreceive(None) self.onreceive(None)
@ -358,7 +369,7 @@ class NonBlockingClient:
self.send('<starttls xmlns="%s"/>' % NS_TLS) self.send('<starttls xmlns="%s"/>' % NS_TLS)
else: else:
# we got <proceed> or <failure> # we got <proceed> or <failure>
if tag.getNamespace() <> NS_TLS: if tag.getNamespace() != NS_TLS:
self.disconnect('Unknown namespace: %s' % tag.getNamespace()) self.disconnect('Unknown namespace: %s' % tag.getNamespace())
return return
tagname = tag.getName() tagname = tag.getName()
@ -379,15 +390,17 @@ class NonBlockingClient:
def raise_event(self, event_type, data): def raise_event(self, event_type, data):
''' '''
raises event to connection instance - DATA_SENT and DATA_RECIVED events are Raises event to connection instance. DATA_SENT and DATA_RECIVED events
used in XML console to show XMPP traffic are used in XML console to show XMPP traffic
''' '''
log.info('raising event from transport: :::::%s::::\n_____________\n%s\n_____________\n' % (event_type,data)) log.info('raising event from transport: :::::%s::::\n_____________\n%s\n_____________\n' % (event_type,data))
if hasattr(self, 'Dispatcher'): if hasattr(self, 'Dispatcher'):
self.Dispatcher.Event('', event_type, data) self.Dispatcher.Event('', event_type, data)
# follows code for authentication, resource bind, session and roster download ###############################################################################
# ### follows code for authentication, resource bind, session and roster download
###############################################################################
def auth(self, user, password, resource = '', sasl = 1, on_auth = None): def auth(self, user, password, resource = '', sasl = 1, on_auth = None):
''' '''
Authenticate connnection and bind resource. If resource is not provided Authenticate connnection and bind resource. If resource is not provided
@ -450,13 +463,12 @@ class NonBlockingClient:
else: else:
self.on_auth(self, None) self.on_auth(self, None)
def initRoster(self): def initRoster(self):
''' Plug in the roster. ''' ''' Plug in the roster. '''
if not self.__dict__.has_key('NonBlockingRoster'): if not self.__dict__.has_key('NonBlockingRoster'):
roster_nb.NonBlockingRoster().PlugIn(self) roster_nb.NonBlockingRoster().PlugIn(self)
def getRoster(self, on_ready = None): def getRoster(self, on_ready=None):
''' Return the Roster instance, previously plugging it in and ''' Return the Roster instance, previously plugging it in and
requesting roster from server if needed. ''' requesting roster from server if needed. '''
if self.__dict__.has_key('NonBlockingRoster'): if self.__dict__.has_key('NonBlockingRoster'):
@ -466,10 +478,15 @@ class NonBlockingClient:
def sendPresence(self, jid=None, typ=None, requestRoster=0): def sendPresence(self, jid=None, typ=None, requestRoster=0):
''' Send some specific presence state. ''' Send some specific presence state.
Can also request roster from server if according agrument is set.''' Can also request roster from server if according agrument is set.'''
if requestRoster: roster_nb.NonBlockingRoster().PlugIn(self) if requestRoster:
# FIXME: used somewhere?
roster_nb.NonBlockingRoster().PlugIn(self)
self.send(dispatcher_nb.Presence(to=jid, typ=typ)) self.send(dispatcher_nb.Presence(to=jid, typ=typ))
# following methods are moved from blocking client class from xmpppy: ###############################################################################
### following methods are moved from blocking client class of xmpppy
###############################################################################
def RegisterDisconnectHandler(self,handler): def RegisterDisconnectHandler(self,handler):
''' Register handler that will be called on disconnect.''' ''' Register handler that will be called on disconnect.'''
self.disconnect_handlers.append(handler) self.disconnect_handlers.append(handler)
@ -493,8 +510,8 @@ class NonBlockingClient:
def get_peerhost(self): def get_peerhost(self):
''' '''
Gets the ip address of the account, from which is made connection to the Gets the ip address of the account, from which is made connection to the
server , (e.g. IP and port of gajim's socket. We will create listening socket server (e.g. IP and port of gajim's socket).
on the same ip We will create listening socket on the same ip
''' '''
# FIXME: tuple (ip, port) is expected (and checked for) but port num is # FIXME: tuple (ip, port) is expected (and checked for) but port num is
# useless # useless