Merge branch 'refactor/raknet-nomenclature' into feature/steamcmd

This commit is contained in:
amcmanu3 2023-04-14 16:26:01 -04:00
commit 4bc3d90b1e
10 changed files with 68 additions and 48 deletions

View File

@ -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))

View File

@ -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?

View File

@ -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")

View File

@ -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]

View File

@ -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

View File

@ -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

View File

@ -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))

View File

@ -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))

View File

@ -1,5 +1,5 @@
{ {
"major": 4, "major": 4,
"minor": 0, "minor": 0,
"sub": 22 "sub": 23
} }

View File

@ -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) {