예제 #1
0
class ConnectionManager(object):
    '''
    manage the peer connections
    '''


    def __init__(self, peer_port = PeerServer.DEFAULT_PORT, \
                 data_port = DataServer.DEFAULT_PORT, \
                 data_transfer_protocal = 'tcp',
                 p2p_prefix = None, callbacks = {}):
        '''
        Constructor
        *peer_port*: int. Peer server service port.
        *data_port*: int. Data server service port.
        *data_transfer_protocal*: string. data transfer protocal. supports 'tcp', 'http', 'udp'
        *p2p_prefix*: str. the protocal prefix to identify the peer data package.
        *callbacks*: the external callback functions to handle events.
                you need to parse the data depends your business.

                "register" - register callback. Be invoked after a peer registered to me.
                "query" - query callback. to parse query string and perform query.
                "message" - message callback. to populate the message when received.
                "action" - action callback. to parse and perform the action.
        *callback returns*:
                *"query"* callback should return (resource, service_protocal, service_port).
                        "resource" identify how to get the resource.
                        "service_protocal" is the transfer protocal(http,tcp,udp) to serving the resource.
                        "service_port" is the port to serving the resource.

        '''
        self.log = util.getLogger('ConnManager(%d)' % peer_port)
        if p2p_prefix:
            P.setPrefix(p2p_prefix)

        self.peer_port = peer_port
        self.data_port = data_port
        self.peerServer = PeerServer(('0.0.0.0', peer_port), PeerServerHandler)
        self.ip = self.peerServer.server_address[0]

        # initialize internal and external callbacks
        self.callbacks = callbacks  #external callbacks
        
        # init peer callbacks
        peerCallbacks = {
            'register'      : self._on_register,
            'query'         : self._on_query,
            'message'       : self._on_message,
            'action'        : self._on_action,
        }
        self.peerServer.init(peerCallbacks) #internal callbacks
        self.log.info("P2P Sever initialized on %s:%d:%d" % (self.ip, self.peer_port, self.data_port))
        
        
        dataCallbacks = {
            'connect'       : self._on_connect,
            'transfer'      : self._on_transfer,
            'disconnect'    : self._on_disconnect,
            'resource'      : self._on_resource,
            'signature'     : self._on_signature,
        
        }
        self.dataServer = DataServer(port=data_port, protocal=data_transfer_protocal, callbacks=dataCallbacks)

    def __del__(self):
        self.stop()
        del self.peerServer
        del self.dataServer
    
    def start(self):
        '''
        Start a P2P server
        '''
        self.peerServer.start()
        self.dataServer.start()

    def stop(self):
        '''
        Stop serving
        '''
        self.peerServer.stop()
        self.dataServer.stop()

    def isAlive(self):
        return self.peerServer.isAlive() or self.dataServer.isAlive()
    
    @property
    def paused(self):
        return self.peerServer.paused()

    @paused.setter
    def paused(self, val):
        self.peerServer.pause(val)

    def _broadcast(self, message=None, port=None, loop=False):
        '''
        Broadcast to the network
        '''
        self.peerServer.broadcast(message=message, port=port, loop=loop)
        
    def sendRegister(self, data=None, ip=None, port=None, loop=False):
        ''' Send a register request to a peer server or network
        *ip*: the ip address of the registered peer. if not specified, *broadcast* to network
        *port*: the peer port. if not specified, will try sending to the default port.
        *loop*: specify whether the register message will be sent endlessly. Default interval is 5 seconds.
        '''
        self.peerServer.sendRegister(data=data, ip=ip, port=port, loop=loop)

    def sendMessage(self, message, ip=None, port=None):
        ''' Send a message to a peer.
        *message*: the message to be sent. DO NOT include the protocal splitter (default is "||")
        *ip*: the peer ip. If the ip is not registered, will *broadcast* to the network.
        *port*: the peer port. if not specified, will try sending to the default port.
        '''
        self.peerServer.sendMessage(message=message, ip=ip, port=port)

    def sendQuery(self, query, ip=None):
        ''' Send a query request to a peer server or network. If sender is not registered on remote peer, no response
        *query*: the query string. You need to combine/parse it yourself.
        *ip*: the ip address of the registered peer. if not specified, *broadcast* to network
        '''
        self.peerServer.sendQuery(query=query, ip=ip)
        
    def getQueryResult(self, key):
        ''' Retrieve a query result by given key
        *key*: the key (generally it's the query string) for results.
        *return*: the result address list [(ip, port), (ip, port) ...]
        '''
        return self.peerServer.getQueryResult(key=key)
    
    def removeQueryResult(self, key, ip=None):
        ''' Remove a query result. Generally it should be invoked while a peer disconnected.
        *key*: the key for result.
        *ip*: the ip address for the result of this key.
        '''
        return self.peerServer.removeQueryResult(query=key, ip=ip)

    def addPeer(self, ip, port=PeerServer.DEFAULT_PORT):
        '''
        Add a specified peer to registered peers.
        '''
        self.peerServer.addPeer(ip, port)

    # -------------- PeerServer command events -------------

    def _on_register(self, **kwargs):
        '''
        Callback when a client PeerServer registered.
        '''
        ret = False
        self.log.info(':: _on_register')
        if 'register' in self.callbacks:
            fn = self.callbacks['register']
            ret = fn(**kwargs)
        return ret

    def _on_message(self, **kwargs):
        '''
        Callback when message received from a client peer.
        '''
        ret = False
        self.log.info(':: _on_message')
        if 'message' in self.callbacks:
            fn = self.callbacks['message']
            ret = fn(**kwargs)
        return ret

    def _on_query(self, **kwargs):
        '''
        Callback when query received from a client peer.
        '''
        ret = (None, self.dataServer.protocal, self.data_port)
        
        # to not being picked out when busy
        if self.dataServer.isBusy():
            return
        
        self.log.info(':: _on_query')
        if 'query' in self.callbacks:
            fn = self.callbacks['query']
            ret = fn(**kwargs)
        return ret

    def _on_action(self, **kwargs):
        '''
        Callback when action received from a client peer.
        '''
        self.log.info(':: _on_action')
        ret = None
        if 'action' in self.callbacks:
            fn = self.callbacks['action']
            ret = fn(**kwargs)
        return ret


    # -------------- DataServer events -------------

    def _on_connect(self, requst, **kwargs):
        '''
        Callback when a client connecting.
        '''
        self.log.info(':: _on_connect')
        ret = None
        if 'connect' in self.callbacks:
            fn = self.callbacks['connect']
            ret = fn(**kwargs)
        return ret

    def _on_transfer(self, **kwargs):
        '''
        Callback when data transfering
        '''
        self.log.info(':: _on_transfer')
        ret = None
        if 'transfer' in self.callbacks:
            fn = self.callbacks['transfer']
            ret = fn(**kwargs)
        return ret

    def _on_disconnect(self, request, **kwargs):
        self.log.info(':: _on_disconnect')
        ret = None
        if 'disconnect' in self.callbacks:
            fn = self.callbacks['disconnect']
            ret = fn(**kwargs)
        return ret
    
    def _on_resource(self, request, **kwargs):
        ret = ''
        self.log.info(':: _on_resource')
        if 'resource' in self.callbacks:
            fn = self.callbacks['resource']
            ret = fn(request, **kwargs)
        return ret
    
    def _on_signature(self, **kwargs):
        ret = False
        self.log.info(':: _on_signature')
        if 'signature' in self.callbacks:
            fn = self.callbacks['signature']
            ret = fn(**kwargs)
        return ret