diff --git a/app/classes/controllers/servers_controller.py b/app/classes/controllers/servers_controller.py index 9db60e2c..95ed242c 100644 --- a/app/classes/controllers/servers_controller.py +++ b/app/classes/controllers/servers_controller.py @@ -50,6 +50,18 @@ class Servers_Controller: def update_server(server_obj): return servers_helper.update_server(server_obj) + @staticmethod + def set_download(server_id): + return servers_helper.set_download(server_id) + + @staticmethod + def finish_download(server_id): + return servers_helper.finish_download(server_id) + + @staticmethod + def get_download_status(server_id): + return servers_helper.get_download_status(server_id) + @staticmethod def remove_server(server_id): roles_list = server_permissions.get_roles_from_server(server_id) diff --git a/app/classes/minecraft/serverjars.py b/app/classes/minecraft/serverjars.py index 95e013aa..8a2a7dda 100644 --- a/app/classes/minecraft/serverjars.py +++ b/app/classes/minecraft/serverjars.py @@ -8,6 +8,9 @@ from datetime import datetime from app.classes.shared.helpers import helper from app.classes.shared.console import console +from app.classes.controllers.servers_controller import Servers_Controller +from app.classes.web.websocket_helper import websocket_helper +from app.classes.models.server_permissions import server_permissions logger = logging.getLogger(__name__) @@ -170,23 +173,53 @@ class ServerJars: response = self._get_api_result(url) return response - def download_jar(self, server, version, path): - update_thread = threading.Thread(target=self.a_download_jar, daemon=True, args=(server, version, path)) + 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): + 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 + return False server_jar_obj = ServerJars() diff --git a/app/classes/models/servers.py b/app/classes/models/servers.py index 9109f45a..c391bb65 100644 --- a/app/classes/models/servers.py +++ b/app/classes/models/servers.py @@ -75,6 +75,7 @@ class Server_Stats(Model): waiting_start = BooleanField(default=False) first_run = BooleanField(default=True) crashed = BooleanField(default=False) + downloading = BooleanField(default=False) class Meta: @@ -194,6 +195,22 @@ class helper_servers: with database.atomic(): Server_Stats.update(crashed=True).where(Server_Stats.server_id == server_id).execute() + @staticmethod + def set_download(server_id): + with database.atomic(): + Server_Stats.update(downloading=True).where(Server_Stats.server_id == server_id).execute() + + @staticmethod + def finish_download(server_id): + with database.atomic(): + Server_Stats.update(downloading=False).where(Server_Stats.server_id == server_id).execute() + + @staticmethod + def get_download_status(server_id): + download_status = Server_Stats.select().where(Server_Stats.server_id == server_id).get() + return download_status.downloading + + @staticmethod def server_crash_reset(server_id): with database.atomic(): diff --git a/app/classes/shared/main_controller.py b/app/classes/shared/main_controller.py index bf0a2137..871c0d53 100644 --- a/app/classes/shared/main_controller.py +++ b/app/classes/shared/main_controller.py @@ -292,11 +292,12 @@ class Controller: server_log_file = f"{server_dir}/logs/latest.log" server_stop = "stop" - # download the jar - server_jar_obj.download_jar(server, version, full_jar_path) - new_id = self.register_server(name, server_id, server_dir, backup_path, server_command, server_file, server_log_file, server_stop, port, server_type='minecraft-java') + + # download the jar + server_jar_obj.download_jar(server, version, full_jar_path, new_id) + return new_id @staticmethod diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py index 7b799fd4..355ead93 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -188,6 +188,13 @@ class Server: else: user_lang = users_helper.get_user_lang_by_id(user_id) + if servers_helper.get_download_status(self.server_id): + if user_id: + websocket_helper.broadcast_user(user_id, 'send_start_error',{ + 'error': translation.translate('error', 'not-downloaded', user_lang) + }) + return False + logger.info(f"Start command detected. Reloading settings from DB for server {self.name}") self.setup_server_run_command() # fail safe in case we try to start something already running diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py index 11469e33..3f06457b 100644 --- a/app/classes/web/panel_handler.py +++ b/app/classes/web/panel_handler.py @@ -150,7 +150,7 @@ class PanelHandler(BaseHandler): else: if not self.controller.servers.server_id_authorized(server_id, exec_user["user_id"]): print(f'User {exec_user["user_id"]} does not have permission') - self.redirect("/panel/error?error=Invalid Server ID") + self.redirect("/pandel/error?error=Invalid Server ID") return None return server_id @@ -209,14 +209,17 @@ class PanelHandler(BaseHandler): user_order = user_order['server_order'].split(',') page_servers = [] server_ids = [] + un_used_servers = defined_servers for server_id in user_order: - for server in defined_servers: + for server in un_used_servers: if str(server['server_id']) == str(server_id): page_servers.append(server) + un_used_servers.remove(server) + user_order.remove(server_id) - for server in defined_servers: + for server in un_used_servers: server_ids.append(str(server['server_id'])) if server not in page_servers: page_servers.append(server) @@ -335,14 +338,33 @@ class PanelHandler(BaseHandler): user_order = user_order['server_order'].split(',') page_servers = [] server_ids = [] + un_used_servers = page_data['servers'] + flag = 0 for server_id in user_order: - for server in page_data['servers']: + for server in un_used_servers: + if flag == 0: + server['stats']['downloading'] = self.controller.servers.get_download_status( + str(server['stats']['server_id']['server_id'])) + server['stats']['crashed'] = self.controller.servers.is_crashed( + str(server['stats']['server_id']['server_id'])) + try: + server['stats']['waiting_start'] = self.controller.servers.get_waiting_start( + str(server['stats']['server_id']['server_id'])) + except Exception as e: + logger.error(f"Failed to get server waiting to start: {e}") + server['stats']['waiting_start'] = False + if str(server['server_data']['server_id']) == str(server_id): page_servers.append(server) + un_used_servers.remove(server) + user_order.remove(server_id) + #we only want to set these server stats values once. We need to update the flag so it only hits that if once. + flag += 1 - for server in page_data['servers']: + + for server in un_used_servers: server_ids.append(str(server['server_data']['server_id'])) if server not in page_servers: page_servers.append(server) @@ -352,17 +374,6 @@ class PanelHandler(BaseHandler): user_order.remove(server_id) page_data['servers'] = page_servers - - for data in page_data['servers']: - data['stats']['crashed'] = self.controller.servers.is_crashed( - str(data['stats']['server_id']['server_id'])) - try: - data['stats']['waiting_start'] = self.controller.servers.get_waiting_start( - str(data['stats']['server_id']['server_id'])) - except Exception as e: - logger.error(f"Failed to get server waiting to start: {e}") - data['stats']['waiting_start'] = False - try: self.fetch_server_data(page_data) except: @@ -390,6 +401,8 @@ class PanelHandler(BaseHandler): # server_data isn't needed since the server_stats also pulls server data page_data['server_data'] = self.controller.servers.get_server_data_by_id(server_id) page_data['server_stats'] = self.controller.servers.get_server_stats_by_id(server_id) + page_data['downloading'] = self.controller.servers.get_download_status( + server_id) try: page_data['waiting_start'] = self.controller.servers.get_waiting_start(server_id) except Exception as e: diff --git a/app/frontend/templates/panel/dashboard.html b/app/frontend/templates/panel/dashboard.html index 9e5a434f..d721be41 100644 --- a/app/frontend/templates/panel/dashboard.html +++ b/app/frontend/templates/panel/dashboard.html @@ -158,6 +158,9 @@ {{ translate('dashboard', 'starting', data['lang']) }} + {% elif server['stats']['downloading']%} + {{ translate('serverTerm', 'downloading', + data['lang']) }} {% else %} diff --git a/app/frontend/templates/panel/server_term.html b/app/frontend/templates/panel/server_term.html index c6c7f0e6..0949cd9f 100644 --- a/app/frontend/templates/panel/server_term.html +++ b/app/frontend/templates/panel/server_term.html @@ -59,6 +59,13 @@ + {% elif data['downloading'] %} +
+ + + +
{% else %}
@@ -153,6 +160,12 @@ restartBtn.setAttribute('disabled', 'disabled'); stopBtn.setAttribute('disabled', 'disabled'); } + + if (webSocket) { + webSocket.on('send_start_reload', function () { + location.reload() + }); + } //{% end %} function get_server_log() { diff --git a/app/migrations/20220303_downloading.py b/app/migrations/20220303_downloading.py new file mode 100644 index 00000000..276012b0 --- /dev/null +++ b/app/migrations/20220303_downloading.py @@ -0,0 +1,16 @@ +# Generated by database migrator +import peewee + +def migrate(migrator, database, **kwargs): + migrator.add_columns('server_stats', downloading=peewee.BooleanField(default=False)) + """ + Write your migrations here. + """ + + + +def rollback(migrator, database, **kwargs): + migrator.drop_columns('server_stats', ['downloading']) + """ + Write your rollback migrations here. + """ diff --git a/app/translations/en_EN.json b/app/translations/en_EN.json index 7d4f51ad..fcd04232 100644 --- a/app/translations/en_EN.json +++ b/app/translations/en_EN.json @@ -165,7 +165,8 @@ "stop": "Stop", "updating": "Updating...", "starting": "Delayed-Start", - "delay-explained": "The service/agent has recently started and is delaying the start of the minecraft server instance" + "delay-explained": "The service/agent has recently started and is delaying the start of the minecraft server instance", + "downloading": "Downloading..." }, "serverPlayerManagement": { "players": "Players",