<s> import random <EOL> from zope . interface import implements <EOL> from twisted . internet import error , interfaces <EOL> from twisted . names import client , dns <EOL> from twisted . names . error import DNSNameError <EOL> from twisted . python . compat import reduce <EOL> class _SRVConnector_ClientFactoryWrapper : <EOL> def __init__ ( self , connector , wrappedFactory ) : <EOL> self . __connector = connector <EOL> self . __wrappedFactory = wrappedFactory <EOL> def startedConnecting ( self , connector ) : <EOL> self . __wrappedFactory . startedConnecting ( self . __connector ) <EOL> def clientConnectionFailed ( self , connector , reason ) : <EOL> self . __connector . connectionFailed ( reason ) <EOL> def clientConnectionLost ( self , connector , reason ) : <EOL> self . __connector . connectionLost ( reason ) <EOL> def __getattr__ ( self , key ) : <EOL> return getattr ( self . __wrappedFactory , key ) <EOL> class SRVConnector : <EOL> """<STR_LIT>""" <EOL> implements ( interfaces . IConnector ) <EOL> stopAfterDNS = <NUM_LIT:0> <EOL> def __init__ ( self , reactor , service , domain , factory , <EOL> protocol = '<STR_LIT>' , connectFuncName = '<STR_LIT>' , <EOL> connectFuncArgs = ( ) , <EOL> connectFuncKwArgs = { } , <EOL> defaultPort = None , <EOL> ) : <EOL> """<STR_LIT>""" <EOL> self . reactor = reactor <EOL> self . service = service <EOL> self . domain = domain <EOL> self . factory = factory <EOL> self . protocol = protocol <EOL> self . connectFuncName = connectFuncName <EOL> self . connectFuncArgs = connectFuncArgs <EOL> self . connectFuncKwArgs = connectFuncKwArgs <EOL> self . _defaultPort = defaultPort <EOL> self . connector = None <EOL> self . servers = None <EOL> self . orderedServers = None <EOL> def connect ( self ) : <EOL> """<STR_LIT>""" <EOL> self . factory . doStart ( ) <EOL> self . factory . startedConnecting ( self ) <EOL> if not self . servers : <EOL> if self . domain is None : <EOL> self . connectionFailed ( error . DNSLookupError ( "<STR_LIT>" ) ) <EOL> return <EOL> d = client . lookupService ( '<STR_LIT>' % ( self . service , <EOL> self . protocol , <EOL> self . domain ) ) <EOL> d . addCallbacks ( self . _cbGotServers , self . _ebGotServers ) <EOL> d . addCallback ( lambda x , self = self : self . _reallyConnect ( ) ) <EOL> if self . _defaultPort : <EOL> d . addErrback ( self . _ebServiceUnknown ) <EOL> d . addErrback ( self . connectionFailed ) <EOL> elif self . connector is None : <EOL> self . _reallyConnect ( ) <EOL> else : <EOL> self . connector . connect ( ) <EOL> def _ebGotServers ( self , failure ) : <EOL> failure . trap ( DNSNameError ) <EOL> self . servers = [ ] <EOL> self . orderedServers = [ ] <EOL> def _cbGotServers ( self , ( answers , auth , add ) ) : <EOL> if len ( answers ) == <NUM_LIT:1> and answers [ <NUM_LIT:0> ] . type == dns . SRV and answers [ <NUM_LIT:0> ] . payload and answers [ <NUM_LIT:0> ] . payload . target == dns . Name ( '<STR_LIT:.>' ) : <EOL> raise error . DNSLookupError ( "<STR_LIT>" <EOL> % ( repr ( self . service ) , repr ( self . domain ) ) ) <EOL> self . servers = [ ] <EOL> self . orderedServers = [ ] <EOL> for a in answers : <EOL> if a . type != dns . SRV or not a . payload : <EOL> continue <EOL> self . orderedServers . append ( ( a . payload . priority , a . payload . weight , <EOL> str ( a . payload . target ) , a . payload . port ) ) <EOL> def _ebServiceUnknown ( self , failure ) : <EOL> """<STR_LIT>""" <EOL> failure . trap ( error . ServiceNameUnknownError ) <EOL> self . servers = [ ( <NUM_LIT:0> , <NUM_LIT:0> , self . domain , self . _defaultPort ) ] <EOL> self . orderedServers = [ ] <EOL> self . connect ( ) <EOL> def _serverCmp ( self , a , b ) : <EOL> if a [ <NUM_LIT:0> ] != b [ <NUM_LIT:0> ] : <EOL> return cmp ( a [ <NUM_LIT:0> ] , b [ <NUM_LIT:0> ] ) <EOL> else : <EOL> return cmp ( a [ <NUM_LIT:1> ] , b [ <NUM_LIT:1> ] ) <EOL> def pickServer ( self ) : <EOL> assert self . servers is not None <EOL> assert self . orderedServers is not None <EOL> if not self . servers and not self . orderedServers : <EOL> return self . domain , self . service <EOL> if not self . servers and self . orderedServers : <EOL> self . servers = self . orderedServers <EOL> self . orderedServers = [ ] <EOL> assert self . servers <EOL> self . servers . sort ( self . _serverCmp ) <EOL> minPriority = self . servers [ <NUM_LIT:0> ] [ <NUM_LIT:0> ] <EOL> weightIndex = zip ( xrange ( len ( self . servers ) ) , [ x [ <NUM_LIT:1> ] for x in self . servers <EOL> if x [ <NUM_LIT:0> ] == minPriority ] ) <EOL> weightSum = reduce ( lambda x , y : ( None , x [ <NUM_LIT:1> ] + y [ <NUM_LIT:1> ] ) , weightIndex , ( None , <NUM_LIT:0> ) ) [ <NUM_LIT:1> ] <EOL> rand = random . randint ( <NUM_LIT:0> , weightSum ) <EOL> for index , weight in weightIndex : <EOL> weightSum -= weight <EOL> if weightSum <= <NUM_LIT:0> : <EOL> chosen = self . servers [ index ] <EOL> del self . servers [ index ] <EOL> self . orderedServers . append ( chosen ) <EOL> p , w , host , port = chosen <EOL> return host , port <EOL> raise RuntimeError , '<STR_LIT>' % self . __class__ . __name__ <EOL> def _reallyConnect ( self ) : <EOL> if self . stopAfterDNS : <EOL> self . stopAfterDNS = <NUM_LIT:0> <EOL> return <EOL> self . host , self . port = self . pickServer ( ) <EOL> assert self . host is not None , '<STR_LIT>' <EOL> assert self . port is not None , '<STR_LIT>' <EOL> connectFunc = getattr ( self . reactor , self . connectFuncName ) <EOL> self . connector = connectFunc ( <EOL> self . host , self . port , <EOL> _SRVConnector_ClientFactoryWrapper ( self , self . factory ) , <EOL> * self . connectFuncArgs , ** self . connectFuncKwArgs ) <EOL> def stopConnecting ( self ) : <EOL> """<STR_LIT>""" <EOL> if self . connector : <EOL> self . connector . stopConnecting ( ) <EOL> else : <EOL> self . stopAfterDNS = <NUM_LIT:1> <EOL> def disconnect ( self ) : <EOL> """<STR_LIT>""" <EOL> if self . connector is not None : <EOL> self . connector . disconnect ( ) <EOL> else : <EOL> self . stopConnecting ( ) <EOL> def getDestination ( self ) : <EOL> assert self . connector <EOL> return self . connector . getDestination ( ) <EOL> def connectionFailed ( self , reason ) : <EOL> self . factory . clientConnectionFailed ( self , reason ) <EOL> self . factory . doStop ( ) <EOL> def connectionLost ( self , reason ) : <EOL> self . factory . clientConnectionLost ( self , reason ) <EOL> self . factory . doStop ( ) </s>
