2025-07-01 16:21:34 +02:00
from modules . globalvars import *
2025-07-07 12:13:25 +02:00
from modules . volta . main import _ , check_missing_translations
2025-06-22 20:49:07 +02:00
import time
import os
import sys
import subprocess
2025-07-06 21:06:04 +02:00
import sysconfig
2025-06-22 20:49:07 +02:00
import ast
2025-06-28 16:56:05 -04:00
import json
2025-07-06 21:06:04 +02:00
import re
2025-07-07 17:17:44 +02:00
from spacy . util import is_package
2025-07-06 21:06:04 +02:00
import importlib . metadata
2025-07-08 17:02:10 +03:00
import logging
logger = logging . getLogger ( " goober " )
2025-07-06 21:06:04 +02:00
2025-06-28 16:56:05 -04:00
# import shutil
2025-06-27 19:45:44 +02:00
psutilavaliable = True
try :
import requests
import psutil
except ImportError :
psutilavaliable = False
2025-07-08 17:02:10 +03:00
logger . error ( _ ( ' missing_requests_psutil ' ) )
2025-07-01 16:21:34 +02:00
2025-07-07 17:17:44 +02:00
def check_for_model ( ) :
if is_package ( " en_core_web_sm " ) :
2025-07-08 17:02:10 +03:00
logger . info ( " Model is installed. " )
2025-07-07 17:17:44 +02:00
else :
2025-07-08 17:02:10 +03:00
logger . info ( " Model is not installed. " )
2025-07-07 17:17:44 +02:00
2025-07-06 21:45:30 +02:00
def iscloned ( ) :
if os . path . exists ( " .git " ) :
return True
else :
2025-07-08 17:02:10 +03:00
logger . error ( f " { _ ( ' not_cloned ' ) } " )
2025-07-06 21:45:30 +02:00
sys . exit ( 1 )
2025-07-06 21:06:04 +02:00
def get_stdlib_modules ( ) :
stdlib_path = pathlib . Path ( sysconfig . get_paths ( ) [ ' stdlib ' ] )
modules = set ( )
if hasattr ( sys , ' builtin_module_names ' ) :
modules . update ( sys . builtin_module_names )
for file in stdlib_path . glob ( ' *.py ' ) :
if file . stem != ' __init__ ' :
modules . add ( file . stem )
for folder in stdlib_path . iterdir ( ) :
if folder . is_dir ( ) and ( folder / ' __init__.py ' ) . exists ( ) :
modules . add ( folder . name )
for file in stdlib_path . glob ( ' *.* ' ) :
if file . suffix in ( ' .so ' , ' .pyd ' ) :
modules . add ( file . stem )
return modules
2025-06-22 20:49:07 +02:00
def check_requirements ( ) :
2025-07-06 21:06:04 +02:00
STD_LIB_MODULES = get_stdlib_modules ( )
2025-06-22 20:49:07 +02:00
PACKAGE_ALIASES = {
" discord " : " discord.py " ,
2025-06-22 20:55:13 +02:00
" better_profanity " : " better-profanity " ,
2025-07-07 16:54:19 +02:00
" dotenv " : " python-dotenv "
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__ ) )
2025-07-06 21:06:04 +02:00
requirements_path = os . path . abspath ( os . path . join ( parent_dir , ' .. ' , ' requirements.txt ' ) )
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-08 17:02:10 +03:00
logger . error ( f " { ( _ ( ' requirements_not_found ' ) ) . format ( path = requirements_path ) } " )
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
2025-07-06 21:06:04 +02:00
cogs_dir = os . path . abspath ( os . path . join ( parent_dir , ' .. ' , ' assets ' , ' cogs ' ) )
2025-06-22 20:55:13 +02:00
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-08 17:02:10 +03:00
logger . warning ( f " { ( _ ( ' warning_failed_parse_imports ' ) ) . format ( filename = filename , error = e ) } " )
2025-06-22 20:55:13 +02:00
else :
2025-07-08 17:02:10 +03:00
logger . warning ( f " { ( _ ( ' cogs_dir_not_found ' ) ) . format ( path = cogs_dir ) } " )
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-05 20:15:54 +02:00
print ( ( _ ( ' 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-08 17:02:10 +03:00
logger . info ( f " { _ ( ' ok_installed ' ) . format ( package = check_name ) } { check_name } " )
2025-06-22 20:55:13 +02:00
else :
2025-07-08 17:02:10 +03:00
logger . error ( f " { ( _ ( ' missing_package ' ) ) . format ( package = check_name ) } { check_name } { ( _ ( ' 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-08 17:02:10 +03:00
logger . error ( _ ( ' missing_packages_detected ' ) )
2025-06-22 20:49:07 +02:00
for pkg in missing :
print ( f " - { pkg } " )
2025-07-08 17:02:10 +03:00
logger . info ( ( _ ( ' 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** \n Missing packages have been detected, Failed to start " ,
" token " : gooberTOKEN
}
2025-06-22 20:55:13 +02:00
try :
2025-07-07 20:41:24 +02:00
requests . post ( VERSION_URL + " /ping " , json = payload ) # type: ignore
2025-06-22 20:55:13 +02:00
except Exception as e :
2025-07-08 17:02:10 +03:00
logger . error ( f " { ( _ ( ' failed_to_contact ' ) ) . format ( url = VERSION_URL , error = e ) } " )
2025-06-22 20:49:07 +02:00
sys . exit ( 1 )
else :
2025-07-08 17:02:10 +03:00
logger . info ( _ ( ' 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-08 17:02:10 +03:00
logger . info ( ( _ ( ' ping_to ' ) ) . format ( host = host , latency = latency_ms ) )
2025-06-23 13:56:23 +02:00
if latency_ms > 300 :
2025-07-08 17:02:10 +03:00
logger . warning ( f " { ( _ ( ' high_latency ' ) ) } " )
2025-06-23 13:56:23 +02:00
else :
2025-07-08 17:02:10 +03:00
logger . warning ( ( _ ( ' could_not_parse_latency ' ) ) )
2025-06-23 13:56:23 +02:00
else :
print ( result . stderr )
2025-07-08 17:02:10 +03:00
logger . error ( f " { ( _ ( ' ping_failed ' ) ) . format ( host = host ) } { RESET } " )
2025-06-23 13:56:23 +02:00
except Exception as e :
2025-07-08 17:02:10 +03:00
logger . error ( ( _ ( ' error_running_ping ' ) ) . format ( error = e ) )
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 :
2025-07-07 20:41:24 +02:00
memory_info = psutil . virtual_memory ( ) # type: ignore
2025-06-22 20:49:07 +02:00
total_memory = memory_info . total / ( 1024 * * 3 )
used_memory = memory_info . used / ( 1024 * * 3 )
free_memory = memory_info . available / ( 1024 * * 3 )
2025-07-08 17:02:10 +03:00
logger . info ( ( _ ( ' 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-05 20:15:54 +02:00
print ( f " { YELLOW } { ( _ ( ' memory_above_90 ' ) ) . format ( percent = ( used_memory / total_memory ) * 100 ) } { RESET } " )
2025-07-08 17:02:10 +03:00
logger . info ( ( _ ( ' total_memory ' ) ) . format ( total = total_memory ) )
logger . info ( ( _ ( ' used_memory ' ) ) . format ( used = used_memory ) )
2025-06-22 20:49:07 +02:00
if free_memory < 1 :
2025-07-08 17:02:10 +03:00
logger . warning ( f " { ( _ ( ' low_free_memory ' ) ) . format ( free = free_memory ) } " )
2025-06-22 20:49:07 +02:00
sys . exit ( 1 )
except ImportError :
2025-07-08 17:02:10 +03:00
logger . error ( _ ( ' psutil_not_installed ' ) ) # todo: translate this into italian and put it in the translations "psutil is not installed. Memory check skipped."
2025-06-22 20:49:07 +02:00
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-08 17:02:10 +03:00
logger . info ( ( _ ( ' measuring_cpu ' ) ) )
2025-07-07 20:41:24 +02:00
cpu_per_core = psutil . cpu_percent ( interval = 1 , percpu = True ) # type: ignore
2025-06-28 16:56:05 -04:00
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-08 17:02:10 +03:00
logger . info ( ( _ ( ' 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-08 17:02:10 +03:00
logger . info ( ( _ ( ' total_cpu_usage ' ) ) . format ( usage = total_cpu ) )
2025-06-28 16:56:05 -04:00
if total_cpu > 85 :
2025-07-08 17:02:10 +03:00
logger . warning ( f " { ( _ ( ' high_avg_cpu ' ) ) . format ( usage = total_cpu ) } " )
2025-06-28 16:56:05 -04:00
if total_cpu > 95 :
2025-07-08 17:02:10 +03:00
logger . error ( _ ( ' really_high_cpu ' ) )
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-08 17:02:10 +03:00
logger . info ( ( _ ( ' 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-08 17:02:10 +03:00
logger . warning ( f " { ( _ ( ' memory_file_large ' ) ) } " )
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-08 17:02:10 +03:00
logger . error ( f " { ( _ ( ' memory_file_corrupted ' ) ) . format ( error = e ) } " )
logger . warning ( f " { ( _ ( ' consider_backup_memory ' ) ) } " )
2025-06-28 16:56:05 -04:00
except UnicodeDecodeError as e :
2025-07-08 17:02:10 +03:00
logger . error ( f " { ( _ ( ' memory_file_encoding ' ) ) . format ( error = e ) } " )
logger . warning ( f " { ( _ ( ' consider_backup_memory ' ) ) } " )
2025-06-28 16:56:05 -04:00
except Exception as e :
2025-07-08 17:02:10 +03:00
logger . error ( f " { ( _ ( ' error_reading_memory ' ) ) . format ( error = e ) } " )
2025-06-22 20:49:07 +02:00
except FileNotFoundError :
2025-07-08 17:02:10 +03:00
logger ( f " { ( _ ( ' memory_file_not_found ' ) ) } " )
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 )
2025-07-05 20:15:54 +02:00
beta = beta
2025-06-22 20:49:07 +02:00
def start_checks ( ) :
2025-07-05 20:15:54 +02:00
if CHECKS_DISABLED == " True " :
2025-07-08 17:02:10 +03:00
logger . warning ( f " { ( _ ( ' checks_disabled ' ) ) } " )
2025-07-05 20:15:54 +02:00
return
2025-07-08 17:02:10 +03:00
logger . info ( _ ( ' running_prestart_checks ' ) )
2025-07-07 17:17:44 +02:00
check_for_model ( )
2025-07-06 21:45:30 +02:00
iscloned ( )
2025-07-06 21:06:04 +02:00
check_missing_translations ( )
2025-06-28 16:56:05 -04:00
check_requirements ( )
check_latency ( )
check_memory ( )
check_memoryjson ( )
check_cpu ( )
2025-07-01 23:22:38 +02:00
if os . path . exists ( " .env " ) :
pass
else :
2025-07-08 17:02:10 +03:00
logger . warning ( f " { ( _ ( ' env_file_not_found ' ) ) } " )
2025-07-01 23:22:38 +02:00
sys . exit ( 1 )
2025-07-05 20:15:54 +02:00
if beta == True :
2025-07-08 17:02:10 +03:00
logger . warning ( f " this build isnt finished yet, some things might not work as expected " )
2025-07-05 20:15:54 +02:00
else :
pass
2025-07-08 17:02:10 +03:00
logger . info ( _ ( ' 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 )