Beispiel #1
0
class RobotManager(_InterfaceManager):
    """ Manager which handles the management of robots and converters.
    """
    class _Robot(object):
        """ Class which represents a robot before he actually connects.
        """
        def __init__(self, key):
            self.key = key
            self.timestamp = datetime.now()
            self.conn = None
    
    def __init__(self, reactor):
        super(RobotManager, self).__init__(reactor)
        
        self._converter = Converter(self._loader)
        self._reqSender = None
        
        # Add all custom converters to the Converter
        for converter in self._CUSTOM_CONVERTERS:
            # Get correct path/name of the converter
            convList = converter.rsplit('.', 1)
            module = convList[0]
            className = convList[1]
    
            # Load the converter
            mod = __import__(module, fromlist=[className])
            self._converter.addCustomConverter(getattr(mod, className))
        
        self.__cleaner = LoopingCall(self.__clean)
        self.__cleaner.start(self._ROBOT_TIMEOUT/2)
    
    @property
    def converter(self):
        """ ROS Message <-> JSON Message Converter. """
        return self._converter
    
    def registerRequestSender(self, sender):
        """ Register the RequestSender.
            
            @param sender:      RequestSender which should be registered.
            @type  sender:      core.interfaces.IRequestSender
        """
        if self._reqSender:
            raise InternalError('There is already a RequestSender registered.')
        
        verifyObject(IRequestSender, sender)
        
        self._reqSender = sender
    
    @_UserManagerBase.verifyUser
    def addRobot(self, userID, robot):
        """ # TODO: Add description
        """
        robotID = robot.robotID
        robots = self._users[userID].robots
        
        if robotID in robots:
            raise InternalError('There already exists a robot with the robot '
                                'ID "{0}".'.format(robotID))
        
        robots[robotID] = RobotManager._Robot(robot.key)
    
    @_UserManagerBase.verifyUser
    def removeRobot(self, userID, tag):
        """ # TODO: Add description
        """
        robots = self._users[userID].robots
        
        if tag not in robots:
            raise InternalError('Tried to remove a robot which does not '
                                'exist.')
        
        if robots[tag].conn:
            raise InternalError('Connection to robot is not closed yet.')
        
        del robots[tag]
    
    @_UserManagerBase.verifyUser
    def robotConnected(self, userID, robotID, key, conn):
        """ # TODO: Add description
                (Called by client.protocol.RobotWebSocketProtocol
                 during initialization/verification of the connection)
        """
        robots = self._users[userID].robots
        
        if robotID not in robots:
            raise AuthenticationError('There is no connection expected from '
                                      'a robot with robotID '
                                      '"{0}".'.format(robotID))
        
        robot = robots[robotID]
        
        if robot.conn:
            raise AuthenticationError('There is already a robot with the same '
                                      'robotID registered.')
        
        if not key == robot.key:
            raise AuthenticationError('The key is not correct.')
        
        robot.timestamp = None
        robot.conn = conn
    
    @_UserManagerBase.verifyUser
    def robotClosed(self, userID, robotID):
        """ # TODO: Add description
                (Called by client.protocol.RobotWebSocketProtocol
                 in onClose)
        """
        robots = self._users[userID].robots
        
        if robotID in robots and robots[robotID]:
            robot = robots[robotID]
            robot.timestamp = datetime.now()
            robot.conn = None
    
    def sendRequest(self, request):
        """ Send a request received from the robot to the master manager for
            processing.
                (Called by client.handler.*)
            
            @param request:     Request which should be sent to the master
                                manager.
            @type  request:     { 'user' : str, 'type' : str, 'args' : tuple }
        """
        self._reqSender.processRequest(request)
    
    @_UserManagerBase.verifyUser
    def receivedFromClient(self, userID, robotID, iTag, msgType, msgID, msg):
        """ Received a message from a client and should now be processed.
                (Called by client.handler.DataMessageHandler)
            
            @param userID:      User ID of the converter owner.
            @type  userID:      str
            
            @param robotID:     Robot ID of the robot for which this converter
                                works.
            @type  robotID:     str
            
            @param iTag:        Tag of the converter to which this message
                                should sent.
            @type  iTag:        str
            
            @param msgType:     Message type of the received message.
            @type  msgType:     str
            
            @param msgID:       Identifier which is used to match request /
                                response message.
            @type  msgID:       str
            
            @param msg:         JSON compatible message which should be sent to
                                the client/robot.
            @type  msg:         dict
        """
        # TODO: robotID at the moment not used...
        self._getInterface(userID, iTag).receive(msgType, msgID, msg)
    
    @_UserManagerBase.verifyUser
    def sendToClient(self, userID, robotID, msg):
        """ Send a message to a client.
                (Called by core.monitor._ConverterMonitor)
            
            @param userID:      User ID of the converter owner.
            @type  userID:      str
            
            @param robotID:     Robot ID of the robot for which this converter
                                works.
            @type  robotID:     str
            
            @param msg:         JSON compatible message which should be sent to
                                the client/robot.
            @type  msg:         dict
        """
        try:
            self._users[userID].robots[robotID].conn.sendMessage(
                {'data' : msg, 'type' : clientTypes.DATA_MESSAGE})
        except KeyError:
            log.msg('Message could not be sent: The robot "{0}" is no longer '
                    'connected.'.format(robotID))
        except AttributeError:
            raise InternalError('Tried to send a message to an unverified '
                                'robot.')
    
    def shutdown(self):
        self.__cleaner.stop()
        
        for user in self._users.itervalues():
            user.robots = {}
        
        super(RobotManager, self).shutdown()
        
        self._reqSender = None
    
    def __clean(self):
        """ Internally used method to remove unclaimed robot connections.
        """
        limit = datetime.now() - timedelta(seconds=self._ROBOT_TIMEOUT)
        
        for userID, user in self._users.iteritems():
            for robotID in [
                robotID for robotID, robot in user.robots.iteritems()
                    if robot.timestamp and robot.timestamp < limit]:
                self._reqSender.processRequest({'user' : userID,
                                                'type' : req.DESTROY_ROBOT,
                                                'args' : (robotID,) })
    
    addInterface = _UserManagerBase.verifyUser(
        _InterfaceManager.addInterface)
    removeInterface = _UserManagerBase.verifyUser(
        _InterfaceManager.removeInterface)
    _getInterface = _UserManagerBase.verifyUser(
        _InterfaceManager._getInterface)