class UserStrategy(Strategy):
    """ Limited User Number """
    prefix = 'user_strategy:*'
    conn = get_report_redis_client()
    source_cls = UserSource

    def __init__(self, d):
        super(UserStrategy, self).__init__(d)
        self.threshold = d['strategy_limit']
        self.daily_count = d['strategy_day']

        name = d['strategy_source']
        keys = [x.strip() for x in d['strategy_body'].split(',')]
        self.source = self.source_cls(name, keys)

    def get_thresholds(self):
        return [self.daily_count, self.threshold]

    def build_strategy_name_from_thresholds(self, thresholds):
        strategy_day, threshold = thresholds
        tmp_str = self.name
        if "That day" in self.name:
            if int(strategy_day) > 1:
                tmp_str = re.sub(r'_("That day")',
                                 strategy_day + _("Default Day"), self.name)
        else:
            if strategy_day == "1":
                tmp_str = re.sub(r'[\d]' + _('Default Day'), 'That day',
                                 self.name)
            else:
                tmp_str = re.sub(r'[\d]' + _('Default Day'),
                                 strategy_day + _('Default Day'), self.name)
        return re.sub(r'[\d]' + _('Individual_User'),
                      threshold + _('Individual_User'), tmp_str)

    def get_callable(self):
        return self.query_with_history

    def _build_key_member_score_map(self, history_data):
        key_member_score_map = defaultdict(list)
        for data in history_data:
            keys, member, score = self.source.get_all(data)
            for key in keys:
                key_member_score_map[key].append((member, score))
        return key_member_score_map

    def query_with_history(self, req_body, history_data):
        zkeys = self.source.get_zkeys(req_body)
        #  Can't get built-in variables, default to let go
        if not zkeys:
            return False

        daily_count = int(self.daily_count)
        now = datetime.now()
        seconds = (daily_count -
                   1) * 86400 + now.hour * 3600 + now.minute * 60 + now.second
        start = time.time() - seconds
        threshold = int(self.threshold)
        key_member_score_map = self._build_key_member_score_map(history_data)

        for zkey in zkeys:
            hit_users = set()
            for (member, score) in key_member_score_map[zkey]:
                if int(score) >= start:
                    user_id = member.split(':', 1)[0]
                    hit_users.add(user_id)
            hit_users.discard(req_body['user_id'])
            if len(hit_users) >= threshold:
                return True
        return False

    def query(self, req_body, threshold, daily_count):
        self.query_count += 1
        #  If the request is illegal, leave it by default
        if not self.source.check_key(req_body):
            logger.error(_('invalid req_body(%s)'), req_body)
            return False

        zkeys = self.source.get_zkeys(req_body)
        if not zkeys:
            return False

        cur_time = datetime.now()
        seconds = (
            daily_count - 1
        ) * 86400 + cur_time.hour * 3600 + cur_time.minute * 60 + cur_time.second
        end = time.time()
        start = math.floor(end - seconds)
        for zkey in zkeys:
            count = 0
            #  Count
            try:
                records = self.conn.zrangebyscore(zkey, start, end) or []
                hit_users = {x.split(':', 1)[0] for x in records}
                hit_users.discard(req_body['user_id'])
                count = len(hit_users)
            except redis.RedisError:
                logger.error('zrangebyscore({}, {}, {}) failed'.format(
                    zkey, start, end))

            if count >= threshold:
                return True
        return False

    @partial_bind_uuid
    def get_callable_from_threshold_list(self, threshold_list):
        daily_count, threshold = threshold_list
        daily_count, threshold = int(daily_count), int(threshold)
        return partial(self.query,
                       daily_count=daily_count,
                       threshold=threshold)
Beispiel #2
0
 def __init__(self, auto_fresh=False):
     self.name_sources_map = defaultdict(set)
     self.conn = get_report_redis_client()
     if auto_fresh:
         gevent.spawn(self.refresh)
class FreqStrategy(Strategy):
    """ Time-time frequency control """
    prefix = 'freq_strategy:*'
    conn = get_report_redis_client()
    source_cls = FreqSource

    def __init__(self, d):
        super(FreqStrategy, self).__init__(d)
        self.threshold = d['strategy_limit']
        self.second_count = d['strategy_time']

        name = d['strategy_source']
        keys = [x.strip() for x in d['strategy_body'].split(',')]
        self.source = self.source_cls(name, keys)

    def get_thresholds(self):
        return [self.second_count, self.threshold]

    def build_strategy_name_from_thresholds(self, thresholds):
        strategy_time, threshold = thresholds
        tmp_str = re.sub(r'[\d]+s', strategy_time + 's', self.name)
        return re.sub(r'[\d]' + _('Times'), threshold, tmp_str)

    def get_callable(self):
        return self.query_with_history

    def _build_key_member_score_map(self, history_data):
        key_member_score_map = defaultdict(list)
        for data in history_data:
            keys, member, score = self.source.get_all(data)
            for key in keys:
                key_member_score_map[key].append((member, score))
        return key_member_score_map

    def query_with_history(self, req_body, history_data):
        zkeys = self.source.get_zkeys(req_body)
        #  Can't get built-in variables, default to let go
        if not zkeys:
            return False

        second_count = int(self.second_count)
        start = time.time() - second_count
        threshold = int(self.threshold)
        key_member_score_map = self._build_key_member_score_map(history_data)

        for zkey in zkeys:
            count = 0
            for (member, score) in key_member_score_map[zkey]:
                if int(score) >= start:
                    count += 1
            if count >= threshold:
                return True
        return False

    def query(self, req_body, threshold, second_count):
        self.query_count += 1
        #  If the request is illegal, leave it by default
        if not self.source.check_key(req_body):
            logger.error(_('invalid req_body(%s)'), req_body)
            return False

        zkeys = self.source.get_zkeys(req_body)
        #  Can't get built-in variables, default to let go
        if not zkeys:
            return False

        end = time.time()
        start = end - second_count

        for zkey in zkeys:
            count = 0
            #  计数
            try:
                count = self.conn.zcount(zkey, start, end) or 0
            except redis.RedisError:
                logger.error('zcount({}, {}, {}) failed'.format(
                    zkey, start, end))

            #  Return final judgment result, any hit returns hit
            if count >= threshold:
                return True

        #  All misses, returns hit
        return False

    @partial_bind_uuid
    def get_callable_from_threshold_list(self, threshold_list):
        second_count, threshold = threshold_list
        second_count, threshold = int(second_count), int(threshold)
        return partial(self.query,
                       threshold=threshold,
                       second_count=second_count)
Beispiel #4
0
class FreqStrategy(Strategy):
    """ 时段频控型 """
    prefix = 'freq_strategy:*'
    conn = get_report_redis_client()
    source_cls = FreqSource

    def __init__(self, d):
        super(FreqStrategy, self).__init__(d)
        self.threshold = d['strategy_limit']
        self.second_count = d['strategy_time']

        name = d['strategy_source']
        keys = [x.strip() for x in d['strategy_body'].split(',')]
        self.source = self.source_cls(name, keys)

    def get_thresholds(self):
        return [self.second_count, self.threshold]

    def build_strategy_name_from_thresholds(self, thresholds):
        strategy_time, threshold = thresholds
        tmp_str = re.sub(r'[\d]+s', strategy_time + 's', self.name)
        return re.sub(r'[\d]+次', threshold, tmp_str)

    def get_callable(self):
        return self.query_with_history

    def _build_key_member_score_map(self, history_data):
        key_member_score_map = defaultdict(list)
        for data in history_data:
            keys, member, score = self.source.get_all(data)
            for key in keys:
                key_member_score_map[key].append((member, score))
        return key_member_score_map

    def query_with_history(self, req_body, history_data):
        zkeys = self.source.get_zkeys(req_body)
        #  获取不到内置变量,默认放过
        if not zkeys:
            return False

        second_count = int(self.second_count)
        start = time.time() - second_count
        threshold = int(self.threshold)
        key_member_score_map = self._build_key_member_score_map(history_data)

        for zkey in zkeys:
            count = 0
            for (member, score) in key_member_score_map[zkey]:
                if int(score) >= start:
                    count += 1
            if count >= threshold:
                return True
        return False

    def query(self, req_body, threshold, second_count):
        self.query_count += 1
        #  若请求不合法,则默认放过
        if not self.source.check_key(req_body):
            logger.error('invalid req_body(%s)', req_body)
            return False

        zkeys = self.source.get_zkeys(req_body)
        #  获取不到内置变量,默认放过
        if not zkeys:
            return False

        end = time.time()
        start = end - second_count

        for zkey in zkeys:
            count = 0
            #  计数
            try:
                count = self.conn.zcount(zkey, start, end) or 0
            except redis.RedisError:
                logger.error('zcount({}, {}, {}) failed'.format(
                    zkey, start, end))

            #  返回最终判断结果,任意命中即返回命中
            if count >= threshold:
                return True

        #  所有都不命中,返回不命中
        return False

    @partial_bind_uuid
    def get_callable_from_threshold_list(self, threshold_list):
        second_count, threshold = threshold_list
        second_count, threshold = int(second_count), int(threshold)
        return partial(self.query,
                       threshold=threshold,
                       second_count=second_count)