mirror of
				https://github.com/Mikaela/Limnoria.git
				synced 2025-10-30 23:27:24 +01:00 
			
		
		
		
	Updated to allow multiple servers.
This commit is contained in:
		
							parent
							
								
									544bfa35da
								
							
						
					
					
						commit
						2336af5525
					
				
							
								
								
									
										5
									
								
								RELNOTES
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								RELNOTES
									
									
									
									
									
								
							| @ -9,12 +9,13 @@ configuration variable won't work.  To fix this, add these lines to | ||||
| your configuration: | ||||
| 
 | ||||
|     supybot.networks.default: <network> | ||||
|     supybot.networks.<network>.server: <server> | ||||
|     supybot.networks.<network>.servers: <server> | ||||
|     supybot.networks.<network>.password: <password> | ||||
| 
 | ||||
| Where <network> is the name of the network you're connecting to, | ||||
| <server> is the old supybot.server, and <password> is the old | ||||
| supybot.password. | ||||
| supybot.password.  Also note the "servers" rather than "server": we | ||||
| now allow the configuration of multiple servers per network. | ||||
| 
 | ||||
| Since we support multiple networks and multiple servers now, the | ||||
| --server option has been removed from scripts/supybot, as has the | ||||
|  | ||||
| @ -183,13 +183,13 @@ class Relay(callbacks.Privmsg): | ||||
|             if serverPort is None: | ||||
|                 raise ValueError, '_connect requires a (server, port) if ' \ | ||||
|                                   'the network is not registered.' | ||||
|             conf.registerNetwork(network, server=('%s:%s' % serverPort)) | ||||
|             conf.registerNetwork(network, servers=('%s:%s' % serverPort,)) | ||||
|         if makeNew: | ||||
|             self.log.info('Creating new Irc for relaying to %s.', network) | ||||
|             newIrc = irclib.Irc(network) | ||||
|             newIrc.state.history = realIrc.state.history | ||||
|             newIrc.callbacks = realIrc.callbacks | ||||
|             driver = drivers.newDriver(serverPort, newIrc) | ||||
|             driver = drivers.newDriver(newIrc) | ||||
|         else: | ||||
|             newIrc = realIrc | ||||
|         self._addIrc(newIrc) | ||||
|  | ||||
| @ -109,7 +109,6 @@ if __name__ == '__main__': | ||||
|     # -p (profiling) | ||||
|     # -O (optimizing) | ||||
|     # -n, --nick (nick) | ||||
|     # -s, --server (server) | ||||
|     # --startup (commands to run onStart) | ||||
|     # --connect (commands to run afterConnect) | ||||
|     # --config (configuration values) | ||||
| @ -216,14 +215,6 @@ if __name__ == '__main__': | ||||
|         sys.stderr.write('default when the bot starts.') | ||||
|         sys.exit(-1) | ||||
| 
 | ||||
|     server = network.server() | ||||
|     if ':' in server: | ||||
|         serverAndPort = server.split(':', 1) | ||||
|         serverAndPort[1] = int(serverAndPort[1]) | ||||
|         server = tuple(serverAndPort) | ||||
|     else: | ||||
|         server = (server, 6667) | ||||
| 
 | ||||
|     if options.optimize: | ||||
|         # This doesn't work anymore. | ||||
|         __builtins__.__debug__ = False | ||||
| @ -262,7 +253,7 @@ if __name__ == '__main__': | ||||
|     irc = irclib.Irc(network=defaultNetwork) | ||||
|     callback = Owner.Class() | ||||
|     irc.addCallback(callback) | ||||
|     driver = drivers.newDriver(server, irc) | ||||
|     driver = drivers.newDriver(irc) | ||||
| 
 | ||||
|     if options.debug: | ||||
|         for (name, module) in sys.modules.iteritems(): | ||||
|  | ||||
| @ -63,28 +63,45 @@ class AsyncoreRunnerDriver(drivers.IrcDriver): | ||||
| 
 | ||||
| 
 | ||||
| class AsyncoreDriver(asynchat.async_chat, object): | ||||
|     def __init__(self, (server, port), irc): | ||||
|     def __init__(self, irc): | ||||
|         asynchat.async_chat.__init__(self) | ||||
|         self.server = (server, port) | ||||
|         self.irc = irc | ||||
|         self.irc.driver = self | ||||
|         self.buffer = '' | ||||
|         self.servers = () | ||||
|         self.networkGroup = conf.supybot.networks.get(self.irc.network) | ||||
|         self.set_terminator('\n') | ||||
|         # XXX: Use utils.getSocket. | ||||
|         self.create_socket(socket.AF_INET, socket.SOCK_STREAM) | ||||
|         try: | ||||
|             self.connect(self.server) | ||||
|             self.connect(self._getNextServer()) | ||||
|         except socket.error, e: | ||||
|             log.warning('Error connecting to %s: %s', self.server[0], e) | ||||
|             log.warning('Error connecting to %s: %s', self.currentServer, e) | ||||
|             self.reconnect(wait=True) | ||||
| 
 | ||||
|     def _getServers(self): | ||||
|         # We do this, rather than itertools.cycle the servers in __init__, | ||||
|         # because otherwise registry updates given as setValues or sets | ||||
|         # wouldn't be visible until a restart. | ||||
|         return self.networkGroup.servers()[:] # Be sure to copy! | ||||
| 
 | ||||
|     def _getNextServer(self): | ||||
|         if not self.servers: | ||||
|             self.servers = self._getServers() | ||||
|         assert self.servers, 'Servers value for %s is empty.' % \ | ||||
|                              self.networkGroup.name | ||||
|         server = self.servers.pop(0) | ||||
|         self.currentServer = '%s:%s' % server | ||||
|         return server | ||||
|          | ||||
|     def _scheduleReconnect(self, at=60): | ||||
|         when = time.time() + at | ||||
|         if not world.dying: | ||||
|             whenS = log.timestamp(when) | ||||
|             log.info('Scheduling reconnect to %s at %s', self.server[0], whenS) | ||||
|             log.info('Scheduling reconnect to %s at %s', | ||||
|                      self.currentServer, whenS) | ||||
|         def makeNewDriver(): | ||||
|             self.irc.reset() | ||||
|             driver = self.__class__(self.server, self.irc) | ||||
|             driver = self.__class__(self.irc) | ||||
|         schedule.addEvent(makeNewDriver, when) | ||||
| 
 | ||||
|     def writable(self): | ||||
|  | ||||
							
								
								
									
										33
									
								
								src/conf.py
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								src/conf.py
									
									
									
									
									
								
							| @ -163,20 +163,41 @@ registerGlobalValue(supybot, 'user', | ||||
|     registry.String('Supybot %s' % version, """Determines the user the bot | ||||
|     sends to the server.""")) | ||||
| 
 | ||||
| # TODO: Make this check for validity. | ||||
| registerGroup(supybot, 'networks') | ||||
| registerGlobalValue(supybot.networks, 'default', registry.String('', | ||||
|     """Determines what the default network joined by the bot will be.""")) | ||||
| registerGlobalValue(supybot.networks, 'default', | ||||
|     registry.String('', """Determines what the default network joined by the | ||||
|     bot will be.""")) | ||||
| 
 | ||||
| def registerNetwork(name, password='', server=''): | ||||
| class Servers(registry.SpaceSeparatedListOfStrings): | ||||
|     def normalize(self, s): | ||||
|         if ':' not in s: | ||||
|             s += ':6667' | ||||
|         return s | ||||
| 
 | ||||
|     def convert(self, s): | ||||
|         s = self.normalize(s) | ||||
|         (server, port) = s.split(':') | ||||
|         port = int(port) | ||||
|         return (server, port) | ||||
|      | ||||
|     def __call__(self): | ||||
|         L = registry.SpaceSeparatedListOfStrings.__call__(self) | ||||
|         return map(self.convert, L) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return ' '.join(registry.SpaceSeparatedListOfStrings.__call__(self)) | ||||
|          | ||||
| def registerNetwork(name, password='', servers=()): | ||||
|     name = intern(name) | ||||
|     network = registerGroup(supybot.networks, name) | ||||
|     registerGlobalValue(network, 'password', registry.String(password, | ||||
|         """Determines what password will be used on %s.  Yes, we know that | ||||
|         technically passwords are server-specific and not network-specific, | ||||
|         but this is the best we can do right now.""" % name)) | ||||
|     registerGlobalValue(network, 'server', registry.String(server, | ||||
|         """Determines what server the bot will connect to for %s.""" % name)) | ||||
|     registerGlobalValue(network, 'servers', Servers(servers, | ||||
|         """Determines what servers the bot will connect to for %s.  Each will | ||||
|         be tried in order, wrapping back to the first when the cycle is | ||||
|         completed.""" % name)) | ||||
|     return network | ||||
| 
 | ||||
| # Let's fill our networks. | ||||
|  | ||||
| @ -54,8 +54,6 @@ class IrcDriver(object): | ||||
|     """Base class for drivers.""" | ||||
|     def __init__(self): | ||||
|         add(self.name(), self) | ||||
|         if not hasattr(self, 'irc'): | ||||
|             self.irc = None # This is to satisfy PyChecker. | ||||
| 
 | ||||
|     def run(self): | ||||
|         raise NotImplementedError | ||||
| @ -113,7 +111,7 @@ def run(): | ||||
|             del _drivers[name] | ||||
|         _drivers[name] = driver | ||||
| 
 | ||||
| def newDriver(server, irc, moduleName=None): | ||||
| def newDriver(irc, moduleName=None): | ||||
|     """Returns a new driver for the given server using the irc given and using | ||||
|     conf.supybot.driverModule to determine what driver to pick.""" | ||||
|     if moduleName is None: | ||||
| @ -128,9 +126,8 @@ def newDriver(server, irc, moduleName=None): | ||||
|     elif not moduleName.startswith('supybot.'): | ||||
|         moduleName = 'supybot.' + moduleName | ||||
|     driverModule = __import__(moduleName, {}, {}, ['not empty']) | ||||
|     log.debug('Creating new driver for %s:%s (%s)', | ||||
|               server[0], server[1], moduleName) | ||||
|     driver = driverModule.Driver(server, irc) | ||||
|     log.debug('Creating new driver for %s.', irc) | ||||
|     driver = driverModule.Driver(irc) | ||||
|     irc.driver = driver | ||||
|     return driver | ||||
| 
 | ||||
|  | ||||
| @ -53,30 +53,47 @@ import supybot.drivers as drivers | ||||
| import supybot.ircmsgs as ircmsgs | ||||
| import supybot.schedule as schedule | ||||
| 
 | ||||
| instances = 0 | ||||
| originalPoll = conf.supybot.drivers.poll() | ||||
| def resetPoll(): | ||||
|     log.info('Resetting supybot.drivers.poll to %s', originalPoll) | ||||
|     conf.supybot.drivers.poll.setValue(originalPoll) | ||||
| atexit.register(resetPoll) | ||||
| 
 | ||||
| reconnectWaits = (0, 60, 300) | ||||
| class SocketDriver(drivers.IrcDriver): | ||||
|     def __init__(self, (server, port), irc, reconnectWaits=(0, 60, 300)): | ||||
|         global instances | ||||
|         instances += 1 | ||||
|         conf.supybot.drivers.poll.setValue(originalPoll / instances) | ||||
|         self.server = (server, port) | ||||
|         drivers.IrcDriver.__init__(self) # Must come after server is set. | ||||
|     def __init__(self, irc): | ||||
|         self.irc = irc | ||||
|         self.irc.driver = self | ||||
|         drivers.IrcDriver.__init__(self) # Must come after setting irc. | ||||
|         self.networkGroup = conf.supybot.networks.get(self.irc.network) | ||||
|         self.servers = () | ||||
|         self.eagains = 0 | ||||
|         self.inbuffer = '' | ||||
|         self.outbuffer = '' | ||||
|         self.connected = False | ||||
|         self.eagains = 0 | ||||
|         self.reconnectWaitsIndex = 0 | ||||
|         self.reconnectWaits = reconnectWaits | ||||
|         self.connect() | ||||
| 
 | ||||
|     def _getServers(self): | ||||
|         # We do this, rather than itertools.cycle the servers in __init__, | ||||
|         # because otherwise registry updates given as setValues or sets | ||||
|         # wouldn't be visible until a restart. | ||||
|         return self.networkGroup.servers()[:] # Be sure to copy! | ||||
| 
 | ||||
|     def _getNextServer(self): | ||||
|         if not self.servers: | ||||
|             self.servers = self._getServers() | ||||
|         assert self.servers, 'Servers value for %s is empty.' % \ | ||||
|                              self.networkGroup.name | ||||
|         server = self.servers.pop(0) | ||||
|         self.currentServer = '%s:%s' % server | ||||
|         return server | ||||
|          | ||||
|     def _handleSocketError(self, e): | ||||
|         # (11, 'Resource temporarily unavailable') raised if connect | ||||
|         # hasn't finished yet.  We'll keep track of how many we get. | ||||
|         if e.args[0] != 11 and self.eagains > 120: | ||||
|             log.warning('Disconnect from %s: %s.', | ||||
|                         self.currentServer, e.args[1]) | ||||
|             self.reconnect(wait=True) | ||||
|         else: | ||||
|             log.debug('Got EAGAIN, current count: %s.', self.eagains) | ||||
|             self.eagains += 1 | ||||
| 
 | ||||
|     def _sendIfMsgs(self): | ||||
|         msgs = [self.irc.takeMsg()] | ||||
|         while msgs[-1] is not None: | ||||
| @ -89,15 +106,7 @@ class SocketDriver(drivers.IrcDriver): | ||||
|                 self.outbuffer = self.outbuffer[sent:] | ||||
|                 self.eagains = 0 | ||||
|             except socket.error, e: | ||||
|                 # (11, 'Resource temporarily unavailable') raised if connect | ||||
|                 # hasn't finished yet. | ||||
|                 if e.args[0] != 11 and self.eagains > 120: | ||||
|                     server = '%s:%s' % self.server | ||||
|                     log.warning('Disconnect from %s: %s', server, e.args[1]) | ||||
|                     self.reconnect(wait=True) | ||||
|                 else: | ||||
|                     log.debug('Got EAGAIN, current count: %s', self.eagains) | ||||
|                     self.eagains += 1 | ||||
|                 self._handleSocketError(e) | ||||
| 
 | ||||
|     def run(self): | ||||
|         if not self.connected: | ||||
| @ -119,13 +128,7 @@ class SocketDriver(drivers.IrcDriver): | ||||
|         except socket.timeout: | ||||
|             pass | ||||
|         except socket.error, e: | ||||
|             # Same as with _sendIfMsgs. | ||||
|             if e.args[0] != 11 or self.eagains > 120: | ||||
|                 log.warning('Disconnect from %s: %s', self.server, e) | ||||
|                 self.reconnect(wait=True) | ||||
|             else: | ||||
|                 log.debug('Got EAGAIN, current count: %s', self.eagains) | ||||
|                 self.eagains += 1 | ||||
|             self._handleSocketError(e) | ||||
|             return | ||||
|         self._sendIfMsgs() | ||||
| 
 | ||||
| @ -133,7 +136,7 @@ class SocketDriver(drivers.IrcDriver): | ||||
|         self.reconnect(reset=False, **kwargs) | ||||
|          | ||||
|     def reconnect(self, wait=False, reset=True): | ||||
|         server = '%s:%s' % self.server | ||||
|         server = self._getNextServer() | ||||
|         if reset: | ||||
|             log.debug('Resetting %s.', self.irc) | ||||
|             self.irc.reset() | ||||
| @ -143,16 +146,17 @@ class SocketDriver(drivers.IrcDriver): | ||||
|             log.info('Reconnect called on driver for %s.', self.irc) | ||||
|             self.conn.close() | ||||
|         elif not wait: | ||||
|             log.info('Connecting to %s.', server) | ||||
|             log.info('Connecting to %s.', self.currentServer) | ||||
|         self.connected = False | ||||
|         if wait: | ||||
|             log.info('Reconnect to %s waiting.', server) | ||||
|             log.info('Reconnect to %s waiting.', self.currentServer) | ||||
|             self._scheduleReconnect() | ||||
|             return | ||||
|         try: | ||||
|             self.conn = utils.getSocket(self.server[0]) | ||||
|             self.conn = utils.getSocket(server[0]) | ||||
|         except socket.error, e: | ||||
|             log.warning('Error connecting to %s: %s', server, e.args[1]) | ||||
|             log.warning('Error connecting to %s: %s', | ||||
|                         self.currentServer, e.args[1]) | ||||
|             self.reconnect(wait=True) | ||||
|             return | ||||
|         # We allow more time for the connect here, since it might take longer. | ||||
| @ -161,7 +165,7 @@ class SocketDriver(drivers.IrcDriver): | ||||
|         if self.reconnectWaitsIndex < len(self.reconnectWaits)-1: | ||||
|             self.reconnectWaitsIndex += 1 | ||||
|         try: | ||||
|             self.conn.connect(self.server) | ||||
|             self.conn.connect(server) | ||||
|             self.conn.settimeout(conf.supybot.drivers.poll()) | ||||
|         except socket.error, e: | ||||
|             if e.args[0] == 115: | ||||
| @ -172,7 +176,7 @@ class SocketDriver(drivers.IrcDriver): | ||||
|                          'check for %s', whenS) | ||||
|                 schedule.addEvent(self._checkAndWriteOrReconnect, when) | ||||
|             else: | ||||
|                 log.warning('Error connecting to %s: %s', self.server[0], e) | ||||
|                 log.warning('Error connecting to %s: %s', self.currentServer,e) | ||||
|                 self.reconnect(wait=True) | ||||
|             return | ||||
|         self.connected = True | ||||
| @ -186,15 +190,15 @@ class SocketDriver(drivers.IrcDriver): | ||||
|             self.connected = True | ||||
|             self.reconnectWaitPeriodsIndex = 0 | ||||
|         else: | ||||
|             log.warning('Error connecting to %s: Timed out.', self.server[0]) | ||||
|             log.warning('Error connecting to %s: Timed out.',self.currentServer) | ||||
|             self.reconnect() | ||||
| 
 | ||||
|     def _scheduleReconnect(self): | ||||
|         when = time.time() + self.reconnectWaits[self.reconnectWaitsIndex] | ||||
|         if not world.dying: | ||||
|             whenS = log.timestamp(when) | ||||
|             server = '%s:%s' % self.server | ||||
|             log.info('Scheduling reconnect to %s at %s', server, whenS) | ||||
|             log.info('Scheduling reconnect to %s at %s', | ||||
|                      self.irc.network, whenS) | ||||
|         schedule.addEvent(self.reconnect, when) | ||||
| 
 | ||||
|     def die(self): | ||||
| @ -203,7 +207,7 @@ class SocketDriver(drivers.IrcDriver): | ||||
|         # self.irc.die() Kill off the ircs yourself, jerk! | ||||
| 
 | ||||
|     def name(self): | ||||
|         return '%s%s' % (self.__class__.__name__, self.server) | ||||
|         return '%s(%s)' % (self.__class__.__name__, self.irc) | ||||
| 
 | ||||
| 
 | ||||
| Driver = SocketDriver | ||||
|  | ||||
| @ -92,12 +92,29 @@ class SupyIrcProtocol(LineReceiver): | ||||
| class SupyReconnectingFactory(ReconnectingClientFactory): | ||||
|     maxDelay = 300 | ||||
|     protocol = SupyIrcProtocol | ||||
|     def __init__(self, (server, port), irc): | ||||
|     def __init__(self, irc): | ||||
|         self.irc = irc | ||||
|         self.server = (server, port) | ||||
|         reactor.connectTCP(server, port, self) | ||||
|         self.networkGroup = conf.supybot.networks.get(self.irc.network) | ||||
|         self.servers = () | ||||
|         reactor.connectTCP('', 0, self) | ||||
| 
 | ||||
|     def _getServers(self): | ||||
|         # We do this, rather than itertools.cycle the servers in __init__, | ||||
|         # because otherwise registry updates given as setValues or sets | ||||
|         # wouldn't be visible until a restart. | ||||
|         return self.networkGroup.servers()[:] # Be sure to copy! | ||||
| 
 | ||||
|     def _getNextServer(self): | ||||
|         if not self.servers: | ||||
|             self.servers = self._getServers() | ||||
|         assert self.servers, 'Servers value for %s is empty.' % \ | ||||
|                              self.networkGroup.name | ||||
|         server = self.servers.pop(0) | ||||
|         self.currentServer = '%s:%s' % server | ||||
|         return server | ||||
|          | ||||
|     def buildProtocol(self, addr): | ||||
|         addr = self._getNextServer() | ||||
|         protocol = ReconnectingClientFactory.buildProtocol(self, addr) | ||||
|         protocol.irc = self.irc | ||||
|         return protocol | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jeremy Fincher
						Jeremy Fincher