You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
4.1 KiB

from flask import Flask, redirect, flash, render_template, session, g, request, get_flashed_messages
import werkzeug.exceptions
import json
from datetime import datetime
import hra.config as config
import hra.db as db
from hra.web import app, NeedLoginError
import hra.web.jinja_mac as jinja_mac
import hra.lib as lib
def json_endpoint(f):
def l(*arg, **kvarg):
x = f(*arg, **kvarg)
response = app.response_class(
response=json.dumps(x),
status=200,
mimetype='application/json'
)
return response
l.__name__ = f.__name__
return l
def args_get(name, type, optional=False, default=None):
v = request.args.get(name)
if v is None:
if optional:
return default
else:
raise werkzeug.exceptions.BadRequest(f"Missing mandatory option {name}.")
try:
return type(v)
except ValueError:
raise werkzeug.exceptions.BadRequest(f"Option {name} have wrong type.")
def get_context():
if g.user is None:
raise NeedLoginError
game_name = args_get("game", str, True, "main")
team = db.get_session().query(db.Team).filter_by(user_id=g.user.id, name=game_name).one_or_none()
if team is None:
raise werkzeug.exceptions.NotFound("No such game")
return team
@app.route("/api/state", methods=['GET'])
@json_endpoint
def api_state():
ses = db.get_session()
team = get_context()
game = team.game
game = game.lock()
team_id = team.team_id
min_round = args_get("min_round", int, True)
t = datetime.now()
state = game.current_state()
if state is None:
ses.commit()
return {
"status": "working",
"wait": 1.0,
}
if game.step_mode == db.StepMode.automatic:
time_to_end = max(1, game.step_every_s - (t - state.create_time).total_seconds())
else:
time_to_end = None
if min_round is not None and min_round > game.current_round:
ses.commit()
return {
"status": "too_early",
"wait": time_to_end + 1.0 if time_to_end is not None else 3.0,
}
move = team.get_move(state.round)
move.reads_count += 1
ses.commit()
return {
"status": "ok",
"round": state.round,
"team_id": team_id,
"time_to_response": time_to_end,
"state": game.get_logic().personalize_state(state.get_state(), team_id, state.round),
}
@app.route("/api/action", methods=['POST'])
@json_endpoint
def api_action():
ses = db.get_session()
def to_late():
return {
"status": "too_late",
}
team = get_context()
game = team.game
team_id = team.team_id
j = request.get_json()
state = game.current_state()
round_id = args_get('round', int)
if round_id < 0 or round_id > game.current_round:
raise werkzeug.exceptions.BadRequest("Wrong round.")
if game.working_on_next_state or round_id < game.current_round:
return to_late()
try:
warnings = game.get_logic().validate_move(state.get_state(), team_id, j, round_id)
except Exception as e:
game = game.lock()
move = team.get_move(state.round_id)
move.err_pushs_count += 1
ses.commit()
return {
"status": "error",
"description": f"{type(e).__name__}: {e}"
}
db.get_session().expire_all()
game = game.lock()
if game.working_on_next_state or round_id < game.current_round:
db.get_session().commit()
return to_late()
move = team.get_move(state.round)
move.move = db.new_big_data(j)
if warnings is None:
move.ok_pushs_count += 1
else:
move.warnings_pushs_count += 1
ses.commit()
if warnings is not None:
return warnings
return {
"status": "ok",
}
@app.route("/api/step", methods=['POST'])
@json_endpoint
def api_step():
team = get_context()
game = team.game
if game.step_mode != db.StepMode.user:
raise werkzeug.exceptions.Forbidden("Je zakázáno krokovat tuto hru")
lib.game_step(game.game_id)
return {
"status": "ok",
}