import json import threading import time import shutil import logging from datetime import datetime from app.classes.controllers.servers_controller import Servers_Controller from app.classes.models.server_permissions import server_permissions from app.classes.shared.helpers import helper from app.classes.web.websocket_helper import websocket_helper logger = logging.getLogger(__name__) try: import requests except ModuleNotFoundError as err: helper.auto_installer_fix(err) class ServerJars: def __init__(self): self.base_url = "https://serverjars.com" def _get_api_result(self, call_url: str): full_url = f"{self.base_url}{call_url}" try: r = requests.get(full_url, timeout=2) if r.status_code not in [200, 201]: return {} except Exception as e: logger.error(f"Unable to connect to serverjar.com api due to error: {e}") return {} try: api_data = json.loads(r.content) except Exception as e: logger.error(f"Unable to parse serverjar.com api result due to error: {e}") return {} api_result = api_data.get("status") api_response = api_data.get("response", {}) if api_result != "success": logger.error(f"Api returned a failed status: {api_result}") return {} return api_response @staticmethod def _read_cache(): cache_file = helper.serverjar_cache cache = {} try: with open(cache_file, "r", encoding="utf-8") as f: cache = json.load(f) except Exception as e: logger.error(f"Unable to read serverjars.com cache file: {e}") return cache def get_serverjar_data(self): data = self._read_cache() return data.get("servers") def get_serverjar_data_sorted(self): data = self.get_serverjar_data() def str_to_int(x, counter=0): try: return ord(x[0]) + str_to_int(x[1:], counter + 1) + len(x) except IndexError: return 0 def to_int(x): try: return int(x) except ValueError: temp = x.split("-") return to_int(temp[0]) + str_to_int(temp[1]) / 100000 sort_key_fn = lambda x: [to_int(y) for y in x.split(".")] for key in data.keys(): data[key] = sorted(data[key], key=sort_key_fn) return data def _check_api_alive(self): logger.info("Checking serverjars.com API status") check_url = f"{self.base_url}/api/fetchTypes" try: r = requests.get(check_url, timeout=2) if r.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 {} logger.error("unable to contact serverjars.com api") return False def refresh_cache(self): cache_file = helper.serverjar_cache cache_old = helper.is_file_older_than_x_days(cache_file) # 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"), "servers": {}} jar_types = self._get_server_type_list() # for each jar type for j in jar_types: # for each server for s in jar_types.get(j): # jar versions for this server versions = self._get_jar_details(s) # add these versions (a list) to the dict with # a key of the server type data["servers"].update({s: versions}) # 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}") def _get_jar_details(self, jar_type="servers"): url = f"/api/fetchAll/{jar_type}" response = self._get_api_result(url) temp = [] for v in response: temp.append(v.get("version")) time.sleep(0.5) return temp def _get_server_type_list(self): url = "/api/fetchTypes/" response = self._get_api_result(url) return response def download_jar(self, server, version, path, server_id): update_thread = threading.Thread( target=self.a_download_jar, daemon=True, args=(server, version, path, server_id), ) update_thread.start() def a_download_jar(self, server, version, path, server_id): # delaying download for server register to finish time.sleep(3) fetch_url = f"{self.base_url}/api/fetchJar/{server}/{version}" server_users = server_permissions.get_server_user_list(server_id) # We need to make sure the server is registered before # we submit a db update for it's stats. while True: try: Servers_Controller.set_download(server_id) for user in server_users: websocket_helper.broadcast_user(user, "send_start_reload", {}) break except: logger.debug("server not registered yet. Delaying download.") # open a file stream with requests.get(fetch_url, timeout=2, stream=True) as r: try: with open(path, "wb") as output: shutil.copyfileobj(r.raw, output) Servers_Controller.finish_download(server_id) for user in server_users: websocket_helper.broadcast_user( user, "notification", "Executable download finished" ) time.sleep(3) websocket_helper.broadcast_user(user, "send_start_reload", {}) return True except Exception as e: logger.error(f"Unable to save jar to {path} due to error:{e}") Servers_Controller.finish_download(server_id) server_users = server_permissions.get_server_user_list(server_id) for user in server_users: websocket_helper.broadcast_user( user, "notification", "Executable download finished" ) time.sleep(3) websocket_helper.broadcast_user(user, "send_start_reload", {}) return False server_jar_obj = ServerJars()