mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Merge branch 'dev' into bugfix/config-empty-mounts
This commit is contained in:
commit
1383accefd
12
CHANGELOG.md
12
CHANGELOG.md
@ -1,21 +1,25 @@
|
||||
# Changelog
|
||||
## --- [4.2.2] - 2023/TBD
|
||||
### New features
|
||||
TBD
|
||||
- Loading Screen for Crafty during startup ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/668))
|
||||
### Refactor
|
||||
- Remove deprecated API V1 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/670))
|
||||
- Tidy up main.py to be more comprehensive ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/668))
|
||||
### Bug fixes
|
||||
- Remove webhook `custom` option from webook provider list as it's not currently an option ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/664))
|
||||
- Bump cryptography for CVE-2023-49083 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/680))
|
||||
- Fix bug where su cannot edit general user password ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/676))
|
||||
- Fix bug where no file error on import root dir ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/677))
|
||||
- Fix Unban button failing to pardon users ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/671))
|
||||
- Fix stack in API error handling ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/674))
|
||||
### Tweaks
|
||||
- Homogenize Panel logos/branding ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/666))
|
||||
- Retain previous tab when revisiting server details page (#272)([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/667))
|
||||
- Add server name tag in panel header (#272)([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/667))
|
||||
- Setup logging for panel authentication attempts ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/669))
|
||||
- Update minimum password length from 6 to 8, and unrestrict maximum password length ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/669))
|
||||
- Fix Unban button failing to pardon users ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/671))
|
||||
- Fix stack in API error handling ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/674))
|
||||
### Lang
|
||||
TBD
|
||||
- pl_PL Minor fixes ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/675))
|
||||
<br><br>
|
||||
|
||||
## --- [4.2.1] - 2023/11/01
|
||||
|
@ -22,6 +22,7 @@ from app.classes.models.server_permissions import (
|
||||
PermissionsServers,
|
||||
EnumPermissionsServer,
|
||||
)
|
||||
from app.classes.shared.websocket_manager import WebSocketManager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -36,6 +37,7 @@ class ServersController(metaclass=Singleton):
|
||||
self.management_helper = management_helper
|
||||
self.servers_list = []
|
||||
self.stats = Stats(self.helper, self)
|
||||
self.web_sock = WebSocketManager()
|
||||
self.server_subpage = {}
|
||||
|
||||
# **********************************************************************************
|
||||
@ -170,8 +172,15 @@ class ServersController(metaclass=Singleton):
|
||||
def init_all_servers(self):
|
||||
servers = self.get_all_defined_servers()
|
||||
self.failed_servers = []
|
||||
|
||||
for server in servers:
|
||||
self.web_sock.broadcast_to_admins(
|
||||
"update",
|
||||
{"section": "server", "server": server["server_name"]},
|
||||
)
|
||||
self.web_sock.broadcast_to_non_admins(
|
||||
"update",
|
||||
{"section": "init"},
|
||||
)
|
||||
server_id = server.get("server_id")
|
||||
|
||||
# if we have already initialized this server, let's skip it.
|
||||
|
@ -80,6 +80,7 @@ class Helpers:
|
||||
self.translation = Translation(self)
|
||||
self.update_available = False
|
||||
self.ignored_names = ["crafty_managed.txt", "db_stats"]
|
||||
self.crafty_starting = False
|
||||
|
||||
@staticmethod
|
||||
def auto_installer_fix(ex):
|
||||
|
@ -85,7 +85,7 @@ class Controller:
|
||||
encoding="utf-8",
|
||||
) as f:
|
||||
self.auth_tracker = json.load(f)
|
||||
except:
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
self.auth_tracker = {}
|
||||
|
||||
def log_attempt(self, remote_ip, username):
|
||||
|
@ -37,7 +37,15 @@ class WebSocketManager(metaclass=Singleton):
|
||||
|
||||
def broadcast_to_admins(self, event_type: str, data):
|
||||
def filter_fn(client):
|
||||
if client.get_user_id in HelperUsers.get_super_user_list():
|
||||
if str(client.get_user_id()) in str(HelperUsers.get_super_user_list()):
|
||||
return True
|
||||
return False
|
||||
|
||||
self.broadcast_with_fn(filter_fn, event_type, data)
|
||||
|
||||
def broadcast_to_non_admins(self, event_type: str, data):
|
||||
def filter_fn(client):
|
||||
if str(client.get_user_id()) not in str(HelperUsers.get_super_user_list()):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -210,6 +210,8 @@ class PanelHandler(BaseHandler):
|
||||
error = self.get_argument("error", "WTF Error!")
|
||||
|
||||
template = "panel/denied.html"
|
||||
if self.helper.crafty_starting:
|
||||
page = "loading"
|
||||
|
||||
now = time.time()
|
||||
formatted_time = str(
|
||||
@ -243,9 +245,13 @@ class PanelHandler(BaseHandler):
|
||||
for r in exec_user["roles"]:
|
||||
role = self.controller.roles.get_role(r)
|
||||
exec_user_role.add(role["role_name"])
|
||||
defined_servers = self.controller.servers.get_authorized_servers(
|
||||
exec_user["user_id"]
|
||||
)
|
||||
# get_auth_servers will throw an exception if run while Crafty is starting
|
||||
if not self.helper.crafty_starting:
|
||||
defined_servers = self.controller.servers.get_authorized_servers(
|
||||
exec_user["user_id"]
|
||||
)
|
||||
else:
|
||||
defined_servers = []
|
||||
|
||||
user_order = self.controller.users.get_user_by_id(exec_user["user_id"])
|
||||
user_order = user_order["server_order"].split(",")
|
||||
@ -1615,7 +1621,8 @@ class PanelHandler(BaseHandler):
|
||||
logs_thread.start()
|
||||
self.redirect("/panel/dashboard")
|
||||
return
|
||||
|
||||
if self.helper.crafty_starting:
|
||||
template = "panel/loading.html"
|
||||
self.render(
|
||||
template,
|
||||
data=page_data,
|
||||
|
@ -7,6 +7,7 @@ from jsonschema.exceptions import ValidationError
|
||||
from app.classes.models.crafty_permissions import EnumPermissionsCrafty
|
||||
from app.classes.shared.helpers import Helpers
|
||||
from app.classes.web.base_api_handler import BaseApiHandler
|
||||
from app.classes.web.websocket_handler import WebSocketManager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
files_get_schema = {
|
||||
@ -73,7 +74,7 @@ class ApiImportFilesIndexHandler(BaseApiHandler):
|
||||
else:
|
||||
if user_id:
|
||||
user_lang = self.controller.users.get_user_lang_by_id(user_id)
|
||||
self.helper.websocket_helper.broadcast_user(
|
||||
WebSocketManager().broadcast_user(
|
||||
user_id,
|
||||
"send_start_error",
|
||||
{
|
||||
@ -85,7 +86,7 @@ class ApiImportFilesIndexHandler(BaseApiHandler):
|
||||
else:
|
||||
if not self.helper.check_path_exists(folder) and user_id:
|
||||
user_lang = self.controller.users.get_user_lang_by_id(user_id)
|
||||
self.helper.websocket_helper.broadcast_user(
|
||||
WebSocketManager().broadcast_user(
|
||||
user_id,
|
||||
"send_start_error",
|
||||
{
|
||||
|
@ -215,7 +215,7 @@ class ApiUsersUserIndexHandler(BaseApiHandler):
|
||||
|
||||
user_obj = HelperUsers.get_user_model(user_id)
|
||||
if "password" in data and str(user["user_id"]) != str(user_id):
|
||||
if str(user["user_id"]) != str(user_obj.manager):
|
||||
if str(user["user_id"]) != str(user_obj.manager) and not user["superuser"]:
|
||||
# TODO: edit your own password
|
||||
return self.finish_json(
|
||||
400, {"status": "error", "error": "INVALID_PASSWORD_MODIFY"}
|
||||
|
73
app/frontend/templates/panel/loading.html
Normal file
73
app/frontend/templates/panel/loading.html
Normal file
@ -0,0 +1,73 @@
|
||||
{% extends ../base.html %}
|
||||
|
||||
{% block meta %}
|
||||
{% end %}
|
||||
|
||||
{% block title %}Crafty Controller Starting{% end %}
|
||||
|
||||
{% block content %}
|
||||
<div class="content-wrapper">
|
||||
<div class="card-header justify-content-between align-items-center" style="border: none;">
|
||||
<div id="image-div" style="width: 100%;">
|
||||
<img class="img-center" id="logo-animate" src="../static/assets/images/crafty-logo-square-1024.png"
|
||||
alt="Crafty Logo, Crafty is loading" width="20%" style="clear: both;">
|
||||
</div>
|
||||
<br>
|
||||
</br>
|
||||
<div id="text-div" style="width: 100%; text-align: center;">
|
||||
<h2 id="status" style="display: block;" data-init="{{ translate('startup', 'serverInit', data['lang']) }}"
|
||||
data-server="{{ translate('startup', 'server', data['lang']) }}"
|
||||
data-internet="{{ translate('startup', 'internet', data['lang']) }}"
|
||||
data-tasks="{{ translate('startup', 'tasks', data['lang']) }}"
|
||||
data-internals="{{ translate('startup', 'internals', data['lang']) }}"
|
||||
data-almost="{{ translate('startup', 'almost', data['lang']) }}">
|
||||
{{ translate('startup', 'starting', data['lang']) }}</h2>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.img-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function rotateImage(degree) {
|
||||
$('#logo-animate').animate({ transform: degree }, {
|
||||
step: function (now, fx) {
|
||||
$(this).css({
|
||||
'-webkit-transform': 'rotate(' + now + 'deg)',
|
||||
'-moz-transform': 'rotate(' + now + 'deg)',
|
||||
'transform': 'rotate(' + now + 'deg)'
|
||||
});
|
||||
}
|
||||
});
|
||||
setTimeout(function () {
|
||||
rotateImage(360);
|
||||
}, 2000);
|
||||
}
|
||||
$(document).ready(function () {
|
||||
setTimeout(function () {
|
||||
rotateImage(360);
|
||||
}, 2000);
|
||||
if (webSocket) {
|
||||
webSocket.on('update', function (data) {
|
||||
if ("server" in data) {
|
||||
$("#status").html(`${$("#status").data(data.section)} ${data.server}...`);
|
||||
} else {
|
||||
$("#status").html($("#status").data(data.section));
|
||||
}
|
||||
});
|
||||
webSocket.on('send_start_reload', function () {
|
||||
setTimeout(function () {
|
||||
location.href = '/panel/dashboard'
|
||||
}, 5000);
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
{% end %}
|
@ -591,6 +591,15 @@
|
||||
"newServer": "Create New Server",
|
||||
"servers": "Servers"
|
||||
},
|
||||
"startup": {
|
||||
"starting": "Crafty Is Starting...",
|
||||
"serverInit": "Initializing Servers",
|
||||
"server": "Initializing ",
|
||||
"internet": "Checking for internet connection",
|
||||
"tasks": "Starting Tasks Scheduler",
|
||||
"internals": "Configuring and starting Crafty's internal componenets",
|
||||
"almost": "Finishing up. Hang on tight..."
|
||||
},
|
||||
"userConfig": {
|
||||
"apiKey": "API Keys",
|
||||
"auth": "Authorized? ",
|
||||
|
@ -326,8 +326,8 @@
|
||||
"bePatientDeleteFiles": "Poczekaj, aż usuniemy twój serwer i jego pliki. Strona za chwilę się zamknie.",
|
||||
"bePatientUpdate": "Poczekaj kiedy my aktualizujemy twój serwer. Pobieranie zależy od prędkości twojego internetu.<br /> Strona się odświeży za chwile.",
|
||||
"cancel": "Anuluj",
|
||||
"crashTime": "Crash wyszedł poza limit czasu",
|
||||
"crashTimeDesc": "How long should we wait before we consider your server as crashed?",
|
||||
"crashTime": "Crash serwera wyszedł poza limit czasu",
|
||||
"crashTimeDesc": "Jak długo powinniśmy poczekać zanim uznać serwer za zcrashowany?",
|
||||
"deleteFilesQuestion": "Usuń pliki serwera z maszyny?",
|
||||
"deleteFilesQuestionMessage": "Czy chcesz aby Crafty usunął wszystkie pliki tego serwera? <br><br><strong>To zawiera backupy.</strong>",
|
||||
"deleteServer": "Usuń serwer",
|
||||
@ -403,7 +403,7 @@
|
||||
"filterList": "Filtrowane słowa",
|
||||
"logs": "Logi",
|
||||
"metrics": "Statystyki",
|
||||
"playerControls": "Player Management",
|
||||
"playerControls": "Zarządzanie użytkownikami",
|
||||
"reset": "Resetuj Scrolla",
|
||||
"schedule": "Harmonogram",
|
||||
"serverDetails": "Detale serwera",
|
||||
@ -421,7 +421,7 @@
|
||||
"deleteItemQuestion": "Czy jesteś pewien że chcesz usunąć \" + name + \"?",
|
||||
"deleteItemQuestionMessage": "Usuwasz \\\"\" + path + \"\\\"!<br/><br/>Ta akcja jest nieodwracalna i zostanie usunięta na zawsze!",
|
||||
"download": "Pobierz",
|
||||
"editingFile": "Edytuję plik",
|
||||
"editingFile": "Edytuj plik",
|
||||
"error": "Error while getting files",
|
||||
"fileReadError": "Error odczytu pliku",
|
||||
"files": "Pliki",
|
||||
@ -432,7 +432,7 @@
|
||||
"rename": "Zmień nazwę",
|
||||
"renameItemQuestion": "Jaka ma być nowa nazwa?",
|
||||
"save": "Zapisz",
|
||||
"size": "Włącz zmienianie rozmiaru edytora",
|
||||
"size": "Włącz rozszerzanie i zmniejszanie edytora",
|
||||
"stayHere": "NIE WYCHODŹ Z TEJ STRONY!",
|
||||
"unsupportedLanguage": "Uwaga: To nie jest wspierany typ pliku",
|
||||
"unzip": "Rozpakuj",
|
||||
@ -545,7 +545,7 @@
|
||||
"buildServer": "Zbuduj serwer!",
|
||||
"clickRoot": "Kilknij tutaj aby zaznaczyć główną ścieżkę",
|
||||
"close": "Zamknij",
|
||||
"defaultPort": "25565 podstawowy",
|
||||
"defaultPort": "Domyślnie 25565",
|
||||
"downloading": "Pobieranie serwera...",
|
||||
"explainRoot": "Proszę, kliknij przycisk poniżej aby zaznaczyć główną ścieżkę w tym archiwum",
|
||||
"importServer": "Importuj egzystujący serwer",
|
||||
@ -640,12 +640,12 @@
|
||||
"edit": "Edytuj",
|
||||
"enabled": "Włączony",
|
||||
"jar_update": "Plik startowy zaktualizowany",
|
||||
"kill": "Serwer zatrzymany",
|
||||
"kill": "Serwer został zabity",
|
||||
"name": "Nazwa",
|
||||
"new": "Nowy Webhook",
|
||||
"newWebhook": "Nowy Webhook",
|
||||
"no-webhook": "Nie posiadasz aktualnie żadnych Webhooków dla tego serwera. Aby dodać webhook kliknij na",
|
||||
"run": "Włącz Webhook",
|
||||
"run": "Przetestuj Webhook",
|
||||
"send_command": "Komenda serwera otrzymana!",
|
||||
"start_server": "Serwer włączony",
|
||||
"stop_server": "Serwer wyłączony",
|
||||
|
342
main.py
342
main.py
@ -20,6 +20,18 @@ from app.classes.shared.websocket_manager import WebSocketManager
|
||||
|
||||
console = Console()
|
||||
helper = Helpers()
|
||||
# Get the path our application is running on.
|
||||
if getattr(sys, "frozen", False):
|
||||
APPLICATION_PATH = os.path.dirname(sys.executable)
|
||||
RUNNING_MODE = "Frozen/executable"
|
||||
else:
|
||||
try:
|
||||
app_full_path = os.path.realpath(__file__)
|
||||
APPLICATION_PATH = os.path.dirname(app_full_path)
|
||||
RUNNING_MODE = "Non-interactive (e.g. 'python main.py')"
|
||||
except NameError:
|
||||
APPLICATION_PATH = os.getcwd()
|
||||
RUNNING_MODE = "Interactive"
|
||||
if helper.check_root():
|
||||
Console.critical(
|
||||
"Root detected. Root/Admin access denied. "
|
||||
@ -51,7 +63,178 @@ except ModuleNotFoundError as err:
|
||||
helper.auto_installer_fix(err)
|
||||
|
||||
|
||||
def internet_check():
|
||||
"""
|
||||
This checks to see if the Crafty host is connected to the
|
||||
internet. This will show a warning in the console if no interwebs.
|
||||
"""
|
||||
print()
|
||||
logger.info("Checking Internet. This may take a minute.")
|
||||
Console.info("Checking Internet. This may take a minute.")
|
||||
|
||||
if not helper.check_internet():
|
||||
logger.warning(
|
||||
"We have detected the machine running Crafty has no "
|
||||
"connection to the internet. Client connections to "
|
||||
"the server may be limited."
|
||||
)
|
||||
Console.warning(
|
||||
"We have detected the machine running Crafty has no "
|
||||
"connection to the internet. Client connections to "
|
||||
"the server may be limited."
|
||||
)
|
||||
|
||||
|
||||
def controller_setup():
|
||||
"""
|
||||
Method sets up the software controllers.
|
||||
This also sets the application path as well as the
|
||||
master server dir (if not set).
|
||||
|
||||
This also clears the support logs status.
|
||||
"""
|
||||
if not controller.check_system_user():
|
||||
controller.add_system_user()
|
||||
|
||||
master_server_dir = controller.management.get_master_server_dir()
|
||||
if master_server_dir == "":
|
||||
logger.debug("Could not find master server path. Setting default")
|
||||
controller.set_master_server_dir(
|
||||
os.path.join(controller.project_root, "servers")
|
||||
)
|
||||
else:
|
||||
helper.servers_dir = master_server_dir
|
||||
|
||||
Console.debug(f"Execution Mode: {RUNNING_MODE}")
|
||||
Console.debug(f"Application path : '{APPLICATION_PATH}'")
|
||||
|
||||
controller.clear_support_status()
|
||||
|
||||
|
||||
def tasks_starter():
|
||||
"""
|
||||
Method starts stats recording, app scheduler, and
|
||||
serverjars/steamCMD cache refreshers
|
||||
"""
|
||||
# start stats logging
|
||||
tasks_manager.start_stats_recording()
|
||||
|
||||
# once the controller is up and stats are logging, we can kick off
|
||||
# the scheduler officially
|
||||
tasks_manager.start_scheduler()
|
||||
|
||||
# refresh our cache and schedule for every 12 hoursour cache refresh
|
||||
# for serverjars.com
|
||||
tasks_manager.serverjar_cache_refresher()
|
||||
|
||||
|
||||
def signal_handler(signum, _frame):
|
||||
"""
|
||||
Method handles sigterm and shuts the app down.
|
||||
"""
|
||||
if not args.daemon:
|
||||
print() # for newline after prompt
|
||||
signame = signal.Signals(signum).name
|
||||
logger.info(f"Recieved signal {signame} [{signum}], stopping Crafty...")
|
||||
Console.info(f"Recieved signal {signame} [{signum}], stopping Crafty...")
|
||||
tasks_manager._main_graceful_exit()
|
||||
crafty_prompt.universal_exit()
|
||||
|
||||
|
||||
def do_cleanup():
|
||||
"""
|
||||
Checks Crafty's temporary directory and clears it out on boot.
|
||||
"""
|
||||
try:
|
||||
logger.info("Removing old temp dirs")
|
||||
FileHelpers.del_dirs(os.path.join(controller.project_root, "temp"))
|
||||
except:
|
||||
logger.info("Did not find old temp dir.")
|
||||
os.mkdir(os.path.join(controller.project_root, "temp"))
|
||||
|
||||
|
||||
def do_version_check():
|
||||
"""
|
||||
Checks for remote version differences.
|
||||
|
||||
Prints in terminal with differences if true.
|
||||
|
||||
Also sets helper variable to update available when pages
|
||||
are served.
|
||||
"""
|
||||
|
||||
# Check if new version available
|
||||
remote_ver = helper.check_remote_version()
|
||||
if remote_ver:
|
||||
notice = f"""
|
||||
A new version of Crafty is available!
|
||||
{'/' * 37}
|
||||
New version available: {remote_ver}
|
||||
Current version: {pkg_version.parse(helper.get_version_string())}
|
||||
{'/' * 37}
|
||||
"""
|
||||
Console.yellow(notice)
|
||||
|
||||
crafty_prompt.prompt = f"Crafty Controller v{helper.get_version_string()} > "
|
||||
|
||||
|
||||
def setup_starter():
|
||||
"""
|
||||
This method starts our setup threads.
|
||||
(tasks scheduler, internet checks, controller setups)
|
||||
|
||||
Once our threads complete we will set our startup
|
||||
variable to false and send a reload to any clients waiting.
|
||||
|
||||
|
||||
"""
|
||||
if not args.daemon:
|
||||
time.sleep(0.01) # Wait for the prompt to start
|
||||
print() # Make a newline after the prompt so logs are on an empty line
|
||||
else:
|
||||
time.sleep(0.01) # Wait for the daemon info message
|
||||
|
||||
Console.info("Setting up Crafty's internal components...")
|
||||
# Start the setup threads
|
||||
web_sock.broadcast("update", {"section": "tasks"})
|
||||
time.sleep(2)
|
||||
tasks_starter_thread.start()
|
||||
web_sock.broadcast("update", {"section": "internet"})
|
||||
time.sleep(2)
|
||||
internet_check_thread.start()
|
||||
web_sock.broadcast(
|
||||
"update",
|
||||
{"section": "internals"},
|
||||
)
|
||||
time.sleep(2)
|
||||
controller_setup_thread.start()
|
||||
|
||||
# Wait for the setup threads to finish
|
||||
web_sock.broadcast(
|
||||
"update",
|
||||
{"section": "almost"},
|
||||
)
|
||||
tasks_starter_thread.join()
|
||||
internet_check_thread.join()
|
||||
controller_setup_thread.join()
|
||||
helper.crafty_starting = False
|
||||
web_sock.broadcast("send_start_reload", "")
|
||||
do_version_check()
|
||||
Console.info("Crafty has fully started and is now ready for use!")
|
||||
|
||||
do_cleanup()
|
||||
|
||||
if not args.daemon:
|
||||
# Put the prompt under the cursor
|
||||
crafty_prompt.print_prompt()
|
||||
|
||||
|
||||
def do_intro():
|
||||
"""
|
||||
Runs the Crafty Controller Terminal Intro with information about the software
|
||||
This method checks for a "settings file" or config.json. If it does not find
|
||||
one it will create one.
|
||||
"""
|
||||
logger.info("***** Crafty Controller Started *****")
|
||||
|
||||
version = helper.get_version_string()
|
||||
@ -72,6 +255,11 @@ def do_intro():
|
||||
|
||||
|
||||
def setup_logging(debug=True):
|
||||
"""
|
||||
This method sets up our logging for Crafty. It takes
|
||||
one optional (defaulted to True) parameter which
|
||||
determines whether or not the logging level is "debug" or verbose.
|
||||
"""
|
||||
logging_config_file = os.path.join(os.path.curdir, "app", "config", "logging.json")
|
||||
if not helper.check_file_exists(
|
||||
os.path.join(os.path.curdir, "logs", "auth_tracker.log")
|
||||
@ -117,11 +305,11 @@ if __name__ == "__main__":
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
helper.ensure_logging_setup()
|
||||
|
||||
helper.crafty_starting = True
|
||||
# Init WebSocket Manager Here
|
||||
web_sock = WebSocketManager()
|
||||
setup_logging(debug=args.verbose)
|
||||
|
||||
if args.verbose:
|
||||
Console.level = "debug"
|
||||
|
||||
@ -133,23 +321,27 @@ if __name__ == "__main__":
|
||||
|
||||
# print our pretty start message
|
||||
do_intro()
|
||||
|
||||
# our session file, helps prevent multiple controller agents on the same machine.
|
||||
helper.create_session_file(ignore=args.ignore)
|
||||
|
||||
# start the database
|
||||
database = peewee.SqliteDatabase(
|
||||
helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10}
|
||||
)
|
||||
database_proxy.initialize(database)
|
||||
|
||||
migration_manager = MigrationManager(database, helper)
|
||||
migration_manager.up() # Automatically runs migrations
|
||||
|
||||
# do our installer stuff
|
||||
# init classes
|
||||
# now the tables are created, we can load the tasks_manager and server controller
|
||||
user_helper = HelperUsers(database, helper)
|
||||
management_helper = HelpersManagement(database, helper)
|
||||
installer = DatabaseBuilder(database, helper, user_helper, management_helper)
|
||||
file_helper = FileHelpers(helper)
|
||||
import_helper = ImportHelpers(helper, file_helper)
|
||||
controller = Controller(database, helper, file_helper, import_helper)
|
||||
controller.set_project_root(APPLICATION_PATH)
|
||||
tasks_manager = TasksManager(helper, controller, file_helper)
|
||||
import3 = Import3(helper, controller)
|
||||
FRESH_INSTALL = installer.is_fresh_install()
|
||||
|
||||
if FRESH_INSTALL:
|
||||
@ -171,153 +363,45 @@ if __name__ == "__main__":
|
||||
helper.set_setting("reset_secrets_on_next_boot", False)
|
||||
else:
|
||||
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)
|
||||
|
||||
# Check to see if client config.json version is different than the
|
||||
# Master config.json in helpers.py
|
||||
Console.info("Checking for remote changes to config.json")
|
||||
controller.get_config_diff()
|
||||
Console.info("Remote change complete.")
|
||||
|
||||
import3 = Import3(helper, controller)
|
||||
tasks_manager = TasksManager(helper, controller, file_helper)
|
||||
# startup the web server
|
||||
tasks_manager.start_webserver()
|
||||
|
||||
def signal_handler(signum, _frame):
|
||||
if not args.daemon:
|
||||
print() # for newline after prompt
|
||||
signame = signal.Signals(signum).name
|
||||
logger.info(f"Recieved signal {signame} [{signum}], stopping Crafty...")
|
||||
Console.info(f"Recieved signal {signame} [{signum}], stopping Crafty...")
|
||||
tasks_manager._main_graceful_exit()
|
||||
crafty_prompt.universal_exit()
|
||||
|
||||
signal.signal(signal.SIGTERM, signal_handler)
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
# init servers
|
||||
logger.info("Initializing all servers defined")
|
||||
Console.info("Initializing all servers defined")
|
||||
web_sock.broadcast(
|
||||
"update",
|
||||
{"section": "serverInit"},
|
||||
)
|
||||
controller.servers.init_all_servers()
|
||||
|
||||
def tasks_starter():
|
||||
# start stats logging
|
||||
tasks_manager.start_stats_recording()
|
||||
|
||||
# once the controller is up and stats are logging, we can kick off
|
||||
# the scheduler officially
|
||||
tasks_manager.start_scheduler()
|
||||
|
||||
# refresh our cache and schedule for every 12 hoursour cache refresh
|
||||
# for serverjars.com
|
||||
tasks_manager.serverjar_cache_refresher()
|
||||
|
||||
# start up our tasks handler in tasks.py
|
||||
tasks_starter_thread = Thread(target=tasks_starter, name="tasks_starter")
|
||||
|
||||
def internet_check():
|
||||
print()
|
||||
logger.info("Checking Internet. This may take a minute.")
|
||||
Console.info("Checking Internet. This may take a minute.")
|
||||
|
||||
if not helper.check_internet():
|
||||
logger.warning(
|
||||
"We have detected the machine running Crafty has no "
|
||||
"connection to the internet. Client connections to "
|
||||
"the server may be limited."
|
||||
)
|
||||
Console.warning(
|
||||
"We have detected the machine running Crafty has no "
|
||||
"connection to the internet. Client connections to "
|
||||
"the server may be limited."
|
||||
)
|
||||
|
||||
# check to see if instance has internet
|
||||
internet_check_thread = Thread(target=internet_check, name="internet_check")
|
||||
|
||||
def controller_setup():
|
||||
if not controller.check_system_user():
|
||||
controller.add_system_user()
|
||||
|
||||
if getattr(sys, "frozen", False):
|
||||
application_path = os.path.dirname(sys.executable)
|
||||
running_mode = "Frozen/executable"
|
||||
else:
|
||||
try:
|
||||
app_full_path = os.path.realpath(__file__)
|
||||
application_path = os.path.dirname(app_full_path)
|
||||
running_mode = "Non-interactive (e.g. 'python main.py')"
|
||||
except NameError:
|
||||
application_path = os.getcwd()
|
||||
running_mode = "Interactive"
|
||||
|
||||
controller.set_project_root(application_path)
|
||||
master_server_dir = controller.management.get_master_server_dir()
|
||||
if master_server_dir == "":
|
||||
logger.debug("Could not find master server path. Setting default")
|
||||
controller.set_master_server_dir(
|
||||
os.path.join(controller.project_root, "servers")
|
||||
)
|
||||
else:
|
||||
helper.servers_dir = master_server_dir
|
||||
|
||||
Console.debug(f"Execution Mode: {running_mode}")
|
||||
Console.debug(f"Application path : '{application_path}'")
|
||||
|
||||
controller.clear_support_status()
|
||||
|
||||
# start the Crafty console.
|
||||
crafty_prompt = MainPrompt(
|
||||
helper, tasks_manager, migration_manager, controller, import3
|
||||
)
|
||||
|
||||
# set up all controllers
|
||||
controller_setup_thread = Thread(target=controller_setup, name="controller_setup")
|
||||
|
||||
def setup_starter():
|
||||
if not args.daemon:
|
||||
time.sleep(0.01) # Wait for the prompt to start
|
||||
print() # Make a newline after the prompt so logs are on an empty line
|
||||
else:
|
||||
time.sleep(0.01) # Wait for the daemon info message
|
||||
setup_starter_thread = Thread(target=setup_starter, name="setup_starter")
|
||||
|
||||
Console.info("Setting up Crafty's internal components...")
|
||||
|
||||
# Start the setup threads
|
||||
tasks_starter_thread.start()
|
||||
internet_check_thread.start()
|
||||
controller_setup_thread.start()
|
||||
|
||||
# Wait for the setup threads to finish
|
||||
tasks_starter_thread.join()
|
||||
internet_check_thread.join()
|
||||
controller_setup_thread.join()
|
||||
|
||||
Console.info("Crafty has fully started and is now ready for use!")
|
||||
|
||||
# Check if new version available
|
||||
remote_ver = helper.check_remote_version()
|
||||
if remote_ver:
|
||||
notice = f"""
|
||||
A new version of Crafty is available!
|
||||
{'/' * 37}
|
||||
New version available: {remote_ver}
|
||||
Current version: {pkg_version.parse(helper.get_version_string())}
|
||||
{'/' * 37}
|
||||
"""
|
||||
Console.yellow(notice)
|
||||
|
||||
crafty_prompt.prompt = f"Crafty Controller v{helper.get_version_string()} > "
|
||||
try:
|
||||
logger.info("Removing old temp dirs")
|
||||
FileHelpers.del_dirs(os.path.join(controller.project_root, "temp"))
|
||||
except:
|
||||
logger.info("Did not find old temp dir.")
|
||||
os.mkdir(os.path.join(controller.project_root, "temp"))
|
||||
|
||||
if not args.daemon:
|
||||
# Put the prompt under the cursor
|
||||
crafty_prompt.print_prompt()
|
||||
|
||||
Thread(target=setup_starter, name="setup_starter").start()
|
||||
setup_starter_thread.start()
|
||||
|
||||
if not args.daemon:
|
||||
# Start the Crafty prompt
|
||||
|
@ -4,13 +4,13 @@ argon2-cffi==23.1.0
|
||||
cached_property==1.5.2
|
||||
colorama==0.4.6
|
||||
croniter==1.4.1
|
||||
cryptography==41.0.4
|
||||
cryptography==41.0.7
|
||||
libgravatar==1.0.4
|
||||
nh3==0.2.14
|
||||
packaging==23.2
|
||||
peewee==3.13
|
||||
psutil==5.9.5
|
||||
pyOpenSSL==23.2.0
|
||||
pyOpenSSL==23.3.0
|
||||
pyjwt==2.8.0
|
||||
PyYAML==6.0.1
|
||||
requests==2.31.0
|
||||
|
Loading…
Reference in New Issue
Block a user