diff --git a/app/classes/minecraft/serverjars.py b/app/classes/minecraft/serverjars.py
index faa12a7d..447cf80b 100644
--- a/app/classes/minecraft/serverjars.py
+++ b/app/classes/minecraft/serverjars.py
@@ -8,6 +8,7 @@ import requests
from app.classes.controllers.servers_controller import ServersController
from app.classes.models.server_permissions import PermissionsServers
+from app.classes.shared.websocket_manager import WebSocketManager
logger = logging.getLogger(__name__)
@@ -179,9 +180,7 @@ class ServerJars:
try:
ServersController.set_import(server_id)
for user in server_users:
- self.helper.websocket_helper.broadcast_user(
- user, "send_start_reload", {}
- )
+ WebSocketManager().broadcast_user(user, "send_start_reload", {})
break
except Exception as ex:
@@ -206,11 +205,9 @@ class ServerJars:
server_users = PermissionsServers.get_server_user_list(server_id)
for user in server_users:
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user, "notification", "Executable download finished"
)
time.sleep(3)
- self.helper.websocket_helper.broadcast_user(
- user, "send_start_reload", {}
- )
+ WebSocketManager().broadcast_user(user, "send_start_reload", {})
return success
diff --git a/app/classes/models/management.py b/app/classes/models/management.py
index 2c64a8ff..1213bda0 100644
--- a/app/classes/models/management.py
+++ b/app/classes/models/management.py
@@ -17,6 +17,7 @@ from app.classes.models.users import HelperUsers
from app.classes.models.servers import Servers
from app.classes.models.server_permissions import PermissionsServers
from app.classes.shared.main_models import DatabaseShortcuts
+from app.classes.shared.websocket_manager import WebSocketManager
logger = logging.getLogger(__name__)
@@ -158,9 +159,7 @@ class HelpersManagement:
server_users = PermissionsServers.get_server_user_list(server_id)
for user in server_users:
try:
- self.helper.websocket_helper.broadcast_user(
- user, "notification", audit_msg
- )
+ WebSocketManager().broadcast_user(user, "notification", audit_msg)
except Exception as e:
logger.error(f"Error broadcasting to user {user} - {e}")
diff --git a/app/classes/shared/command.py b/app/classes/shared/command.py
index 26fdd2f0..413f74b2 100644
--- a/app/classes/shared/command.py
+++ b/app/classes/shared/command.py
@@ -11,6 +11,7 @@ from app.classes.shared.helpers import Helpers
from app.classes.shared.tasks import TasksManager
from app.classes.shared.migration import MigrationManager
from app.classes.shared.main_controller import Controller
+from app.classes.shared.websocket_manager import WebSocketManager
logger = logging.getLogger(__name__)
@@ -115,7 +116,7 @@ class MainPrompt(cmd.Cmd):
Console.info(
"Stopping all server daemons / threads - This may take a few seconds"
)
- self.helper.websocket_helper.disconnect_all()
+ WebSocketManager().disconnect_all()
Console.info("Waiting for main thread to stop")
while True:
if self.tasks_manager.get_main_thread_run_status():
diff --git a/app/classes/shared/file_helpers.py b/app/classes/shared/file_helpers.py
index 4005e965..f42930f7 100644
--- a/app/classes/shared/file_helpers.py
+++ b/app/classes/shared/file_helpers.py
@@ -8,6 +8,7 @@ from zipfile import ZipFile, ZIP_DEFLATED
from app.classes.shared.helpers import Helpers
from app.classes.shared.console import Console
+from app.classes.shared.websocket_manager import WebSocketManager
logger = logging.getLogger(__name__)
@@ -149,7 +150,7 @@ class FileHelpers:
"percent": 0,
"total_files": self.helper.human_readable_file_size(dir_bytes),
}
- self.helper.websocket_helper.broadcast_page_params(
+ WebSocketManager().broadcast_page_params(
"/panel/server_detail",
{"id": str(server_id)},
"backup_status",
@@ -194,7 +195,7 @@ class FileHelpers:
"percent": percent,
"total_files": self.helper.human_readable_file_size(dir_bytes),
}
- self.helper.websocket_helper.broadcast_page_params(
+ WebSocketManager().broadcast_page_params(
"/panel/server_detail",
{"id": str(server_id)},
"backup_status",
@@ -215,7 +216,7 @@ class FileHelpers:
"percent": 0,
"total_files": self.helper.human_readable_file_size(dir_bytes),
}
- self.helper.websocket_helper.broadcast_page_params(
+ WebSocketManager().broadcast_page_params(
"/panel/server_detail",
{"id": str(server_id)},
"backup_status",
@@ -274,7 +275,7 @@ class FileHelpers:
"total_files": self.helper.human_readable_file_size(dir_bytes),
}
# send status results to page.
- self.helper.websocket_helper.broadcast_page_params(
+ WebSocketManager().broadcast_page_params(
"/panel/server_detail",
{"id": str(server_id)},
"backup_status",
@@ -325,3 +326,20 @@ class FileHelpers:
else:
return "false"
return
+
+ # TODO Look if not redundant with the precendent function prefixed ajax_ de differentiate and not broke things
+
+ def ajax_unzip_server(self, zip_path, user_id):
+ if Helpers.check_file_perms(zip_path):
+ temp_dir = tempfile.mkdtemp()
+ with zipfile.ZipFile(zip_path, "r") as zip_ref:
+ # extracts archive to temp directory
+ zip_ref.extractall(temp_dir)
+ if user_id:
+ WebSocketManager().broadcast_user(
+ user_id, "send_temp_path", {"path": temp_dir}
+ )
+
+ def ajax_backup_select(self, path, user_id):
+ if user_id:
+ WebSocketManager().broadcast_user(user_id, "send_temp_path", {"path": path})
diff --git a/app/classes/shared/helpers.py b/app/classes/shared/helpers.py
index 489115ae..30f70d3a 100644
--- a/app/classes/shared/helpers.py
+++ b/app/classes/shared/helpers.py
@@ -29,7 +29,6 @@ from app.classes.shared.null_writer import NullWriter
from app.classes.shared.console import Console
from app.classes.shared.installer import installer
from app.classes.shared.translation import Translation
-from app.classes.web.websocket_helper import WebSocketHelper
with redirect_stderr(NullWriter()):
import psutil
@@ -78,7 +77,6 @@ class Helpers:
self.passhasher = PasswordHasher()
self.exiting = False
- self.websocket_helper = WebSocketHelper(self)
self.translation = Translation(self)
self.update_available = False
self.ignored_names = ["crafty_managed.txt", "db_stats"]
@@ -1216,23 +1214,6 @@ class Helpers:
"""
return output
- def unzip_server(self, zip_path, user_id):
- if Helpers.check_file_perms(zip_path):
- temp_dir = tempfile.mkdtemp()
- with zipfile.ZipFile(zip_path, "r") as zip_ref:
- # extracts archive to temp directory
- zip_ref.extractall(temp_dir)
- if user_id:
- self.websocket_helper.broadcast_user(
- user_id, "send_temp_path", {"path": temp_dir}
- )
-
- def backup_select(self, path, user_id):
- if user_id:
- self.websocket_helper.broadcast_user(
- user_id, "send_temp_path", {"path": path}
- )
-
@staticmethod
def unzip_backup_archive(backup_path, zip_name):
zip_path = os.path.join(backup_path, zip_name)
diff --git a/app/classes/shared/import_helper.py b/app/classes/shared/import_helper.py
index e3762aad..1acf7a03 100644
--- a/app/classes/shared/import_helper.py
+++ b/app/classes/shared/import_helper.py
@@ -9,6 +9,7 @@ from app.classes.controllers.server_perms_controller import PermissionsServers
from app.classes.controllers.servers_controller import ServersController
from app.classes.shared.helpers import Helpers
from app.classes.shared.file_helpers import FileHelpers
+from app.classes.shared.websocket_manager import WebSocketManager
logger = logging.getLogger(__name__)
@@ -64,7 +65,7 @@ class ImportHelpers:
ServersController.finish_import(new_id)
server_users = PermissionsServers.get_server_user_list(new_id)
for user in server_users:
- self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {})
+ WebSocketManager().broadcast_user(user, "send_start_reload", {})
def import_java_zip_server(self, temp_dir, new_server_dir, port, new_id):
import_thread = threading.Thread(
@@ -108,7 +109,7 @@ class ImportHelpers:
server_users = PermissionsServers.get_server_user_list(new_id)
ServersController.finish_import(new_id)
for user in server_users:
- self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {})
+ WebSocketManager().broadcast_user(user, "send_start_reload", {})
# deletes temp dir
FileHelpers.del_dirs(temp_dir)
@@ -162,7 +163,7 @@ class ImportHelpers:
ServersController.finish_import(new_id)
server_users = PermissionsServers.get_server_user_list(new_id)
for user in server_users:
- self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {})
+ WebSocketManager().broadcast_user(user, "send_start_reload", {})
def import_bedrock_zip_server(
self, temp_dir, new_server_dir, full_jar_path, port, new_id
@@ -209,7 +210,7 @@ class ImportHelpers:
ServersController.finish_import(new_id)
server_users = PermissionsServers.get_server_user_list(new_id)
for user in server_users:
- self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {})
+ WebSocketManager().broadcast_user(user, "send_start_reload", {})
if os.name != "nt":
if Helpers.check_file_exists(full_jar_path):
os.chmod(full_jar_path, 0o2760)
@@ -253,4 +254,4 @@ class ImportHelpers:
ServersController.finish_import(new_id)
server_users = PermissionsServers.get_server_user_list(new_id)
for user in server_users:
- self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {})
+ WebSocketManager().broadcast_user(user, "send_start_reload", {})
diff --git a/app/classes/shared/main_controller.py b/app/classes/shared/main_controller.py
index 95872884..2a299934 100644
--- a/app/classes/shared/main_controller.py
+++ b/app/classes/shared/main_controller.py
@@ -32,6 +32,7 @@ from app.classes.shared.helpers import Helpers
from app.classes.shared.file_helpers import FileHelpers
from app.classes.shared.import_helper import ImportHelpers
from app.classes.minecraft.serverjars import ServerJars
+from app.classes.shared.websocket_manager import WebSocketManager
logger = logging.getLogger(__name__)
@@ -101,7 +102,7 @@ class Controller:
self.del_support_file(exec_user["support_logs"])
# pausing so on screen notifications can run for user
time.sleep(7)
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
exec_user["user_id"], "notification", "Preparing your support logs"
)
self.helper.ensure_dir_exists(
@@ -197,17 +198,15 @@ class Controller:
) as f:
f.write(sys_info_string)
FileHelpers.make_compressed_archive(temp_zip_storage, temp_dir, sys_info_string)
- if len(self.helper.websocket_helper.clients) > 0:
- self.helper.websocket_helper.broadcast_user(
+ if len(WebSocketManager().clients) > 0:
+ WebSocketManager().broadcast_user(
exec_user["user_id"],
"support_status_update",
Helpers.calc_percent(temp_dir, temp_zip_storage + ".zip"),
)
temp_zip_storage += ".zip"
- self.helper.websocket_helper.broadcast_user(
- exec_user["user_id"], "send_logs_bootbox", {}
- )
+ WebSocketManager().broadcast_user(exec_user["user_id"], "send_logs_bootbox", {})
self.users.set_support_path(exec_user["user_id"], temp_zip_storage)
@@ -240,8 +239,8 @@ class Controller:
results = Helpers.calc_percent(source_path, dest_path)
self.log_stats = results
- if len(self.helper.websocket_helper.clients) > 0:
- self.helper.websocket_helper.broadcast_user(
+ if len(WebSocketManager().clients) > 0:
+ WebSocketManager().broadcast_user(
exec_user["user_id"], "support_status_update", results
)
@@ -1025,7 +1024,7 @@ class Controller:
def t_update_master_server_dir(self, new_server_path, user_id):
new_server_path = self.helper.wtol_path(new_server_path)
new_server_path = os.path.join(new_server_path, "servers")
- self.helper.websocket_helper.broadcast_page(
+ WebSocketManager().broadcast_page(
"/panel/panel_config", "move_status", "Checking dir"
)
current_master = self.helper.wtol_path(
@@ -1035,7 +1034,7 @@ class Controller:
logger.info(
"Admin tried to change server dir to current server dir. Canceling..."
)
- self.helper.websocket_helper.broadcast_page(
+ WebSocketManager().broadcast_page(
"/panel/panel_config",
"move_status",
"done",
@@ -1046,18 +1045,18 @@ class Controller:
"Admin tried to change server dir to be inside a sub directory of the"
" current server dir. This will result in a copy loop."
)
- self.helper.websocket_helper.broadcast_page(
+ WebSocketManager().broadcast_page(
"/panel/panel_config",
"move_status",
"done",
)
return
- self.helper.websocket_helper.broadcast_page(
+ WebSocketManager().broadcast_page(
"/panel/panel_config", "move_status", "Checking permissions"
)
if not self.helper.ensure_dir_exists(new_server_path):
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user_id,
"send_start_error",
{
@@ -1079,7 +1078,7 @@ class Controller:
new_server_path, server.get("server_uuid")
)
if os.path.isdir(server_path):
- self.helper.websocket_helper.broadcast_page(
+ WebSocketManager().broadcast_page(
"/panel/panel_config",
"move_status",
f"Moving {server.get('server_name')}",
@@ -1120,7 +1119,7 @@ class Controller:
self.servers.update_unloaded_server(server_obj)
self.servers.init_all_servers()
self.helper.dir_migration = False
- self.helper.websocket_helper.broadcast_page(
+ WebSocketManager().broadcast_page(
"/panel/panel_config",
"move_status",
"done",
diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py
index c1a11158..abf63362 100644
--- a/app/classes/shared/server.py
+++ b/app/classes/shared/server.py
@@ -32,6 +32,8 @@ from app.classes.shared.console import Console
from app.classes.shared.helpers import Helpers
from app.classes.shared.file_helpers import FileHelpers
from app.classes.shared.null_writer import NullWriter
+from app.classes.shared.websocket_manager import WebSocketManager
+from app.classes.shared.websocket_manager import WebSocketManager
with redirect_stderr(NullWriter()):
import psutil
@@ -92,12 +94,13 @@ class ServerOutBuf:
# TODO: Do not send data to clients who do not have permission to view
# this server's console
- self.helper.websocket_helper.broadcast_page_params(
- "/panel/server_detail",
- {"id": self.server_id},
- "vterm_new_line",
- {"line": highlighted + "
"},
- )
+ if len(WebSocketManager().auth_clients) > 0:
+ WebSocketManager().broadcast_page_params(
+ "/panel/server_detail",
+ {"id": self.server_id},
+ "vterm_new_line",
+ {"line": highlighted + "
"},
+ )
# **********************************************************************************
@@ -322,7 +325,7 @@ class ServerInstance:
# Checks if user is currently attempting to move global server
# dir
if self.helper.dir_migration:
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user_id,
"send_start_error",
{
@@ -337,7 +340,7 @@ class ServerInstance:
if self.stats_helper.get_import_status() and not forge_install:
if user_id:
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user_id,
"send_start_error",
{
@@ -383,7 +386,7 @@ class ServerInstance:
e_flag = True
if not e_flag and self.settings["type"] == "minecraft-java":
if user_id:
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user_id, "send_eula_bootbox", {"id": self.server_id}
)
else:
@@ -416,7 +419,7 @@ class ServerInstance:
except:
if user_id:
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user_id,
"send_start_error",
{
@@ -452,7 +455,7 @@ class ServerInstance:
f"Server {self.name} failed to start with error code: {ex}"
)
if user_id:
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user_id,
"send_start_error",
{
@@ -479,7 +482,7 @@ class ServerInstance:
# Checks for java on initial fail
if not self.helper.detect_java():
if user_id:
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user_id,
"send_start_error",
{
@@ -493,7 +496,7 @@ class ServerInstance:
f"Server {self.name} failed to start with error code: {ex}"
)
if user_id:
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user_id,
"send_start_error",
{
@@ -540,7 +543,7 @@ class ServerInstance:
self.stats_helper.set_first_run()
loc_server_port = self.stats_helper.get_server_stats()["server_port"]
# Sends port reminder message.
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user_id,
"send_start_error",
{
@@ -552,15 +555,11 @@ class ServerInstance:
server_users = PermissionsServers.get_server_user_list(self.server_id)
for user in server_users:
if user != user_id:
- self.helper.websocket_helper.broadcast_user(
- user, "send_start_reload", {}
- )
+ WebSocketManager().broadcast_user(user, "send_start_reload", {})
else:
server_users = PermissionsServers.get_server_user_list(self.server_id)
for user in server_users:
- self.helper.websocket_helper.broadcast_user(
- user, "send_start_reload", {}
- )
+ WebSocketManager().broadcast_user(user, "send_start_reload", {})
else:
logger.warning(
f"Server PID {self.process.pid} died right after starting "
@@ -592,7 +591,7 @@ class ServerInstance:
def check_internet_thread(self, user_id, user_lang):
if user_id:
if not Helpers.check_internet():
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user_id,
"send_start_error",
{
@@ -719,9 +718,7 @@ class ServerInstance:
server_users = PermissionsServers.get_server_user_list(self.server_id)
for user in server_users:
- self.helper.websocket_helper.broadcast_user(
- user, "send_start_reload", {}
- )
+ WebSocketManager().broadcast_user(user, "send_start_reload", {})
break
def stop_crash_detection(self):
@@ -834,7 +831,7 @@ class ServerInstance:
self.record_server_stats()
for user in server_users:
- self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {})
+ WebSocketManager().broadcast_user(user, "send_start_reload", {})
def restart_threaded_server(self, user_id):
bu_conf = HelpersManagement.get_backup_config(self.server_id)
@@ -1034,8 +1031,8 @@ class ServerInstance:
logger.info(f"Backup Thread started for server {self.settings['server_name']}.")
def a_backup_server(self):
- if len(self.helper.websocket_helper.clients) > 0:
- self.helper.websocket_helper.broadcast_page_params(
+ if len(WebSocketManager().auth_clients) > 0:
+ WebSocketManager().broadcast_page_params(
"/panel/server_detail",
{"id": str(self.server_id)},
"backup_reload",
@@ -1045,7 +1042,7 @@ class ServerInstance:
logger.info(f"Starting server {self.name} (ID {self.server_id}) backup")
server_users = PermissionsServers.get_server_user_list(self.server_id)
for user in server_users:
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user,
"notification",
self.helper.translation.translate(
@@ -1120,8 +1117,8 @@ class ServerInstance:
self.is_backingup = False
logger.info(f"Backup of server: {self.name} completed")
results = {"percent": 100, "total_files": 0, "current_file": 0}
- if len(self.helper.websocket_helper.clients) > 0:
- self.helper.websocket_helper.broadcast_page_params(
+ if len(WebSocketManager().auth_clients) > 0:
+ WebSocketManager().broadcast_page_params(
"/panel/server_detail",
{"id": str(self.server_id)},
"backup_status",
@@ -1129,7 +1126,7 @@ class ServerInstance:
)
server_users = PermissionsServers.get_server_user_list(self.server_id)
for user in server_users:
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user,
"notification",
self.helper.translation.translate(
@@ -1158,8 +1155,8 @@ class ServerInstance:
f"Failed to create backup of server {self.name} (ID {self.server_id})"
)
results = {"percent": 100, "total_files": 0, "current_file": 0}
- if len(self.helper.websocket_helper.clients) > 0:
- self.helper.websocket_helper.broadcast_page_params(
+ if len(WebSocketManager().clients) > 0:
+ WebSocketManager().broadcast_page_params(
"/panel/server_detail",
{"id": str(self.server_id)},
"backup_status",
@@ -1176,8 +1173,8 @@ class ServerInstance:
def backup_status(self, source_path, dest_path):
results = Helpers.calc_percent(source_path, dest_path)
self.backup_stats = results
- if len(self.helper.websocket_helper.clients) > 0:
- self.helper.websocket_helper.broadcast_page_params(
+ if len(WebSocketManager().auth_clients) > 0:
+ WebSocketManager().broadcast_page_params(
"/panel/server_detail",
{"id": str(self.server_id)},
"backup_status",
@@ -1280,14 +1277,14 @@ class ServerInstance:
self.stop_threaded_server()
else:
was_started = False
- if len(self.helper.websocket_helper.clients) > 0:
+ if len(WebSocketManager().auth_clients) > 0:
# There are clients
self.check_update()
message = (
' UPDATING...'
)
for user in server_users:
- self.helper.websocket_helper.broadcast_user_page(
+ WebSocketManager().broadcast_user_page(
"/panel/server_detail",
user,
"update_button_status",
@@ -1340,7 +1337,7 @@ class ServerInstance:
# check if backup was successful
if self.last_backup_failed:
for user in server_users:
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user,
"notification",
"Backup failed for " + self.name + ". canceling update.",
@@ -1386,11 +1383,11 @@ class ServerInstance:
logger.info("Executable updated successfully. Starting Server")
self.stats_helper.set_update(False)
- if len(self.helper.websocket_helper.clients) > 0:
+ if len(WebSocketManager().auth_clients) > 0:
# There are clients
self.check_update()
for user in server_users:
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user,
"notification",
"Executable update finished for " + self.name,
@@ -1398,7 +1395,7 @@ class ServerInstance:
# sleep so first notif can completely run
time.sleep(3)
for user in server_users:
- self.helper.websocket_helper.broadcast_user_page(
+ WebSocketManager().broadcast_user_page(
"/panel/server_detail",
user,
"update_button_status",
@@ -1408,10 +1405,10 @@ class ServerInstance:
"wasRunning": was_started,
},
)
- self.helper.websocket_helper.broadcast_user_page(
+ WebSocketManager().broadcast_user_page(
user, "/panel/dashboard", "send_start_reload", {}
)
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user,
"notification",
"Executable update finished for " + self.name,
@@ -1428,7 +1425,7 @@ class ServerInstance:
self.run_threaded_server(HelperUsers.get_user_id_by_name("system"))
else:
for user in server_users:
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user,
"notification",
"Executable update failed for "
@@ -1438,7 +1435,7 @@ class ServerInstance:
logger.error("Executable download failed.")
self.stats_helper.set_update(False)
for user in server_users:
- self.helper.websocket_helper.broadcast_user(user, "remove_spinner", {})
+ WebSocketManager().broadcast_user(user, "remove_spinner", {})
def start_dir_calc_task(self):
server_dt = HelperServers.get_server_data_by_id(self.server_id)
@@ -1467,7 +1464,7 @@ class ServerInstance:
def realtime_stats(self):
# only get stats if clients are connected.
# no point in burning cpu
- if len(self.helper.websocket_helper.clients) > 0:
+ if len(WebSocketManager().public_clients | WebSocketManager().auth_clients) > 0:
total_players = 0
max_players = 0
servers_ping = []
@@ -1498,8 +1495,8 @@ class ServerInstance:
"crashed": self.is_crashed,
}
)
- if len(self.helper.websocket_helper.clients) > 0:
- self.helper.websocket_helper.broadcast_page_params(
+ if len(WebSocketManager().auth_clients) > 0:
+ WebSocketManager().broadcast_page_params(
"/panel/server_detail",
{"id": str(self.server_id)},
"update_server_details",
@@ -1532,14 +1529,17 @@ class ServerInstance:
self.record_server_stats()
- if (len(servers_ping) > 0) & (
- len(self.helper.websocket_helper.clients) > 0
- ):
+ if (len(servers_ping) > 0) & (len(WebSocketManager().auth_clients) > 0):
try:
- self.helper.websocket_helper.broadcast_page(
+ WebSocketManager().broadcast_page(
"/panel/dashboard", "update_server_status", servers_ping
)
- self.helper.websocket_helper.broadcast_page(
+ except:
+ Console.critical("Can't broadcast server status to websocket")
+
+ if (len(servers_ping) > 0) & (len(WebSocketManager().public_clients) > 0):
+ try:
+ WebSocketManager().broadcast_page(
"/status", "update_server_status", servers_ping
)
except:
diff --git a/app/classes/shared/tasks.py b/app/classes/shared/tasks.py
index acdc1cac..d35cf8dd 100644
--- a/app/classes/shared/tasks.py
+++ b/app/classes/shared/tasks.py
@@ -20,6 +20,7 @@ from app.classes.shared.file_helpers import FileHelpers
from app.classes.shared.helpers import Helpers
from app.classes.shared.main_controller import Controller
from app.classes.web.tornado_handler import Webserver
+from app.classes.shared.websocket_manager import WebSocketManager
logger = logging.getLogger("apscheduler")
scheduler_intervals = {
@@ -688,10 +689,10 @@ class TasksManager:
# Stats are different
host_stats = HelpersManagement.get_latest_hosts_stats()
- if len(self.helper.websocket_helper.clients) > 0:
+ if len(WebSocketManager().auth_clients) > 0:
# There are clients
try:
- self.helper.websocket_helper.broadcast_page(
+ WebSocketManager().broadcast_page(
"/panel/dashboard",
"update_host_stats",
{
@@ -708,7 +709,7 @@ class TasksManager:
},
)
except:
- self.helper.websocket_helper.broadcast_page(
+ WebSocketManager().broadcast_page(
"/panel/dashboard",
"update_host_stats",
{
diff --git a/app/classes/web/websocket_helper.py b/app/classes/shared/websocket_manager.py
similarity index 63%
rename from app/classes/web/websocket_helper.py
rename to app/classes/shared/websocket_manager.py
index cd70df50..b1729c76 100644
--- a/app/classes/web/websocket_helper.py
+++ b/app/classes/shared/websocket_manager.py
@@ -1,44 +1,65 @@
import json
import logging
+from enum import Enum
+from app.classes.shared.singleton import Singleton
from app.classes.shared.console import Console
+from app.classes.models.users import HelperUsers
logger = logging.getLogger(__name__)
-class WebSocketHelper:
- def __init__(self, helper):
- self.helper = helper
- self.clients = set()
+class EnumWebSocketState(Enum):
+ WS_UNKNOWN = -1
+ WS_PUBLIC = 0
+ WS_USER_AUTH = 1
+
+
+class WebSocketManager(metaclass=Singleton):
+ def __init__(self):
+ self.auth_clients = set()
+ self.public_clients = set()
def add_client(self, client):
- self.clients.add(client)
+ if client.ws_state == EnumWebSocketState.WS_PUBLIC:
+ self.public_clients.add(client)
+ elif client.ws_state == EnumWebSocketState.WS_USER_AUTH:
+ self.auth_clients.add(client)
+ else:
+ logging.debug("Unknown WebSocket")
+ client.close()
def remove_client(self, client):
- self.clients.remove(client)
-
- def send_message(self, client, event_type: str, data):
- if client.check_auth():
- message = str(json.dumps({"event": event_type, "data": data}))
- client.write_message_helper(message)
+ if client.ws_state == EnumWebSocketState.WS_PUBLIC:
+ self.public_clients.remove(client)
+ elif client.ws_state == EnumWebSocketState.WS_USER_AUTH:
+ self.auth_clients.remove(client)
def broadcast(self, event_type: str, data):
logger.debug(
- f"Sending to {len(self.clients)} clients: "
+ f"Sending to {len(self.public_clients | self.auth_clients)} clients: "
f"{json.dumps({'event': event_type, 'data': data})}"
)
- for client in self.clients:
+ for client in self.public_clients | self.auth_clients:
try:
- self.send_message(client, event_type, data)
+ client.send_message(event_type, data)
except Exception as e:
logger.exception(
f"Error caught while sending WebSocket message to "
f"{client.get_remote_ip()} {e}"
)
+ def broadcast_to_admins(self, event_type: str, data):
+ def filter_fn(client):
+ if client.get_user_id in HelperUsers.get_super_user_list():
+ return True
+ return False
+
+ self.broadcast_with_fn(filter_fn, event_type, data)
+
def broadcast_page(self, page: str, event_type: str, data):
def filter_fn(client):
- return client.page == page
+ return client.check_policy(event_type) and client.page == page
self.broadcast_with_fn(filter_fn, event_type, data)
@@ -87,16 +108,16 @@ class WebSocketHelper:
def broadcast_with_fn(self, filter_fn, event_type: str, data):
# assign self.clients to a static variable here so hopefully
# the set size won't change
- static_clients = self.clients
+ static_clients = self.public_clients | self.auth_clients
clients = list(filter(filter_fn, static_clients))
logger.debug(
- f"Sending to {len(clients)} out of {len(self.clients)} "
+ f"Sending to {len(clients)} out of {len(self.public_clients | self.auth_clients)} "
f"clients: {json.dumps({'event': event_type, 'data': data})}"
)
for client in clients[:]:
try:
- self.send_message(client, event_type, data)
+ client.send_message(event_type, data)
except Exception as e:
logger.exception(
f"Error catched while sending WebSocket message to "
@@ -105,6 +126,6 @@ class WebSocketHelper:
def disconnect_all(self):
Console.info("Disconnecting WebSocket clients")
- for client in self.clients:
+ for client in self.public_clients | self.auth_clients:
client.close()
Console.info("Disconnected WebSocket clients")
diff --git a/app/classes/web/ajax_handler.py b/app/classes/web/ajax_handler.py
index efe8d2fa..7202bfd6 100644
--- a/app/classes/web/ajax_handler.py
+++ b/app/classes/web/ajax_handler.py
@@ -12,8 +12,10 @@ import tornado.escape
from app.classes.models.server_permissions import EnumPermissionsServer
from app.classes.shared.console import Console
from app.classes.shared.helpers import Helpers
+from app.classes.shared.file_helpers import FileHelpers
from app.classes.shared.server import ServerOutBuf
from app.classes.web.base_handler import BaseHandler
+from app.classes.shared.websocket_manager import WebSocketManager
logger = logging.getLogger(__name__)
@@ -558,13 +560,13 @@ class AjaxHandler(BaseHandler):
urllib.parse.unquote(self.get_argument("file", "")),
)
if Helpers.check_file_exists(path):
- self.helper.unzip_server(path, exec_user["user_id"])
+ FileHelpers.ajax_unzip_server(path, exec_user["user_id"])
else:
user_id = exec_user["user_id"]
if user_id:
time.sleep(5)
user_lang = self.controller.users.get_user_lang_by_id(user_id)
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
user_id,
"send_start_error",
{
@@ -577,7 +579,7 @@ class AjaxHandler(BaseHandler):
elif page == "backup_select":
path = self.get_argument("path", None)
- self.helper.backup_select(path, exec_user["user_id"])
+ FileHelpers.ajax_backup_select(path, exec_user["user_id"])
return
elif page == "jar_cache":
@@ -593,7 +595,7 @@ class AjaxHandler(BaseHandler):
return
for server in self.controller.servers.get_all_servers_stats():
if server["stats"]["running"]:
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
exec_user["user_id"],
"send_start_error",
{
diff --git a/app/classes/web/server_handler.py b/app/classes/web/server_handler.py
index eae3ce0c..dbff9003 100644
--- a/app/classes/web/server_handler.py
+++ b/app/classes/web/server_handler.py
@@ -11,6 +11,7 @@ from app.classes.shared.helpers import Helpers
from app.classes.shared.file_helpers import FileHelpers
from app.classes.shared.main_models import DatabaseShortcuts
from app.classes.web.base_handler import BaseHandler
+from app.classes.shared.websocket_manager import WebSocketManager
logger = logging.getLogger(__name__)
@@ -207,7 +208,7 @@ class ServerHandler(BaseHandler):
)
):
time.sleep(3)
- self.helper.websocket_helper.broadcast_user(
+ WebSocketManager().broadcast_user(
exec_user["user_id"],
"send_start_error",
{
diff --git a/app/classes/web/tornado_handler.py b/app/classes/web/tornado_handler.py
index d2b047d7..0a7f0cb8 100644
--- a/app/classes/web/tornado_handler.py
+++ b/app/classes/web/tornado_handler.py
@@ -34,7 +34,7 @@ from app.classes.web.api_handler import (
ListServers,
SendCommand,
)
-from app.classes.web.websocket_handler import SocketHandler
+from app.classes.web.websocket_handler import AuthSocketHandler, PublicSocketHandler
from app.classes.web.static_handler import CustomStaticHandler
from app.classes.web.upload_handler import UploadHandler
from app.classes.web.http_handler import HTTPHandler, HTTPHandlerPage
@@ -48,7 +48,7 @@ class Webserver:
controller: Controller
helper: Helpers
- def __init__(self, helper, controller, tasks_manager):
+ def __init__(self, helper: Helpers, controller: Controller, tasks_manager):
self.ioloop = None
self.http_server = None
self.https_server = None
@@ -153,7 +153,8 @@ class Webserver:
(r"/server/(.*)", ServerHandler, handler_args),
(r"/ajax/(.*)", AjaxHandler, handler_args),
(r"/files/(.*)", FileHandler, handler_args),
- (r"/ws", SocketHandler, handler_args),
+ (r"/ws/auth", AuthSocketHandler, handler_args),
+ (r"/ws/public", PublicSocketHandler, handler_args),
(r"/upload", UploadHandler, handler_args),
(r"/status", StatusHandler, handler_args),
# API Routes V1
diff --git a/app/classes/web/upload_handler.py b/app/classes/web/upload_handler.py
index adce3ab9..21b6c64c 100644
--- a/app/classes/web/upload_handler.py
+++ b/app/classes/web/upload_handler.py
@@ -12,6 +12,7 @@ from app.classes.shared.console import Console
from app.classes.shared.helpers import Helpers
from app.classes.shared.main_controller import Controller
from app.classes.web.base_handler import BaseHandler
+from app.classes.shared.websocket_manager import WebSocketManager
logger = logging.getLogger(__name__)
@@ -113,7 +114,7 @@ class UploadHandler(BaseHandler):
self.request.headers.get("X-FileName", None)
)
if not str(filename).endswith(".zip"):
- self.helper.websocket_helper.broadcast("close_upload_box", "error")
+ WebSocketManager().broadcast("close_upload_box", "error")
self.finish("error")
full_path = os.path.join(path, filename)
@@ -313,13 +314,13 @@ class UploadHandler(BaseHandler):
if self.do_upload:
time.sleep(5)
if files_left == 0:
- self.helper.websocket_helper.broadcast("close_upload_box", "success")
+ WebSocketManager().broadcast("close_upload_box", "success")
self.finish("success") # Nope, I'm sending "success"
self.f.close()
else:
time.sleep(5)
if files_left == 0:
- self.helper.websocket_helper.broadcast("close_upload_box", "error")
+ WebSocketManager().broadcast("close_upload_box", "error")
self.finish("error")
def data_received(self, chunk):
diff --git a/app/classes/web/websocket_handler.py b/app/classes/web/websocket_handler.py
index 78b33951..d15d6c7d 100644
--- a/app/classes/web/websocket_handler.py
+++ b/app/classes/web/websocket_handler.py
@@ -4,15 +4,20 @@ import asyncio
from urllib.parse import parse_qsl
import tornado.websocket
+from app.classes.shared.main_controller import Controller
from app.classes.shared.helpers import Helpers
+from app.classes.shared.websocket_manager import WebSocketManager, EnumWebSocketState
logger = logging.getLogger(__name__)
-class SocketHandler(tornado.websocket.WebSocketHandler):
+class BaseSocketHandler(tornado.websocket.WebSocketHandler):
+ ws_state = EnumWebSocketState.WS_UNKNOWN # Must be overridden at init
+ ws_authorized_pages = {} # Must be overridden at init
+ ws_authorized_events = {} # Must be overridden at init
page = None
page_query_params = None
- controller = None
+ controller: Controller = None
tasks_manager = None
translator = None
io_loop = None
@@ -34,6 +39,102 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
)
return remote_ip
+ # pylint: disable=arguments-differ
+ def open(self):
+ """
+ This method must be overridden
+ """
+ raise NotImplementedError
+
+ def handle(self):
+ """
+ This method must be overridden
+ """
+ raise NotImplementedError
+
+ def get_user_id(self):
+ """
+ This method must be overridden
+ """
+ raise NotImplementedError
+
+ def check_auth(self):
+ """
+ This method must be overridden
+ """
+ raise NotImplementedError
+
+ # pylint: disable=arguments-renamed
+ def on_message(self, raw_message):
+ logger.debug(f"Got message from WebSocket connection {raw_message}")
+ message = json.loads(raw_message)
+ logger.debug(f"Event Type: {message['event']}, Data: {message['data']}")
+
+ def on_close(self):
+ WebSocketManager().remove_client(self)
+ logger.debug("Closed WebSocket connection")
+
+ async def write_message_int(self, message):
+ self.write_message(message)
+
+ def write_message_async(self, message):
+ asyncio.run_coroutine_threadsafe(
+ self.write_message_int(message), self.io_loop.asyncio_loop
+ )
+
+ def send_message(self, event_type: str, data):
+ message = str(json.dumps({"event": event_type, "data": data}))
+ self.write_message_async(message)
+
+ def check_policy(self, event_type: str):
+ # Looking if the client is the right one for the page
+ if self.page.split("/")[1] not in self.ws_authorized_pages:
+ return False
+ # Looking if the event is send to the right page
+ if event_type not in self.ws_authorized_events:
+ return False
+ # All seams good so we can agree
+ return True
+
+
+class AuthSocketHandler(BaseSocketHandler):
+ ws_state = EnumWebSocketState.WS_USER_AUTH
+ ws_authorized_pages = {"panel", "server", "ajax", "files", "upload", "api"}
+ ws_authorized_events = {
+ "notification",
+ "update_host_stats",
+ "update_server_details",
+ "update_server_status",
+ "send_start_reload",
+ "send_start_error",
+ # TODO "send_temp_path",
+ "support_status_update",
+ "send_logs_bootbox",
+ "move_status",
+ "vterm_new_line",
+ "send_eula_bootbox",
+ "backup_reload",
+ "backup_status",
+ "update_button_status",
+ "remove_spinner",
+ "close_upload_box",
+ } # Must be overridden at init
+ page = None
+ page_query_params = None
+ controller = None
+ tasks_manager = None
+ translator = None
+ io_loop = None
+
+ def initialize(
+ self, helper=None, controller=None, tasks_manager=None, translator=None
+ ):
+ self.helper = helper
+ self.controller = controller
+ self.tasks_manager = tasks_manager
+ self.translator = translator
+ self.io_loop = tornado.ioloop.IOLoop.current()
+
def get_user_id(self):
_, _, user = self.controller.authentication.check(self.get_cookie("token"))
return user["user_id"]
@@ -47,10 +148,10 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
if self.check_auth():
self.handle()
else:
- self.helper.websocket_helper.send_message(
+ WebSocketManager().broadcast_to_admins(
self, "notification", "Not authenticated for WebSocket connection"
)
- self.close()
+ self.close(1011, "Forbidden WS Access")
self.controller.management.add_to_audit_log_raw(
"unknown",
0,
@@ -58,7 +159,7 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
"Someone tried to connect via WebSocket without proper authentication",
self.get_remote_ip(),
)
- self.helper.websocket_helper.broadcast(
+ WebSocketManager().broadcast(
"notification",
"Someone tried to connect via WebSocket without proper authentication",
)
@@ -73,24 +174,47 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
Helpers.remove_prefix(self.get_query_argument("page_query_params"), "?")
)
)
- self.helper.websocket_helper.add_client(self)
+ WebSocketManager().add_client(self)
logger.debug("Opened WebSocket connection")
- # pylint: disable=arguments-renamed
- @staticmethod
- def on_message(raw_message):
- logger.debug(f"Got message from WebSocket connection {raw_message}")
- message = json.loads(raw_message)
- logger.debug(f"Event Type: {message['event']}, Data: {message['data']}")
- def on_close(self):
- self.helper.websocket_helper.remove_client(self)
- logger.debug("Closed WebSocket connection")
+class PublicSocketHandler(BaseSocketHandler):
+ ws_state = EnumWebSocketState.WS_PUBLIC
+ ws_authorized_pages = {"404", "error", "login", "offline", "status"}
+ ws_authorized_events = {"update_server_status"} # Must be overridden at init
+ page = None
+ page_query_params = None
+ controller = None
+ tasks_manager = None
+ translator = None
+ io_loop = None
- async def write_message_int(self, message):
- self.write_message(message)
+ def initialize(
+ self, helper=None, controller=None, tasks_manager=None, translator=None
+ ):
+ self.helper = helper
+ self.controller = controller
+ self.tasks_manager = tasks_manager
+ self.translator = translator
+ self.io_loop = tornado.ioloop.IOLoop.current()
- def write_message_helper(self, message):
- asyncio.run_coroutine_threadsafe(
- self.write_message_int(message), self.io_loop.asyncio_loop
+ def get_user_id(self):
+ return None
+
+ def check_auth(self):
+ return False
+
+ # pylint: disable=arguments-differ
+ def open(self):
+ logger.debug("Checking Public WebSocket")
+ self.handle()
+
+ def handle(self):
+ self.page = self.get_query_argument("page")
+ self.page_query_params = dict(
+ parse_qsl(
+ Helpers.remove_prefix(self.get_query_argument("page_query_params"), "?")
+ )
)
+ WebSocketManager().add_client(self)
+ logger.debug("Opened Public WebSocket connection")
diff --git a/app/frontend/templates/base.html b/app/frontend/templates/base.html
index 58d49c53..72e73cbd 100755
--- a/app/frontend/templates/base.html
+++ b/app/frontend/templates/base.html
@@ -14,11 +14,10 @@
-
+
-
+
@@ -50,15 +49,9 @@
-
-
-
+
+
+
@@ -91,8 +84,7 @@
{% include notify.html %}
-