2025-07-01 16:21:34 +02:00
|
|
|
from modules.globalvars import *
|
|
|
|
from modules.translations import get_translation
|
|
|
|
|
2025-06-22 20:49:07 +02:00
|
|
|
import time
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import subprocess
|
|
|
|
import ast
|
2025-06-28 16:56:05 -04:00
|
|
|
import json
|
|
|
|
# import shutil
|
2025-06-27 19:45:44 +02:00
|
|
|
psutilavaliable = True
|
|
|
|
try:
|
|
|
|
import requests
|
|
|
|
import psutil
|
|
|
|
except ImportError:
|
|
|
|
psutilavaliable = False
|
2025-07-01 16:21:34 +02:00
|
|
|
print(RED, get_translation(LOCALE, 'missing_requests_psutil'), RESET)
|
|
|
|
|
|
|
|
|
2025-06-23 13:56:23 +02:00
|
|
|
import re
|
2025-06-22 20:55:13 +02:00
|
|
|
import importlib.metadata
|
2025-06-22 20:49:07 +02:00
|
|
|
|
2025-07-01 16:21:34 +02:00
|
|
|
|
2025-06-23 13:56:23 +02:00
|
|
|
|
2025-06-22 20:49:07 +02:00
|
|
|
|
|
|
|
def check_requirements():
|
|
|
|
STD_LIB_MODULES = {
|
|
|
|
"os", "sys", "time", "ast", "asyncio", "re", "subprocess", "json",
|
|
|
|
"datetime", "threading", "math", "logging", "functools", "itertools",
|
|
|
|
"collections", "shutil", "socket", "types", "enum", "pathlib",
|
|
|
|
"inspect", "traceback", "platform", "typing", "warnings", "email",
|
|
|
|
"http", "urllib", "argparse", "io", "copy", "pickle", "gzip", "csv",
|
|
|
|
}
|
|
|
|
PACKAGE_ALIASES = {
|
|
|
|
"discord": "discord.py",
|
2025-06-22 20:55:13 +02:00
|
|
|
"better_profanity": "better-profanity",
|
|
|
|
|
2025-06-22 20:49:07 +02:00
|
|
|
}
|
2025-06-22 20:55:13 +02:00
|
|
|
|
2025-06-22 20:49:07 +02:00
|
|
|
parent_dir = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
requirements_path = os.path.join(parent_dir, '..', 'requirements.txt')
|
|
|
|
requirements_path = os.path.abspath(requirements_path)
|
2025-06-22 20:55:13 +02:00
|
|
|
|
2025-06-22 20:49:07 +02:00
|
|
|
if not os.path.exists(requirements_path):
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{RED}{get_translation(LOCALE, 'requirements_not_found').format(path=requirements_path)}{RESET}")
|
2025-06-22 20:49:07 +02:00
|
|
|
return
|
2025-06-22 20:55:13 +02:00
|
|
|
|
2025-06-22 20:49:07 +02:00
|
|
|
with open(requirements_path, 'r') as f:
|
|
|
|
lines = f.readlines()
|
|
|
|
requirements = {
|
|
|
|
line.strip() for line in lines
|
|
|
|
if line.strip() and not line.startswith('#')
|
|
|
|
}
|
2025-06-22 20:55:13 +02:00
|
|
|
|
|
|
|
cogs_dir = os.path.abspath(os.path.join(parent_dir, '..', 'cogs'))
|
|
|
|
if os.path.isdir(cogs_dir):
|
|
|
|
for filename in os.listdir(cogs_dir):
|
|
|
|
if filename.endswith('.py'):
|
|
|
|
filepath = os.path.join(cogs_dir, filename)
|
|
|
|
with open(filepath, 'r', encoding='utf-8') as f:
|
|
|
|
try:
|
|
|
|
tree = ast.parse(f.read(), filename=filename)
|
|
|
|
for node in ast.walk(tree):
|
|
|
|
if isinstance(node, ast.Import):
|
|
|
|
for alias in node.names:
|
|
|
|
pkg = alias.name.split('.')[0]
|
|
|
|
if pkg in STD_LIB_MODULES or pkg == 'modules':
|
|
|
|
continue
|
|
|
|
requirements.add(pkg)
|
|
|
|
elif isinstance(node, ast.ImportFrom):
|
|
|
|
if node.module:
|
|
|
|
pkg = node.module.split('.')[0]
|
|
|
|
if pkg in STD_LIB_MODULES or pkg == 'modules':
|
|
|
|
continue
|
|
|
|
requirements.add(pkg)
|
|
|
|
except Exception as e:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{YELLOW}{get_translation(LOCALE, 'warning_failed_parse_imports').format(filename=filename, error=e)}{RESET}")
|
2025-06-22 20:55:13 +02:00
|
|
|
else:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{YELLOW}{get_translation(LOCALE, 'cogs_dir_not_found').format(path=cogs_dir)}{RESET}")
|
2025-06-22 20:55:13 +02:00
|
|
|
|
|
|
|
installed_packages = {dist.metadata['Name'].lower() for dist in importlib.metadata.distributions()}
|
2025-06-22 20:49:07 +02:00
|
|
|
missing = []
|
2025-06-22 20:55:13 +02:00
|
|
|
|
2025-06-22 20:49:07 +02:00
|
|
|
for req in sorted(requirements):
|
|
|
|
if req in STD_LIB_MODULES or req == 'modules':
|
2025-07-01 16:21:34 +02:00
|
|
|
print(get_translation(LOCALE, "std_lib_local_skipped").format(package=req))
|
2025-06-22 20:49:07 +02:00
|
|
|
continue
|
2025-06-22 20:55:13 +02:00
|
|
|
|
|
|
|
check_name = PACKAGE_ALIASES.get(req, req).lower()
|
|
|
|
|
|
|
|
if check_name in installed_packages:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"[ {GREEN}{get_translation(LOCALE, 'ok_installed').format(package=check_name)}{RESET} ] {check_name}")
|
2025-06-22 20:55:13 +02:00
|
|
|
else:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"[ {RED}{get_translation(LOCALE, 'missing_package').format(package=check_name)}{RESET} ] {check_name} {get_translation(LOCALE, 'missing_package2')}")
|
2025-06-22 20:49:07 +02:00
|
|
|
missing.append(check_name)
|
2025-06-22 20:55:13 +02:00
|
|
|
|
2025-06-22 20:49:07 +02:00
|
|
|
if missing:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(RED, get_translation(LOCALE, "missing_packages_detected"), RESET)
|
2025-06-22 20:49:07 +02:00
|
|
|
for pkg in missing:
|
|
|
|
print(f" - {pkg}")
|
2025-07-01 16:21:34 +02:00
|
|
|
print(get_translation(LOCALE, "telling_goober_central").format(url=VERSION_URL))
|
2025-06-22 20:49:07 +02:00
|
|
|
payload = {
|
|
|
|
"name": NAME,
|
|
|
|
"version": local_version,
|
|
|
|
"slash_commands": f"{slash_commands_enabled}\n\n**Error**\nMissing packages have been detected, Failed to start",
|
|
|
|
"token": gooberTOKEN
|
|
|
|
}
|
2025-06-22 20:55:13 +02:00
|
|
|
try:
|
|
|
|
response = requests.post(VERSION_URL + "/ping", json=payload)
|
|
|
|
except Exception as e:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{RED}{get_translation(LOCALE, 'failed_to_contact').format(url=VERSION_URL, error=e)}{RESET}")
|
2025-06-22 20:49:07 +02:00
|
|
|
sys.exit(1)
|
|
|
|
else:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(get_translation(LOCALE, "all_requirements_satisfied"))
|
2025-06-22 20:49:07 +02:00
|
|
|
|
|
|
|
def check_latency():
|
2025-06-23 13:56:23 +02:00
|
|
|
host = "1.1.1.1"
|
|
|
|
|
|
|
|
system = platform.system()
|
|
|
|
if system == "Windows":
|
|
|
|
cmd = ["ping", "-n", "1", "-w", "1000", host]
|
|
|
|
latency_pattern = r"Average = (\d+)ms"
|
2025-06-22 20:49:07 +02:00
|
|
|
else:
|
2025-06-23 13:56:23 +02:00
|
|
|
cmd = ["ping", "-c", "1", "-W", "1", host]
|
|
|
|
latency_pattern = r"time[=<]\s*([\d\.]+)\s*ms"
|
|
|
|
|
|
|
|
try:
|
|
|
|
result = subprocess.run(
|
|
|
|
cmd,
|
|
|
|
stdout=subprocess.PIPE,
|
|
|
|
stderr=subprocess.PIPE,
|
|
|
|
text=True
|
|
|
|
)
|
|
|
|
|
|
|
|
if result.returncode == 0:
|
|
|
|
print(result.stdout)
|
|
|
|
match = re.search(latency_pattern, result.stdout)
|
|
|
|
if match:
|
|
|
|
latency_ms = float(match.group(1))
|
2025-07-01 16:21:34 +02:00
|
|
|
print(get_translation(LOCALE, "ping_to").format(host=host, latency=latency_ms))
|
2025-06-23 13:56:23 +02:00
|
|
|
if latency_ms > 300:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{YELLOW}{get_translation(LOCALE, 'high_latency')}{RESET}")
|
2025-06-23 13:56:23 +02:00
|
|
|
else:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{YELLOW}{get_translation(LOCALE, 'could_not_parse_latency')}{RESET}")
|
2025-06-23 13:56:23 +02:00
|
|
|
else:
|
|
|
|
print(result.stderr)
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{RED}{get_translation(LOCALE, 'ping_failed').format(host=host)}{RESET}")
|
2025-06-23 13:56:23 +02:00
|
|
|
except Exception as e:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{RED}{get_translation(LOCALE, 'error_running_ping').format(error=e)}{RESET}")
|
2025-06-22 20:49:07 +02:00
|
|
|
|
|
|
|
def check_memory():
|
2025-06-27 19:45:44 +02:00
|
|
|
if psutilavaliable == False:
|
|
|
|
return
|
2025-06-22 20:49:07 +02:00
|
|
|
try:
|
|
|
|
memory_info = psutil.virtual_memory()
|
|
|
|
total_memory = memory_info.total / (1024 ** 3)
|
|
|
|
used_memory = memory_info.used / (1024 ** 3)
|
|
|
|
free_memory = memory_info.available / (1024 ** 3)
|
|
|
|
|
2025-07-01 16:21:34 +02:00
|
|
|
print(get_translation(LOCALE, "memory_usage").format(used=used_memory, total=total_memory, percent=(used_memory / total_memory) * 100))
|
2025-06-22 20:49:07 +02:00
|
|
|
if used_memory > total_memory * 0.9:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{YELLOW}{get_translation(LOCALE, 'memory_above_90').format(percent=(used_memory / total_memory) * 100)}{RESET}")
|
|
|
|
print(get_translation(LOCALE, "total_memory").format(total=total_memory))
|
|
|
|
print(get_translation(LOCALE, "used_memory").format(used=used_memory))
|
2025-06-22 20:49:07 +02:00
|
|
|
if free_memory < 1:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{RED}{get_translation(LOCALE, 'low_free_memory').format(free=free_memory)}{RESET}")
|
2025-06-22 20:49:07 +02:00
|
|
|
sys.exit(1)
|
|
|
|
except ImportError:
|
|
|
|
print("psutil is not installed. Memory check skipped.")
|
|
|
|
|
2025-06-22 23:08:33 +02:00
|
|
|
def check_cpu():
|
2025-06-27 19:45:44 +02:00
|
|
|
if psutilavaliable == False:
|
|
|
|
return
|
2025-07-01 16:21:34 +02:00
|
|
|
print(get_translation(LOCALE, "measuring_cpu"))
|
2025-06-28 16:56:05 -04:00
|
|
|
cpu_per_core = psutil.cpu_percent(interval=1, percpu=True)
|
|
|
|
for idx, core_usage in enumerate(cpu_per_core):
|
|
|
|
bar_length = int(core_usage / 5)
|
|
|
|
bar = '█' * bar_length + '-' * (20 - bar_length)
|
|
|
|
if core_usage > 85:
|
|
|
|
color = RED
|
|
|
|
elif core_usage > 60:
|
|
|
|
color = YELLOW
|
|
|
|
else:
|
|
|
|
color = GREEN
|
2025-07-01 16:21:34 +02:00
|
|
|
print(get_translation(LOCALE, "core_usage").format(idx=idx, bar=bar, usage=core_usage))
|
2025-06-28 16:56:05 -04:00
|
|
|
total_cpu = sum(cpu_per_core) / len(cpu_per_core)
|
2025-07-01 16:21:34 +02:00
|
|
|
print(get_translation(LOCALE, "total_cpu_usage").format(usage=total_cpu))
|
2025-06-28 16:56:05 -04:00
|
|
|
if total_cpu > 85:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{YELLOW}{get_translation(LOCALE, 'high_avg_cpu').format(usage=total_cpu)}{RESET}")
|
2025-06-28 16:56:05 -04:00
|
|
|
if total_cpu > 95:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{RED}{get_translation(LOCALE, 'really_high_cpu')}{RESET}")
|
2025-06-28 16:56:05 -04:00
|
|
|
sys.exit(1)
|
2025-06-22 23:08:33 +02:00
|
|
|
|
2025-06-22 20:49:07 +02:00
|
|
|
def check_memoryjson():
|
|
|
|
try:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(get_translation(LOCALE, "memory_file").format(size=os.path.getsize(MEMORY_FILE) / (1024 ** 2)))
|
2025-06-22 23:08:33 +02:00
|
|
|
if os.path.getsize(MEMORY_FILE) > 1_073_741_824:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{YELLOW}{get_translation(LOCALE, 'memory_file_large')}{RESET}")
|
2025-06-28 16:56:05 -04:00
|
|
|
try:
|
|
|
|
with open(MEMORY_FILE, 'r', encoding='utf-8') as f:
|
|
|
|
json.load(f)
|
|
|
|
except json.JSONDecodeError as e:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{RED}{get_translation(LOCALE, 'memory_file_corrupted').format(error=e)}{RESET}")
|
|
|
|
print(f"{YELLOW}{get_translation(LOCALE, 'consider_backup_memory')}{RESET}")
|
2025-06-28 16:56:05 -04:00
|
|
|
except UnicodeDecodeError as e:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{RED}{get_translation(LOCALE, 'memory_file_encoding').format(error=e)}{RESET}")
|
|
|
|
print(f"{YELLOW}{get_translation(LOCALE, 'consider_backup_memory')}{RESET}")
|
2025-06-28 16:56:05 -04:00
|
|
|
except Exception as e:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{RED}{get_translation(LOCALE, 'error_reading_memory').format(error=e)}{RESET}")
|
2025-06-22 20:49:07 +02:00
|
|
|
except FileNotFoundError:
|
2025-07-01 16:21:34 +02:00
|
|
|
print(f"{YELLOW}{get_translation(LOCALE, 'memory_file_not_found')}{RESET}")
|
2025-06-22 20:49:07 +02:00
|
|
|
|
|
|
|
def presskey2skip(timeout):
|
|
|
|
if os.name == 'nt':
|
|
|
|
import msvcrt
|
|
|
|
start_time = time.time()
|
|
|
|
while True:
|
|
|
|
if msvcrt.kbhit():
|
|
|
|
msvcrt.getch()
|
|
|
|
break
|
|
|
|
if time.time() - start_time > timeout:
|
|
|
|
break
|
|
|
|
time.sleep(0.1)
|
|
|
|
else:
|
|
|
|
import select
|
|
|
|
import sys
|
|
|
|
import termios
|
|
|
|
import tty
|
|
|
|
|
|
|
|
fd = sys.stdin.fileno()
|
|
|
|
old_settings = termios.tcgetattr(fd)
|
|
|
|
try:
|
|
|
|
tty.setcbreak(fd)
|
|
|
|
start_time = time.time()
|
|
|
|
while True:
|
|
|
|
if select.select([sys.stdin], [], [], 0)[0]:
|
|
|
|
sys.stdin.read(1)
|
|
|
|
break
|
|
|
|
if time.time() - start_time > timeout:
|
|
|
|
break
|
|
|
|
time.sleep(0.1)
|
|
|
|
finally:
|
|
|
|
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
|
|
|
|
|
|
|
def start_checks():
|
2025-07-01 16:21:34 +02:00
|
|
|
print(get_translation(LOCALE, "running_prestart_checks"))
|
2025-06-28 16:56:05 -04:00
|
|
|
check_requirements()
|
|
|
|
check_latency()
|
|
|
|
check_memory()
|
|
|
|
check_memoryjson()
|
|
|
|
check_cpu()
|
2025-07-01 16:21:34 +02:00
|
|
|
print(get_translation(LOCALE, "continuing_in_seconds").format(seconds=5))
|
2025-06-28 16:56:05 -04:00
|
|
|
presskey2skip(timeout=5)
|
|
|
|
os.system('cls' if os.name == 'nt' else 'clear')
|
|
|
|
print(splashtext)
|