def get_effective_resend_option(self):
     """
     return the resend option
     :return:
     """
     if self.has_received_message() and self.has_resend_option() and \
             (self.option.resend_all is not None or
              self.option.resend_from is not None or
              self.option.resend_from_time is not None):
         return Option(resend_from=self.last_received_offset + 1)
     else:
         return Option(resend_from_time=self.option.resend_from_time,
                       resend_from=self.option.resend_from,
                       resend_all=self.option.resend_all,
                       resend_last=self.option.resend_last,
                       resend_to=self.option.resend_to)
Exemple #2
0
 def gap_handler(from_, to_):
     """
     handler when subscription detect a gap
     :param from_:
     :param to_:
     :return: None
     """
     if not sub.resending:
         self.__request_resend(sub,
                               Option(resend_from=from_, resend_to=to_))
def test_get_original_resend_option():
    def callback(_, __):
        """
        empty callback func
        :param _:
        :param __:
        :return:
        """
        print('done')

    sub = Subscription(stream_id, stream_partition, 'api_key', callback,
                       Option(resend_all=True))

    assert sub.get_effective_resend_option().resend_all is True
def test_resend_request():
    msg = {
        'sessionToken': 'my_sessionToken',
        'authKey': 'authKey',
        'type': 'resend',
        'stream': 'id',
        'partition': 0,
        'sub': 'subId',
        'resend_all': True,
    }

    rest = ResendRequest.deserialize(json.dumps(msg))

    assert isinstance(rest, ResendRequest)
    assert rest.stream_id == msg['stream']
    assert rest.stream_partition == msg['partition']
    assert rest.sub_id == msg['sub']
    assert rest.resend_option == Option(resend_all=True)
    assert rest.api_key == msg['authKey']
    assert rest.session_token == msg['sessionToken']

    msg = {
        'type': 'resend',
        'stream': 'id',
        'partition': 0,
        'sub': 'subId',
        'resend_all': True,
        'sessionToken': 'my_sessionToken',
        'authKey': 'authKey'
    }

    serialized = ResendRequest('id', 0, 'subId', Option(resend_all=True),
                               'authKey', 'my_sessionToken').serialize()
    assert (isinstance(serialized, str))

    dic = json.loads(serialized)
    assert dic == msg
def test_get_resend_option_after_received_data3():
    def callback(_, __):
        """
        empty callback func
        :param _:
        :param __:
        :return:
        """
        print('done')

    sub = Subscription(stream_id, stream_partition, 'api_key', callback,
                       Option(resend_from_time=time.time()))
    sub.handle_message(create_msg(10))
    dic = sub.get_effective_resend_option()
    assert dic.resend_from == 11
def test_get_resend_option_after_received_data4():
    msg = create_msg()

    def callback(_, __):
        """
        empty callback func
        :param _:
        :param __:
        :return:
        """
        print('done')

    sub = Subscription(stream_id, stream_partition, 'api_key', callback,
                       Option(resend_last=10))
    sub.handle_message(msg)
    dic = sub.get_effective_resend_option()
    assert dic.resend_last == 10
    def __init__(self,
                 stream_id=None,
                 stream_partition=0,
                 api_key=None,
                 callback=None,
                 option=None):
        super().__init__()

        if stream_id is None:
            raise ValueError('No stream_id given!')
        if api_key is None:
            raise ValueError('No api_key given!')
        if not hasattr(callback, '__call__'):
            raise ValueError('No callback given')

        self.sub_id = generate_subscription_id()
        self.stream_id = stream_id
        self.stream_partition = stream_partition
        self.api_key = api_key
        self.callback = callback if hasattr(callback,
                                            '__call__') else lambda x, y: None
        if isinstance(option, Option):
            self.option = option
        else:
            self.option = Option()
        self.queue = []
        self.state = EventConstant.UNSUBSCRIBED
        self.resending = False
        self.last_received_offset = None

        if self.option.check_resend() > 1:
            raise ValueError(
                'Multiple resend option active! Please use only one: %s' %
                self.option)

        if self.option.resend_from_time is not None:
            t = self.option.resend_from_time
            if not isinstance(t, (int, float)):
                raise ValueError(
                    '"resend_from_time option" must be an int or float')

        def unsubscribed():
            """
            callback function of unsubscribed event
            :return:
            """
            self.set_resending(False)

        self.on(EventConstant.UNSUBSCRIBED, unsubscribed)

        def no_resend(response=None):
            """
            callback function of no_resend event
            :param response:
            :return:
            """
            logger.debug('Sub %s no_resend:%s' % (self.sub_id, response))
            self.set_resending(False)
            self.check_queue()

        self.on(EventConstant.NO_RESEND, no_resend)

        def resent(response=None):
            """
            callback function of resent event
            :param response:
            :return:
            """
            logger.debug('Sub %s resent: %s' % (self.sub_id, response))
            self.set_resending(False)
            self.check_queue()

        self.on(EventConstant.RESENT, resent)

        def connected():
            """
            callback function of connected event
            :return:
            """
            pass

        self.on(EventConstant.CONNECTED, connected)

        def disconnected():
            """
            callback function of disconnected event
            :return:
            """
            self.set_state(EventConstant.UNSUBSCRIBED)
            self.set_resending(False)

        self.on(EventConstant.DISCONNECTED, disconnected)
Exemple #8
0
    def subscribe(self, stream, callback, legacy_option=None):
        """
        subscribe to stream with given id
        :param stream: object or dict contains stream_id and stream_partition
        :param callback: callback function when subscribed
        :param legacy_option: backward compatibility
        :return: subscription
        """
        if hasattr(stream, 'stream_id'):
            stream_id = stream.stream_id
        elif isinstance(stream, dict) and ('stream_id' in stream.keys()
                                           or 'stream' in stream.keys()):
            stream_id = stream.get('stream', None) or stream.get(
                'stream_id', None)
        elif isinstance(stream, str):
            stream_id = stream
        else:
            raise ValueError(
                'subscribe: stream_id and stream_partition should be given. Given :%s'
                % (type(stream)))

        if isinstance(legacy_option, Option):
            opt = copy.copy(legacy_option)
            opt.stream_id = stream_id
        else:
            opt = Option()

        sub = Subscription(stream_id, opt.stream_partition or 0,
                           self.option.api_key, callback, opt)

        def gap_handler(from_, to_):
            """
            handler when subscription detect a gap
            :param from_:
            :param to_:
            :return: None
            """
            if not sub.resending:
                self.__request_resend(sub,
                                      Option(resend_from=from_, resend_to=to_))

        sub.on(EventConstant.GAP, gap_handler)

        def done_handler():
            """
            handler when subscription is done
            :return: None
            """
            logger.debug('done event for sub %s ' % sub.sub_id)
            self.unsubscribe(sub)

        sub.on(EventConstant.DONE, done_handler)

        self.__add_subscription(sub)

        if self.connection.state == EventConstant.CONNECTED:
            self.__resend_and_subscribe(sub)
        elif self.option.auto_connect is True:
            try:
                self.connect()
            except Exception as e:
                import traceback
                traceback.print_exc()
                raise ConnectionErr(e)

        return sub