Beispiel #1
0
class OscarTimeoutSocket(common.socket):
    def tryconnect(self, ips, on_connect, on_fail, timeout = 2.0):
        self._connectedonce = False
        info('tryconnect Y=%r, N=%r', on_connect, on_fail)
        self.ips = self.iptuples(ips)

        if not callable(on_connect) or not callable(on_fail):
            raise TypeError( 'on_connect and on_fail must be callables' )

        self.on_connect = on_connect
        self.on_fail = on_fail
        self.timetowait = timeout
        self._tryagain(timeout)

    def tryaccept(self, addr, on_connect, on_fail, timeout = 1.5):
        self._connectedonce = False
        info('tryaccept Y=%r, N=%r', on_connect, on_fail)
        self.ips = ()
        self.on_connect = on_connect
        self.on_fail    = on_fail

        info('listening for a connection at %s:%d', *addr)
        self.bind( addr )
        self.listen(1)

        if timeout:
            info('timeout in %r secs', timeout)

            def dotimeout():
                info('TIMEOUT. calling %r', self.on_fail)
                self.on_fail()

            self.timeout = Timer(timeout, dotimeout)
            self.timeout.start()

    def _tryagain(self, timetowait):
        # Try the next IP.
        addr = self.ips.pop(0)

        if len(self.ips) > 0:
            timeoutfunc = partial(self._tryagain, timetowait)
        else:
            # This is the last one.
            timeoutfunc = self.on_fail

        self.timeout = Timer(timetowait, timeoutfunc)
        info('%r attempting conn: %s:%d', self, *addr)

        self.make_socket()
        self.connect(addr, error=timeoutfunc)

        info('timeout is %r seconds...', timetowait)
        if self.timeout is not None:
            self.timeout.start()

    def handle_expt(self):
        info('handle_expt in %r', self)
        self.handle_disconnect()

    def handle_error(self, e=None):
        info('handle_error in %r', self)

        import traceback
        traceback.print_exc()

        if not self._connectedonce:
            self.handle_disconnect()
        else:
            self.close()

    def handle_disconnect(self):
        self.cancel_timeout()
        self.close()

        if len(self.ips) > 0:
            info('got an error, trying next ip immediately: ' + \
                 repr(self.ips[0]))
            self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
            self._tryagain(self.timetowait)
        elif not self._connectedonce:
            info('no more ips to attempt, calling on_fail (%r)', self.on_fail)
            self.on_fail()

    def handle_connect(self):
        info('connected!')
        self.cancel_timeout()
        #self.handle_disconnect = lambda: None
        self._connectedonce = True
        self.on_connect()
        self.on_fail = Sentinel

    def handle_accept(self):
        self.cancel_timeout()
        conn, address = self.accept()
        info('%r connection accepted (%r), canceling timeout and calling %r', self, address, self.on_connect)
        self._connectedonce = True
        self.on_connect(conn)

    def cancel_timeout(self):
        # Cancel any timeout.
        if hasattr(self, 'timeout') and self.timeout is not None:
            self.timeout.cancel()
            self.timeout = None

    def iptuples(self, ips):
        if not hasattr(ips, '__len__'):
            raise TypeError('ips must be (host, port) or [(host,port), (host,port)]')
        if not hasattr(ips[0], '__len__'):
            ips = tuple([ips])

        # ips is now a sequence of (host, port) tuples
        assert all(isinstance(a, basestring) and isinstance(p, int) for a, p in ips)
        return ips

    def __repr__(self):
        try:    pn = self.getpeername()
        except Exception: pn = None
        return '<TimeoutSocket peername=%r ips=%r at 0x%08x>' % (pn, getattr(self, 'ips', None), id(self))
Beispiel #2
0
class OscarTimeoutSocket(common.socket):
    def tryconnect(self, ips, on_connect, on_fail, timeout=2.0):
        self._connectedonce = False
        info('tryconnect Y=%r, N=%r', on_connect, on_fail)
        self.ips = self.iptuples(ips)

        if not callable(on_connect) or not callable(on_fail):
            raise TypeError('on_connect and on_fail must be callables')

        self.on_connect = on_connect
        self.on_fail = on_fail
        self.timetowait = timeout
        self._tryagain(timeout)

    def tryaccept(self, addr, on_connect, on_fail, timeout=1.5):
        self._connectedonce = False
        info('tryaccept Y=%r, N=%r', on_connect, on_fail)
        self.ips = ()
        self.on_connect = on_connect
        self.on_fail = on_fail

        info('listening for a connection at %s:%d', *addr)
        self.bind(addr)
        self.listen(1)

        if timeout:
            info('timeout in %r secs', timeout)

            def dotimeout():
                info('TIMEOUT. calling %r', self.on_fail)
                self.on_fail()

            self.timeout = Timer(timeout, dotimeout)
            self.timeout.start()

    def _tryagain(self, timetowait):
        # Try the next IP.
        addr = self.ips.pop(0)

        if len(self.ips) > 0:
            timeoutfunc = partial(self._tryagain, timetowait)
        else:
            # This is the last one.
            timeoutfunc = self.on_fail

        self.timeout = Timer(timetowait, timeoutfunc)
        info('%r attempting conn: %s:%d', self, *addr)

        self.make_socket()
        self.connect(addr, error=timeoutfunc)

        info('timeout is %r seconds...', timetowait)
        if self.timeout is not None:
            self.timeout.start()

    def handle_expt(self):
        info('handle_expt in %r', self)
        self.handle_disconnect()

    def handle_error(self, e=None):
        info('handle_error in %r', self)

        import traceback
        traceback.print_exc()

        if not self._connectedonce:
            self.handle_disconnect()
        else:
            self.close()

    def handle_disconnect(self):
        self.cancel_timeout()
        self.close()

        if len(self.ips) > 0:
            info('got an error, trying next ip immediately: ' + \
                 repr(self.ips[0]))
            self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
            self._tryagain(self.timetowait)
        elif not self._connectedonce:
            info('no more ips to attempt, calling on_fail (%r)', self.on_fail)
            self.on_fail()

    def handle_connect(self):
        info('connected!')
        self.cancel_timeout()
        #self.handle_disconnect = lambda: None
        self._connectedonce = True
        self.on_connect()
        self.on_fail = Sentinel

    def handle_accept(self):
        self.cancel_timeout()
        conn, address = self.accept()
        info('%r connection accepted (%r), canceling timeout and calling %r',
             self, address, self.on_connect)
        self._connectedonce = True
        self.on_connect(conn)

    def cancel_timeout(self):
        # Cancel any timeout.
        if hasattr(self, 'timeout') and self.timeout is not None:
            self.timeout.cancel()
            self.timeout = None

    def iptuples(self, ips):
        if not hasattr(ips, '__len__'):
            raise TypeError(
                'ips must be (host, port) or [(host,port), (host,port)]')
        if not hasattr(ips[0], '__len__'):
            ips = tuple([ips])

        # ips is now a sequence of (host, port) tuples
        assert all(
            isinstance(a, basestring) and isinstance(p, int) for a, p in ips)
        return ips

    def __repr__(self):
        try:
            pn = self.getpeername()
        except Exception:
            pn = None
        return '<TimeoutSocket peername=%r ips=%r at 0x%08x>' % (
            pn, getattr(self, 'ips', None), id(self))
Beispiel #3
0
class TimeoutSocketOne(common.socket):
    '''
    single socket timeout socket
    '''

    @lock
    def try_connect(self, address, succ, fail, time_to_wait, provide_init):
        provide_init(self)
        self.real_success = succ
        self.fail = fail
        self.dead = False
        self.data = None
        #make new socket
        self.make_socket()
        self.timeoutvalid = True
        self.timeout = Timer(time_to_wait, self.handle_timeout)
        self.timeout.start()

        print '*'*40
        from util import funcinfo
        print funcinfo(self.connect)
        print '*'*40

        self.connect(address, error=self.do_fail)
        #do connect with callback
        #success indicates that the socket started, but guarantees nothing
        #error indicates that there was a problem, should try to close + do fail

    def succ(self):
        info('succ')
        self.real_success()

    @lock
    def do_fail(self, *a, **k):
        info('do_fail')
        if self.timeout is not None:
            self.timeout.cancel()
            self.timeout = None
        self.timeoutvalid = False
        self.close()
        print a, k
        self.fail(*a,**k)


    @lock
    def handle_connect(self):
        info('CONNECT')
        if self.timeout is not None:
            self.timeout.cancel()
            self.timeout = None
        self.timeoutvalid = False
        self.succ()
        #cancel timeout
        #success

    @lock
    def handle_timeout(self):
        info('TIMEOUT')
        #mark as dead
        if self.timeoutvalid:
            if self.timeout is not None:
                self.timeout.cancel()
                self.timeout = None
            self.timeoutvalid = False
            self.close()
            self.dead = True
            self.fail()

    @lock
    def collect_incoming_data(self, data):
        self.data += data

    @lock
    def __error(self):
        olddead = self.dead
        self.dead = True
        if self.timeout is not None:
            self.timeout.cancel()
            self.timeout = None
        self.timeoutvalid = False
        #cancel timeout
        self.close()
        if not olddead:
            self.fail()

    def handle_error(self, e=None):
        info('ERROR: %r', e)
        import traceback;traceback.print_exc()
        self.__error()

    def handle_expt(self):
        info('EXPT')
        self.__error()

    def handle_close(self):
        info('CLOSE')
        self.__error()
Beispiel #4
0
class Vote:
    def __init__(self, bot):
        self._bot = bot
        self._current_room_users = self._sort_user_by_join_time(self._bot.users.all)
        self._has_voted = []    # user handle of the users who voted
        self._votes = []        # list of tuple(User, vote)

        self._user_to_vote = None
        self._vote_session = 0
        self._vote_type = ''
        self._vote_timer = None

    @property
    def is_active(self):
        """
        Check for active vote session.

        :return: True if active vote session.
        :rtype: bool
        """
        return self._has_active_session()

    @property
    def has_voted(self):
        """
        Returns a list of user handles that have already voted.

        :return: A list of user handles.
        :rtype: list
        """
        return self._has_voted

    @property
    def vote_user(self):
        """
        Return the User object of the user up for vote.

        :return: The User object of the user up for vote.
        :rtype: User
        """
        return self._user_to_vote

    @property
    def active_vote_type(self):
        """
        Return the type of vote session.

        :return: Type of vote session.
        :rtype: str
        """
        return self._vote_type

    def vote(self, user, vote):
        """
        Add a vote to the vote session.

        :param user: A User object.
        :type user: User
        :param vote: A yes/no vote.
        :type vote: str
        :return: True if the vote was accepted.
        :rtype: bool
        """
        if self._can_vote(user):
            if vote in YES or vote in NO:
                # there might not be a reason to store the user
                self._votes.append((user, vote))
                self._has_voted.append(user.handle)

                return True

        return False

    @staticmethod
    def can_start(user, seconds=300):
        """
        Helper method to check if a user is allowed
        to start the vote session.

        The intention was, that this method should
        be called before start(), to check if the
        user wanting to start the vote session,
        have been in the room long enough.

        :param user: The user to check.
        :type user: User
        :param seconds: The time the user must have been in the room.
        :type seconds: int
        :return: True if the user is allowed to start the session.
        :rtype: bool
        """
        now = datetime.now()

        dif = now - user.join_time
        if dif.seconds > seconds:
            return True

        return False

    def start(self, user_to_vote, session, vote_type):
        """
        Start the voting session.

        :param user_to_vote: The user up for voting.
        :type user_to_vote: User
        :param session: The session time in seconds.
        :type session: int
        :param vote_type: The type of vote.
        :type vote_type: str
        :return: True if the vote session was started
        :rtype: bool
        """
        log.debug('%s, session=%s, vote_type=%s' %
                  (user_to_vote, session, vote_type))

        if not self._has_active_session():
            self._user_to_vote = user_to_vote
            self._vote_session = session
            self._vote_type = vote_type

            # start the timer
            self._vote_timer = Timer()
            self._vote_timer.start(self._decide_vote, self._vote_session)

            return True

        return False

    def cancel(self):
        """
        Cancel the vote session.

        :return: True if canceled.
        :rtype: bool
        """
        if self._has_active_session():
            return self._vote_timer.cancel()

        return False

    def _sort_user_by_join_time(self, users):
        # only allow users who have been in the room
        # for more than 5 minutes(300seconds) to vote
        sorted_users = {}
        now = datetime.now()

        for handle in users:
            dif = now - users[handle].join_time
            if dif.seconds > 300:
                # do not add the bot itself
                if handle != self._bot.users.client.handle:
                    sorted_users[handle] = users[handle]

        return sorted_users

    def _can_vote(self, user):
        # was the user among the room users
        # when the vote session was started
        if user.handle in self._current_room_users:
            # has the user already voted
            if user.handle not in self._has_voted:
                return True

        return False

    def _has_active_session(self):
        # is there an active vote session running
        if self._vote_timer is not None:
            if isinstance(self._vote_timer, Timer):
                if self._vote_timer.is_alive:
                    return True

        return False

    def _was_vote_yes(self):
        # the result of the votes, True if yes, False on tie or no
        # Thanks to notnola (https://github.com/notnola/pinychat)
        yes = 0
        no = 0
        for _, vote in self._votes:

            if vote in YES:
                yes += 1
            else:
                no += 1

        return yes > no

    def _calculate_vote_percentage(self):
        # calculate the voting percentage
        return len(self._has_voted) * 100 / len(self._current_room_users)

    def _decide_vote(self):
        # decide based on vote percentage and votes
        percentage = self._calculate_vote_percentage()
        # at least 1/3 or the room should have voted. maybe adjust this
        if percentage >= 33:
            if self._was_vote_yes():
                self._bot.responder('With %s voters (%s%%) the room has decided to %s %s.' %
                                    (len(self._has_voted), percentage, self._vote_type,
                                     self._user_to_vote.nick))
                self._vote_action()
            else:
                self._bot.responder('With %s voters (%s%%) the room has decided NOT to %s %s.' %
                                    (len(self._has_voted), percentage, self._vote_type,
                                     self._user_to_vote.nick))
        else:
            self._bot.responder('With %s voters (%s%%) there were not '
                                'enough votes to make a decision.' %
                                (len(self._has_voted), percentage))

    def _vote_action(self):
        # initiate the action of the vote, based on vote type
        user = self._bot.users.search(self._user_to_vote.handle)
        if user is None:
            user = self._bot.users.search_by_nick(self._user_to_vote.nick)

        log.debug('%s' % user)
        if user is not None:

            if self._vote_type == 'ban':
                self._bot.send_ban_msg(user.handle)

            elif self._vote_type == 'kick':
                self._bot.send_kick_msg(user.handle)

            elif self._vote_type == 'close':
                if user.is_broadcasting:
                    self._bot.send_close_user_msg(user.handle)
                # prevent further user cam
                user.can_broadcast = False
Beispiel #5
0
class TimeoutSocket(common.socket):

    def tryconnect(self, ips, on_connect, on_fail, timeout=2.0):
        '''
        Setup for a new set of ips and start the connect routine

        @param ips:
        @param on_connect:
        @param on_fail:
        @param timeout:
        '''
        self.cancel_timeout()
        self.timetowait = timeout
        self.on_connect = on_connect
        self.on_fail    = on_fail
        self._ips       = iptuples(ips)
        self.attempts = 0
        self._accepting = False
        self.try_connect()

    def try_connect(self):
        'Do the connection routine.'

        addr = self._ips[self.attempts]
        log.warning('tryconnect: %r', (addr,))
        self.attempts += 1
        self.timeout = Timer(self.timetowait, lambda s=self.socket: self.handle_timeout(s))
        self.make_socket()
        if self.timeout is not None:
            self.timeout.start()
        def succ(*a, **k):
            log.info("WIN")
        def fail(*a, **k):
            log.info("FAIL")
        self.connect(addr, success=succ, error=fail)

    def tryaccept(self, addr, on_connect, on_fail, timeout = 1.5):
        self._accepting = True
        info('tryaccept Y=%r, N=%r', on_connect, on_fail)
        self.on_connect = on_connect
        self.on_fail    = on_fail

        info('listening for a connection at %r', (addr,))
        self.make_socket()
        common.socket.bind( self, addr )
        self.listen(1)

        if timeout:
            info('timeout in %r secs', timeout)
            self.timeout = Timer(timeout, lambda s=self.socket: self.handle_timeout(s))
            self.timeout.start()

    def handle_timeout(self, socket):
        info('TIMEOUT %r', socket)
        if socket is self.socket:
            self.do_disconnect()
        elif socket is not None:
            socket.close()

    def handle_expt(self):
        info('handle_expt in %r', self)
        self.do_disconnect()

    def handle_error(self, e=None):
        info('handle_error in %r', self)
        import traceback
        traceback.print_exc()
        self.do_disconnect()

    def do_disconnect(self):
        '''
        toss away the current connection
        will try the next address immediately
        '''

        log.warning('do_disconnect')
        self.cancel_timeout()
        self.close()

        if not self._accepting and self.attempts < len(self._ips):
            self.try_connect()
        else:
            self.on_fail()

    def handle_connect(self):
        info('connected!')
        self.cancel_timeout()
        self.on_connect(self)

    def handle_accept(self):
        self.cancel_timeout()
        conn, address = self.accept()
        info('%r connection accepted (%r), canceling timeout and calling %r', self, address, self.on_connect)
        self.on_connect(conn)

    def cancel_timeout(self):
        # Cancel any timeout.
        if hasattr(self, 'timeout') and self.timeout is not None:
            info('cancelling timeout')
            self.timeout.cancel()
        else:
            log.warning('there was no timeout to cancel')
        self.timeout = None

    def __repr__(self):
        if hasattr(self,'ips') and len(self.ips):
            return '<TimeoutSocket %s:%d>' % self.ips[0]
        else:
            pn = None
            try:     pn = self.socket.getpeername()
            finally: return "<%s connected to %r>" % (self.__class__.__name__,pn)