Example #1
0
def try_add_stolen_flag(flag: models.Flag, attacker: int, current_round: int) -> bool:
    """
    Flag validation function.

    Checks that flag is valid for current round, adds it to cache for team,
    atomically checking if it's already submitted by the attacker.

    :param flag: Flag model instance
    :param attacker: attacker team id
    :param current_round: current round
    """
    stolen_key = CacheKeys.team_stolen_flags(attacker)
    with utils.redis_pipeline(transaction=True) as pipe:
        # optimization of redis request count
        cached_stolen = pipe.exists(stolen_key).execute()

        if not cached_stolen:
            cache_helper(
                pipeline=pipe,
                cache_key=stolen_key,
                cache_func=caching.cache_last_stolen,
                cache_args=(attacker, current_round, pipe),
            )

        is_new, = pipe.sadd(stolen_key, flag.id).execute()
    return bool(is_new)
Example #2
0
def cache_last_stolen(team_id: int, current_round: int,
                      pipe: Pipeline) -> None:
    """
    Caches stolen flags from "flag_lifetime" rounds.

    Just adds commands to pipeline stack, don't forget to execute afterwards.

    :param team_id: attacker team id
    :param current_round: current round
    :param pipe: redis connection to add command to
    """
    game_config = game.get_current_game_config()

    with utils.db_cursor() as (_, curs):
        curs.execute(
            _SELECT_LAST_STOLEN_TEAM_FLAGS_QUERY,
            {
                'round': current_round - game_config.flag_lifetime,
                'attacker_id': team_id,
            },
        )
        flags = curs.fetchall()

    key = CacheKeys.team_stolen_flags(team_id)
    pipe.delete(key)
    if flags:
        pipe.sadd(key, *(flag[0] for flag in flags))