#!flask/bin/python import subprocess import sqlite3 import secrets from flask import Flask, abort, request, jsonify START_PORT = 8128 GAME_EXEC = '/opt/godot/Godot_v3.1.1-stable_linux_server.64' GAME_EXEC_ARG_PACK = '--main-pack' GAME_EXEC_ARG_PACK_PATH = '/opt/godot/Muffrace Pre Alpha.pck' GAME_EXEC_ARG_PORT = '--port={0}' GAME_EXEC_ARG_ID = '--server-id={0}' GAME_EXEC_ARG_SECRET = '--secret={0}' GAME_EXEC_ARG_BOTS = '--bots={0}' games = {} try: with sqlite3.connect("database.db") as con: cur = con.cursor() cur.execute( 'CREATE TABLE IF NOT EXISTS games (id INTEGER PRIMARY KEY, name TEXT, secret TEXT, ip TEXT, running INTEGER, port INTEGER, player_count INTEGER, bots INTEGER)') con.commit() except: con.rollback() finally: con.close() app = Flask(__name__) @app.route('/client/game/create', methods=['POST']) def create_game(): # TODO: block multiple request from same user if not request.json: abort(400) if not 'name' in request.json: abort(400) bots = False name = request.json.get('name') if 'bots' in request.json: bots = request.json.get('bots') try: with sqlite3.connect("database.db") as con: # check free port port = START_PORT cur = con.cursor() cur.execute("SELECT * FROM games WHERE port=?", (port,)) rows = cur.fetchall() while rows: port += 1 cur.execute("SELECT * FROM games WHERE port=?", (port,)) rows = cur.fetchall() # check duplicate name base_name = name base_name_count = 1 cur.execute("SELECT * FROM games WHERE name=?", (name,)) rows = cur.fetchall() while rows: base_name_count += 1 name = base_name + "_" + str(base_name_count) cur.execute("SELECT * FROM games WHERE name=?", (name,)) rows = cur.fetchall() # gen secret secret = secrets.token_hex(32) cur.execute("INSERT INTO games (name,secret,ip,port,bots,running) VALUES (?,?,?,?,?,0)", (name, secret, request.remote_addr, port, bots)) con.commit() cur.execute("SELECT id FROM games WHERE secret=?", (secret,)) result = cur.fetchone() if result[0]: games[result[0]] = subprocess.Popen([GAME_EXEC, GAME_EXEC_ARG_PACK, GAME_EXEC_ARG_PACK_PATH, GAME_EXEC_ARG_ID.format(int(result[0])), GAME_EXEC_ARG_PORT.format( port), GAME_EXEC_ARG_SECRET.format(secret), GAME_EXEC_ARG_BOTS.format(int(bots))]) except: con.rollback() abort(500) finally: con.close() return jsonify({'name': name, 'port': port}) @app.route('/client/games', methods=['GET']) def get_games(): try: with sqlite3.connect("database.db") as con: cur = con.cursor() query = "SELECT * FROM games ORDER BY running" if 'open' in request.args: query = "SELECT * FROM games WHERE running=0" cur.execute(query) rows = cur.fetchall() except: con.rollback() finally: con.close() result = [] for row in rows: result.append( {'name': row[1], 'player_count': row[6], 'running': (row[4] == 1), 'port': row[5], 'bots': row[7]}) return jsonify(result) @app.route('/game', methods=['PUT']) def update_game(): if not request.json: abort(400) if not 'secret' in request.json or not 'player_count' in request.json or not 'running' in request.json: abort(400) secret = request.json.get('secret') player_count = request.json.get('player_count') running = request.json.get('running') try: with sqlite3.connect("database.db") as con: cur = con.cursor() cur.execute("SELECT id FROM games WHERE secret=?", (secret,)) result = cur.fetchone() if result[0]: game_id = result[0] cur.execute("UPDATE games SET player_count=?,running=? WHERE id=?", (player_count, running, game_id,)) con.commit() else: abort(401) except: con.rollback() return jsonify(False) finally: con.close() return jsonify(True) @app.route('/game', methods=['DELETE']) def close_game(): if not request.json: abort(400) if not 'secret' in request.json: abort(400) secret = request.json.get('secret') try: with sqlite3.connect("database.db") as con: cur = con.cursor() cur.execute("SELECT id FROM games WHERE secret=?", (secret,)) result = cur.fetchone() if result[0]: game_id = result[0] cur.execute("DELETE FROM games WHERE id=?", (game_id,)) con.commit() if games[game_id]: games[game_id].terminate() games[game_id].communicate() del games[game_id] else: abort(401) except: con.rollback() return jsonify(False) finally: con.close() return jsonify(True) if __name__ == '__main__': app.run(debug=True)