crafty-4/app/classes/minecraft/serverjars.py

246 lines
8.4 KiB
Python
Raw Normal View History

2020-08-23 22:43:28 +00:00
import json
import threading
2020-08-23 22:43:28 +00:00
import time
import shutil
2020-08-23 22:43:28 +00:00
import logging
from datetime import datetime
import requests
2020-08-23 22:43:28 +00:00
from app.classes.controllers.servers_controller import ServersController
from app.classes.models.server_permissions import PermissionsServers
from app.classes.shared.websocket_manager import WebSocketManager
2020-08-23 22:43:28 +00:00
logger = logging.getLogger(__name__)
MINEACADEMYJARS = ["paper", "folia"]
2020-08-23 22:43:28 +00:00
2022-04-11 10:08:36 +00:00
class ServerJars:
def __init__(self, helper):
self.helper = helper
self.base_url = "https://serverjars.com"
self.academy = "https://mineacademy.org"
2024-01-12 00:35:08 +00:00
@staticmethod
def get_mineacademy_jars():
return MINEACADEMYJARS
2020-08-23 22:43:28 +00:00
def _get_api_result(self, call_url: str):
full_url = f"{self.base_url}{call_url}"
2020-08-23 22:43:28 +00:00
try:
response = requests.get(full_url, timeout=2)
response.raise_for_status()
api_data = json.loads(response.content)
2020-08-23 22:43:28 +00:00
except Exception as e:
logger.error(f"Unable to load {full_url} api due to error: {e}")
2020-08-23 22:43:28 +00:00
return {}
api_result = api_data.get("status")
api_response = api_data.get("response", {})
2020-08-23 22:43:28 +00:00
if api_result != "success":
logger.error(f"Api returned a failed status: {api_result}")
2020-08-23 22:43:28 +00:00
return {}
return api_response
def get_paper_versions(self, project):
try:
response = requests.get(
f"https://api.papermc.io/v2/projects/{project}/", timeout=2
)
response.raise_for_status()
api_data = json.loads(response.content)
except Exception as e:
logger.error(
f"Unable to load https://api.papermc.io/v2/projects/{project}/"
f"api due to error: {e}"
)
return {}
versions = api_data.get("versions", [])
versions.reverse()
return versions
def _read_cache(self):
cache_file = self.helper.serverjar_cache
2020-08-23 22:43:28 +00:00
cache = {}
try:
with open(cache_file, "r", encoding="utf-8") as f:
2020-08-23 22:43:28 +00:00
cache = json.load(f)
except Exception as e:
logger.error(f"Unable to read serverjars.com cache file: {e}")
2020-08-23 22:43:28 +00:00
return cache
def get_serverjar_data(self):
data = self._read_cache()
return data.get("types")
2020-08-23 22:43:28 +00:00
def _check_api_alive(self):
2020-08-23 22:43:28 +00:00
logger.info("Checking serverjars.com API status")
check_url = f"{self.base_url}/api/fetchTypes"
try:
response = requests.get(check_url, timeout=2)
2020-08-23 22:43:28 +00:00
if response.status_code in [200, 201]:
logger.info("Serverjars.com API is alive")
return True
except Exception as e:
logger.error(f"Unable to connect to serverjar.com api due to error: {e}")
return {}
2020-08-23 22:43:28 +00:00
logger.error("unable to contact serverjars.com api")
2020-08-23 22:43:28 +00:00
return False
2022-08-03 19:38:44 +00:00
def manual_refresh_cache(self):
cache_file = self.helper.serverjar_cache
# debug override
# cache_old = True
# if the API is down... we bomb out
if not self._check_api_alive():
return False
logger.info("Manual Refresh requested.")
now = datetime.now()
data = {
"last_refreshed": now.strftime("%m/%d/%Y, %H:%M:%S"),
"types": {},
}
jar_types = self._get_server_type_list()
data["types"].update(jar_types)
for s in data["types"]:
data["types"].update({s: dict.fromkeys(data["types"].get(s), {})})
for j in data["types"].get(s):
versions = self._get_jar_details(j, s)
data["types"][s].update({j: versions})
for item in MINEACADEMYJARS:
data["types"]["servers"][item] = self.get_paper_versions(item)
2022-08-03 19:38:44 +00:00
# save our cache
try:
with open(cache_file, "w", encoding="utf-8") as f:
f.write(json.dumps(data, indent=4))
logger.info("Cache file refreshed")
except Exception as e:
logger.error(f"Unable to update serverjars.com cache file: {e}")
2020-08-23 22:43:28 +00:00
def refresh_cache(self):
cache_file = self.helper.serverjar_cache
cache_old = self.helper.is_file_older_than_x_days(cache_file)
2020-08-23 22:43:28 +00:00
# debug override
# cache_old = True
# if the API is down... we bomb out
if not self._check_api_alive():
return False
logger.info("Checking Cache file age")
# if file is older than 1 day
if cache_old:
logger.info("Cache file is over 1 day old, refreshing")
now = datetime.now()
data = {
"last_refreshed": now.strftime("%m/%d/%Y, %H:%M:%S"),
"types": {},
}
2020-08-23 22:43:28 +00:00
jar_types = self._get_server_type_list()
data["types"].update(jar_types)
for s in data["types"]:
data["types"].update({s: dict.fromkeys(data["types"].get(s), {})})
for j in data["types"].get(s):
versions = self._get_jar_details(j, s)
data["types"][s].update({j: versions})
for item in MINEACADEMYJARS:
data["types"]["servers"][item] = self.get_paper_versions()
2020-08-23 22:43:28 +00:00
# save our cache
try:
with open(cache_file, "w", encoding="utf-8") as f:
2020-08-23 22:43:28 +00:00
f.write(json.dumps(data, indent=4))
logger.info("Cache file refreshed")
except Exception as e:
logger.error(f"Unable to update serverjars.com cache file: {e}")
2020-08-23 22:43:28 +00:00
def _get_jar_details(self, server_type, jar_type="servers"):
url = f"/api/fetchAll/{jar_type}/{server_type}"
2020-08-23 22:43:28 +00:00
response = self._get_api_result(url)
temp = []
for v in response:
temp.append(v.get("version"))
time.sleep(0.5)
2020-08-23 22:43:28 +00:00
return temp
def _get_server_type_list(self):
url = "/api/fetchTypes/"
2020-08-23 22:43:28 +00:00
response = self._get_api_result(url)
if "bedrock" in response.keys():
# remove pocketmine from options
del response["bedrock"]
2020-08-23 22:43:28 +00:00
return response
def download_jar(self, jar, server, version, path, server_id):
update_thread = threading.Thread(
name=f"server_download-{server_id}-{server}-{version}",
target=self.a_download_jar,
daemon=True,
args=(jar, server, version, path, server_id),
)
update_thread.start()
def a_download_jar(self, jar, server, version, path, server_id):
# delaying download for server register to finish
2022-03-04 00:36:36 +00:00
time.sleep(3)
if server not in MINEACADEMYJARS:
fetch_url = f"{self.base_url}/api/fetchJar/{jar}/{server}/{version}"
else:
fetch_url = (
f"https://mineacademy.org/api/{server}/{str(version).replace('.', '_')}"
)
server_users = PermissionsServers.get_server_user_list(server_id)
2022-03-04 00:36:36 +00:00
# We need to make sure the server is registered before
# we submit a db update for it's stats.
2022-03-04 00:36:36 +00:00
while True:
try:
ServersController.set_import(server_id)
2022-03-04 00:36:36 +00:00
for user in server_users:
WebSocketManager().broadcast_user(user, "send_start_reload", {})
2022-03-04 00:36:36 +00:00
break
except Exception as ex:
logger.debug(f"server not registered yet. Delaying download - {ex}")
2020-08-23 22:43:28 +00:00
# open a file stream
with requests.get(fetch_url, timeout=2, stream=True) as r:
success = False
2020-08-23 22:43:28 +00:00
try:
with open(path, "wb") as output:
shutil.copyfileobj(r.raw, output)
# If this is the newer forge version we will run the installer
if server == "forge":
ServersController.finish_import(server_id, True)
else:
ServersController.finish_import(server_id)
success = True
2020-08-23 22:43:28 +00:00
except Exception as e:
logger.error(f"Unable to save jar to {path} due to error:{e}")
ServersController.finish_import(server_id)
server_users = PermissionsServers.get_server_user_list(server_id)
2020-08-23 22:43:28 +00:00
for user in server_users:
WebSocketManager().broadcast_user(
user, "notification", "Executable download finished"
)
time.sleep(3)
WebSocketManager().broadcast_user(user, "send_start_reload", {})
return success