Beispiel #1
0
async def cue_the_music(request: "Request") -> "Response":
    if config.TRACE:
        logger.debug(f"{request.url}")
    score_name = request.match_info["score_name"]
    if score_name not in scores:
        return util.johann_response(False, f"unrecognized score '{score_name}'", 404)
    score = scores[score_name]

    # make sure score isn't already running (e.g. by another user)
    if score.started_at and not score.finished:
        return util.johann_response(False, "score already playing", 400)

    # make sure each Player in the Score is matched to actual entities/containers
    success, err_msgs = score.validate_create_host_mappings()
    if not success:
        logger.warning(
            f"{score.name}: tuning failed; errors validating host mappings:\n{err_msgs}"
        )
        return util.johann_response(False, err_msgs, 400)

    task = asyncio.ensure_future(score.play())
    task = util.wrap_future(task, score.name, None, score_or_measure=score)
    asyncio.ensure_future(task)

    return util.johann_response(True, "score is playing")
Beispiel #2
0
async def get_measure_status(request: "Request") -> "Response":
    if config.TRACE:
        logger.debug(f"{request.url}")
    measure, msg = _get_measure_helper(request)
    if not measure:
        return util.johann_response(False, msg, 404)

    return util.johann_response(True, [], data=measure.get_status())
Beispiel #3
0
async def get_score_measures(request: "Request") -> "Response":
    if config.TRACE:
        logger.debug(f"{request.url}")
    score_name = request.match_info["score_name"]
    if score_name not in scores:
        return util.johann_response(False, f"unrecognized score '{score_name}'", 404)

    score = scores[score_name]
    return util.johann_response(True, [], data=[x.name for x in score.measures])
Beispiel #4
0
async def get_host(request: "Request") -> "Response":
    if config.TRACE:
        logger.debug(f"{request.url}")
    host_name = request.match_info["host_name"]
    if host_name not in hosts:
        return util.johann_response(False, f"unrecognized host '{host_name}'", 404)

    host = hosts[host_name]
    return util.johann_response(True, [], data=host.dump())
Beispiel #5
0
async def get_score_raw(request: "Request") -> "Response":
    if config.TRACE:
        logger.debug(f"{request.url}")
    score_name = request.match_info["score_name"]
    if score_name not in scores:
        return util.johann_response(False, f"unrecognized score '{score_name}'", 404)

    score = scores[score_name]
    return util.johann_response(
        True, [], data=score.dump(exclude_local=False, yaml_fields_only=False)
    )
Beispiel #6
0
async def _retrieve_stored_data(
    score_name: str,
    key: Optional[str] = None,
    subkey: Optional[str] = None,
    subsubkey: Optional[str] = None,
    subsubsubkey: Optional[str] = None,
) -> "Response":
    if score_name not in scores:
        return util.johann_response(False, f"unrecognized score '{score_name}'", 404)
    score = scores[score_name]

    success, msg, code, data = score.fetch_stored_data(
        key, subkey, subsubkey, subsubsubkey
    )
    logger.debug(f"retrieve_stored_data API call: {msg}")
    return util.johann_response(success, msg, code, data=data)
Beispiel #7
0
async def get_hosts(request: "Request") -> "Response":
    if config.TRACE:
        logger.debug(f"{request.url}")
    ret = {}

    for name, host in hosts.items():
        ret[name] = {"name": host.name, "image": host.get_image()}

    return util.johann_response(True, [], data=ret)
Beispiel #8
0
async def api_read_score(request: "Request") -> "Response":
    if config.TRACE:
        logger.debug(f"{request.url}")
    score_name = request.match_info["score_name"]

    # check for force
    params = request.rel_url.query
    if "force" in params:
        if score_name not in scores:
            logger.warning("Force resetting a score that isn't loaded")
        else:
            del scores[score_name]

    score_dict, err_msg, status_code = read_score(score_name)

    if score_dict:
        return util.johann_response(True, [], data=score_dict, status_code=status_code)
    else:
        return util.johann_response(False, err_msg, status_code=status_code)
Beispiel #9
0
async def get_score_status_alt(request: "Request") -> "Response":
    if config.TRACE:
        logger.debug(f"{request.url}")
    score_name = request.match_info["score_name"]
    if score_name not in scores:
        return util.johann_response(False, f"unrecognized score '{score_name}'", 404)

    score = scores[score_name]
    status = score.get_status(short=False)

    ret = {}
    measures = {}
    current = 0
    totals = score.get_host_totals()
    total = totals["total"]
    fails = 0
    for m_name, m_status in status["measures"].items():
        measure_ret = {}
        m_current = 0
        m_fails = 0
        for p_status in m_status["task_status"].values():
            m_fails += p_status["failed_count"]
            m_current += p_status["meta"]["current"]
        measure_ret["total"] = totals[m_name]["total"]
        measure_ret["current"] = m_current
        measure_ret["failed_count"] = m_fails
        current += m_current
        fails += m_fails
        measure_ret["state"] = m_status["state"]
        measures[m_name] = measure_ret

    ret["current"] = current
    ret["total"] = total
    ret["failed_count"] = fails
    ret["state"] = status["state"]
    ret["status"] = ret["state"]
    ret["measures"] = measures
    ret["raw"] = status
    return util.johann_response(True, [], data=ret)
Beispiel #10
0
async def manually_play_measure(request: "Request") -> "Response":
    if config.TRACE:
        logger.debug(f"{request.url}")
    score_name = request.match_info["score_name"]
    measure_name = request.match_info["measure_name"]
    if score_name not in scores:
        return util.johann_response(False, f"unrecognized score '{score_name}'", 404)

    score = scores[score_name]
    measure_names = [x.name for x in score.measures]
    if measure_name not in measure_names:
        return util.johann_response(
            False, f"unrecognized measure '{measure_name}'", 404
        )

    measure = [x for x in score.measures if x.name == measure_name][0]
    m = measure

    if m.started():
        if (
            "force" in request.rel_url.query
            and request.rel_url.query["force"].lower() != "false"
        ):
            msg = f"Forcing re-play of measure '{m.name}'"
            logger.warning(msg)
        else:
            return util.johann_response(
                False,
                "measure already played/playing; to run anyway, include query param"
                " 'force=true'",
                400,
            )
    else:
        msg = f"Manually playing measure '{m.name}'"
        logger.info(msg)

    score.queue_measure(m)
    return util.johann_response(True, msg)
Beispiel #11
0
async def get_scores(request: "Request") -> "Response":
    if config.TRACE:
        logger.debug(f"{request.url}")

    ret = {}

    for name, score in scores.items():
        if score.category not in ret:
            ret[score.category] = []
        ret[score.category].append({"name": name, "description": score.description})
        ret[score.category].sort(key=lambda t: t["name"])

    ret = OrderedDict(sorted(ret.items(), key=lambda t: t[0]))  # sort by category
    return util.johann_response(True, [], data=ret)
Beispiel #12
0
async def add_hosts(request: "Request") -> "Response":
    if config.TRACE:
        logger.debug(f"{request.url}")
    try:
        data = await request.json()
    except json.JSONDecodeError as e:
        msg = "add_hosts: invalid json"
        logger.warning(f"{msg}\n{str(e)}")
        return util.johann_response(False, msg, 400)

    logger.debug("add_hosts endpoint called")
    if "hosts" in data and isinstance(data["hosts"], dict):
        success, err_msgs, successful_hostnames = _update_hosts(
            data["hosts"], allow_invalid=False
        )

        if not success:
            return util.johann_response(False, err_msgs, 400)
        else:
            return util.johann_response(True, [], data=successful_hostnames)
    else:
        msg = "invalid format for key 'hosts'"
        logger.warning(msg)
        return util.johann_response(False, msg, 400)
Beispiel #13
0
async def api_get_codehash(request: "Request") -> "Response":
    if config.TRACE:
        logger.debug(f"{request.url}")
    return util.johann_response(True, [], data=util.get_codehash())
Beispiel #14
0
async def roll_call(request: "Request") -> "Response":
    if config.TRACE:
        logger.debug(f"{request.url}")
    score_name = request.match_info["score_name"]
    if score_name not in scores:
        return util.johann_response(False, f"unrecognized score '{score_name}'", 404)

    logger.debug(f"{request.method} roll_call for score '{score_name}'")
    score = scores[score_name]

    # make sure score isn't already running (e.g. by another user)
    if score.started_at and not score.finished:
        return util.johann_response(False, "score already playing", 400)

    # update score/players if changed
    if request.method == "POST":
        data = await request.json()
        score.create_hosts = data["create_hosts"]  # PLANNED: REMOVE
        score.discard_hosts = data["discard_hosts"]  # PLANNED: REMOVE

        if "players" in data and isinstance(data["players"], dict):
            posted_players = {}
            for p_name, p_data in data["players"].items():
                try:
                    p: "Player" = PlayerSchema().load(p_data)
                except marshmallow.ValidationError as e:
                    msg = f"invalid player data provided ({p_name}): {str(e)}"
                    logger.warning(f"roll_call: {msg}")
                    return util.johann_response(False, msg, 400)

                posted_players[p.name] = p
                if p.name in score.players:
                    score_player = score.players[p.name]
                    success, err_msg = score_player.copy_from(p, score)
                    if success is None:
                        pass  # no changes required
                    elif success:
                        logger.debug(
                            f"roll_call: updated player '{p.name}'"
                            f" to:\n{score_player.dump()}"
                        )
                    else:
                        msg = f"failed to update player '{p.name}': {err_msg}"
                        logger.warning(f"roll_call: {msg}")
                        return util.johann_response(False, msg, 400)
                else:
                    msg = f"unrecognized player: '{p.name}'"
                    logger.warning(f"roll_call: {msg}")
                    return util.johann_response(False, msg, 400)
        else:
            logger.warning(
                "roll_call: POST missing or invalid format for key 'players'"
            )

    # actual roll call
    success, err_msgs = score.validate_create_host_mappings()
    if not success:
        logger.warning(f"{score_name}: errors validating host mappings:\n{err_msgs}")
        return util.johann_response(False, err_msgs, 400)
    else:
        score.last_successful_roll_call = datetime.utcnow()
        return util.johann_response(
            True, "roll_call successful; you are now free to cue the music"
        )