mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Merge branch 'refactor/raknet-nomenclature' into feature/steamcmd
This commit is contained in:
commit
4bc3d90b1e
11
CHANGELOG.md
11
CHANGELOG.md
@ -1,5 +1,5 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
## --- [4.0.22] - 2023/TBD
|
## --- [4.0.23] - 2023/TBD
|
||||||
### New features
|
### New features
|
||||||
TBD
|
TBD
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
@ -10,6 +10,15 @@ TBD
|
|||||||
TBD
|
TBD
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
|
## --- [4.0.22] - 2023/04/08
|
||||||
|
### Bug fixes
|
||||||
|
- Fix dashboard crash for users without disks or if crafty doesn't have permission to access mount point ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/571))
|
||||||
|
- Strip Minecraft motd obfuscation chars to prevent text jumping on dashboard ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/572))
|
||||||
|
### Tweaks
|
||||||
|
- Improve logging on tz failures ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/569))
|
||||||
|
- Add fallback for ping domain to provide better feedback on internet connection ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/570))
|
||||||
|
<br><br>
|
||||||
|
|
||||||
## --- [4.0.21] - 2023/03/04
|
## --- [4.0.21] - 2023/03/04
|
||||||
### New features
|
### New features
|
||||||
- Add better feedback for uploads with a progress bar ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/546))
|
- Add better feedback for uploads with a progress bar ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/546))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[![Crafty Logo](app/frontend/static/assets/images/logo_long.svg)](https://craftycontrol.com)
|
[![Crafty Logo](app/frontend/static/assets/images/logo_long.svg)](https://craftycontrol.com)
|
||||||
# Crafty Controller 4.0.22
|
# Crafty Controller 4.0.23
|
||||||
> Python based Control Panel for your Minecraft Server
|
> Python based Control Panel for your Minecraft Server
|
||||||
|
|
||||||
## What is Crafty Controller?
|
## What is Crafty Controller?
|
||||||
|
@ -8,7 +8,7 @@ import logging.config
|
|||||||
import uuid
|
import uuid
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from app.classes.minecraft.bedrock_ping import BedrockPing
|
from app.classes.minecraft.raknet_ping import RaknetPing
|
||||||
from app.classes.shared.console import Console
|
from app.classes.shared.console import Console
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -40,8 +40,6 @@ class Server:
|
|||||||
lines.append(get_code_format("underlined"))
|
lines.append(get_code_format("underlined"))
|
||||||
if "strikethrough" in e.keys():
|
if "strikethrough" in e.keys():
|
||||||
lines.append(get_code_format("strikethrough"))
|
lines.append(get_code_format("strikethrough"))
|
||||||
if "obfuscated" in e.keys():
|
|
||||||
lines.append(get_code_format("obfuscated"))
|
|
||||||
if "color" in e.keys():
|
if "color" in e.keys():
|
||||||
lines.append(get_code_format(e["color"]))
|
lines.append(get_code_format(e["color"]))
|
||||||
# Then append the text
|
# Then append the text
|
||||||
@ -175,7 +173,7 @@ def ping(ip, port):
|
|||||||
|
|
||||||
|
|
||||||
# For the rest of requests see wiki.vg/Protocol
|
# For the rest of requests see wiki.vg/Protocol
|
||||||
def ping_bedrock(ip, port):
|
def ping_raknet(ip, port):
|
||||||
rand = random.Random()
|
rand = random.Random()
|
||||||
try:
|
try:
|
||||||
# pylint: disable=consider-using-f-string
|
# pylint: disable=consider-using-f-string
|
||||||
@ -184,7 +182,7 @@ def ping_bedrock(ip, port):
|
|||||||
except:
|
except:
|
||||||
client_guid = 0
|
client_guid = 0
|
||||||
try:
|
try:
|
||||||
brp = BedrockPing(ip, port, client_guid)
|
brp = RaknetPing(ip, port, client_guid)
|
||||||
return brp.ping()
|
return brp.ping()
|
||||||
except:
|
except:
|
||||||
logger.debug("Unable to get RakNet stats")
|
logger.debug("Unable to get RakNet stats")
|
@ -9,7 +9,7 @@ with redirect_stderr(NullWriter()):
|
|||||||
import psutil
|
import psutil
|
||||||
|
|
||||||
|
|
||||||
class BedrockPing:
|
class RaknetPing:
|
||||||
magic = b"\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78"
|
magic = b"\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78"
|
||||||
fields = { # (len, signed)
|
fields = { # (len, signed)
|
||||||
"byte": (1, False),
|
"byte": (1, False),
|
||||||
@ -25,19 +25,19 @@ class BedrockPing:
|
|||||||
}
|
}
|
||||||
byte_order = "big"
|
byte_order = "big"
|
||||||
|
|
||||||
def __init__(self, bedrock_addr, bedrock_port, client_guid=0, timeout=5):
|
def __init__(self, server_addr, server_port, client_guid=0, timeout=5):
|
||||||
self.addr = bedrock_addr
|
self.addr = server_addr
|
||||||
self.port = bedrock_port
|
self.port = server_port
|
||||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
self.sock.settimeout(timeout)
|
self.sock.settimeout(timeout)
|
||||||
self.proc = psutil.Process(os.getpid())
|
self.proc = psutil.Process(os.getpid())
|
||||||
self.guid = client_guid
|
self.guid = client_guid
|
||||||
self.guid_bytes = self.guid.to_bytes(8, BedrockPing.byte_order)
|
self.guid_bytes = self.guid.to_bytes(8, RaknetPing.byte_order)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __byter(in_val, to_type):
|
def __byter(in_val, to_type):
|
||||||
f = BedrockPing.fields[to_type]
|
f = RaknetPing.fields[to_type]
|
||||||
return in_val.to_bytes(f[0], BedrockPing.byte_order, signed=f[1])
|
return in_val.to_bytes(f[0], RaknetPing.byte_order, signed=f[1])
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __slice(in_bytes, pattern):
|
def __slice(in_bytes, pattern):
|
||||||
@ -46,7 +46,7 @@ class BedrockPing:
|
|||||||
pattern_index = 0
|
pattern_index = 0
|
||||||
while bytes_index < len(in_bytes):
|
while bytes_index < len(in_bytes):
|
||||||
try:
|
try:
|
||||||
field = BedrockPing.fields[pattern[pattern_index]]
|
field = RaknetPing.fields[pattern[pattern_index]]
|
||||||
except IndexError as index_error:
|
except IndexError as index_error:
|
||||||
raise IndexError(
|
raise IndexError(
|
||||||
"Ran out of pattern with additional bytes remaining"
|
"Ran out of pattern with additional bytes remaining"
|
||||||
@ -55,7 +55,7 @@ class BedrockPing:
|
|||||||
string_header_length = field[0]
|
string_header_length = field[0]
|
||||||
string_length = int.from_bytes(
|
string_length = int.from_bytes(
|
||||||
in_bytes[bytes_index : bytes_index + string_header_length],
|
in_bytes[bytes_index : bytes_index + string_header_length],
|
||||||
BedrockPing.byte_order,
|
RaknetPing.byte_order,
|
||||||
signed=field[1],
|
signed=field[1],
|
||||||
)
|
)
|
||||||
length = string_header_length + string_length
|
length = string_header_length + string_length
|
||||||
@ -75,7 +75,7 @@ class BedrockPing:
|
|||||||
ret.append(
|
ret.append(
|
||||||
int.from_bytes(
|
int.from_bytes(
|
||||||
in_bytes[bytes_index : bytes_index + length],
|
in_bytes[bytes_index : bytes_index + length],
|
||||||
BedrockPing.byte_order,
|
RaknetPing.byte_order,
|
||||||
signed=field[1],
|
signed=field[1],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -89,10 +89,10 @@ class BedrockPing:
|
|||||||
return time.perf_counter_ns() // 1000000
|
return time.perf_counter_ns() // 1000000
|
||||||
|
|
||||||
def __sendping(self):
|
def __sendping(self):
|
||||||
pack_id = BedrockPing.__byter(0x01, "byte")
|
pack_id = RaknetPing.__byter(0x01, "byte")
|
||||||
now = BedrockPing.__byter(BedrockPing.__get_time(), "ulong")
|
now = RaknetPing.__byter(RaknetPing.__get_time(), "ulong")
|
||||||
guid = self.guid_bytes
|
guid = self.guid_bytes
|
||||||
d2s = pack_id + now + BedrockPing.magic + guid
|
d2s = pack_id + now + RaknetPing.magic + guid
|
||||||
# print("S:", d2s)
|
# print("S:", d2s)
|
||||||
self.sock.sendto(d2s, (self.addr, self.port))
|
self.sock.sendto(d2s, (self.addr, self.port))
|
||||||
|
|
||||||
@ -100,10 +100,10 @@ class BedrockPing:
|
|||||||
data = self.sock.recv(4096)
|
data = self.sock.recv(4096)
|
||||||
if data[0] == 0x1C:
|
if data[0] == 0x1C:
|
||||||
ret = {}
|
ret = {}
|
||||||
sliced = BedrockPing.__slice(
|
sliced = RaknetPing.__slice(
|
||||||
data, ["byte", "ulong", "ulong", "magic", "string"]
|
data, ["byte", "ulong", "ulong", "magic", "string"]
|
||||||
)
|
)
|
||||||
if sliced[3] != BedrockPing.magic:
|
if sliced[3] != RaknetPing.magic:
|
||||||
raise ValueError(f"Incorrect magic received ({sliced[3]})")
|
raise ValueError(f"Incorrect magic received ({sliced[3]})")
|
||||||
ret["server_guid"] = sliced[2]
|
ret["server_guid"] = sliced[2]
|
||||||
ret["server_string_raw"] = sliced[4]
|
ret["server_string_raw"] = sliced[4]
|
@ -6,7 +6,7 @@ import datetime
|
|||||||
import base64
|
import base64
|
||||||
import typing as t
|
import typing as t
|
||||||
|
|
||||||
from app.classes.minecraft.mc_ping import ping
|
from app.classes.minecraft.ping import ping
|
||||||
from app.classes.models.management import HostStats
|
from app.classes.models.management import HostStats
|
||||||
from app.classes.models.servers import HelperServers
|
from app.classes.models.servers import HelperServers
|
||||||
from app.classes.shared.null_writer import NullWriter
|
from app.classes.shared.null_writer import NullWriter
|
||||||
@ -191,6 +191,7 @@ class Stats:
|
|||||||
# ENOENT, pop-up a Windows GUI error for a non-ready
|
# ENOENT, pop-up a Windows GUI error for a non-ready
|
||||||
# partition or just hang.
|
# partition or just hang.
|
||||||
continue
|
continue
|
||||||
|
try:
|
||||||
usage = psutil.disk_usage(part.mountpoint)
|
usage = psutil.disk_usage(part.mountpoint)
|
||||||
disk_data.append(
|
disk_data.append(
|
||||||
{
|
{
|
||||||
@ -206,6 +207,9 @@ class Stats:
|
|||||||
"mount": part.mountpoint,
|
"mount": part.mountpoint,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
except PermissionError:
|
||||||
|
logger.debug(f"Permission error accessing {part.mountpoint}")
|
||||||
|
continue
|
||||||
|
|
||||||
return disk_data
|
return disk_data
|
||||||
|
|
||||||
|
@ -294,6 +294,11 @@ class Helpers:
|
|||||||
try:
|
try:
|
||||||
requests.get("https://ntp.org", timeout=1)
|
requests.get("https://ntp.org", timeout=1)
|
||||||
return True
|
return True
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
logger.error("ntp.org ping failed. Falling back to google")
|
||||||
|
requests.get("https://google.com", timeout=1)
|
||||||
|
return True
|
||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ from apscheduler.schedulers.background import BackgroundScheduler
|
|||||||
from apscheduler.jobstores.base import JobLookupError
|
from apscheduler.jobstores.base import JobLookupError
|
||||||
|
|
||||||
from app.classes.minecraft.stats import Stats
|
from app.classes.minecraft.stats import Stats
|
||||||
from app.classes.minecraft.mc_ping import ping, ping_bedrock
|
from app.classes.minecraft.ping import ping, ping_raknet
|
||||||
from app.classes.models.servers import HelperServers, Servers
|
from app.classes.models.servers import HelperServers, Servers
|
||||||
from app.classes.models.server_stats import HelperServerStats
|
from app.classes.models.server_stats import HelperServerStats
|
||||||
from app.classes.models.management import HelpersManagement
|
from app.classes.models.management import HelpersManagement
|
||||||
@ -134,9 +134,10 @@ class ServerInstance:
|
|||||||
self.last_backup_failed = False
|
self.last_backup_failed = False
|
||||||
try:
|
try:
|
||||||
self.tz = get_localzone()
|
self.tz = get_localzone()
|
||||||
except ZoneInfoNotFoundError:
|
except ZoneInfoNotFoundError as e:
|
||||||
logger.error(
|
logger.error(
|
||||||
"Could not capture time zone from system. Falling back to Europe/London"
|
"Could not capture time zone from system. Falling back to Europe/London"
|
||||||
|
f" error: {e}"
|
||||||
)
|
)
|
||||||
self.tz = ZoneInfo("Europe/London")
|
self.tz = ZoneInfo("Europe/London")
|
||||||
self.server_scheduler = BackgroundScheduler(timezone=str(self.tz))
|
self.server_scheduler = BackgroundScheduler(timezone=str(self.tz))
|
||||||
@ -1514,7 +1515,7 @@ class ServerInstance:
|
|||||||
|
|
||||||
logger.debug(f"Pinging server '{server}' on {internal_ip}:{server_port}")
|
logger.debug(f"Pinging server '{server}' on {internal_ip}:{server_port}")
|
||||||
if HelperServers.get_server_type_by_id(server_id) == "minecraft-bedrock":
|
if HelperServers.get_server_type_by_id(server_id) == "minecraft-bedrock":
|
||||||
int_mc_ping = ping_bedrock(internal_ip, int(server_port))
|
int_mc_ping = ping_raknet(internal_ip, int(server_port))
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
int_mc_ping = ping(internal_ip, int(server_port))
|
int_mc_ping = ping(internal_ip, int(server_port))
|
||||||
@ -1640,7 +1641,7 @@ class ServerInstance:
|
|||||||
|
|
||||||
logger.debug(f"Pinging server '{self.name}' on {internal_ip}:{server_port}")
|
logger.debug(f"Pinging server '{self.name}' on {internal_ip}:{server_port}")
|
||||||
if HelperServers.get_server_type_by_id(server_id) == "minecraft-bedrock":
|
if HelperServers.get_server_type_by_id(server_id) == "minecraft-bedrock":
|
||||||
int_mc_ping = ping_bedrock(internal_ip, int(server_port))
|
int_mc_ping = ping_raknet(internal_ip, int(server_port))
|
||||||
else:
|
else:
|
||||||
int_mc_ping = ping(internal_ip, int(server_port))
|
int_mc_ping = ping(internal_ip, int(server_port))
|
||||||
|
|
||||||
|
@ -47,9 +47,10 @@ class TasksManager:
|
|||||||
self.tornado: Webserver = Webserver(helper, controller, self)
|
self.tornado: Webserver = Webserver(helper, controller, self)
|
||||||
try:
|
try:
|
||||||
self.tz = get_localzone()
|
self.tz = get_localzone()
|
||||||
except ZoneInfoNotFoundError:
|
except ZoneInfoNotFoundError as e:
|
||||||
logger.error(
|
logger.error(
|
||||||
"Could not capture time zone from system. Falling back to Europe/London"
|
"Could not capture time zone from system. Falling back to Europe/London"
|
||||||
|
f" error: {e}"
|
||||||
)
|
)
|
||||||
self.tz = "Europe/London"
|
self.tz = "Europe/London"
|
||||||
self.scheduler = BackgroundScheduler(timezone=str(self.tz))
|
self.scheduler = BackgroundScheduler(timezone=str(self.tz))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"major": 4,
|
"major": 4,
|
||||||
"minor": 0,
|
"minor": 0,
|
||||||
"sub": 22
|
"sub": 23
|
||||||
}
|
}
|
||||||
|
@ -100,6 +100,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% if len(data['hosts_data']['disk_json']) > 0 %}
|
||||||
<div class="col-12 mt-4">
|
<div class="col-12 mt-4">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="wrapper" style="width: 100%;">
|
<div class="wrapper" style="width: 100%;">
|
||||||
@ -107,7 +108,7 @@
|
|||||||
</h5>
|
</h5>
|
||||||
<div id="storage_data">
|
<div id="storage_data">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% for item in data.get('hosts_data').get('disk_json') %}
|
{% for item in data['hosts_data']['disk_json'] %}
|
||||||
{% if item["mount"] in data["monitored"] %}
|
{% if item["mount"] in data["monitored"] %}
|
||||||
<div id="{{item['device']}}" class="col-xl-3 col-lg-3 col-md-4 col-12">
|
<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"
|
<h4 class="mb-0 font-weight-semibold d-inline-block text-truncate storage-heading"
|
||||||
@ -137,6 +138,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% end %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -931,8 +933,8 @@
|
|||||||
var storage_html = '<div class="row">';
|
var storage_html = '<div class="row">';
|
||||||
for (i = 0; i < hostStats.disk_usage.length; i++) {
|
for (i = 0; i < hostStats.disk_usage.length; i++) {
|
||||||
if (hostStats.mounts.includes(hostStats.disk_usage[i].mount)) {
|
if (hostStats.mounts.includes(hostStats.disk_usage[i].mount)) {
|
||||||
storage_html += `<div id="{{item['device']}}" class="col-xl-3 col-lg-3 col-md-4 col-12">
|
storage_html += `<div id="host_storage" 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="${hostStats.disk_usage[i].mount}" style="max-width: 100%;"><i class="fas fa-hdd"></i> ${hostStats.disk_usage[i].mount}</h4>
|
<h4 class="mb-0 font-weight-semibold d-inline-block text-truncate storage-heading" id="title_host_storage" data-toggle="tooltip" data-placement="bottom" title="${hostStats.disk_usage[i].mount}" style="max-width: 100%;"><i class="fas fa-hdd"></i> ${hostStats.disk_usage[i].mount}</h4>
|
||||||
<div class="progress" style="display: inline-block; height: 20px; width: 100%; background-color: rgb(139, 139, 139) !important;">
|
<div class="progress" style="display: inline-block; height: 20px; width: 100%; background-color: rgb(139, 139, 139) !important;">
|
||||||
<div class="progress-bar`;
|
<div class="progress-bar`;
|
||||||
if (hostStats.disk_usage[i].percent_used <= 58) {
|
if (hostStats.disk_usage[i].percent_used <= 58) {
|
||||||
|
Loading…
Reference in New Issue
Block a user