Exemple #1
0
class RTC(ThreadEx):
    """
    Class implementing real time communication using socket-io.
    This runs socket-io wait in a seperate thread.
    """
    def __init__(self):
        """
        Constructor.
        """

        ThreadEx.__init__(self)  #initialize base class
        self.sio = None  #socket-io instance
        self.univ = universal.Universal(
        )  #save the reference to Universal for optimized access
        self.is_stop = False  #flag tells whether to stop the thread.
        self.daemon = True  #run this thread as daemon as it should not block agent from shutting down
        self.is_disconnected = False  #whether socket-io is disconnected
        self.session_id = ''  #session id to verify handshake error
        self.update_heartbeat()  #set the heardbeat

    def on_response(self, response, *args, **kwargs):
        """
        This is a callback method to check whether the http response is a handshake error.
        Python implementation of Socket-io has a bug because of which it fails to identify this error.
        """

        if 'handshake error' in response.text:
            raise SocketIOHandShakeError(
                '%d; %s' % (response.status_code, response.text)
            )  #raise an exception so that socket-io wait can finish

    def connect(self):
        """
        Public method to connect socket-io
        """

        SocketIONamespace.rtc = self  #we need to access this object from socket-io namespace

        #keyword arguments for socket-io instance
        kwargs = {
            'Namespace': SocketIONamespace,  #socket-io namespace
            'cookies': api.session.cookies,  #cookies for authentication
            'hooks': {
                'response': self.on_response
            },  #hook for response
            'stream': True  #for long polling
        }

        #socket-io by default uses websocket transport, but websockets wont work behind a proxy
        #we force xhr polling in such cases
        if self.univ.details['isProxy'] == True:
            _log.info('Proxy detected; Forcing xhr-polling for SocketIO')
            kwargs['transports'] = ['xhr-polling']

        _log.debug('Waiting for SocketIO connection')
        exception = None

        try:
            #instantiate socket-io
            self.sio = None
            self.session_id = api.session.cookies.get('SessionID')
            self.sio = SocketIO(self.univ.get_url(), **kwargs)
        except SocketIOHandShakeError as e:  #handshake error
            exception = e
            _log.error('Failed to connect SocketIO; %s' % unicode(e))
        except Exception as e:
            exception = e
            _log.error(unicode(e))

        return exception

    def disconnect(self):
        """
        Method to disconnect socket-io
        """

        if self.sio != None:
            _log.debug('Disconnecting SocketIO')

            try:
                self.sio.disconnect()  #disconnect socket-io
            except:
                pass

            self.sio = None

    def stop(self):
        """
        Public method to stop RTC session thereby socket-io
        """

        self.is_stop = True  #set the stop flag
        self.disconnect()  #disconnect socket-io

    def update_heartbeat(self):
        """
        Public method to update socket-io heartbeat flag. 
        This is called whenever an activity happens in socket-io.
        """

        self.last_heartbeat = int(time.time())

    def is_heartbeating(self):
        """
        Public method to check whether socket-io is alive.
        Socket-io is considered alive if there was a heartbeat in last one hour.
        
        Returns:
            True if socket-io is alive else False
        """

        t = int(time.time())
        is_beating = True if t - self.last_heartbeat < (60 * 60) else False
        return is_beating

    def wait_for_auth(self):
        """
        Method to check and perform auth
        The method returns imeediately if session ids missmatch or the stop event is set
        """

        #check whether we have a conflict in session ids, if so we can return immediately and connect again
        if self.session_id != api.session.cookies.get(
                'SessionID') or self.is_stop or self.univ.stop_event.is_set():
            return

        #try to set auth status, if another thread has done it already we dont have to do anything
        #else we reset the post event and reauthenticate
        if api.session.auth_status(api.AuthStatus.UNAUTHORIZED):
            api.session.set_events(post_event=False)
            connection.Connection().reconnect()  #reauthenticate

        if self.univ.post_event.is_set() == False:
            _log.debug('%s waiting for post event' % self.name)
            self.univ.post_event.wait()
            #wait for the auth to complete

    def exe(self):
        """
        Method runs in a new thread
        """

        is_handshake_exception = True  #whether we have a handshake error

        while 1:  #continuous wait
            is_handshake_exception and self.wait_for_auth(
            )  #reauth on handshake error

            if self.is_stop == True or self.univ.stop_event.is_set(
            ):  #do we need to stop
                _log.debug('%s received stop event' % self.name)
                break

            exception = self.connect()  #try to connect

            if exception:  #redo in case of exception
                is_handshake_exception = isinstance(exception,
                                                    SocketIOHandShakeError)
                continue

            try:
                self.sio.wait()  #wait and process socket-io events
            except SocketIOHandShakeError as e:  #a handshake error happens when authentication fails
                _log.error('Failed to connect SocketIO; %s' % unicode(e))
                is_handshake_exception = True  #mark as handshake error so that next iteration will perform auth
            except Exception as e:
                _log.error(unicode(e))
                is_handshake_exception = False
                self.disconnect()  #disconnect socket-io
                self.is_disconnected = True  #for any other exception we set the disconnect flag, so that we can call config again
Exemple #2
0
class RTC(ThreadEx):    
    """
    Class implementing real time communication using socket-io.
    This runs socket-io wait in a seperate thread.
    """
    
    def __init__(self):
        """
        Constructor.
        """
        
        ThreadEx.__init__(self)  #initialize base class
        self.sio = None  #socket-io instance
        self.univ = universal.Universal()  #save the reference to Universal for optimized access
        self.is_stop = False  #flag tells whether to stop the thread.
        self.daemon = True  #run this thread as daemon as it should not block agent from shutting down
        self.is_disconnected = False  #whether socket-io is disconnected
        self.session_id = ''  #session id to verify handshake error
        self.update_heartbeat()  #set the heardbeat
        
    def on_response(self, response, *args, **kwargs):
        """
        This is a callback method to check whether the http response is a handshake error.
        Python implementation of Socket-io has a bug because of which it fails to identify this error.
        """
        
        if 'handshake error' in response.text:
            raise SocketIOHandShakeError('%d; %s' % (response.status_code, response.text))  #raise an exception so that socket-io wait can finish
               
    def connect(self):
        """
        Public method to connect socket-io
        """
        
        SocketIONamespace.rtc = self  #we need to access this object from socket-io namespace
        
        #keyword arguments for socket-io instance
        kwargs = {
            'Namespace': SocketIONamespace,  #socket-io namespace
            'cookies': api.session.cookies,  #cookies for authentication
            'hooks': {'response': self.on_response},  #hook for response
            'stream': True  #for long polling
        }
        
        #socket-io by default uses websocket transport, but websockets wont work behind a proxy
        #we force xhr polling in such cases
        if self.univ.details['isProxy'] == True:
            _log.info('Proxy detected; Forcing xhr-polling for SocketIO')
            kwargs['transports'] = ['xhr-polling']
        
        _log.debug('Waiting for SocketIO connection')
        exception = None
        
        try:
            #instantiate socket-io
            self.sio = None
            self.session_id = api.session.cookies.get('SessionID')
            self.sio = SocketIO(self.univ.get_url(), **kwargs)
        except SocketIOHandShakeError as e:  #handshake error
            exception = e
            _log.error('Failed to connect SocketIO; %s' % unicode(e))
        except Exception as e:
            exception = e
            _log.error(unicode(e))
        
        return exception
    
    def disconnect(self):
        """
        Method to disconnect socket-io
        """
        
        if self.sio != None:
            _log.debug('Disconnecting SocketIO')
            
            try:
                self.sio.disconnect()  #disconnect socket-io
            except:
                pass
            
            self.sio = None
    
    def stop(self):
        """
        Public method to stop RTC session thereby socket-io
        """
        
        self.is_stop = True  #set the stop flag
        self.disconnect()  #disconnect socket-io
            
    def update_heartbeat(self):
        """
        Public method to update socket-io heartbeat flag. 
        This is called whenever an activity happens in socket-io.
        """
        
        self.last_heartbeat = int(time.time())
        
    def is_heartbeating(self):
        """
        Public method to check whether socket-io is alive.
        Socket-io is considered alive if there was a heartbeat in last one hour.
        
        Returns:
            True if socket-io is alive else False
        """
        
        t = int(time.time())        
        is_beating = True if t - self.last_heartbeat < (60 * 60) else False
        return is_beating
    
    def wait_for_auth(self):
        """
        Method to check and perform auth
        The method returns imeediately if session ids missmatch or the stop event is set
        """
        
        #check whether we have a conflict in session ids, if so we can return immediately and connect again
        if self.session_id != api.session.cookies.get('SessionID') or self.is_stop or self.univ.stop_event.is_set():
            return
            
        #try to set auth status, if another thread has done it already we dont have to do anything
        #else we reset the post event and reauthenticate
        if api.session.auth_status(api.AuthStatus.UNAUTHORIZED):
            api.session.set_events(post_event = False)
            connection.Connection().reconnect()  #reauthenticate

        if self.univ.post_event.is_set() == False:
            _log.debug('%s waiting for post event' % self.name)
            self.univ.post_event.wait();  #wait for the auth to complete

    def exe(self):        
        """
        Method runs in a new thread
        """
        
        is_handshake_exception = True  #whether we have a handshake error
        
        while 1:  #continuous wait  
            is_handshake_exception and self.wait_for_auth()  #reauth on handshake error
        
            if self.is_stop == True or self.univ.stop_event.is_set():  #do we need to stop
                _log.debug('%s received stop event' % self.name)
                break
                
            exception = self.connect()  #try to connect
            
            if exception:  #redo in case of exception
                is_handshake_exception = isinstance(exception, SocketIOHandShakeError)
                continue
        
            try:
                self.sio.wait()  #wait and process socket-io events
            except SocketIOHandShakeError as e:  #a handshake error happens when authentication fails
                _log.error('Failed to connect SocketIO; %s' % unicode(e))
                is_handshake_exception = True  #mark as handshake error so that next iteration will perform auth
            except Exception as e:
                _log.error(unicode(e))
                is_handshake_exception = False
                self.disconnect()  #disconnect socket-io
                self.is_disconnected = True  #for any other exception we set the disconnect flag, so that we can call config again