def upgrade(): bind = op.get_bind() session = Session(bind=bind) config_data = RedisManager.get().config_get('maxmemory') max_memory = config_data['maxmemory'] print('redis max memory: {}'.format(max_memory)) RedisManager.get().config_set('maxmemory', str(int(max_memory) * 10)) with RedisManager.pipeline_context() as pipeline: streamer = pb_config['main']['streamer'] num_lines_key = '{streamer}:users:num_lines'.format(streamer=streamer) ignored_key = '{streamer}:users:ignored'.format(streamer=streamer) last_active_key = '{streamer}:users:last_active'.format(streamer=streamer) last_seen_key = '{streamer}:users:last_seen'.format(streamer=streamer) banned_key = '{streamer}:users:banned'.format(streamer=streamer) username_raw_key = '{streamer}:users:username_raw'.format(streamer=streamer) pipeline.delete(num_lines_key, ignored_key, last_active_key, last_seen_key, banned_key, username_raw_key) for user in session.query(User): if user.num_lines > 0: pipeline.zadd(num_lines_key, user.username, user.num_lines) if user.ignored: pipeline.hset(ignored_key, user.username, 1) if user.banned: pipeline.hset(banned_key, user.username, 1) if user.username != user.username_raw: pipeline.hset(username_raw_key, user.username, user.username_raw) if user._last_seen: pipeline.hset(last_seen_key, user.username, user._last_seen.timestamp()) if user._last_active: pipeline.hset(last_active_key, user.username, user._last_active.timestamp()) RedisManager.get().config_set('maxmemory', int(max_memory)) ### commands auto generated by Alembic - please adjust! ### with op.batch_alter_table('tb_user') as batch_op: batch_op.drop_column('num_lines') batch_op.drop_column('ignored') batch_op.drop_column('last_active') batch_op.drop_column('last_seen') batch_op.drop_column('banned') ### end Alembic commands ### session.commit()
def test(): redis = RedisManager.get() current_quest_key = '{streamer}:current_quest'.format(streamer=StreamHelper.get_streamer()) current_quest_id = redis.get(current_quest_key) current_quest = module_manager[current_quest_id] current_quest.load_data() return render_template('test.html', current_quest=current_quest)
def start_quest(self): HandlerManager.add_handler('on_message', self.on_message) redis = RedisManager.get() self.load_progress(redis=redis) self.load_data(redis=redis)
def on_stream_stop(self): if self.current_quest is None: log.info('No quest active on stream stop.') return False self.current_quest.stop_quest() self.current_quest = None self.bot.say('Stream ended, quest has been reset.') redis = RedisManager.get() # Remove any mentions of the current quest redis.delete(self.current_quest_key) last_stream_id = StreamHelper.get_last_stream_id() if last_stream_id is False: log.error('No last stream ID found.') # No last stream ID found. why? return False # XXX: Should we use a pipeline for any of this? # Go through user tokens and remove any from more than 2 streams ago for key in redis.keys('{streamer}:*:tokens'.format(streamer=StreamHelper.get_streamer())): all_tokens = redis.hgetall(key) for stream_id_str in all_tokens: try: stream_id = int(stream_id_str) except (TypeError, ValueError): log.error('Invalid stream id in tokens by {}'.format(key)) continue if last_stream_id - stream_id > 1: log.info('Removing tokens for stream {}'.format(stream_id)) redis.hdel(key, stream_id)
def stop_quest(self): HandlerManager.remove_handler('on_message', self.on_message) redis = RedisManager.get() self.reset_progress(redis=redis) redis.delete(self.current_emote_key)
def on_duel_complete(self, winner, loser, points_won, points_bet): if points_won < 1: # This duel did not award any points. # That means it's entirely irrelevant to us return if winner.username in self.progress: total_points_won = self.progress[winner.username] if total_points_won >= self.points_required: # The user has already won enough points, and been rewarded already. return else: total_points_won = 0 # If we get here, this means the user has not completed the quest yet. # And the user won some points in this duel total_points_won += points_won redis = RedisManager.get() if total_points_won >= self.points_required: # Reward the user with some tokens winner.award_tokens(self.REWARD, redis=redis) # Save the users "points won" progress self.progress[winner.username] = total_points_won redis.hset(self.progress_key, winner.username, total_points_won)
def stop_quest(self): HandlerManager.remove_handler('on_duel_complete', self.on_duel_complete) redis = RedisManager.get() self.reset_progress(redis=redis)
def start_quest(self): HandlerManager.add_handler('on_user_win_hs_bet', self.on_user_win_hs_bet) redis = RedisManager.get() self.load_progress(redis=redis)
def stop_quest(self): HandlerManager.remove_handler('on_user_win_hs_bet', self.on_user_win_hs_bet) redis = RedisManager.get() self.reset_progress(redis=redis)
def start_quest(self): HandlerManager.add_handler('on_duel_complete', self.on_duel_complete) redis = RedisManager.get() self.progress = {} old_progress = redis.hgetall(self.progress_key) for user, progress in old_progress.items(): try: self.progress[user.decode('utf8')] = int(progress) except (TypeError, ValueError): pass self.points_required = redis.get(self.points_required_key) try: self.points_required = int(self.points_required) except (TypeError, ValueError): pass if self.points_required is None: try: self.points_required = random.randint(self.settings['min_value'], self.settings['max_value'] + 1) except ValueError: # someone f****d up self.points_required = 500 redis.set(self.points_required_key, self.points_required)
def get_follow_relationship(self, username, streamer): """Returns the follow relationship between the user and a streamer. Returns False if `username` is not following `streamer`. Otherwise, return a datetime object. This value is cached in Redis for 2 minutes. """ redis = RedisManager.get() fr_key = "fr_{username}_{streamer}".format(username=username, streamer=streamer) follow_relationship = redis.get(fr_key) if follow_relationship is None: try: data = self.get(endpoints=["users", username, "follows", "channels", streamer], base=self.kraken_url) created_at = data["created_at"] redis.setex(fr_key, time=120, value=created_at) return TwitchAPI.parse_datetime(created_at) except urllib.error.HTTPError: redis.setex(fr_key, time=120, value="-1") return False except: log.exception("Unhandled exception in get_follow_relationship") return False else: if follow_relationship == b"-1": return False else: return TwitchAPI.parse_datetime(follow_relationship.decode("utf-8"))
def award_tokens(self, tokens, redis=None, force=False): """ Returns True if tokens were awarded properly. Returns False if not. Tokens can only be rewarded once per stream ID. """ streamer = StreamHelper.get_streamer() stream_id = StreamHelper.get_current_stream_id() if stream_id is False: return False if redis is None: redis = RedisManager.get() key = '{streamer}:{username}:tokens'.format(streamer=streamer, username=self.username) if force: res = True redis.hset(key, stream_id, tokens) else: res = True if redis.hsetnx(key, stream_id, tokens) == 1 else False if res is True: HandlerManager.trigger('on_user_gain_tokens', self, tokens) return res
def spend_tokens(self, tokens_to_spend, redis=None): if redis is None: redis = RedisManager.get() user_token_key = '{streamer}:{username}:tokens'.format( streamer=StreamHelper.get_streamer(), username=self.username) token_dict = redis.hgetall(user_token_key) for stream_id in token_dict: try: num_tokens = int(token_dict[stream_id]) except (TypeError, ValueError): continue if num_tokens == 0: continue decrease_by = min(tokens_to_spend, num_tokens) tokens_to_spend -= decrease_by num_tokens -= decrease_by redis.hset(user_token_key, stream_id, num_tokens) if tokens_to_spend == 0: return True return False
def get_follow_relationship(self, username, streamer): """Returns the follow relationship between the user and a streamer. Returns False if `username` is not following `streamer`. Otherwise, return a datetime object. This value is cached in Redis for 2 minutes. """ redis = RedisManager.get() fr_key = 'fr_{username}_{streamer}'.format(username=username, streamer=streamer) follow_relationship = redis.get(fr_key) if follow_relationship is None: try: data = self.get(endpoints=['users', username, 'follows', 'channels', streamer], base=self.kraken_url) created_at = data['created_at'] redis.setex(fr_key, time=120, value=created_at) return TwitchAPI.parse_datetime(created_at) except urllib.error.HTTPError: redis.setex(fr_key, time=120, value='-1') return False except: log.exception('Unhandled exception in get_follow_relationship') return False else: if follow_relationship == '-1': return False else: return TwitchAPI.parse_datetime(follow_relationship)
def award_tokens(self, tokens, redis=None, force=False): """ Returns True if tokens were awarded properly. Returns False if not. Tokens can only be rewarded once per stream ID. """ streamer = StreamHelper.get_streamer() stream_id = StreamHelper.get_current_stream_id() if stream_id is False: return False if redis is None: redis = RedisManager.get() key = '{streamer}:{username}:tokens'.format( streamer=streamer, username=self.username) if force: res = True redis.hset(key, stream_id, tokens) else: res = True if redis.hsetnx(key, stream_id, tokens) == 1 else False if res is True: HandlerManager.trigger('on_user_gain_tokens', self, tokens) return res
def progress_quest(self, amount, limit, completion_reward): """ Progress the quest for `stream_id` by `amount`. We load data from redis in case no progress has been made yet. """ streamer = StreamHelper.get_streamer() stream_id = StreamHelper.get_current_stream_id() if stream_id is False: return False redis = RedisManager.get() quest_progress_key = '{streamer}:{stream_id}:{username}:quest_progress'.format( streamer=streamer, stream_id=stream_id, username=self.username) if stream_id not in self.quest_progress: # Load the old progress, or set it to 0 if no progress was found self.init_quest_progress() if self.quest_progress[stream_id] >= limit: # The user has already completed this quest. return False self.quest_progress[stream_id] += amount if self.quest_progress[stream_id] >= limit: # The user just completed the quest for the first time self.award_tokens(completion_reward, redis=redis) return False redis.set(quest_progress_key, self.quest_progress[stream_id])
def timeout(self, timeout_length, warning_module=None, use_warnings=True): """ Returns a tuple with the follow data: How long to timeout the user for, and what the punishment string is set to. The punishment string is used to clarify whether this was a warning or the real deal. """ punishment = 'timed out for {} seconds'.format(timeout_length) if use_warnings and warning_module is not None: redis = RedisManager.get() """ How many chances the user has before receiving a full timeout. """ total_chances = warning_module.settings['total_chances'] warning_keys = self.get_warning_keys(total_chances, warning_module.settings['redis_prefix']) warnings = self.get_warnings(redis, warning_keys) chances_used = self.get_chances_used(warnings) if chances_used < total_chances: """ The user used up one of his warnings. Calculate for how long we should time him out. """ timeout_length = warning_module.settings['base_timeout'] * (chances_used + 1) punishment = 'timed out for {} seconds (warning)'.format(timeout_length) self.add_warning(redis, warning_module.settings['length'], warning_keys, warnings) return (timeout_length, punishment)
def stop_quest(self): HandlerManager.remove_handler('on_duel_complete', self.on_duel_complete) redis = RedisManager.get() self.reset_progress(redis=redis) redis.delete(self.points_required_key)
def get_tags(self, redis=None): if redis is None: redis = RedisManager.get() val = redis.hget('global:usertags', self.username) if val: return json.loads(val) else: return {}
def redis_test2(self, username): redis = RedisManager.get() values = [ redis.hget('pajlada:users:points', username), redis.hget('pajlada:users:ignored', username), redis.hget('pajlada:users:banned', username), redis.hget('pajlada:users:last_active', username), ] return values
def start_quest(self): HandlerManager.add_handler('on_duel_complete', self.on_duel_complete) redis = RedisManager.get() self.load_progress(redis=redis) self.load_data(redis=redis) self.LIMIT = self.points_required
def start_quest(self): HandlerManager.add_handler('on_user_win_hs_bet', self.on_user_win_hs_bet) redis = RedisManager.get() self.load_progress(redis=redis) self.load_data(redis=redis) self.LIMIT = self.hsbet_points_required
def load_progress(self, redis=None): if redis is None: redis = RedisManager.get() self.progress = {} old_progress = redis.hgetall(self.progress_key) for user, progress in old_progress.items(): try: self.progress[user] = int(progress) except (TypeError, ValueError): pass
def load_progress(self, redis=None): if redis is None: redis = RedisManager.get() self.progress = {} old_progress = redis.hgetall(self.progress_key) for user, progress in old_progress.items(): try: self.progress[user.decode('utf8')] = int(progress) except (TypeError, ValueError): pass
def load_data(self, redis=None): if redis is None: redis = RedisManager.get() self.current_emote = redis.get(self.current_emote_key) if self.current_emote is None: # randomize an emote global_twitch_emotes = self.bot.emotes.get_global_emotes() self.current_emote = random.choice(global_twitch_emotes) redis.set(self.current_emote_key, self.current_emote) else: self.current_emote = self.current_emote
def redis_test(self, username): try: pipeline = RedisManager.get().pipeline() pipeline.hget('pajlada:users:points', username) pipeline.hget('pajlada:users:ignored', username) pipeline.hget('pajlada:users:banned', username) pipeline.hget('pajlada:users:last_active', username) except: pipeline.reset() finally: b = pipeline.execute() log.info(b)
def home(): redis = RedisManager.get() values = redis.hgetall("stream_data") for x in bots: x.online = values.get("{streamer}:online".format(streamer=x.streamer[0])) == "True" try: x.viewers = int(values.get("{streamer}:viewers".format(streamer=x.streamer[0]))) except: x.viewers = -1 x.viewers_str = millify(x.viewers) x.game = values.get("{streamer}:game".format(streamer=x.streamer[0])) bots.sort(key=lambda x: (x.online, x.viewers, x.bot), reverse=True) return render_template("home.html", bots=bots, values=values)
def home(): custom_content = '' redis = RedisManager.get() streamer = StreamHelper.get_streamer() keys = ('online', 'viewers', 'game') stream_data_keys = [ '{streamer}:{key}'.format(streamer=streamer, key=key) for key in keys ] stream_data_list = redis.hmget('stream_data', stream_data_keys) stream_data = { keys[x]: stream_data_list[x] for x in range(0, len(keys)) } keys = StreamHelper.social_keys streamer_info_keys = [ '{streamer}:{key}'.format(streamer=streamer, key=key) for key in keys.keys() ] log.info(streamer_info_keys) streamer_info_list = redis.hmget('streamer_info', streamer_info_keys) streamer_info = collections.OrderedDict() for key in keys: value = streamer_info_list.pop(0) if value: streamer_info[key] = { 'value': keys[key]['format'].format(value), 'title': keys[key]['title'], 'format': keys[key]['format'], } current_quest_key = '{streamer}:current_quest'.format( streamer=StreamHelper.get_streamer()) current_quest_id = redis.get(current_quest_key) if current_quest_id is not None: current_quest = app.module_manager[current_quest_id] if current_quest: current_quest.load_data() else: current_quest = None return render_template('home.html', custom_content=custom_content, current_quest=current_quest, stream_data=stream_data, streamer_info=streamer_info)
def refresh_stream_status(self): try: status = self.bot.twitchapi.get_status(self.bot.streamer) if status['error'] is True: log.error('An error occured while fetching stream status') return redis = RedisManager.get() redis.hmset( 'stream_data', { '{streamer}:online'.format(streamer=self.bot.streamer): status['online'], '{streamer}:viewers'.format(streamer=self.bot.streamer): status['viewers'], '{streamer}:game'.format(streamer=self.bot.streamer): status['game'], }) self.num_viewers = status['viewers'] if status['online']: if self.current_stream is None: self.create_stream(status) if self.current_stream_chunk is None: self.create_stream_chunk(status) if self.current_stream_chunk.broadcast_id != status[ 'broadcast_id']: log.debug('Detected a new chunk!') self.create_stream_chunk(status) self.num_offlines = 0 self.first_offline = None self.bot.ascii_timeout_duration = 120 self.bot.msg_length_timeout_duration = 120 else: self.bot.ascii_timeout_duration = 10 self.bot.msg_length_timeout_duration = 10 if self.online is True: log.info('Offline. {0}'.format(self.num_offlines)) if self.first_offline is None: self.first_offline = datetime.datetime.now() if self.num_offlines >= 10: log.info('Switching to offline state!') self.go_offline() self.num_offlines += 1 except: log.exception('Uncaught exception while refreshing stream status')
def on_stream_start(self): available_quests = list(filter(lambda m: m.ID.startswith('quest-'), self.submodules)) if len(available_quests) == 0: log.error('No quests enabled.') return False self.current_quest = random.choice(available_quests) self.current_quest.start_quest() redis = RedisManager.get() redis.set(self.current_quest_key, self.current_quest.ID) self.bot.say('Stream started, new quest has been chosen!') self.bot.say('Current quest objective: {}'.format(self.current_quest.get_objective()))
def start_quest(self): HandlerManager.add_handler('on_message', self.on_message) redis = RedisManager.get() self.load_progress(redis=redis) self.current_emote = redis.get(self.current_emote_key) if self.current_emote is None: # randomize an emote global_twitch_emotes = self.bot.emotes.get_global_emotes() self.current_emote = random.choice(global_twitch_emotes) redis.set(self.current_emote_key, self.current_emote) else: self.current_emote = self.current_emote.decode('utf8')
def load_data(self, redis=None): if redis is None: redis = RedisManager.get() self.hsbet_points_required = redis.get(self.hsbet_points_key) try: self.hsbet_points_required = int(self.hsbet_points_required) except (TypeError, ValueError): pass if self.hsbet_points_required is None: try: self.hsbet_points_required = random.randint(self.settings['min_value'], self.settings['max_value'] + 1) except ValueError: self.hsbet_points_required = 500 redis.set(self.hsbet_points_key, self.hsbet_points_required)
def get_tokens(self, redis=None): streamer = StreamHelper.get_streamer() if redis is None: redis = RedisManager.get() tokens = redis.hgetall('{streamer}:{username}:tokens'.format( streamer=streamer, username=self.username)) num_tokens = 0 for token_value in tokens.values(): try: num_tokens += int(token_value) except (TypeError, ValueError): log.warn('Invalid value for tokens, user {}'.format(self.username)) return num_tokens
def on_message(self, source, message, emotes, whisper, urls, event): if len(message) >= self.get_quest_message_length(): if event.type == 'action': user_progress = self.get_user_progress(source.username, default=0) if user_progress >= self.get_limit(): return user_progress += 1 redis = RedisManager.get() if user_progress == self.get_limit(): source.award_tokens(self.REWARD, redis=redis) self.set_user_progress(source.username, user_progress, redis=redis)
def init_quest_progress(self, redis=None): """ Initialize quest progress for the current stream. """ streamer = StreamHelper.get_streamer() stream_id = StreamHelper.get_current_stream_id() if redis is None: redis = RedisManager.get() quest_progress_key = '{streamer}:{stream_id}:{username}:quest_progress'.format( streamer=streamer, stream_id=stream_id, username=self.username) old_progress = 0 try: old_progress = int(redis.get(quest_progress_key)) except (TypeError, ValueError): pass self.quest_progress[stream_id] = old_progress
def on_user_win_hs_bet(self, user, points_reward): if points_reward < 1: return user_progress = self.get_user_progress(user.username, default=0) if user_progress >= self.hsbet_points_required: return user_progress += points_reward redis = RedisManager.get() if user_progress >= self.hsbet_points_required: user.award_tokens(self.REWARD, redis=redis) self.set_user_progress(user.username, user_progress, redis=redis)
def on_duel_complete(self, winner, loser, points_won, points_bet): if points_won < 1: return user_progress = self.get_user_progress(winner.username, default=0) if user_progress >= self.get_limit(): return user_progress += 1 redis = RedisManager.get() if user_progress == self.get_limit(): winner.award_tokens(self.REWARD, redis=redis) self.set_user_progress(winner.username, user_progress, redis=redis)
def load_data(self, redis=None): if redis is None: redis = RedisManager.get() self.points_required = redis.get(self.points_required_key) try: self.points_required = int(self.points_required) except (TypeError, ValueError): pass if self.points_required is None: try: self.points_required = random.randint(self.settings['min_value'], self.settings['max_value'] + 1) except ValueError: # someone f****d up self.points_required = 500 redis.set(self.points_required_key, self.points_required)
def on_user_win_hs_bet(self, user, points_reward): # User needs to make 1 point profit at least # if points_reward < 1: # return user_progress = self.get_user_progress(user.username, default=0) if user_progress >= self.get_limit(): return user_progress += 1 redis = RedisManager.get() if user_progress == self.get_limit(): user.award_tokens(self.REWARD, redis=redis) self.set_user_progress(user.username, user_progress, redis=redis)
def get_viewer_data(self, redis=None): if self.offline: return False if not redis: redis = RedisManager.get() data = redis.hget( '{streamer}:viewer_data'.format(streamer=self.bot.streamer), self.current_stream.id) if data is None: data = {} else: data = json.loads(data) return data
def on_message(self, source, message, emotes, whisper, urls, event): for emote in emotes: if emote['code'] == self.current_emote: user_progress = self.get_user_progress(source.username, default=0) + 1 if user_progress > self.get_limit(): log.debug('{} has already complete the quest. Moving along.'.format(source.username)) # no need to do more return redis = RedisManager.get() if user_progress == self.get_limit(): source.award_tokens(self.REWARD, redis=redis) self.set_user_progress(source.username, user_progress, redis=redis) return
def get_tokens(self, redis=None): streamer = StreamHelper.get_streamer() if redis is None: redis = RedisManager.get() tokens = redis.hgetall('{streamer}:{username}:tokens'.format( streamer=streamer, username=self.username)) num_tokens = 0 for token_value in tokens.values(): try: num_tokens += int(token_value) except (TypeError, ValueError): log.warn('Invalid value for tokens, user {}'.format( self.username)) return num_tokens
def on_managers_loaded(self): if self.current_quest is None: redis = RedisManager.get() current_quest_id = redis.get(self.current_quest_key) log.info('Try to load submodule with ID {}'.format(current_quest_id)) if current_quest_id is not None: current_quest_id = current_quest_id.decode('utf8') quest = find(lambda m: m.ID == current_quest_id, self.submodules) if quest is not None: log.info('Resumed quest {}'.format(quest.get_objective())) self.current_quest = quest self.current_quest.start_quest() else: log.info('No quest with id {} found in submodules ({})'.format(current_quest_id, self.submodules))