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)
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)
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)