Rename client.py to plugin.py, as all client logic has already been moved to client_nb.py

Introduce a get_instance factory method for all plugins and other xmpp related classes. This will help us to decouple plugs in order to make them testable.
This commit is contained in:
Stephan Erb 2009-01-09 00:49:58 +00:00
parent e00f871b26
commit bc3445881f
11 changed files with 75 additions and 42 deletions

View file

@ -13,7 +13,7 @@ Thanks and credits to the xmpppy developers. See: http://xmpppy.sourceforge.net/
import simplexml, protocol, auth_nb, transports_nb, roster_nb import simplexml, protocol, auth_nb, transports_nb, roster_nb
import dispatcher_nb, features_nb, idlequeue, bosh, tls_nb, proxy_connectors import dispatcher_nb, features_nb, idlequeue, bosh, tls_nb, proxy_connectors
from client_nb import NonBlockingClient from client_nb import NonBlockingClient
from client import PlugIn from plugin import PlugIn
from protocol import * from protocol import *
# vim: se ts=3: # vim: se ts=3:

View file

@ -21,7 +21,7 @@ See client_nb.py
''' '''
from protocol import NS_SASL, NS_SESSION, NS_STREAMS, NS_BIND, NS_AUTH from protocol import NS_SASL, NS_SESSION, NS_STREAMS, NS_BIND, NS_AUTH
from protocol import Node, NodeProcessed, isResultNode, Iq, Protocol, JID from protocol import Node, NodeProcessed, isResultNode, Iq, Protocol, JID
from client import PlugIn from plugin import PlugIn
import base64 import base64
import random import random
import itertools import itertools
@ -127,7 +127,7 @@ class SASL(PlugIn):
self.password = password self.password = password
self.on_sasl = on_sasl self.on_sasl = on_sasl
self.realm = None self.realm = None
def plugin(self, owner): def plugin(self, owner):
if 'version' not in self._owner.Dispatcher.Stream._document_attrs: if 'version' not in self._owner.Dispatcher.Stream._document_attrs:
self.startsasl = SASL_UNSUPPORTED self.startsasl = SASL_UNSUPPORTED
@ -255,8 +255,8 @@ class SASL(PlugIn):
# Openfire) # Openfire)
old_features = self._owner.Dispatcher.Stream.features old_features = self._owner.Dispatcher.Stream.features
self._owner.Dispatcher.PlugOut() self._owner.Dispatcher.PlugOut()
dispatcher_nb.Dispatcher().PlugIn(self._owner, after_SASL=True, dispatcher_nb.Dispatcher.get_instance().PlugIn(self._owner,
old_features=old_features) after_SASL=True, old_features=old_features)
self._owner.Dispatcher.restoreHandlers(handlers) self._owner.Dispatcher.restoreHandlers(handlers)
self._owner.User = self.username self._owner.User = self.username

View file

@ -1,6 +1,5 @@
''' XML canonicalisation methods (for XEP-0116) '''
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*-
## src/common/stanza_session.py ## c14n.py
## ##
## Copyright (C) 2007-2008 Brendan Taylor <whateley AT gmail.com> ## Copyright (C) 2007-2008 Brendan Taylor <whateley AT gmail.com>
## ##
@ -18,6 +17,8 @@
## You should have received a copy of the GNU General Public License ## You should have received a copy of the GNU General Public License
## along with Gajim. If not, see <http://www.gnu.org/licenses/>. ## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
## ##
''' XML canonicalisation methods (for XEP-0116) '''
from simplexml import ustr from simplexml import ustr
def c14n(node): def c14n(node):

View file

@ -1,6 +1,5 @@
## client_nb.py ## client_nb.py
## based on client.py, changes backported up to revision 1.60 ## based on client.py, changes backported up to revision 1.60
## ##
## Copyright (C) 2003-2005 Alexey "Snake" Nezhdanov ## Copyright (C) 2003-2005 Alexey "Snake" Nezhdanov
## modified by Dimitur Kirov <dkirov@gmail.com> ## modified by Dimitur Kirov <dkirov@gmail.com>
@ -21,9 +20,7 @@
Client class establishs connection to XMPP Server and handles authentication 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 protocol import NS_TLS from protocol import NS_TLS
import logging import logging
@ -185,7 +182,7 @@ class NonBlockingClient:
if proxy['type'] == 'bosh': if proxy['type'] == 'bosh':
# Setup BOSH transport # Setup BOSH transport
self.socket = bosh.NonBlockingBOSH( self.socket = bosh.NonBlockingBOSH.get_instance(
on_disconnect=self.disconnect, on_disconnect=self.disconnect,
raise_event=self.raise_event, raise_event=self.raise_event,
idlequeue=self.idlequeue, idlequeue=self.idlequeue,
@ -206,7 +203,7 @@ class NonBlockingClient:
if not proxy or proxy['type'] != 'bosh': if not proxy or proxy['type'] != 'bosh':
# Setup ordinary TCP transport # Setup ordinary TCP transport
self.socket = transports_nb.NonBlockingTCP( self.socket = transports_nb.NonBlockingTCP.get_instance(
on_disconnect=self.disconnect, on_disconnect=self.disconnect,
raise_event=self.raise_event, raise_event=self.raise_event,
idlequeue=self.idlequeue, idlequeue=self.idlequeue,
@ -297,7 +294,7 @@ class NonBlockingClient:
if self.__dict__.has_key('Dispatcher'): if self.__dict__.has_key('Dispatcher'):
self.Dispatcher.PlugOut() self.Dispatcher.PlugOut()
self.got_features = False self.got_features = False
dispatcher_nb.Dispatcher().PlugIn(self) dispatcher_nb.Dispatcher.get_instance().PlugIn(self)
on_next_receive('RECEIVE_DOCUMENT_ATTRIBUTES') on_next_receive('RECEIVE_DOCUMENT_ATTRIBUTES')
elif mode == 'FAILURE': elif mode == 'FAILURE':
@ -451,13 +448,13 @@ class NonBlockingClient:
def _on_doc_attrs(self): def _on_doc_attrs(self):
''' Plug authentication objects and start auth. ''' ''' Plug authentication objects and start auth. '''
if self._sasl: if self._sasl:
auth_nb.SASL(self._User, self._Password, auth_nb.SASL.get_instance(self._User, self._Password,
self._on_start_sasl).PlugIn(self) self._on_start_sasl).PlugIn(self)
if not self._sasl or self.SASL.startsasl == 'not-supported': if not self._sasl or self.SASL.startsasl == 'not-supported':
if not self._Resource: if not self._Resource:
self._Resource = 'xmpppy' self._Resource = 'xmpppy'
auth_nb.NonBlockingNonSASL(self._User, self._Password, self._Resource, auth_nb.NonBlockingNonSASL.get_instance(self._User, self._Password,
self._on_old_auth).PlugIn(self) self._Resource, self._on_old_auth).PlugIn(self)
return return
self.SASL.auth() self.SASL.auth()
return True return True
@ -479,7 +476,7 @@ class NonBlockingClient:
self.connected = None # FIXME: is this intended? self.connected = None # FIXME: is this intended?
self._on_sasl_auth(None) self._on_sasl_auth(None)
elif self.SASL.startsasl == 'success': elif self.SASL.startsasl == 'success':
auth_nb.NonBlockingBind().PlugIn(self) auth_nb.NonBlockingBind.get_instance().PlugIn(self)
self.onreceive(self._on_auth_bind) self.onreceive(self._on_auth_bind)
return True return True
@ -495,7 +492,7 @@ class NonBlockingClient:
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.get_instance().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
@ -509,7 +506,7 @@ class NonBlockingClient:
Can also request roster from server if according agrument is set.''' Can also request roster from server if according agrument is set.'''
if requestRoster: if requestRoster:
# FIXME: used somewhere? # FIXME: used somewhere?
roster_nb.NonBlockingRoster().PlugIn(self) roster_nb.NonBlockingRoster.get_instance().PlugIn(self)
self.send(dispatcher_nb.Presence(to=jid, typ=typ)) self.send(dispatcher_nb.Presence(to=jid, typ=typ))
############################################################################### ###############################################################################

View file

@ -22,9 +22,9 @@ different handlers to different XMPP stanzas and namespaces.
import simplexml, sys, locale import simplexml, sys, locale
from xml.parsers.expat import ExpatError from xml.parsers.expat import ExpatError
from client import PlugIn from plugin import PlugIn
from protocol import NS_STREAMS, NS_XMPP_STREAMS, NS_HTTP_BIND, Iq, Presence, \ from protocol import (NS_STREAMS, NS_XMPP_STREAMS, NS_HTTP_BIND, Iq, Presence,
Message, Protocol, Node, Error, ERR_FEATURE_NOT_IMPLEMENTED, StreamError Message, Protocol, Node, Error, ERR_FEATURE_NOT_IMPLEMENTED, StreamError)
import logging import logging
log = logging.getLogger('gajim.c.x.dispatcher_nb') log = logging.getLogger('gajim.c.x.dispatcher_nb')
@ -52,6 +52,16 @@ class Dispatcher():
XMPPDispatcher().PlugIn(client_obj) XMPPDispatcher().PlugIn(client_obj)
elif client_obj.protocol_type == 'BOSH': elif client_obj.protocol_type == 'BOSH':
BOSHDispatcher().PlugIn(client_obj, after_SASL, old_features) BOSHDispatcher().PlugIn(client_obj, after_SASL, old_features)
@classmethod
def get_instance(cls, *args, **kwargs):
'''
Factory Method for object creation.
Use this instead of directly initializing the class in order to make
unit testing much easier.
'''
return cls(*args, **kwargs)
class XMPPDispatcher(PlugIn): class XMPPDispatcher(PlugIn):

View file

@ -1,4 +1,4 @@
## client.py ## plugin.py
## ##
## Copyright (C) 2003-2005 Alexey "Snake" Nezhdanov ## Copyright (C) 2003-2005 Alexey "Snake" Nezhdanov
## ##
@ -82,5 +82,16 @@ class PlugIn:
if hasattr(self,'plugout'): if hasattr(self,'plugout'):
return self.plugout() return self.plugout()
del self._owner del self._owner
@classmethod
def get_instance(cls, *args, **kwargs):
'''
Factory Method for object creation.
Use this instead of directly initializing the class in order to make
unit testing easier. For testing, this method can be patched to inject
mock objects.
'''
return cls(*args, **kwargs)
# vim: se ts=3: # vim: se ts=3:

View file

@ -55,6 +55,16 @@ class ProxyConnector:
self.old_on_receive = old_on_receive self.old_on_receive = old_on_receive
self.start_connecting() self.start_connecting()
@classmethod
def get_instance(cls, *args, **kwargs):
'''
Factory Method for object creation.
Use this instead of directly initializing the class in order to make
unit testing much easier.
'''
return cls(*args, **kwargs)
def start_connecting(self): def start_connecting(self):
raise NotImplementedError raise NotImplementedError

View file

@ -22,7 +22,7 @@ mass-renaming of contacts.
''' '''
from protocol import JID, Iq, Presence, Node, NodeProcessed, NS_ROSTER from protocol import JID, Iq, Presence, Node, NodeProcessed, NS_ROSTER
from client import PlugIn from plugin import PlugIn
import logging import logging
log = logging.getLogger('gajim.c.x.roster_nb') log = logging.getLogger('gajim.c.x.roster_nb')

View file

@ -16,7 +16,7 @@
## GNU General Public License for more details. ## GNU General Public License for more details.
import socket import socket
from client import PlugIn from plugin import PlugIn
import sys import sys
import os import os

View file

@ -25,7 +25,7 @@ connection handling.
''' '''
from simplexml import ustr from simplexml import ustr
from client import PlugIn from plugin import PlugIn
from idlequeue import IdleObject from idlequeue import IdleObject
import proxy_connectors import proxy_connectors
import tls_nb import tls_nb
@ -74,22 +74,27 @@ DISCONNECT_TIMEOUT_SECONDS = 5
#: size of the buffer which reads data from server #: size of the buffer which reads data from server
# if lower, more stanzas will be fragmented and processed twice # if lower, more stanzas will be fragmented and processed twice
RECV_BUFSIZE = 32768 # 2x maximum size of ssl packet, should be plenty RECV_BUFSIZE = 32768 # 2x maximum size of ssl packet, should be plenty
#RECV_BUFSIZE = 16 # FIXME: (#2634) gajim breaks with this setting: it's inefficient but should work. # FIXME: (#2634) gajim breaks with #RECV_BUFSIZE = 16
# it's inefficient but should work. Problem is that connect machine makes wrong
# assumptions and that we only check for pending data in sockets but not in SSL
# buffer...
DATA_RECEIVED='DATA RECEIVED' DATA_RECEIVED = 'DATA RECEIVED'
DATA_SENT='DATA SENT' DATA_SENT = 'DATA SENT'
DISCONNECTED = 'DISCONNECTED' DISCONNECTED = 'DISCONNECTED'
DISCONNECTING = 'DISCONNECTING' DISCONNECTING = 'DISCONNECTING'
CONNECTING = 'CONNECTING' CONNECTING = 'CONNECTING'
PROXY_CONNECTING = 'PROXY_CONNECTING' PROXY_CONNECTING = 'PROXY_CONNECTING'
CONNECTED = 'CONNECTED' CONNECTED = 'CONNECTED'
STATES = [DISCONNECTED, CONNECTING, PROXY_CONNECTING, CONNECTED, DISCONNECTING] STATES = (DISCONNECTED, CONNECTING, PROXY_CONNECTING, CONNECTED, DISCONNECTING)
# Transports have different arguments in constructor and same connect() method.
class NonBlockingTransport(PlugIn): class NonBlockingTransport(PlugIn):
''' '''
Abstract class representing a transport. Abstract class representing a transport.
Subclasses CAN have different constructor signature but connect method SHOULD
be the same.
''' '''
def __init__(self, raise_event, on_disconnect, idlequeue, estabilish_tls, def __init__(self, raise_event, on_disconnect, idlequeue, estabilish_tls,
certs): certs):
@ -322,15 +327,14 @@ class NonBlockingTCP(NonBlockingTransport, IdleObject):
proxyclass = proxy_connectors.SOCKS5Connector proxyclass = proxy_connectors.SOCKS5Connector
elif self.proxy_dict['type'] == 'http' : elif self.proxy_dict['type'] == 'http' :
proxyclass = proxy_connectors.HTTPCONNECTConnector proxyclass = proxy_connectors.HTTPCONNECTConnector
proxyclass( proxyclass.get_instance(
send_method = self.send, send_method=self.send,
onreceive = self.onreceive, onreceive=self.onreceive,
old_on_receive = self.on_receive, old_on_receive=self.on_receive,
on_success = self._on_connect, on_success=self._on_connect,
on_failure = self._on_connect_failure, on_failure=self._on_connect_failure,
xmpp_server = self.proxy_dict['xmpp_server'], xmpp_server=self.proxy_dict['xmpp_server'],
proxy_creds = self.proxy_dict['credentials'] proxy_creds=self.proxy_dict['credentials'])
)
def _on_connect(self): def _on_connect(self):
''' '''
@ -351,7 +355,7 @@ class NonBlockingTCP(NonBlockingTransport, IdleObject):
NonBlockingTLS module NonBlockingTLS module
''' '''
cacerts, mycerts = self.certs cacerts, mycerts = self.certs
result = tls_nb.NonBlockingTLS(cacerts, mycerts).PlugIn(self) result = tls_nb.NonBlockingTLS.get_instance(cacerts, mycerts).PlugIn(self)
if result: if result:
on_succ() on_succ()
else: else:

View file

@ -21,7 +21,7 @@ from common import gajim
import common.xmpp import common.xmpp
from common.xmpp.idlequeue import IdleObject from common.xmpp.idlequeue import IdleObject
from common.xmpp import dispatcher_nb, simplexml from common.xmpp import dispatcher_nb, simplexml
from common.xmpp.client import * from common.xmpp.plugin import *
from common.xmpp.simplexml import ustr from common.xmpp.simplexml import ustr
from common.xmpp.transports_nb import DATA_RECEIVED, DATA_SENT from common.xmpp.transports_nb import DATA_RECEIVED, DATA_SENT
from common.zeroconf import zeroconf from common.zeroconf import zeroconf