# # Copyright (C) 2006-2010 Nexedi SA # # This program 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; either version 2 # of the License, or (at your option) any later version. # # This program 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 this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import neo.lib from .protocol import ( NodeStates, Packets, ErrorCodes, Errors, BrokenNodeDisallowedError, NotReadyError, PacketMalformedError, ProtocolError, UnexpectedPacketError) class EventHandler(object): """This class handles events.""" def __init__(self, app): self.app = app def __repr__(self): return self.__class__.__name__ def __unexpectedPacket(self, conn, packet, message=None): """Handle an unexpected packet.""" if message is None: message = 'unexpected packet type %s in %s' % (type(packet), self.__class__.__name__) else: message = 'unexpected packet: %s in %s' % (message, self.__class__.__name__) neo.lib.logging.error(message) conn.answer(Errors.ProtocolError(message)) conn.abort() # self.peerBroken(conn) def dispatch(self, conn, packet, kw={}): """This is a helper method to handle various packet types.""" try: try: method = getattr(self, packet.handler_method_name) except AttributeError: raise UnexpectedPacketError('no handler found') args = packet.decode() or () conn.setPeerId(packet.getId()) method(conn, *args, **kw) except UnexpectedPacketError, e: self.__unexpectedPacket(conn, packet, *e.args) except PacketMalformedError: neo.lib.logging.error('malformed packet from %r', conn) conn.notify(Packets.Notify('Malformed packet: %r' % (packet, ))) conn.abort() # self.peerBroken(conn) except BrokenNodeDisallowedError: conn.answer(Errors.BrokenNode('go away')) conn.abort() except NotReadyError, message: if not message.args: message = 'Retry Later' message = str(message) conn.answer(Errors.NotReady(message)) conn.abort() except ProtocolError, message: message = str(message) conn.answer(Errors.ProtocolError(message)) conn.abort() def checkClusterName(self, name): # raise an exception if the given name mismatch the current cluster name if self.app.name != name: neo.lib.logging.error('reject an alien cluster') raise ProtocolError('invalid cluster name') # Network level handlers def packetReceived(self, *args): """Called when a packet is received.""" self.dispatch(*args) def connectionStarted(self, conn): """Called when a connection is started.""" neo.lib.logging.debug('connection started for %r', conn) def connectionCompleted(self, conn): """Called when a connection is completed.""" neo.lib.logging.debug('connection completed for %r (from %s:%u)', conn, *conn.getConnector().getAddress()) def connectionFailed(self, conn): """Called when a connection failed.""" neo.lib.logging.debug('connection failed for %r', conn) def connectionAccepted(self, conn): """Called when a connection is accepted.""" def connectionClosed(self, conn): """Called when a connection is closed by the peer.""" neo.lib.logging.debug('connection closed for %r', conn) self.connectionLost(conn, NodeStates.TEMPORARILY_DOWN) #def peerBroken(self, conn): # """Called when a peer is broken.""" # neo.lib.logging.error('%r is broken', conn) # # NodeStates.BROKEN def connectionLost(self, conn, new_state): """ this is a method to override in sub-handlers when there is no need to make distinction from the kind event that closed the connection """ pass # Packet handlers. def ping(self, conn): if not conn.isAborted(): conn.answer(Packets.Pong()) def pong(self, conn): # Ignore PONG packets. The only purpose of ping/pong packets is # to test/maintain underlying connection. pass def notify(self, conn, message): neo.lib.logging.info('notification from %r: %s', conn, message) # Error packet handlers. def error(self, conn, code, message): try: getattr(self, Errors[code])(conn, message) except (AttributeError, ValueError): raise UnexpectedPacketError(message) def protocolError(self, conn, message): # the connection should have been closed by the remote peer neo.lib.logging.error('protocol error: %s' % (message,)) def timeoutError(self, conn, message): neo.lib.logging.error('timeout error: %s' % (message,)) def brokenNodeDisallowedError(self, conn, message): raise RuntimeError, 'broken node disallowed error: %s' % (message,) def alreadyPendingError(self, conn, message): neo.lib.logging.error('already pending error: %s' % (message, )) def ack(self, conn, message): neo.lib.logging.debug("no error message : %s" % (message))