2019-10-26 21:03:59 +02:00
|
|
|
import logging
|
2019-10-27 13:42:41 +01:00
|
|
|
import json
|
2019-10-26 21:03:59 +02:00
|
|
|
import subprocess
|
|
|
|
from os.path import isfile
|
|
|
|
from pathlib import Path
|
|
|
|
from time import sleep
|
|
|
|
|
2019-10-27 13:42:41 +01:00
|
|
|
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.poll() is None: # Check is server is online
|
|
|
|
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 server.poll() is not None: # Check if the server is offline
|
|
|
|
update_properties() # Update server.properties
|
|
|
|
# Start the server
|
|
|
|
server = subprocess.Popen(["java", "-Xms"+conf["Server min ram"], "-Xmx"+conf["Server max ram"], "-jar",
|
|
|
|
conf["Jar server"], "nogui"], stdout=subprocess.PIPE, cwd=Path(conf["Path"]))
|
|
|
|
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 because no Rcon connection
|
|
|
|
# Wait for subprocesse full exit
|
|
|
|
while server.poll() is None:
|
|
|
|
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.poll() is None: # Check if server is running
|
|
|
|
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.poll() is None: # Check if the server is running
|
|
|
|
server.kill() # Kill the subprocess
|
|
|
|
return "Ok"
|
|
|
|
else:
|
|
|
|
abort(400, "Server is not running")
|
|
|
|
|
|
|
|
|
|
|
|
@app.route("/cmd/<cmd>")
|
|
|
|
@jwt_required()
|
|
|
|
def cmd(cmd):
|
|
|
|
"""
|
|
|
|
Execute a command by Rcon on the server
|
|
|
|
:param cmd: The command to execute
|
|
|
|
:return: The result of the command or 400 error if server not running also if Rcon connexion fail
|
|
|
|
"""
|
|
|
|
if server and server.poll() is None: # Check if server is running
|
|
|
|
try: # In case of Rcon connexion fail
|
|
|
|
with mcr: # Open a Rco connexion
|
|
|
|
resp = mcr.command(cmd) # Send the command
|
|
|
|
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.poll() is None: # Check if server is running
|
|
|
|
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)
|
2019-10-27 13:42:41 +01:00
|
|
|
update_users()
|
|
|
|
update_mc()
|
2019-10-26 21:03:59 +02:00
|
|
|
return jsonify(conf)
|