mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Merge branch 'dev' into feature/discord-webhooks
This commit is contained in:
commit
65bea2a11a
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,18 +1,26 @@
|
||||
# Changelog
|
||||
## --- [4.2.0] - 2023/TBD
|
||||
### New features
|
||||
- Finish and Activate Arcadia notification backend ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/621))
|
||||
- Finish and Activate Arcadia notification backend ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/621) | [Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/626))
|
||||
### Bug fixes
|
||||
- PWA: Removed the custom offline page in favour of browser default ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/607))
|
||||
- Fix hidden servers appearing visible on public mobile status page ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/612))
|
||||
- Correctly handle if a server returns a string instead of json data on socket ping ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/614))
|
||||
- Bump tornado to resolve #269 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/623))
|
||||
- Bump crypto to resolve #267 & #268 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/622))
|
||||
- Fix select installs failing to start, returning missing python package `packaging` ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/629))
|
||||
- Fix public status page not updating #255 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/615))
|
||||
- Fix service worker vulrn and CQ raised by SonarQ ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/631))
|
||||
### Refactor
|
||||
- Consolidate remaining frontend functions into API V2, and remove ajax internal API ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/585))
|
||||
- Replace bleach with nh3 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/628))
|
||||
- Add API route for historical server stats ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/615))
|
||||
- Add API route for host stats ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/615))
|
||||
### Tweaks
|
||||
- Polish/Enhance display for InApp Documentation ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/613))
|
||||
- Add get_users command to Crafty's console ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/620))
|
||||
- Make files hover cursor pointer ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/627))
|
||||
- Use `Jar` class naming for jar refresh to make room for steamCMD naming in the future ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/630))
|
||||
### Lang
|
||||
TBD
|
||||
<br><br>
|
||||
|
@ -105,9 +105,9 @@ class ServersController(metaclass=Singleton):
|
||||
|
||||
return ret
|
||||
|
||||
def get_history_stats(self, server_id, days):
|
||||
def get_history_stats(self, server_id, hours):
|
||||
srv = ServersController().get_server_instance_by_id(server_id)
|
||||
return srv.stats_helper.get_history_stats(server_id, days)
|
||||
return srv.stats_helper.get_history_stats(server_id, hours)
|
||||
|
||||
@staticmethod
|
||||
def update_unloaded_server(server_obj):
|
||||
|
@ -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
|
||||
|
@ -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__)
|
||||
|
||||
@ -161,9 +162,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}")
|
||||
|
||||
|
@ -50,6 +50,7 @@ class ServerStats(Model):
|
||||
max = IntegerField(default=0)
|
||||
players = CharField(default="")
|
||||
desc = CharField(default="Unable to Connect")
|
||||
icon = CharField(default="")
|
||||
version = CharField(default="")
|
||||
updating = BooleanField(default=False)
|
||||
waiting_start = BooleanField(default=False)
|
||||
@ -141,16 +142,20 @@ class HelperServerStats:
|
||||
self.database.close()
|
||||
return server_data
|
||||
|
||||
def get_history_stats(self, server_id, num_days):
|
||||
def get_history_stats(self, server_id, num_hours):
|
||||
self.database.connect(reuse_if_open=True)
|
||||
max_age = datetime.datetime.now() - timedelta(days=num_days)
|
||||
server_stats = (
|
||||
max_age = datetime.datetime.now() - timedelta(hours=num_hours)
|
||||
query_stats = (
|
||||
ServerStats.select()
|
||||
.where(ServerStats.created > max_age)
|
||||
.where(ServerStats.server_id == server_id)
|
||||
# .order_by(ServerStats.created.desc())
|
||||
.execute(self.database)
|
||||
)
|
||||
self.database.connect(reuse_if_open=True)
|
||||
server_stats = []
|
||||
for stat in query_stats:
|
||||
server_stats.append(DatabaseShortcuts.get_data_obj(stat))
|
||||
self.database.close()
|
||||
return server_stats
|
||||
|
||||
def insert_server_stats(self, server_stats):
|
||||
@ -179,6 +184,7 @@ class HelperServerStats:
|
||||
ServerStats.max: server_stats.get("max", False),
|
||||
ServerStats.players: server_stats.get("players", False),
|
||||
ServerStats.desc: server_stats.get("desc", False),
|
||||
ServerStats.icon: server_stats.get("icon", None),
|
||||
ServerStats.version: server_stats.get("version", False),
|
||||
}
|
||||
).execute(self.database)
|
||||
|
@ -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__)
|
||||
|
||||
@ -118,7 +119,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():
|
||||
|
@ -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",
|
||||
|
@ -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"]
|
||||
|
@ -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", {})
|
||||
|
@ -33,6 +33,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__)
|
||||
|
||||
@ -113,7 +114,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(
|
||||
@ -209,17 +210,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)
|
||||
|
||||
@ -252,8 +251,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
|
||||
)
|
||||
|
||||
@ -910,7 +909,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(
|
||||
@ -920,7 +919,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",
|
||||
@ -931,18 +930,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",
|
||||
{
|
||||
@ -966,7 +965,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')}",
|
||||
@ -1007,7 +1006,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",
|
||||
|
@ -32,6 +32,7 @@ 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
|
||||
|
||||
with redirect_stderr(NullWriter()):
|
||||
import psutil
|
||||
@ -92,12 +93,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 + "<br />"},
|
||||
)
|
||||
if len(WebSocketManager().clients) > 0:
|
||||
WebSocketManager().broadcast_page_params(
|
||||
"/panel/server_detail",
|
||||
{"id": self.server_id},
|
||||
"vterm_new_line",
|
||||
{"line": highlighted + "<br />"},
|
||||
)
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
@ -251,6 +253,23 @@ class ServerInstance:
|
||||
seconds=5,
|
||||
id="stats_" + str(self.server_id),
|
||||
)
|
||||
logger.info(f"Saving server statistics {self.name} every {30} seconds")
|
||||
Console.info(f"Saving server statistics {self.name} every {30} seconds")
|
||||
try:
|
||||
self.server_scheduler.add_job(
|
||||
self.record_server_stats,
|
||||
"interval",
|
||||
seconds=30,
|
||||
id="save_stats_" + str(self.server_id),
|
||||
)
|
||||
except:
|
||||
self.server_scheduler.remove_job("save_" + str(self.server_id))
|
||||
self.server_scheduler.add_job(
|
||||
self.record_server_stats,
|
||||
"interval",
|
||||
seconds=30,
|
||||
id="save_" + str(self.server_id),
|
||||
)
|
||||
|
||||
def setup_server_run_command(self):
|
||||
# configure the server
|
||||
@ -322,7 +341,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 +356,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 +402,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 +435,7 @@ class ServerInstance:
|
||||
|
||||
except:
|
||||
if user_id:
|
||||
self.helper.websocket_helper.broadcast_user(
|
||||
WebSocketManager().broadcast_user(
|
||||
user_id,
|
||||
"send_start_error",
|
||||
{
|
||||
@ -452,7 +471,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 +498,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 +512,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 +559,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 +571,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 +607,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 +734,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 +847,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)
|
||||
@ -1035,8 +1048,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().clients) > 0:
|
||||
WebSocketManager().broadcast_page_params(
|
||||
"/panel/server_detail",
|
||||
{"id": str(self.server_id)},
|
||||
"backup_reload",
|
||||
@ -1046,7 +1059,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(
|
||||
@ -1121,8 +1134,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().clients) > 0:
|
||||
WebSocketManager().broadcast_page_params(
|
||||
"/panel/server_detail",
|
||||
{"id": str(self.server_id)},
|
||||
"backup_status",
|
||||
@ -1130,7 +1143,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(
|
||||
@ -1159,8 +1172,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",
|
||||
@ -1177,8 +1190,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().clients) > 0:
|
||||
WebSocketManager().broadcast_page_params(
|
||||
"/panel/server_detail",
|
||||
{"id": str(self.server_id)},
|
||||
"backup_status",
|
||||
@ -1281,14 +1294,14 @@ class ServerInstance:
|
||||
self.stop_threaded_server()
|
||||
else:
|
||||
was_started = False
|
||||
if len(self.helper.websocket_helper.clients) > 0:
|
||||
if len(WebSocketManager().clients) > 0:
|
||||
# There are clients
|
||||
self.check_update()
|
||||
message = (
|
||||
'<a data-id="' + str(self.server_id) + '" class=""> UPDATING...</i></a>'
|
||||
)
|
||||
for user in server_users:
|
||||
self.helper.websocket_helper.broadcast_user_page(
|
||||
WebSocketManager().broadcast_user_page(
|
||||
"/panel/server_detail",
|
||||
user,
|
||||
"update_button_status",
|
||||
@ -1341,7 +1354,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.",
|
||||
@ -1387,11 +1400,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().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,
|
||||
@ -1399,7 +1412,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",
|
||||
@ -1409,10 +1422,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,
|
||||
@ -1429,7 +1442,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 "
|
||||
@ -1439,7 +1452,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)
|
||||
@ -1468,7 +1481,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().clients) > 0:
|
||||
total_players = 0
|
||||
max_players = 0
|
||||
servers_ping = []
|
||||
@ -1499,50 +1512,43 @@ class ServerInstance:
|
||||
"crashed": self.is_crashed,
|
||||
}
|
||||
)
|
||||
if len(self.helper.websocket_helper.clients) > 0:
|
||||
self.helper.websocket_helper.broadcast_page_params(
|
||||
"/panel/server_detail",
|
||||
{"id": str(self.server_id)},
|
||||
"update_server_details",
|
||||
{
|
||||
"id": raw_ping_result.get("id"),
|
||||
"started": raw_ping_result.get("started"),
|
||||
"running": raw_ping_result.get("running"),
|
||||
"cpu": raw_ping_result.get("cpu"),
|
||||
"mem": raw_ping_result.get("mem"),
|
||||
"mem_percent": raw_ping_result.get("mem_percent"),
|
||||
"world_name": raw_ping_result.get("world_name"),
|
||||
"world_size": raw_ping_result.get("world_size"),
|
||||
"server_port": raw_ping_result.get("server_port"),
|
||||
"int_ping_results": raw_ping_result.get("int_ping_results"),
|
||||
"online": raw_ping_result.get("online"),
|
||||
"max": raw_ping_result.get("max"),
|
||||
"players": raw_ping_result.get("players"),
|
||||
"desc": raw_ping_result.get("desc"),
|
||||
"version": raw_ping_result.get("version"),
|
||||
"icon": raw_ping_result.get("icon"),
|
||||
"crashed": self.is_crashed,
|
||||
"created": datetime.datetime.now().strftime(
|
||||
"%Y/%m/%d, %H:%M:%S"
|
||||
),
|
||||
"players_cache": self.player_cache,
|
||||
},
|
||||
)
|
||||
|
||||
WebSocketManager().broadcast_page_params(
|
||||
"/panel/server_detail",
|
||||
{"id": str(self.server_id)},
|
||||
"update_server_details",
|
||||
{
|
||||
"id": raw_ping_result.get("id"),
|
||||
"started": raw_ping_result.get("started"),
|
||||
"running": raw_ping_result.get("running"),
|
||||
"cpu": raw_ping_result.get("cpu"),
|
||||
"mem": raw_ping_result.get("mem"),
|
||||
"mem_percent": raw_ping_result.get("mem_percent"),
|
||||
"world_name": raw_ping_result.get("world_name"),
|
||||
"world_size": raw_ping_result.get("world_size"),
|
||||
"server_port": raw_ping_result.get("server_port"),
|
||||
"int_ping_results": raw_ping_result.get("int_ping_results"),
|
||||
"online": raw_ping_result.get("online"),
|
||||
"max": raw_ping_result.get("max"),
|
||||
"players": raw_ping_result.get("players"),
|
||||
"desc": raw_ping_result.get("desc"),
|
||||
"version": raw_ping_result.get("version"),
|
||||
"icon": raw_ping_result.get("icon"),
|
||||
"crashed": self.is_crashed,
|
||||
"created": datetime.datetime.now().strftime("%Y/%m/%d, %H:%M:%S"),
|
||||
"players_cache": self.player_cache,
|
||||
},
|
||||
)
|
||||
total_players += int(raw_ping_result.get("online"))
|
||||
max_players += int(raw_ping_result.get("max"))
|
||||
|
||||
self.record_server_stats()
|
||||
# self.record_server_stats()
|
||||
|
||||
if (len(servers_ping) > 0) & (
|
||||
len(self.helper.websocket_helper.clients) > 0
|
||||
):
|
||||
if len(servers_ping) > 0:
|
||||
try:
|
||||
self.helper.websocket_helper.broadcast_page(
|
||||
WebSocketManager().broadcast_page(
|
||||
"/panel/dashboard", "update_server_status", servers_ping
|
||||
)
|
||||
self.helper.websocket_helper.broadcast_page(
|
||||
"/status", "update_server_status", servers_ping
|
||||
)
|
||||
except:
|
||||
Console.critical("Can't broadcast server status to websocket")
|
||||
|
||||
@ -1607,6 +1613,7 @@ class ServerInstance:
|
||||
"players": ping_data.get("players", False),
|
||||
"desc": ping_data.get("server_description", False),
|
||||
"version": ping_data.get("server_version", False),
|
||||
"icon": ping_data.get("server_icon"),
|
||||
}
|
||||
else:
|
||||
server_stats = {
|
||||
@ -1625,6 +1632,7 @@ class ServerInstance:
|
||||
"players": False,
|
||||
"desc": False,
|
||||
"version": False,
|
||||
"icon": None,
|
||||
}
|
||||
|
||||
return server_stats
|
||||
@ -1673,7 +1681,6 @@ class ServerInstance:
|
||||
}
|
||||
|
||||
server_stats = {}
|
||||
server = HelperServers.get_server_obj(server_id)
|
||||
if not server:
|
||||
return {}
|
||||
server_dt = HelperServers.get_server_data_by_id(server_id)
|
||||
@ -1806,3 +1813,7 @@ class ServerInstance:
|
||||
minimum_to_exist = now - datetime.timedelta(days=max_age)
|
||||
|
||||
self.stats_helper.remove_old_stats(minimum_to_exist)
|
||||
|
||||
def get_server_history(self):
|
||||
history = self.stats_helper.get_history_stats(self.server_id, 1)
|
||||
return history
|
||||
|
@ -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().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",
|
||||
{
|
||||
|
@ -1,26 +1,25 @@
|
||||
import json
|
||||
import logging
|
||||
|
||||
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
|
||||
class WebSocketManager(metaclass=Singleton):
|
||||
def __init__(self):
|
||||
self.clients = set()
|
||||
|
||||
def add_client(self, client):
|
||||
self.clients.add(client)
|
||||
|
||||
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 in self.clients:
|
||||
self.clients.remove(client)
|
||||
else:
|
||||
logger.exception("Error caught while removing unknown WebSocket client")
|
||||
|
||||
def broadcast(self, event_type: str, data):
|
||||
logger.debug(
|
||||
@ -29,13 +28,21 @@ class WebSocketHelper:
|
||||
)
|
||||
for client in self.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
|
||||
@ -90,13 +97,14 @@ class WebSocketHelper:
|
||||
static_clients = self.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.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 "
|
@ -2,7 +2,7 @@ import logging
|
||||
import re
|
||||
import typing as t
|
||||
import orjson
|
||||
import bleach
|
||||
import nh3
|
||||
import tornado.web
|
||||
|
||||
from app.classes.models.crafty_permissions import EnumPermissionsCrafty
|
||||
@ -101,7 +101,7 @@ class BaseHandler(tornado.web.RequestHandler):
|
||||
if type(text) in self.nobleach:
|
||||
logger.debug("Auto-bleaching - bypass type")
|
||||
return text
|
||||
return bleach.clean(text)
|
||||
return nh3.clean(text)
|
||||
|
||||
def get_argument(
|
||||
self,
|
||||
|
@ -7,7 +7,7 @@ import json
|
||||
import logging
|
||||
import threading
|
||||
import urllib.parse
|
||||
import bleach
|
||||
import nh3
|
||||
import requests
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
@ -68,9 +68,7 @@ class PanelHandler(BaseHandler):
|
||||
) in self.controller.crafty_perms.list_defined_crafty_permissions():
|
||||
argument = int(
|
||||
float(
|
||||
bleach.clean(
|
||||
self.get_argument(f"permission_{permission.name}", "0")
|
||||
)
|
||||
nh3.clean(self.get_argument(f"permission_{permission.name}", "0"))
|
||||
)
|
||||
)
|
||||
if argument:
|
||||
@ -79,9 +77,7 @@ class PanelHandler(BaseHandler):
|
||||
)
|
||||
|
||||
q_argument = int(
|
||||
float(
|
||||
bleach.clean(self.get_argument(f"quantity_{permission.name}", "0"))
|
||||
)
|
||||
float(nh3.clean(self.get_argument(f"quantity_{permission.name}", "0")))
|
||||
)
|
||||
if q_argument:
|
||||
server_quantity[permission.name] = q_argument
|
||||
@ -480,7 +476,7 @@ class PanelHandler(BaseHandler):
|
||||
template = "panel/dashboard.html"
|
||||
|
||||
elif page == "server_detail":
|
||||
subpage = bleach.clean(self.get_argument("subpage", ""))
|
||||
subpage = nh3.clean(self.get_argument("subpage", ""))
|
||||
|
||||
server_id = self.check_server_id()
|
||||
if server_id is None:
|
||||
@ -748,7 +744,7 @@ class PanelHandler(BaseHandler):
|
||||
0, page_data["options"].pop(page_data["options"].index(days))
|
||||
)
|
||||
page_data["history_stats"] = self.controller.servers.get_history_stats(
|
||||
server_id, days
|
||||
server_id, hours=(days * 24)
|
||||
)
|
||||
if subpage == "webhooks":
|
||||
if (
|
||||
@ -1403,7 +1399,7 @@ class PanelHandler(BaseHandler):
|
||||
template = "panel/panel_edit_user_apikeys.html"
|
||||
|
||||
elif page == "remove_user":
|
||||
user_id = bleach.clean(self.get_argument("id", None))
|
||||
user_id = nh3.clean(self.get_argument("id", None))
|
||||
|
||||
if (
|
||||
not superuser
|
||||
|
@ -1,5 +1,5 @@
|
||||
import logging
|
||||
import bleach
|
||||
import nh3
|
||||
|
||||
from app.classes.shared.helpers import Helpers
|
||||
from app.classes.models.users import HelperUsers
|
||||
@ -28,8 +28,8 @@ class PublicHandler(BaseHandler):
|
||||
# self.clear_cookie("user_data")
|
||||
|
||||
def get(self, page=None):
|
||||
error = bleach.clean(self.get_argument("error", "Invalid Login!"))
|
||||
error_msg = bleach.clean(self.get_argument("error_msg", ""))
|
||||
error = nh3.clean(self.get_argument("error", "Invalid Login!"))
|
||||
error_msg = nh3.clean(self.get_argument("error_msg", ""))
|
||||
|
||||
page_data = {
|
||||
"version": self.helper.get_version_string(),
|
||||
@ -82,8 +82,8 @@ class PublicHandler(BaseHandler):
|
||||
)
|
||||
|
||||
def post(self, page=None):
|
||||
error = bleach.clean(self.get_argument("error", "Invalid Login!"))
|
||||
error_msg = bleach.clean(self.get_argument("error_msg", ""))
|
||||
error = nh3.clean(self.get_argument("error", "Invalid Login!"))
|
||||
error_msg = nh3.clean(self.get_argument("error_msg", ""))
|
||||
|
||||
page_data = {
|
||||
"version": self.helper.get_version_string(),
|
||||
@ -100,8 +100,8 @@ class PublicHandler(BaseHandler):
|
||||
if self.request.query:
|
||||
next_page = "/login?" + self.request.query
|
||||
|
||||
entered_username = bleach.clean(self.get_argument("username"))
|
||||
entered_password = bleach.clean(self.get_argument("password"))
|
||||
entered_username = nh3.clean(self.get_argument("username"))
|
||||
entered_password = nh3.clean(self.get_argument("password"))
|
||||
|
||||
# pylint: disable=no-member
|
||||
try:
|
||||
|
@ -12,6 +12,7 @@ from app.classes.web.routes.api.roles.index import ApiRolesIndexHandler
|
||||
from app.classes.web.routes.api.roles.role.index import ApiRolesRoleIndexHandler
|
||||
from app.classes.web.routes.api.roles.role.servers import ApiRolesRoleServersHandler
|
||||
from app.classes.web.routes.api.roles.role.users import ApiRolesRoleUsersHandler
|
||||
|
||||
from app.classes.web.routes.api.servers.index import ApiServersIndexHandler
|
||||
from app.classes.web.routes.api.servers.server.action import (
|
||||
ApiServersServerActionHandler,
|
||||
@ -21,7 +22,13 @@ from app.classes.web.routes.api.servers.server.logs import ApiServersServerLogsH
|
||||
from app.classes.web.routes.api.servers.server.public import (
|
||||
ApiServersServerPublicHandler,
|
||||
)
|
||||
from app.classes.web.routes.api.servers.server.status import (
|
||||
ApiServersServerStatusHandler,
|
||||
)
|
||||
from app.classes.web.routes.api.servers.server.stats import ApiServersServerStatsHandler
|
||||
from app.classes.web.routes.api.servers.server.history import (
|
||||
ApiServersServerHistoryHandler,
|
||||
)
|
||||
from app.classes.web.routes.api.servers.server.stdin import ApiServersServerStdinHandler
|
||||
from app.classes.web.routes.api.servers.server.tasks.index import (
|
||||
ApiServersServerTasksIndexHandler,
|
||||
@ -68,9 +75,10 @@ from app.classes.web.routes.api.crafty.config.index import (
|
||||
from app.classes.web.routes.api.crafty.config.server_dir import (
|
||||
ApiCraftyConfigServerDirHandler,
|
||||
)
|
||||
from app.classes.web.routes.api.crafty.stats.stats import ApiCraftyHostStatsHandler
|
||||
from app.classes.web.routes.api.crafty.clogs.index import ApiCraftyLogIndexHandler
|
||||
from app.classes.web.routes.api.crafty.imports.index import ApiImportFilesIndexHandler
|
||||
from app.classes.web.routes.api.crafty.exe_cache import ApiCraftyExeCacheIndexHandler
|
||||
from app.classes.web.routes.api.crafty.exe_cache import ApiCraftyJarCacheIndexHandler
|
||||
|
||||
|
||||
def api_handlers(handler_args):
|
||||
@ -106,11 +114,21 @@ def api_handlers(handler_args):
|
||||
ApiCraftyConfigServerDirHandler,
|
||||
handler_args,
|
||||
),
|
||||
(
|
||||
r"/api/v2/crafty/stats/?",
|
||||
ApiCraftyHostStatsHandler,
|
||||
handler_args,
|
||||
),
|
||||
(
|
||||
r"/api/v2/crafty/logs/([a-z0-9_]+)/?",
|
||||
ApiCraftyLogIndexHandler,
|
||||
handler_args,
|
||||
),
|
||||
(
|
||||
r"/api/v2/crafty/JarCache/?",
|
||||
ApiCraftyJarCacheIndexHandler,
|
||||
handler_args,
|
||||
),
|
||||
(
|
||||
r"/api/v2/import/file/unzip/?",
|
||||
ApiImportFilesIndexHandler,
|
||||
@ -179,8 +197,8 @@ def api_handlers(handler_args):
|
||||
handler_args,
|
||||
),
|
||||
(
|
||||
r"/api/v2/crafty/exeCache/?",
|
||||
ApiCraftyExeCacheIndexHandler,
|
||||
r"/api/v2/servers/status/?",
|
||||
ApiServersServerStatusHandler,
|
||||
handler_args,
|
||||
),
|
||||
(
|
||||
@ -233,6 +251,11 @@ def api_handlers(handler_args):
|
||||
ApiServersServerStatsHandler,
|
||||
handler_args,
|
||||
),
|
||||
(
|
||||
r"/api/v2/servers/([0-9]+)/history/?",
|
||||
ApiServersServerHistoryHandler,
|
||||
handler_args,
|
||||
),
|
||||
(
|
||||
r"/api/v2/servers/([0-9]+)/webhook/([0-9]+)/?",
|
||||
ApiServersServerWebhooksWebhookIndexHandler,
|
||||
@ -241,7 +264,6 @@ def api_handlers(handler_args):
|
||||
(
|
||||
r"/api/v2/servers/([0-9]+)/webhook/?",
|
||||
ApiServersServerWebhooksIndexHandler,
|
||||
handler_args,
|
||||
),
|
||||
(
|
||||
r"/api/v2/servers/([0-9]+)/action/([a-z_]+)/?",
|
||||
|
@ -1,7 +1,7 @@
|
||||
from app.classes.web.base_api_handler import BaseApiHandler
|
||||
|
||||
|
||||
class ApiCraftyExeCacheIndexHandler(BaseApiHandler):
|
||||
class ApiCraftyJarCacheIndexHandler(BaseApiHandler):
|
||||
def get(self):
|
||||
auth_data = self.authenticate_user()
|
||||
if not auth_data:
|
||||
|
21
app/classes/web/routes/api/crafty/stats/stats.py
Normal file
21
app/classes/web/routes/api/crafty/stats/stats.py
Normal file
@ -0,0 +1,21 @@
|
||||
import logging
|
||||
from app.classes.web.base_api_handler import BaseApiHandler
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ApiCraftyHostStatsHandler(BaseApiHandler):
|
||||
def get(self):
|
||||
auth_data = self.authenticate_user()
|
||||
if not auth_data:
|
||||
return
|
||||
|
||||
latest = self.controller.management.get_latest_hosts_stats()
|
||||
|
||||
self.finish_json(
|
||||
200,
|
||||
{
|
||||
"status": "ok",
|
||||
"data": latest,
|
||||
},
|
||||
)
|
28
app/classes/web/routes/api/servers/server/history.py
Normal file
28
app/classes/web/routes/api/servers/server/history.py
Normal file
@ -0,0 +1,28 @@
|
||||
import logging
|
||||
from app.classes.web.base_api_handler import BaseApiHandler
|
||||
from app.classes.controllers.servers_controller import ServersController
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ApiServersServerHistoryHandler(BaseApiHandler):
|
||||
def get(self, server_id: str):
|
||||
auth_data = self.authenticate_user()
|
||||
if not auth_data:
|
||||
return
|
||||
|
||||
if server_id not in [str(x["server_id"]) for x in auth_data[0]]:
|
||||
# if the user doesn't have access to the server, return an error
|
||||
return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
|
||||
|
||||
srv = ServersController().get_server_instance_by_id(server_id)
|
||||
history = srv.get_server_history()
|
||||
|
||||
self.finish_json(
|
||||
200,
|
||||
{
|
||||
"status": "ok",
|
||||
"data": history,
|
||||
},
|
||||
)
|
32
app/classes/web/routes/api/servers/server/status.py
Normal file
32
app/classes/web/routes/api/servers/server/status.py
Normal file
@ -0,0 +1,32 @@
|
||||
import logging
|
||||
from app.classes.web.base_api_handler import BaseApiHandler
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ApiServersServerStatusHandler(BaseApiHandler):
|
||||
def get(self):
|
||||
servers_status = []
|
||||
servers_list = self.controller.servers.get_all_servers_stats()
|
||||
for server in servers_list:
|
||||
if server.get("server_data").get("show_status") is True:
|
||||
servers_status.append(
|
||||
{
|
||||
"id": server.get("server_data").get("server_id"),
|
||||
"world_name": server.get("stats").get("world_name"),
|
||||
"running": server.get("stats").get("running"),
|
||||
"online": server.get("stats").get("online"),
|
||||
"max": server.get("stats").get("max"),
|
||||
"version": server.get("stats").get("version"),
|
||||
"desc": server.get("stats").get("desc"),
|
||||
"icon": server.get("stats").get("icon"),
|
||||
}
|
||||
)
|
||||
|
||||
self.finish_json(
|
||||
200,
|
||||
{
|
||||
"status": "ok",
|
||||
"data": servers_status,
|
||||
},
|
||||
)
|
@ -14,6 +14,7 @@ import tornado.httpserver
|
||||
from app.classes.models.management import HelpersManagement
|
||||
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.main_controller import Controller
|
||||
from app.classes.web.public_handler import PublicHandler
|
||||
from app.classes.web.panel_handler import PanelHandler
|
||||
@ -32,7 +33,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 WebSocketHandler
|
||||
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
|
||||
@ -46,7 +47,13 @@ class Webserver:
|
||||
controller: Controller
|
||||
helper: Helpers
|
||||
|
||||
def __init__(self, helper, controller, tasks_manager, file_helper):
|
||||
def __init__(
|
||||
self,
|
||||
helper: Helpers,
|
||||
controller: Controller,
|
||||
tasks_manager,
|
||||
file_helper: FileHelpers,
|
||||
):
|
||||
self.ioloop = None
|
||||
self.http_server = None
|
||||
self.https_server = None
|
||||
@ -151,7 +158,7 @@ class Webserver:
|
||||
(r"/", DefaultHandler, handler_args),
|
||||
(r"/panel/(.*)", PanelHandler, handler_args),
|
||||
(r"/server/(.*)", ServerHandler, handler_args),
|
||||
(r"/ws", SocketHandler, handler_args),
|
||||
(r"/ws", WebSocketHandler, handler_args),
|
||||
(r"/upload", UploadHandler, handler_args),
|
||||
(r"/status", StatusHandler, handler_args),
|
||||
# API Routes V1
|
||||
|
@ -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__)
|
||||
|
||||
@ -115,7 +116,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)
|
||||
|
||||
@ -315,13 +316,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):
|
||||
|
@ -4,15 +4,17 @@ 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
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SocketHandler(tornado.websocket.WebSocketHandler):
|
||||
class WebSocketHandler(tornado.websocket.WebSocketHandler):
|
||||
page = None
|
||||
page_query_params = None
|
||||
controller = None
|
||||
controller: Controller = None
|
||||
tasks_manager = None
|
||||
translator = None
|
||||
io_loop = None
|
||||
@ -40,23 +42,16 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
||||
)
|
||||
return remote_ip
|
||||
|
||||
def get_user_id(self):
|
||||
_, _, user = self.controller.authentication.check(self.get_cookie("token"))
|
||||
return user["user_id"]
|
||||
|
||||
def check_auth(self):
|
||||
return self.controller.authentication.check_bool(self.get_cookie("token"))
|
||||
|
||||
# pylint: disable=arguments-differ
|
||||
def open(self):
|
||||
logger.debug("Checking WebSocket authentication")
|
||||
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,
|
||||
@ -64,7 +59,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",
|
||||
)
|
||||
@ -79,24 +74,34 @@ 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):
|
||||
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):
|
||||
self.helper.websocket_helper.remove_client(self)
|
||||
WebSocketManager().remove_client(self)
|
||||
logger.debug("Closed WebSocket connection")
|
||||
|
||||
async def write_message_int(self, message):
|
||||
self.write_message(message)
|
||||
|
||||
def write_message_helper(self, 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 get_user_id(self):
|
||||
_, _, user = self.controller.authentication.check(self.get_cookie("token"))
|
||||
return user["user_id"]
|
||||
|
||||
def check_auth(self):
|
||||
return self.controller.authentication.check_bool(self.get_cookie("token"))
|
||||
|
@ -6,36 +6,9 @@ importScripts(
|
||||
|
||||
const CACHE = "crafty-controller";
|
||||
|
||||
// TODO: replace the following with the correct offline fallback page i.e.: const offlineFallbackPage = "offline.html";
|
||||
const offlineFallbackPage = "/offline";
|
||||
|
||||
self.addEventListener("message", (event) => {
|
||||
if (event.data && event.data.type === "SKIP_WAITING") {
|
||||
self.skipWaiting();
|
||||
}
|
||||
});
|
||||
//This service worker is basically just here to make browsers
|
||||
//accept the PWA. It's not doing much anymore
|
||||
|
||||
if (workbox.navigationPreload.isSupported()) {
|
||||
workbox.navigationPreload.enable();
|
||||
}
|
||||
|
||||
// self.addEventListener('fetch', (event) => {
|
||||
// if (event.request.mode === 'navigate') {
|
||||
// event.respondWith((async () => {
|
||||
// try {
|
||||
// const preloadResp = await event.preloadResponse;
|
||||
|
||||
// if (preloadResp) {
|
||||
// return preloadResp;
|
||||
// }
|
||||
// const networkResp = await fetch(event.request);
|
||||
// return networkResp;
|
||||
// } catch (error) {
|
||||
|
||||
// const cache = await caches.open(CACHE);
|
||||
// const cachedResp = await cache.match(offlineFallbackPage);
|
||||
// return cachedResp;
|
||||
// }
|
||||
// })());
|
||||
// }
|
||||
// });
|
||||
|
@ -14,8 +14,7 @@
|
||||
<link rel="stylesheet" href="/static/assets/vendors/ti-icons/css/themify-icons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/typicons/typicons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/fontawesome6/css/all.css">
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="https://cdn.datatables.net/v/bs4/dt-1.10.22/fh-3.1.7/r-2.2.6/sc-2.0.3/sp-1.2.2/datatables.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/bs4/dt-1.10.22/fh-3.1.7/r-2.2.6/sc-2.0.3/sp-1.2.2/datatables.min.css" />
|
||||
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
|
||||
<link rel="stylesheet" href="/static/assets/css/crafty.css">
|
||||
|
||||
@ -50,15 +49,9 @@
|
||||
<!-- Bootstrap Toggle -->
|
||||
<link href="https://gitcdn.github.io/bootstrap-toggle/2.2.2/css/bootstrap-toggle.min.css" rel="stylesheet">
|
||||
<script defer src="https://gitcdn.github.io/bootstrap-toggle/2.2.2/js/bootstrap-toggle.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"
|
||||
integrity="sha512-ElRFoEQdI5Ht6kZvyzXhYG9NqjtkmlkfYk0wr6wHxU9JEHakS7UJZNeml5ALk+8IKlU6jDgMabC3vkumRokgJA=="
|
||||
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"
|
||||
integrity="sha512-UXumZrZNiOwnTcZSHLOfcTs0aos2MzBWHXOHOuB0J/R44QB0dwY5JgfbvljXcklVf65Gc4El6RjZ+lnwd2az2g=="
|
||||
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-zoom/1.2.1/chartjs-plugin-zoom.min.js"
|
||||
integrity="sha512-klQv6lz2YR+MecyFYMFRuU2eAl8IPRo6zHnsc9n142TJuJHS8CG0ix4Oq9na9ceeg1u5EkBfZsFcV3U7J51iew=="
|
||||
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js" integrity="sha512-ElRFoEQdI5Ht6kZvyzXhYG9NqjtkmlkfYk0wr6wHxU9JEHakS7UJZNeml5ALk+8IKlU6jDgMabC3vkumRokgJA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js" integrity="sha512-UXumZrZNiOwnTcZSHLOfcTs0aos2MzBWHXOHOuB0J/R44QB0dwY5JgfbvljXcklVf65Gc4El6RjZ+lnwd2az2g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-zoom/1.2.1/chartjs-plugin-zoom.min.js" integrity="sha512-klQv6lz2YR+MecyFYMFRuU2eAl8IPRo6zHnsc9n142TJuJHS8CG0ix4Oq9na9ceeg1u5EkBfZsFcV3U7J51iew==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
|
||||
<!-- End Bootstrap Toggle -->
|
||||
|
||||
@ -91,8 +84,7 @@
|
||||
|
||||
{% include notify.html %}
|
||||
|
||||
<button class="navbar-toggler navbar-toggler-right d-lg-none align-self-center" type="button"
|
||||
data-toggle="offcanvas">
|
||||
<button class="navbar-toggler navbar-toggler-right d-lg-none align-self-center" type="button" data-toggle="offcanvas">
|
||||
<span class="mdi mdi-menu"></span>
|
||||
</button>
|
||||
</div>
|
||||
@ -183,8 +175,7 @@
|
||||
<script src="/static/assets/js/shared/off-canvas.js"></script>
|
||||
<script src="/static/assets/js/shared/hoverable-collapse.js"></script>
|
||||
<script src="/static/assets/js/shared/misc.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="https://cdn.datatables.net/v/bs4/dt-1.10.22/fh-3.1.7/r-2.2.6/sc-2.0.3/sp-1.2.2/datatables.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.datatables.net/v/bs4/dt-1.10.22/fh-3.1.7/r-2.2.6/sc-2.0.3/sp-1.2.2/datatables.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/5.4.0/bootbox.min.js"></script>
|
||||
<script type="text/javascript" src="/static/assets/js/motd.js"></script>
|
||||
|
||||
@ -241,6 +232,7 @@
|
||||
|
||||
let usingWebSockets = false;
|
||||
let webSocket = null;
|
||||
let websocketTimeoutId = null;
|
||||
// {% if request.protocol == 'https' %}
|
||||
usingWebSockets = true;
|
||||
|
||||
@ -291,18 +283,19 @@
|
||||
wsOpen = false;
|
||||
console.log('Closed WebSocket', closeEvent);
|
||||
|
||||
if (typeof reconnectorId !== 'number') {
|
||||
setTimeout(sendWssError, 7000);
|
||||
if (!document.hidden) {
|
||||
if (typeof reconnectorId !== 'number') {
|
||||
setTimeout(sendWssError, 7000);
|
||||
}
|
||||
console.info("Reconnecting with a timeout of", (getRandomArbitrary(0, 2 ** failedConnectionCounter - 1) + 5) * 1000, "milliseconds");
|
||||
// Discard old websocket and create a new one in 5 seconds
|
||||
wsInternal = null
|
||||
reconnectorId = setTimeout(startWebSocket, (getRandomArbitrary(0, 2 ** failedConnectionCounter - 1) + 5) * 1000)
|
||||
|
||||
failedConnectionCounter++;
|
||||
}
|
||||
console.info("Reconnecting with a timeout of", (getRandomArbitrary(0, 2 ** failedConnectionCounter - 1) + 5) * 1000, "milliseconds");
|
||||
// Discard old websocket and create a new one in 5 seconds
|
||||
wsInternal = null
|
||||
reconnectorId = setTimeout(startWebSocket, (getRandomArbitrary(0, 2 ** failedConnectionCounter - 1) + 5) * 1000)
|
||||
|
||||
failedConnectionCounter++;
|
||||
};
|
||||
|
||||
|
||||
webSocket = {
|
||||
on: function (event, callback) {
|
||||
console.log('registered ' + event + ' event');
|
||||
@ -315,6 +308,12 @@
|
||||
}
|
||||
|
||||
wsInternal.send(JSON.stringify(message));
|
||||
},
|
||||
close: function (code, reason) {
|
||||
wsInternal.close(code, reason);
|
||||
},
|
||||
getStatus: function () {
|
||||
return wsInternal.readyState;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@ -328,6 +327,21 @@
|
||||
warn('WebSockets are not supported in Crafty if not using the https protocol')
|
||||
// {% end%}
|
||||
|
||||
// Managing Connexions for Multi Tab opened to reduce bandwith usage
|
||||
document.addEventListener("visibilitychange", () => {
|
||||
if (document.visibilityState == "hidden") {
|
||||
websocketTimeoutId = setTimeout(() => {
|
||||
webSocket.close(1000, "Closed due to Inactivity");
|
||||
console.log('%c[Crafty Controller] %cClose Websocket due to Tab not active after 5s', 'font-weight: 900; color: #800080;', 'font-weight: 900; color: #eee;');
|
||||
}, 10000);
|
||||
} else {
|
||||
clearTimeout(websocketTimeoutId)
|
||||
if (webSocket.getStatus() == WebSocket.CLOSED) {
|
||||
startWebSocket();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (webSocket) {
|
||||
webSocket.on('send_start_error', function (start_error) {
|
||||
var x = document.querySelector('.bootbox');
|
||||
@ -524,10 +538,10 @@
|
||||
|
||||
document.addEventListener('alpine:init', () => {
|
||||
console.log('%c[Crafty Controller] %cAlpine.js pre-initialization!', 'font-weight: 900; color: #800080;', 'color: #eee;');
|
||||
})
|
||||
});
|
||||
document.addEventListener('alpine:initialized', () => {
|
||||
console.log('%c[Crafty Controller] %cAlpine.js initialized!', 'font-weight: 900; color: #800080;', 'color: #eee;');
|
||||
})
|
||||
});
|
||||
|
||||
$(document).ready(function () {
|
||||
console.log('%c[Crafty Controller] %cReady for JS!', 'font-weight: 900; color: #800080;', 'font-weight: 900; color: #eee;');
|
||||
|
@ -65,6 +65,7 @@
|
||||
<style>
|
||||
.badge-notify {
|
||||
background: var(--purple);
|
||||
color: var(--dark);
|
||||
position: absolute;
|
||||
-moz-transform: translate(-70%, -70%);
|
||||
/* For Firefox */
|
||||
|
@ -58,13 +58,11 @@
|
||||
|
||||
</div>
|
||||
<div class="wrapper my-auto ml-auto ml-lg-4">
|
||||
<p id="cpu_data" class="mb-0 text-success" data-toggle="tooltip" data-placement="top" data-html="true"
|
||||
title="{% raw translate('dashboard', 'cpuCores', data['lang']) %}: {{ data.get('hosts_data').get('cpu_cores') }} <br /> {% raw translate('dashboard', 'cpuCurFreq', data['lang']) %}: {{ data.get('hosts_data').get('cpu_cur_freq') }} <br /> {% raw translate('dashboard', 'cpuMaxFreq', data['lang']) %}: {{ data.get('hosts_data').get('cpu_max_freq') }}">
|
||||
<p id="cpu_data" class="mb-0 text-success" data-toggle="tooltip" data-placement="top" data-html="true" title="{% raw translate('dashboard', 'cpuCores', data['lang']) %}: {{ data.get('hosts_data').get('cpu_cores') }} <br /> {% raw translate('dashboard', 'cpuCurFreq', data['lang']) %}: {{ data.get('hosts_data').get('cpu_cur_freq') }} <br /> {% raw translate('dashboard', 'cpuMaxFreq', data['lang']) %}: {{ data.get('hosts_data').get('cpu_max_freq') }}">
|
||||
{{ translate('dashboard', 'cpuUsage', data['lang']) }}: <span id="cpu_usage">{{
|
||||
data.get('hosts_data').get('cpu_usage') }}</span>
|
||||
</p>
|
||||
<p id="mem_usage" class="mb-0 text-danger" data-toggle="tooltip" data-placement="top"
|
||||
title="{{ translate('dashboard', 'memUsage', data['lang']) }}: {{ data.get('hosts_data').get('mem_usage') }}">
|
||||
<p id="mem_usage" class="mb-0 text-danger" data-toggle="tooltip" data-placement="top" title="{{ translate('dashboard', 'memUsage', data['lang']) }}: {{ data.get('hosts_data').get('mem_usage') }}">
|
||||
{{ translate('dashboard', 'memUsage', data['lang']) }}: <span id="mem_percent">{{
|
||||
data.get('hosts_data').get('mem_percent') }}%</span>
|
||||
</p>
|
||||
@ -111,12 +109,9 @@
|
||||
{% for item in data['hosts_data']['disk_json'] %}
|
||||
{% if item["mount"] in data["monitored"] %}
|
||||
<div id="{{item['device']}}" class="col-xl-3 col-lg-3 col-md-4 col-12">
|
||||
<h4 class="mb-0 font-weight-semibold d-inline-block text-truncate storage-heading"
|
||||
id="title_{{item['device']}}" data-toggle="tooltip" data-placement="bottom"
|
||||
title="{{item['mount']}}" style="max-width: 100%;"><i class="fas fa-hdd"></i>
|
||||
<h4 class="mb-0 font-weight-semibold d-inline-block text-truncate storage-heading" id="title_{{item['device']}}" data-toggle="tooltip" data-placement="bottom" title="{{item['mount']}}" style="max-width: 100%;"><i class="fas fa-hdd"></i>
|
||||
{{item["mount"]}}</h4>
|
||||
<div class="progress d-inline-block"
|
||||
style="height: 20px; width: 100%; background-color: rgb(139, 139, 139) !important;">
|
||||
<div class="progress d-inline-block" style="height: 20px; width: 100%; background-color: rgb(139, 139, 139) !important;">
|
||||
<div class="progress-bar
|
||||
{% if item['percent_used'] <= 58 %}
|
||||
bg-success
|
||||
@ -125,8 +120,7 @@
|
||||
{% else %}
|
||||
bg-danger
|
||||
{% end %}
|
||||
" role="progressbar" style="color: black; height: 100%; width: {{item['percent_used']}}%;"
|
||||
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">{{item["used"]}} /
|
||||
" role="progressbar" style="color: black; height: 100%; width: {{item['percent_used']}}%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">{{item["used"]}} /
|
||||
{{item["total"]}}
|
||||
</div>
|
||||
</div>
|
||||
@ -153,9 +147,7 @@
|
||||
data['lang']) }}</h4>
|
||||
{% if len(data['servers']) > 0 %}
|
||||
{% if data['user_data']['hints'] %}
|
||||
<span class="too_small" title="{{ translate('dashboard', 'cannotSeeOnMobile', data['lang']) }}" ,
|
||||
data-content="{{ translate('dashboard', 'cannotSeeOnMobile2', data['lang']) }}" ,
|
||||
data-placement="top"></span>
|
||||
<span class="too_small" title="{{ translate('dashboard', 'cannotSeeOnMobile', data['lang']) }}" , data-content="{{ translate('dashboard', 'cannotSeeOnMobile2', data['lang']) }}" , data-placement="top"></span>
|
||||
{% end %}
|
||||
{% end %}
|
||||
<div><a class="nav-link" href="/server/step1"><i class="fas fa-plus-circle"></i> {{
|
||||
@ -193,8 +185,7 @@
|
||||
<td draggable="false">
|
||||
<i class="fas fa-server"></i>
|
||||
{% if server['alert'] %}
|
||||
<a style="color: red !important;" draggable="false"
|
||||
href="/panel/server_detail?id={{server['server_data']['server_id']}}">
|
||||
<a style="color: red !important;" draggable="false" href="/panel/server_detail?id={{server['server_data']['server_id']}}">
|
||||
{{ server['server_data']['server_name'] }} <i class="fas fa-exclamation-triangle"></i>
|
||||
</a>
|
||||
{% else %}
|
||||
@ -208,13 +199,11 @@
|
||||
{% if server['user_command_permission'] %}
|
||||
{% if server['stats']['importing'] and server['stats']['running'] %}
|
||||
<!-- WHAT HAPPENED HERE -->
|
||||
<a data-id="{{server['server_data']['server_id']}}" class=""><i
|
||||
class="fa fa-spinner fa-spin"></i> {{ translate('serverTerm', 'installing',
|
||||
<a data-id="{{server['server_data']['server_id']}}" class=""><i class="fa fa-spinner fa-spin"></i> {{ translate('serverTerm', 'installing',
|
||||
data['lang']) }}</i></a>
|
||||
{% elif server['stats']['updating']%}
|
||||
<!-- WHAT HAPPENED HERE -->
|
||||
<a data-id="{{server['server_data']['server_id']}}" class=""><i
|
||||
class="fa fa-spinner fa-spin"></i> {{ translate('serverTerm', 'updating',
|
||||
<a data-id="{{server['server_data']['server_id']}}" class=""><i class="fa fa-spinner fa-spin"></i> {{ translate('serverTerm', 'updating',
|
||||
data['lang']) }}</i></a>
|
||||
{% elif server['stats']['waiting_start']%}
|
||||
<!-- WHAT HAPPENED HERE -->
|
||||
@ -226,31 +215,25 @@
|
||||
{{ translate('serverTerm', 'importing',
|
||||
data['lang']) }}</a>
|
||||
{% elif server['stats']['running'] %}
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="stop_button" data-toggle="tooltip"
|
||||
title="{{ translate('dashboard', 'stop' , data['lang']) }}">
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="stop_button" data-toggle="tooltip" title="{{ translate('dashboard', 'stop' , data['lang']) }}">
|
||||
<i class="fas fa-stop"></i>
|
||||
</a>
|
||||
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="restart_button" data-toggle="tooltip"
|
||||
title="{{ translate('dashboard', 'restart' , data['lang']) }}">
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="restart_button" data-toggle="tooltip" title="{{ translate('dashboard', 'restart' , data['lang']) }}">
|
||||
<i class="fas fa-sync"></i>
|
||||
</a>
|
||||
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="kill_button" data-toggle="tooltip"
|
||||
title="{{ translate('dashboard', 'kill' , data['lang']) }}">
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="kill_button" data-toggle="tooltip" title="{{ translate('dashboard', 'kill' , data['lang']) }}">
|
||||
<i class="fas fa-skull"></i>
|
||||
</a>
|
||||
{% else %}
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="play_button" data-toggle="tooltip"
|
||||
title="{{ translate('dashboard', 'start' , data['lang']) }}">
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="play_button" data-toggle="tooltip" title="{{ translate('dashboard', 'start' , data['lang']) }}">
|
||||
<i class="fas fa-play"></i>
|
||||
</a>
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="clone_button" data-toggle="tooltip"
|
||||
title="{{ translate('dashboard', 'clone' , data['lang']) }}">
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="clone_button" data-toggle="tooltip" title="{{ translate('dashboard', 'clone' , data['lang']) }}">
|
||||
<i class="fas fa-clone"></i>
|
||||
</a>
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="kill_button" data-toggle="tooltip"
|
||||
title="{{ translate('dashboard', 'kill' , data['lang']) }}">
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="kill_button" data-toggle="tooltip" title="{{ translate('dashboard', 'kill' , data['lang']) }}">
|
||||
<i class="fas fa-skull"></i>
|
||||
</a>
|
||||
{% end %}
|
||||
@ -258,8 +241,7 @@
|
||||
</td>
|
||||
|
||||
<td draggable="false" id="server_cpu_{{server['server_data']['server_id']}}">
|
||||
<div class="progress mb-1" data-toggle="tooltip" data-placement="top"
|
||||
title="{{server['stats']['cpu']}}">
|
||||
<div class="progress mb-1" data-toggle="tooltip" data-placement="top" title="{{server['stats']['cpu']}}">
|
||||
<div class="progress-bar
|
||||
{% if server['stats']['cpu'] <= 33 %}
|
||||
bg-success
|
||||
@ -268,15 +250,13 @@
|
||||
{% else %}
|
||||
bg-danger
|
||||
{% end %}
|
||||
" role="progressbar" style="width: {{server['stats']['cpu']}}%" aria-valuenow="0"
|
||||
aria-valuemin="0" aria-valuemax="100"></div>
|
||||
" role="progressbar" style="width: {{server['stats']['cpu']}}%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
{{server['stats']['cpu']}}%
|
||||
</td>
|
||||
|
||||
<td draggable="false" id="server_mem_{{server['server_data']['server_id']}}">
|
||||
<div class="progress mb-1" data-toggle="tooltip" data-placement="top"
|
||||
title="{{server['stats']['mem']}}">
|
||||
<div class="progress mb-1" data-toggle="tooltip" data-placement="top" title="{{server['stats']['mem']}}">
|
||||
<div class="progress-bar
|
||||
{% if server['stats']['mem_percent'] <= 33 %}
|
||||
bg-success
|
||||
@ -285,8 +265,7 @@
|
||||
{% else %}
|
||||
bg-danger
|
||||
{% end %}
|
||||
" role="progressbar" style="width: {{server['stats']['mem_percent']}}%" aria-valuenow="0"
|
||||
aria-valuemin="0" aria-valuemax="100"></div>
|
||||
" role="progressbar" style="width: {{server['stats']['mem_percent']}}%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
{{server['stats']['mem_percent']}}% -
|
||||
|
||||
@ -305,8 +284,7 @@
|
||||
data['lang']) }} <br />
|
||||
|
||||
{% if server['stats']['desc'] != 'False' %}
|
||||
<div id="desc_id"
|
||||
style="overflow-wrap: break-word !important; max-width: 85px !important; overflow: scroll;">{{
|
||||
<div id="desc_id" style="overflow-wrap: break-word !important; max-width: 85px !important; overflow: scroll;">{{
|
||||
server['stats']['desc'] }}</div> <br />
|
||||
{% end %}
|
||||
|
||||
@ -334,16 +312,14 @@
|
||||
<br />
|
||||
<br />
|
||||
</td>
|
||||
<span class="server-player-totals" id="server_players_{{server['server_data']['server_id']}}"
|
||||
data-players="{{ server['stats']['online']}}" data-max="{{ server['stats']['max'] }}"></span>
|
||||
<span class="server-player-totals" id="server_players_{{server['server_data']['server_id']}}" data-players="{{ server['stats']['online']}}" data-max="{{ server['stats']['max'] }}"></span>
|
||||
</tr>
|
||||
{% end %}
|
||||
</div>
|
||||
</span>
|
||||
{% for server in data['failed_servers'] %}
|
||||
<tr id="{{server['server_id']}}" draggable="false">
|
||||
<td class="text-warning"><i class="fas fa-server"></i> <a class="text-warning"
|
||||
href="/panel/server_detail?id={{server['server_id']}}&subpage=config">{{server['server_name']}}</a>
|
||||
<td class="text-warning"><i class="fas fa-server"></i> <a class="text-warning" href="/panel/server_detail?id={{server['server_id']}}&subpage=config">{{server['server_name']}}</a>
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
@ -368,28 +344,22 @@
|
||||
<div class="row">
|
||||
<div class="col-10 col-lg-3 mx-0 px-0">
|
||||
{% if server['alert'] %}
|
||||
<a style="color: red !important" class="btn btn-link d-flex justify-content-start" type="button"
|
||||
href="/panel/server_detail?id={{server['server_data']['server_id']}}">
|
||||
<i class="fas fa-server"></i> {{ server['server_data']['server_name'] }} <i
|
||||
class="fas fa-exclamation-triangle"></i>
|
||||
<a style="color: red !important" class="btn btn-link d-flex justify-content-start" type="button" href="/panel/server_detail?id={{server['server_data']['server_id']}}">
|
||||
<i class="fas fa-server"></i> {{ server['server_data']['server_name'] }} <i class="fas fa-exclamation-triangle"></i>
|
||||
</a>
|
||||
{% else %}
|
||||
<a class="btn btn-link d-flex justify-content-start" type="button"
|
||||
href="/panel/server_detail?id={{server['server_data']['server_id']}}">
|
||||
<a class="btn btn-link d-flex justify-content-start" type="button" href="/panel/server_detail?id={{server['server_data']['server_id']}}">
|
||||
<i class="fas fa-server"></i> {{ server['server_data']['server_name'] }}
|
||||
</a>
|
||||
{% end %}
|
||||
</div>
|
||||
<div class="col-2 col-lg-3 mx-0 px-0">
|
||||
<a class="btn btn-link d-flex justify-content-center" type="button" data-toggle="collapse"
|
||||
data-target="#collapse-{{server['server_data']['server_id']}}" aria-expanded="false"
|
||||
aria-controls="collapse-{{server['server_data']['server_id']}}">
|
||||
<a class="btn btn-link d-flex justify-content-center" type="button" data-toggle="collapse" data-target="#collapse-{{server['server_data']['server_id']}}" aria-expanded="false" aria-controls="collapse-{{server['server_data']['server_id']}}">
|
||||
<i class="fas fa-chart-bar"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-4 col-lg-3 mx-0 px-0">
|
||||
<a id="m_server_running_status_{{server['server_data']['server_id']}}"
|
||||
class="btn btn-link d-flex justify-content-start" type="button">
|
||||
<a id="m_server_running_status_{{server['server_data']['server_id']}}" class="btn btn-link d-flex justify-content-start" type="button">
|
||||
{% if server['stats']['running'] %}
|
||||
<span class="text-success"><i class="fas fa-signal"></i> {{ translate('dashboard', 'online',
|
||||
data['lang']) }}</span>
|
||||
@ -410,23 +380,17 @@
|
||||
{% if server['stats']['running'] %}
|
||||
<div class="row">
|
||||
<div class="col-4 px-0">
|
||||
<a data-id="{{server['server_data']['server_id']}}"
|
||||
class="btn btn-link stop_button actions_serveritem" data-toggle="tooltip"
|
||||
title="{{ translate('dashboard', 'stop' , data['lang']) }}">
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="btn btn-link stop_button actions_serveritem" data-toggle="tooltip" title="{{ translate('dashboard', 'stop' , data['lang']) }}">
|
||||
<i class="fas fa-stop"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-4 px-0">
|
||||
<a data-id="{{server['server_data']['server_id']}}"
|
||||
class="btn btn-link restart_button actions_serveritem" data-toggle="tooltip"
|
||||
title="{{ translate('dashboard', 'restart' , data['lang']) }}">
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="btn btn-link restart_button actions_serveritem" data-toggle="tooltip" title="{{ translate('dashboard', 'restart' , data['lang']) }}">
|
||||
<i class="fas fa-sync"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-4 px-0">
|
||||
<a data-id="{{server['server_data']['server_id']}}"
|
||||
class="btn btn-link kill_button actions_serveritem" data-toggle="tooltip"
|
||||
title="{{ translate('dashboard', 'kill' , data['lang']) }}">
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="btn btn-link kill_button actions_serveritem" data-toggle="tooltip" title="{{ translate('dashboard', 'kill' , data['lang']) }}">
|
||||
<i class="fas fa-skull"></i>
|
||||
</a>
|
||||
</div>
|
||||
@ -452,31 +416,24 @@
|
||||
{% elif server['stats']['importing']%}
|
||||
<div class="row">
|
||||
<div class="col-12 px-0">
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="btn btn-link"><i
|
||||
class="fa fa-spinner fa-spin"></i>
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="btn btn-link"><i class="fa fa-spinner fa-spin"></i>
|
||||
{{ translate('serverTerm', 'importing', data['lang']) }}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="row">
|
||||
<div class="col-4 px-0">
|
||||
<a data-id="{{server['server_data']['server_id']}}"
|
||||
class="btn play_button actions_serveritem" data-toggle="tooltip"
|
||||
title="{{ translate('dashboard', 'start' , data['lang']) }}">
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="btn play_button actions_serveritem" data-toggle="tooltip" title="{{ translate('dashboard', 'start' , data['lang']) }}">
|
||||
<i class="fas fa-play"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-4 px-0">
|
||||
<a data-id="{{server['server_data']['server_id']}}"
|
||||
class="btn clone_button actions_serveritem" data-toggle="tooltip"
|
||||
title="{{ translate('dashboard', 'clone' , data['lang']) }}">
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="btn clone_button actions_serveritem" data-toggle="tooltip" title="{{ translate('dashboard', 'clone' , data['lang']) }}">
|
||||
<i class="fas fa-clone"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-4 px-0">
|
||||
<a data-id="{{server['server_data']['server_id']}}"
|
||||
class="btn kill_button actions_serveritem" data-toggle="tooltip"
|
||||
title="{{ translate('dashboard', 'kill' , data['lang']) }}">
|
||||
<a data-id="{{server['server_data']['server_id']}}" class="btn kill_button actions_serveritem" data-toggle="tooltip" title="{{ translate('dashboard', 'kill' , data['lang']) }}">
|
||||
<i class="fas fa-skull"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
@ -488,15 +445,13 @@
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div id="collapse-{{server['server_data']['server_id']}}" class="collapse"
|
||||
aria-labelledby="heading-{{server['server_data']['server_id']}}" data-parent="#accordionServers">
|
||||
<div id="collapse-{{server['server_data']['server_id']}}" class="collapse" aria-labelledby="heading-{{server['server_data']['server_id']}}" data-parent="#accordionServers">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<h6>{{ translate('dashboard', 'cpuUsage', data['lang']) }}</h6>
|
||||
<div id="m_server_cpu_{{server['server_data']['server_id']}}">
|
||||
<div class="progress mb-1" data-toggle="tooltip" data-placement="top"
|
||||
title="{{server['stats']['cpu']}}">
|
||||
<div class="progress mb-1" data-toggle="tooltip" data-placement="top" title="{{server['stats']['cpu']}}">
|
||||
<div class="progress-bar
|
||||
{% if server['stats']['cpu'] <= 33 %}
|
||||
bg-success
|
||||
@ -505,8 +460,7 @@
|
||||
{% else %}
|
||||
bg-danger
|
||||
{% end %}
|
||||
" role="progressbar" style="width: {{server['stats']['cpu']}}%" aria-valuenow="0" aria-valuemin="0"
|
||||
aria-valuemax="100"></div>
|
||||
" role="progressbar" style="width: {{server['stats']['cpu']}}%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
{{server['stats']['cpu']}}%
|
||||
</div>
|
||||
@ -514,8 +468,7 @@
|
||||
<div class="col-6">
|
||||
<h6>{{ translate('dashboard', 'memUsage', data['lang']) }}</h6>
|
||||
<div draggable="false" id="m_server_mem_{{server['server_data']['server_id']}}">
|
||||
<div class="progress mb-1" data-toggle="tooltip" data-placement="top"
|
||||
title="{{server['stats']['mem']}}">
|
||||
<div class="progress mb-1" data-toggle="tooltip" data-placement="top" title="{{server['stats']['mem']}}">
|
||||
<div class="progress-bar
|
||||
{% if server['stats']['mem_percent'] <= 33 %}
|
||||
bg-success
|
||||
@ -524,8 +477,7 @@
|
||||
{% else %}
|
||||
bg-danger
|
||||
{% end %}
|
||||
" role="progressbar" style="width: {{server['stats']['mem_percent']}}%" aria-valuenow="0"
|
||||
aria-valuemin="0" aria-valuemax="100"></div>
|
||||
" role="progressbar" style="width: {{server['stats']['mem_percent']}}%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
{{server['stats']['mem_percent']}}% -
|
||||
|
||||
@ -554,8 +506,7 @@
|
||||
data['lang']) }} <br />
|
||||
|
||||
{% if server['stats']['desc'] != 'False' %}
|
||||
<div id="desc_id"
|
||||
style="overflow-wrap: break-word !important; max-width: 85px !important; overflow: scroll;">
|
||||
<div id="desc_id" style="overflow-wrap: break-word !important; max-width: 85px !important; overflow: scroll;">
|
||||
{{ server['stats']['desc'] }}</div> <br />
|
||||
{% end %}
|
||||
|
||||
@ -796,6 +747,7 @@
|
||||
/* Update Motd */
|
||||
let motd = "";
|
||||
if (server.desc) {
|
||||
m_motd = `<span id="m_input_motd_` + server.id + `" class="input_motd">` + server.desc + `</span>`;
|
||||
motd = `<span id="input_motd_` + server.id + `" class="input_motd">` + server.desc + `</span>`;
|
||||
m_server_infos = server_infos + '<div id="desc_id" style="word-wrap: break-word; overflow: auto;">' + motd + '</div>' + "<br />";
|
||||
server_infos = server_infos + '<div id="desc_id" style="word-wrap: break-word; max-width: 85px !important; overflow: auto;">' + motd + '</div>' + "<br />";
|
||||
|
@ -156,6 +156,9 @@
|
||||
right: 35px;
|
||||
}
|
||||
}
|
||||
.tree-file:hover{
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
<ul class="tree-view">
|
||||
<li>
|
||||
|
@ -89,11 +89,11 @@
|
||||
const cpu = []
|
||||
{% for item in data['history_stats'] %}
|
||||
{% if 'minecraft-java' in data['server_stats']['server_type'] %}
|
||||
players.push("{{ item.online }}");
|
||||
players.push("{{ item.get('online') }}");
|
||||
{% end %}
|
||||
dates.push("{{ item.created.strftime('%Y/%m/%d, %H:%M:%S') }}");
|
||||
ram.push("{{ item.mem_percent }}")
|
||||
cpu.push("{{ item.cpu }}")
|
||||
dates.push("{{ item.get('created').strftime('%Y/%m/%d, %H:%M:%S') }}");
|
||||
ram.push("{{ item.get('mem_percent') }}")
|
||||
cpu.push("{{ item.get('cpu') }}")
|
||||
{% end %}
|
||||
var hist_chart = new Chart(ctxL, {
|
||||
type: 'line',
|
||||
|
@ -30,9 +30,6 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if data['running'] != 0 %}
|
||||
<span id="sync" style="margin-left: 5px;"><i class="fas fa-sync fa-spin"></i></span></h4>
|
||||
{% end %}
|
||||
{% for server in data['servers'] %}
|
||||
{% if server['server_data']['show_status'] %}
|
||||
<tr>
|
||||
@ -47,10 +44,14 @@
|
||||
</td>
|
||||
<td id="server_motd_{{ server['stats']['server_id']['server_id'] }}">
|
||||
{% if server['stats']['desc'] != 'False' %}
|
||||
<img src="/static/assets/images/pack.png" alt="icon"
|
||||
style="-webkit-filter:grayscale(100%); filter:grayscale(100%)" />
|
||||
<span id="input_motd_{{ server['stats']['server_id']['server_id'] }}" class="input_motd">{{
|
||||
server['stats']['desc'] }}</span> <br />
|
||||
<div class="row">
|
||||
<div class="col-auto">
|
||||
<img src="/static/assets/images/pack.png" alt="icon" style="-webkit-filter:grayscale(100%); filter:grayscale(100%)" />
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<span id="input_motd_{{ server['stats']['server_id']['server_id'] }}" class="input_motd">{{ server['stats']['desc'] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% end %}
|
||||
</td>
|
||||
<td id="server_version_{{ server['stats']['server_id']['server_id'] }}">
|
||||
@ -89,12 +90,9 @@
|
||||
</div>
|
||||
<!-- View for Small screen -->
|
||||
<div class="row justify-content-center align-items-sm-center">
|
||||
<div class="content-wrapper login-modal d-sm-none d-block" style="background-color: var(--dropdown-bg);">
|
||||
<div class="content-wrapper login-modal d-sm-none d-block" style="background-color: var(--dropdown-bg);">
|
||||
<img src="/static/assets/images/logo_long.png" style='width: 100%;'>
|
||||
<hr />
|
||||
{% if data['running'] != 0 %}
|
||||
<span id="m_sync" style="margin-left: 5px;"><i class="fas fa-sync fa-spin"></i></span></h4>
|
||||
{% end %}
|
||||
<div class="accordion" id="accordionServers">
|
||||
{% for server in data['servers'] %}
|
||||
{% if server['server_data']['show_status'] %}
|
||||
@ -103,17 +101,13 @@
|
||||
<h2 class="mb-0 container overflow-hidden">
|
||||
<div class="row">
|
||||
<div class="col-8 mx-0 px-0">
|
||||
<a id="m_server_name_{{ server['stats']['server_id']['server_id'] }}"
|
||||
class="btn btn-link d-flex justify-content-center" type="button" data-toggle="collapse"
|
||||
data-target="#collapse-{{server['server_data']['server_id']}}" aria-expanded="false"
|
||||
aria-controls="collapse-{{server['server_data']['server_id']}}">
|
||||
<a id="m_server_name_{{ server['stats']['server_id']['server_id'] }}" class="btn btn-link d-flex justify-content-center" type="button" data-toggle="collapse" data-target="#collapse-{{server['server_data']['server_id']}}" aria-expanded="false" aria-controls="collapse-{{server['server_data']['server_id']}}">
|
||||
<i class="fas fa-server"></i>
|
||||
{{ server['server_data']['server_name'] }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-4 mx-0 px-0">
|
||||
<a id="m_server_online_status_{{ server['stats']['server_id']['server_id'] }}"
|
||||
class="btn btn-link d-flex justify-content-center" type="button">
|
||||
<a id="m_server_online_status_{{ server['stats']['server_id']['server_id'] }}" class="btn btn-link d-flex justify-content-center" type="button">
|
||||
{% if server['stats']['running'] %}
|
||||
<div id="m_server_players_{{ server['stats']['server_id']['server_id'] }}">
|
||||
<span class="text-success"><i class="fas fa-signal"></i> {{ server['stats']['online'] }} / {{
|
||||
@ -129,14 +123,12 @@
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div id="collapse-{{server['server_data']['server_id']}}" class="collapse"
|
||||
aria-labelledby="heading-{{server['server_data']['server_id']}}" data-parent="#accordionServers">
|
||||
<div id="collapse-{{server['server_data']['server_id']}}" class="collapse" aria-labelledby="heading-{{server['server_data']['server_id']}}" data-parent="#accordionServers">
|
||||
<div class="card-body">
|
||||
{% if server['stats']['int_ping_results'] != 'False' %}
|
||||
<div id="m_server_motd_{{ server['stats']['server_id']['server_id'] }}" class="media">
|
||||
{% if server['stats']['desc'] != 'False' %}
|
||||
<img src="/static/assets/images/pack.png" class="w-25 mr-3" alt="icon"
|
||||
style="-webkit-filter:grayscale(100%); filter:grayscale(100%);" />
|
||||
<img src="/static/assets/images/pack.png" class="w-25 mr-3" alt="icon" style="-webkit-filter:grayscale(100%); filter:grayscale(100%);" />
|
||||
{% end %}
|
||||
<div class="media-body">
|
||||
{% if server['stats']['desc'] != 'False' %}
|
||||
@ -198,11 +190,9 @@
|
||||
m_server_online_status = document.getElementById('m_server_online_status_' + server.id);
|
||||
|
||||
/* TODO Update each element */
|
||||
if (server.int_ping_results) {
|
||||
document.getElementById('sync').innerHTML = '';
|
||||
document.getElementById('m_sync').innerHTML = '';
|
||||
if (server.running) {
|
||||
/* Update Players */
|
||||
if (server.players) {
|
||||
if (server.max != 0) {
|
||||
server_players.innerHTML = server.online + ` / ` + server.max + ` {{ translate('dashboard', 'max', data['lang']) }}<br />`
|
||||
}
|
||||
|
||||
@ -210,16 +200,18 @@
|
||||
var motd = "";
|
||||
if (server.desc) {
|
||||
if (server.icon) {
|
||||
motd = `<img src="data:image/png;base64,` + server.icon + `" alt="icon" /> `;
|
||||
img_motd = `<img src="data:image/png;base64,` + server.icon + `" alt="icon" /> `;
|
||||
m_motd = `<img src="data:image/png;base64,` + server.icon + `" alt="icon" /> `;
|
||||
}
|
||||
else {
|
||||
motd = `<img src="/static/assets/images/pack.png" alt="icon" /> `;
|
||||
img_motd = `<img src="/static/assets/images/pack.png" alt="icon" /> `;
|
||||
m_motd = `<img class="w-25 mr-3" src="/static/assets/images/pack.png" alt="icon" /> `;
|
||||
}
|
||||
|
||||
motd = motd + `<span id="input_motd_` + server.id + `" class="input_motd">` + server.desc + `</span> <br />`;
|
||||
desc_motd = `<span id="input_motd_` + server.id + `" class="input_motd">` + server.desc + `</span> <br />`;
|
||||
m_motd = m_motd + `<div class="media-body"><span id="m_input_motd_` + server.id + `" class="input_motd">` + server.desc + `</span></div>`;
|
||||
|
||||
motd = `<div class="row"><div class="col-auto">` + img_motd + `</div><div class="col-auto">` + desc_motd + `</div></div>`;
|
||||
server_motd.innerHTML = motd;
|
||||
m_server_motd.innerHTML = m_motd;
|
||||
}
|
||||
@ -252,17 +244,31 @@
|
||||
}
|
||||
|
||||
function update_servers_status(data) {
|
||||
console.log(data);
|
||||
update_one_server_status(data[0]);
|
||||
console.log("update servers");
|
||||
data.forEach(server => {
|
||||
console.log(server);
|
||||
update_one_server_status(server);
|
||||
});
|
||||
display_motd();
|
||||
}
|
||||
|
||||
function refreshStatus() {
|
||||
let xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.onreadystatechange = function () {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
var myData = JSON.parse(this.responseText);
|
||||
update_servers_status(myData.data);
|
||||
}
|
||||
};
|
||||
xmlHttp.open('GET', '/api/v2/servers/status', true);
|
||||
xmlHttp.send();
|
||||
|
||||
setTimeout(refreshStatus, 30000);
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
console.log("ready!");
|
||||
|
||||
if (webSocket) {
|
||||
webSocket.on('update_server_status', update_servers_status);
|
||||
}
|
||||
refreshStatus();
|
||||
}());
|
||||
</script>
|
||||
|
||||
|
@ -1,167 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ data['lang_page'] }}" class="default">
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
||||
/>
|
||||
{% block meta %}{% end %}
|
||||
<title>{% block title %}{{ _('Default') }}{% end %}</title>
|
||||
<!-- plugins:css -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="/static/assets/vendors/mdi/css/materialdesignicons.min.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="/static/assets/vendors/flag-icon-css/css/flag-icon.min.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="/static/assets/vendors/ti-icons/css/themify-icons.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="/static/assets/vendors/typicons/typicons.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="/static/assets/vendors/css/vendor.bundle.base.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="/static/assets/vendors/fontawesome6/css/all.css"
|
||||
/>
|
||||
<link rel="manifest" href="/static/assets/crafty.webmanifest" />
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
||||
<meta name="apple-mobile-web-app-title" content="Crafty" />
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
href="../static/assets/images/Crafty_4-0.png"
|
||||
/>
|
||||
<!-- endinject -->
|
||||
<!-- Plugin css for this page -->
|
||||
<!-- End Plugin css for this page -->
|
||||
<!-- Layout styles -->
|
||||
<link rel="stylesheet" href="/static/assets/css/dark/style.css" />
|
||||
<!-- End Layout styles -->
|
||||
<link
|
||||
rel="shortcut icon"
|
||||
type="image/svg+xml"
|
||||
href="/static/assets/images/logo_small.svg"
|
||||
/>
|
||||
<link rel="alternate icon" href="/static/assets/images/favicon.png" />
|
||||
</head>
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
{% block meta %}{% end %}
|
||||
<title>{% block title %}{{ _('Default') }}{% end %}</title>
|
||||
<!-- plugins:css -->
|
||||
<link rel="stylesheet" href="/static/assets/vendors/mdi/css/materialdesignicons.min.css" />
|
||||
<link rel="stylesheet" href="/static/assets/vendors/flag-icon-css/css/flag-icon.min.css" />
|
||||
<link rel="stylesheet" href="/static/assets/vendors/ti-icons/css/themify-icons.css" />
|
||||
<link rel="stylesheet" href="/static/assets/vendors/typicons/typicons.css" />
|
||||
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css" />
|
||||
<link rel="stylesheet" href="/static/assets/vendors/fontawesome6/css/all.css" />
|
||||
<link rel="manifest" href="/static/assets/crafty.webmanifest" />
|
||||
|
||||
<body>
|
||||
<div class="container-scroller">
|
||||
<div class="container-fluid page-body-wrapper full-page-wrapper">
|
||||
<div
|
||||
class="content-wrapper d-flex align-items-sm-center auth auth-bg-1 theme-one"
|
||||
>
|
||||
<div class="mx-auto">
|
||||
<div class="auto-form-wrapper">{% block content %} {% end %}</div>
|
||||
</div>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
||||
<meta name="apple-mobile-web-app-title" content="Crafty" />
|
||||
<link rel="apple-touch-icon" href="../static/assets/images/Crafty_4-0.png" />
|
||||
<!-- endinject -->
|
||||
<!-- Plugin css for this page -->
|
||||
<!-- End Plugin css for this page -->
|
||||
<!-- Layout styles -->
|
||||
<link rel="stylesheet" href="/static/assets/css/dark/style.css" />
|
||||
<!-- End Layout styles -->
|
||||
<link rel="shortcut icon" type="image/svg+xml" href="/static/assets/images/logo_small.svg" />
|
||||
<link rel="alternate icon" href="/static/assets/images/favicon.png" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container-scroller">
|
||||
<div class="container-fluid page-body-wrapper full-page-wrapper">
|
||||
<div class="content-wrapper d-flex align-items-sm-center auth auth-bg-1 theme-one">
|
||||
<div class="mx-auto">
|
||||
<div class="auto-form-wrapper">{% block content %} {% end %}</div>
|
||||
</div>
|
||||
<!-- content-wrapper ends -->
|
||||
</div>
|
||||
<!-- page-body-wrapper ends -->
|
||||
<!-- content-wrapper ends -->
|
||||
</div>
|
||||
<!-- container-scroller -->
|
||||
<!-- plugins:js -->
|
||||
<script src="/static/assets/vendors/js/vendor.bundle.base.js"></script>
|
||||
<!-- endinject -->
|
||||
<!-- inject:js -->
|
||||
<script src="/static/assets/js/shared/off-canvas.js"></script>
|
||||
<script src="/static/assets/js/shared/hoverable-collapse.js"></script>
|
||||
<script src="/static/assets/js/shared/misc.js"></script>
|
||||
<!-- endinject -->
|
||||
<script>
|
||||
// {% if request.protocol == 'https' %}
|
||||
let usingWebSockets = true;
|
||||
<!-- page-body-wrapper ends -->
|
||||
</div>
|
||||
<!-- page-body-wrapper ends -->
|
||||
|
||||
let listenEvents = [];
|
||||
<!-- container-scroller -->
|
||||
<!-- plugins:js -->
|
||||
<script src="/static/assets/vendors/js/vendor.bundle.base.js"></script>
|
||||
<!-- endinject -->
|
||||
<!-- inject:js -->
|
||||
<script src="/static/assets/js/shared/off-canvas.js"></script>
|
||||
<script src="/static/assets/js/shared/hoverable-collapse.js"></script>
|
||||
<script src="/static/assets/js/shared/misc.js"></script>
|
||||
<!-- endinject -->
|
||||
|
||||
let pageQueryParams, page;
|
||||
|
||||
try {
|
||||
pageQueryParams =
|
||||
"page_query_params=" + encodeURIComponent(location.search);
|
||||
page = "page=" + encodeURIComponent(location.pathname);
|
||||
var wsInternal = new WebSocket(
|
||||
"wss://" + location.host + "/ws?" + page + "&" + pageQueryParams
|
||||
);
|
||||
wsInternal.onopen = function () {
|
||||
console.log("opened WebSocket connection:", wsInternal);
|
||||
};
|
||||
wsInternal.onmessage = function (rawMessage) {
|
||||
var message = JSON.parse(rawMessage.data);
|
||||
|
||||
console.log("got message: ", message);
|
||||
|
||||
listenEvents
|
||||
.filter((listenedEvent) => listenedEvent.event == message.event)
|
||||
.forEach((listenedEvent) => listenedEvent.callback(message.data));
|
||||
};
|
||||
wsInternal.onerror = function (errorEvent) {
|
||||
console.error("WebSocket Error", errorEvent);
|
||||
};
|
||||
wsInternal.onclose = function (closeEvent) {
|
||||
console.log("Closed WebSocket", closeEvent);
|
||||
};
|
||||
|
||||
webSocket = {
|
||||
on: function (event, callback) {
|
||||
console.log("registered " + event + " event");
|
||||
listenEvents.push({ event: event, callback: callback });
|
||||
},
|
||||
emit: function (event, data) {
|
||||
var message = {
|
||||
event: event,
|
||||
data: data,
|
||||
};
|
||||
|
||||
wsInternal.send(JSON.stringify(message));
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error while making websocket helpers", error);
|
||||
usingWebSockets = false;
|
||||
{% block js %}
|
||||
<!-- Custom js for this page -->
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
let login_opacity_div = document.getElementById('login_opacity');
|
||||
let opacity = login_opacity_div.getAttribute('data-value');
|
||||
document.getElementById('login-form-background').style.background = 'rgb(34, 36, 55, ' + (opacity / 100) + ')';
|
||||
//Register Service worker for mobile app
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/static/assets/js/shared/service-worker.js', { scope: '/' })
|
||||
.then(function (registration) {
|
||||
console.error('Service Worker Registered');
|
||||
});
|
||||
}
|
||||
// {% else %}
|
||||
usingWebSockets = false;
|
||||
warn(
|
||||
"WebSockets are not supported in Crafty if not using the https protocol"
|
||||
);
|
||||
var webSocket;
|
||||
// {% end%}
|
||||
</script>
|
||||
{% block js %}
|
||||
<!-- Custom js for this page -->
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
let login_opacity_div = document.getElementById("login_opacity");
|
||||
let opacity = login_opacity_div.getAttribute("data-value");
|
||||
document.getElementById("login-form-background").style.background =
|
||||
"rgb(34, 36, 55, " + opacity / 100 + ")";
|
||||
//Register Service worker for mobile app
|
||||
if ("serviceWorker" in navigator) {
|
||||
navigator.serviceWorker
|
||||
.register("/static/assets/js/shared/service-worker.js", {
|
||||
scope: "/",
|
||||
})
|
||||
.then(function (registration) {
|
||||
console.log("Service Worker Registered");
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<!-- End custom js for this page -->
|
||||
{% end %}
|
||||
</body>
|
||||
</html>
|
||||
});
|
||||
|
||||
</script>
|
||||
<!-- End custom js for this page -->
|
||||
{% end %}
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1153,7 +1153,7 @@
|
||||
async function refreshCache() {
|
||||
document.getElementById("refresh-cache").classList.add("fa-spin")
|
||||
let token = getCookie("_xsrf")
|
||||
let res = await fetch(`/api/v2/crafty/exeCache`, {
|
||||
let res = await fetch(`/api/v2/crafty/JarCache`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-XSRFToken': token
|
||||
|
16
app/migrations/stats/20230827_add_icon.py
Normal file
16
app/migrations/stats/20230827_add_icon.py
Normal file
@ -0,0 +1,16 @@
|
||||
# Generated by database migrator
|
||||
import peewee
|
||||
|
||||
|
||||
def migrate(migrator, database, **kwargs):
|
||||
migrator.add_columns("server_stats", icon=peewee.CharField(null=True))
|
||||
"""
|
||||
Write your migrations here.
|
||||
"""
|
||||
|
||||
|
||||
def rollback(migrator, database, **kwargs):
|
||||
migrator.drop_columns("server_stats", ["icon"])
|
||||
"""
|
||||
Write your rollback migrations here.
|
||||
"""
|
3
main.py
3
main.py
@ -16,6 +16,7 @@ from app.classes.shared.helpers import Helpers
|
||||
from app.classes.models.users import HelperUsers
|
||||
from app.classes.models.management import HelpersManagement
|
||||
from app.classes.shared.import_helper import ImportHelpers
|
||||
from app.classes.shared.websocket_manager import WebSocketManager
|
||||
|
||||
console = Console()
|
||||
helper = Helpers()
|
||||
@ -164,6 +165,8 @@ if __name__ == "__main__":
|
||||
Console.info("No flag found. Secrets are staying")
|
||||
file_helper = FileHelpers(helper)
|
||||
import_helper = ImportHelpers(helper, file_helper)
|
||||
# Init WebSocket Manager Here
|
||||
WebSocketManager()
|
||||
# now the tables are created, we can load the tasks_manager and server controller
|
||||
controller = Controller(database, helper, file_helper, import_helper)
|
||||
Console.info("Checking for remote changes to config.json")
|
||||
|
@ -1,15 +1,16 @@
|
||||
|
||||
apscheduler==3.8.1
|
||||
argon2-cffi==21.3
|
||||
bleach==4.1
|
||||
cached_property==1.5.2
|
||||
colorama==0.4
|
||||
croniter==1.3.5
|
||||
cryptography==41.0.3
|
||||
libgravatar==1.0.0
|
||||
nh3==0.2.14
|
||||
packaging==23.1
|
||||
peewee==3.13
|
||||
pexpect==4.8
|
||||
psutil==5.9
|
||||
psutil==5.9.5
|
||||
pyOpenSSL==23.2.0
|
||||
pyjwt==2.4.0
|
||||
PyYAML==6.0.1
|
||||
|
Loading…
Reference in New Issue
Block a user