From 8424fc31491332be714eb3a486a6c453ac79b659 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 13 Jan 2022 20:42:53 -0500 Subject: [PATCH] Put support logs into a thread. --- app/classes/controllers/users_controller.py | 4 + app/classes/models/users.py | 6 ++ app/classes/shared/main_controller.py | 39 ++++++++ app/classes/web/panel_handler.py | 88 ++++++++----------- app/frontend/templates/base.html | 24 +++++ .../20210915205501_users_log_path.py | 16 ++++ 6 files changed, 124 insertions(+), 53 deletions(-) create mode 100644 app/migrations/20210915205501_users_log_path.py diff --git a/app/classes/controllers/users_controller.py b/app/classes/controllers/users_controller.py index 072b9335..71157e24 100644 --- a/app/classes/controllers/users_controller.py +++ b/app/classes/controllers/users_controller.py @@ -47,6 +47,10 @@ class Users_Controller: def user_query(user_id): return users_helper.user_query(user_id) + @staticmethod + def set_support_path(user_id, support_path): + users_helper.set_support_path(user_id, support_path) + @staticmethod def update_user(user_id, user_data={}, user_crafty_data={}): base_data = users_helper.get_user(user_id) diff --git a/app/classes/models/users.py b/app/classes/models/users.py index 97d1f9f8..3cf91804 100644 --- a/app/classes/models/users.py +++ b/app/classes/models/users.py @@ -43,6 +43,7 @@ class Users(Model): superuser = BooleanField(default=False) api_token = CharField(default="", unique=True, index=True) # we may need to revisit this lang = CharField(default="en_EN") + support_logs = CharField(default = '') class Meta: table_name = "users" @@ -119,6 +120,7 @@ class helper_users: 'api_token': None, 'roles': [], 'servers': [], + 'support_logs': '', } user = model_to_dict(Users.get(Users.user_id == user_id)) @@ -171,6 +173,10 @@ class helper_users: user = Users.get(Users.user_id == user_id) return user.delete_instance() + @staticmethod + def set_support_path(user_id, support_path): + Users.update(support_logs = support_path).where(Users.user_id == user_id).execute() + @staticmethod def user_id_exists(user_id): if not users_helper.get_user(user_id): diff --git a/app/classes/shared/main_controller.py b/app/classes/shared/main_controller.py index 109af258..6aa3661c 100644 --- a/app/classes/shared/main_controller.py +++ b/app/classes/shared/main_controller.py @@ -3,6 +3,7 @@ import pathlib import time import logging import sys +from app.classes.models.server_permissions import Enum_Permissions_Server from app.classes.models.users import helper_users from peewee import DoesNotExist import schedule @@ -13,6 +14,7 @@ import tempfile import zipfile from distutils import dir_util from app.classes.models.management import helpers_management +from app.classes.web.websocket_helper import websocket_helper from app.classes.shared.helpers import helper from app.classes.shared.console import console @@ -128,6 +130,43 @@ class Controller: else: return False + def package_support_logs(self, exec_user): + websocket_helper.broadcast_user(exec_user['user_id'], 'notification', 'Preparing your support logs') + tempDir = tempfile.mkdtemp() + tempZipStorage = tempfile.mkdtemp() + full_temp = os.path.join(tempDir, 'support_logs') + os.mkdir(full_temp) + tempZipStorage = os.path.join(tempZipStorage, "support_logs") + crafty_path = os.path.join(full_temp, "crafty") + os.mkdir(crafty_path) + server_path = os.path.join(full_temp, "server") + os.mkdir(server_path) + if exec_user['superuser']: + auth_servers = self.servers.get_all_defined_servers() + else: + user_servers = self.servers.get_authorized_servers(int(exec_user['user_id'])) + auth_servers = [] + for server in user_servers: + if Enum_Permissions_Server.Logs in self.server_perms.get_user_permissions_list(exec_user['user_id'], server["server_id"]): + auth_servers.append(server) + else: + logger.info("Logs permission not available for server {}. Skipping.".format(server["server_name"])) + #we'll iterate through our list of log paths from auth servers. + for server in auth_servers: + final_path = os.path.join(server_path, str(server['server_name'])) + os.mkdir(final_path) + shutil.copy(server['log_path'], final_path) + #Copy crafty logs to archive dir + full_log_name = os.path.join(crafty_path, 'logs') + shutil.copytree("logs", full_log_name) + shutil.make_archive(tempZipStorage, "zip", tempDir) + + tempZipStorage += '.zip' + websocket_helper.broadcast_user(exec_user['user_id'], 'send_logs_bootbox', { + }) + + self.users.set_support_path(exec_user['user_id'], tempZipStorage) + @staticmethod def add_system_user(): helper_users.add_user("system", helper.random_string_generator(64), "default@example.com", helper_users.new_api_token(), False, False) diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py index 68da0dad..e67f81ec 100644 --- a/app/classes/web/panel_handler.py +++ b/app/classes/web/panel_handler.py @@ -26,6 +26,7 @@ from app.classes.models.crafty_permissions import Enum_Permissions_Crafty, Permi from app.classes.models.management import management_helper from app.classes.shared.helpers import helper +from app.classes.web.websocket_helper import WebSocketHelper logger = logging.getLogger(__name__) @@ -769,63 +770,44 @@ class PanelHandler(BaseHandler): del chunk self.redirect("/panel/server_detail?id={}&subpage=files".format(server_id)) - elif page == "support_logs": - logger.info("Support logs requested. Packinging logs for user with ID: {}".format(exec_user_id)) - tempDir = tempfile.mkdtemp() - tempZipStorage = tempfile.mkdtemp() - full_temp = os.path.join(tempDir, 'support_logs') - os.mkdir(full_temp) - tempZipStorage = os.path.join(tempZipStorage, "support_logs") - crafty_path = os.path.join(full_temp, "crafty") - os.mkdir(crafty_path) - server_path = os.path.join(full_temp, "server") - os.mkdir(server_path) - if exec_user['superuser']: - auth_servers = self.controller.servers.get_all_defined_servers() - else: - user_servers = self.controller.servers.get_authorized_servers(int(exec_user_id)) - auth_servers = [] - for server in user_servers: - if Enum_Permissions_Server.Logs in self.controller.server_perms.get_user_permissions_list(exec_user['user_id'], server["server_id"]): - auth_servers.append(server) - else: - logger.info("Logs permission not available for server {}. Skipping.".format(server["server_name"])) - #we'll iterate through our list of log paths from auth servers. - for server in auth_servers: - final_path = os.path.join(server_path, str(server['server_name'])) - os.mkdir(final_path) - shutil.copy(server['log_path'], final_path) - #Copy crafty logs to archive dir - full_log_name = os.path.join(crafty_path, 'logs') - shutil.copytree("logs", full_log_name) - shutil.make_archive(tempZipStorage, "zip", tempDir) - - tempZipStorage += '.zip' + elif page == 'download_support_package': + tempZipStorage = exec_user['support_logs'] + #We'll reset the support path for this user now. + self.controller.users.set_support_path(exec_user_id, "") + self.set_header('Content-Type', 'application/octet-stream') self.set_header('Content-Disposition', 'attachment; filename=' + "support_logs.zip") chunk_size = 1024 * 1024 * 4 # 4 MiB - - with open(tempZipStorage, 'rb') as f: - while True: - chunk = f.read(chunk_size) - if not chunk: - break - try: - self.write(chunk) # write the chunk to response - self.flush() # send the chunk to client - except iostream.StreamClosedError: - # this means the client has closed the connection - # so break the loop - break - finally: - # deleting the chunk is very important because - # if many clients are downloading files at the - # same time, the chunks in memory will keep - # increasing and will eat up the RAM - del chunk - - + if tempZipStorage != '': + with open(tempZipStorage, 'rb') as f: + while True: + chunk = f.read(chunk_size) + if not chunk: + break + try: + self.write(chunk) # write the chunk to response + self.flush() # send the chunk to client + except iostream.StreamClosedError: + # this means the client has closed the connection + # so break the loop + break + finally: + # deleting the chunk is very important because + # if many clients are downloading files at the + # same time, the chunks in memory will keep + # increasing and will eat up the RAM + del chunk + self.redirect('/panel/dashboard') + else: + self.redirect('/panel/error?error=No path found for support logs') + return + elif page == "support_logs": + logger.info("Support logs requested. Packinging logs for user with ID: {}".format(exec_user_id)) + logs_thread = threading.Thread(target=self.controller.package_support_logs, daemon=True, args=(exec_user,), name='{}_logs_thread'.format(exec_user['user_id'])) + logs_thread.start() + self.redirect('/panel/dashboard') + return diff --git a/app/frontend/templates/base.html b/app/frontend/templates/base.html index 9210194e..758169fd 100644 --- a/app/frontend/templates/base.html +++ b/app/frontend/templates/base.html @@ -237,6 +237,30 @@ if (webSocket) { }) }); } + if (webSocket) { + webSocket.on('send_logs_bootbox', function (server_id) { + var x = document.querySelector('.bootbox'); + if(x){ + x.remove()} + var x = document.querySelector('.modal-backdrop'); + if(x){ + x.remove()} + bootbox.alert({ + title: 'Download Support Logs?', + message: "We've finished preparing your support logs. Please click download to download", + buttons: { + ok: { + label: 'Download', + className: 'btn-info' + } + }, + callback: function(){ + console.log("in callback") + location.href="/panel/download_support_package"; + } +}); + }); + } if (webSocket) { webSocket.on('send_eula_bootbox', function (server_id) { diff --git a/app/migrations/20210915205501_users_log_path.py b/app/migrations/20210915205501_users_log_path.py new file mode 100644 index 00000000..c79ad322 --- /dev/null +++ b/app/migrations/20210915205501_users_log_path.py @@ -0,0 +1,16 @@ +# Generated by database migrator +import peewee + +def migrate(migrator, database, **kwargs): + migrator.add_columns('users', support_logs=peewee.CharField(default="")) + """ + Write your migrations here. + """ + + + +def rollback(migrator, database, **kwargs): + migrator.drop_columns('users', ['support_logs']) + """ + Write your rollback migrations here. + """