MinecraftServerAPI/app/routes.py

199 lines
6.5 KiB
Python
Raw Normal View History

2019-10-26 21:03:59 +02:00
import logging
import json
import pexpect
2019-10-26 21:03:59 +02:00
from os.path import isfile
from pathlib import Path
from time import sleep
from app import app, server
from configuration import conf, mcr, mcq, update_users, update_mc
from flask import abort, jsonify, request
from flask_jwt import jwt_required
2019-10-26 21:03:59 +02:00
def update_properties():
"""
Update server.properties with configuration arguments
"""
if isfile(Path(conf["Path"]) / "server.properties"): # Check if properties file exist
logging.info("Check server.properties")
# Get the content of the file
with open(Path(conf["Path"]) / "server.properties", "r") as properties_file:
properties = properties_file.read()
# Default configuration
properties_conf = {"enable-rcon": "true", "enable-query": "true", "rcon.port": conf["Rcon port"],
"query.port": conf["Query port"], "rcon.password": conf["Rcon passwd"]}
properties_conf.update(conf["Properties"]) # Add of extra configuration
for c in properties_conf: # For every configuration
# Get the start, the middle (=) and the end of the configuration
s = properties.find(c)
m = properties.find("=", s)
e = properties.find("\n", m)
if properties[s:m] == c and properties[m + 1:e] != properties_conf[c]: # Check if configurations match
logging.info(f"Change {c} to {properties_conf[c]}")
properties = properties.replace(properties[s:e], f"{c}={properties_conf[c]}") # Update configuration
# Save configuration changes
with open(Path(conf["Path"]) / "server.properties", "w") as properties_file:
properties_file.write(properties)
@app.route("/")
@jwt_required()
def root():
"""
Show server status
:return: Actual status of the server
"""
if server and server.isalive(): # Check is server is online
2019-10-26 21:03:59 +02:00
try: # In case of connexion errors
status = mcq.status()
query = mcq.query()
return f"The server has {status.players.online} players and replied in {status.latency} ms"\
+ "\n Online players: " + ", ".join(query.players.names)
except OSError:
abort(400, "Server did not respond")
else:
return "Server is offline"
@app.route("/start")
@jwt_required()
def start():
"""
Start the server
:return: Ok if everything is fine, 400 error f server already running
"""
global server # Get the global value for reallocation
if not server or not server.isalive(): # Check if the server is offline
2019-10-26 21:03:59 +02:00
update_properties() # Update server.properties
# Start the server
server = pexpect.spawn("java", ["-Xms"+conf["Server min ram"], "-Xmx"+conf["Server max ram"], "-jar",
conf["Jar server"], "nogui"], cwd=Path(conf["Path"]), echo=False)
2019-10-26 21:03:59 +02:00
if not isfile(Path(conf["Path"]) / "server.properties"): # If no server.properties reboot to apply the changes
# Wait the creation of the properties fle
while not isfile(Path(conf["Path"]) / "server.properties"):
sleep(1)
kill() # Kill the server
# Wait for processe full exit
while server.isalive():
2019-10-26 21:03:59 +02:00
sleep(1)
start() # Start again the server
return "Ok"
else:
abort(400, "Server is running")
@app.route("/stop")
@jwt_required()
def stop():
"""
Stop the server
:return: The result of the /stop command or 400 error if server is not running
"""
if server and server.isalive(): # Check if server is running
2019-10-26 21:03:59 +02:00
return cmd("/stop") # Launch /stop command
else:
abort(400, "Server is not running")
@app.route("/kill")
@jwt_required()
def kill():
"""
Kill the server
:return: Ok or 400 if the server is not running
"""
if server and server.isalive(): # Check if the server is running
server.terminate() # Kill the process
2019-10-26 21:03:59 +02:00
return "Ok"
else:
abort(400, "Server is not running")
@app.route("/cmd", methods=["POST"])
2019-10-26 21:03:59 +02:00
@jwt_required()
def cmd(command=None):
"""
Execute a command by stdin on the server
:param command: The command to execute
:return: Ok or 400 if server is not running
"""
if not command:
try:
command = request.json["command"]
except (json.JSONDecodeError, KeyError):
raise TypeError
if server and server.isalive():
server.sendline(command)
return "Ok"
else:
abort(400, "Server is not running")
@app.route("/rcmd", methods=["POST"])
@jwt_required()
def rcmd(command=None):
2019-10-26 21:03:59 +02:00
"""
Execute a command by Rcon on the server
:param command: The command to execute
2019-10-26 21:03:59 +02:00
:return: The result of the command or 400 error if server not running also if Rcon connexion fail
"""
if not command:
try:
command = request.json["command"]
except (json.JSONDecodeError, KeyError):
raise TypeError
if server and server.isalive(): # Check if server is running
2019-10-26 21:03:59 +02:00
try: # In case of Rcon connexion fail
with mcr: # Open a Rco connexion
resp = mcr.command(command) # Send the command
2019-10-26 21:03:59 +02:00
except (TimeoutError, ConnectionRefusedError):
abort(400, "Server did not respond")
else:
return str(resp)
else:
abort(400, "Server is not running")
@app.route("/logs")
@jwt_required()
def logs():
"""
Get the server logs
:return: Server last logs or 400 error if server is not running
"""
if server and server.isalive(): # Check if server is running
2019-10-26 21:03:59 +02:00
return open(Path(conf["Path"])/"logs"/"latest.log", "r").read() # Send the content of the server logs
else:
abort(400, "Server is not running")
@app.route("/config", methods=["GET"])
@jwt_required()
def get_config():
"""
Get configuration
:return: The Json configuration
"""
return jsonify(conf)
@app.route("/config", methods=["PUT"])
@jwt_required()
def update_config():
"""
Update the configuration
:return: The updated Json configuration
"""
for p in request.json: # For every entry on the request
if p in conf: # Check if it match wth the configuration
conf[p] = request.json[p] # Update the configuration
# Save configuration changes
with open("config.json", "w") as conf_file:
json.dump(conf, conf_file)
update_users()
update_mc()
2019-10-26 21:03:59 +02:00
return jsonify(conf)