Delete my_server.py

This commit is contained in:
2025-07-08 18:33:06 +02:00
parent cde121ced7
commit 412c58e054

View File

@@ -1,525 +0,0 @@
import os
import subprocess
import threading
import socket
import socketserver
import time
import sys
# --- CONFIGURAZIONE (DA ADATTARE ALLE TUE ESIGENZE) ---
# Queste variabili dovrebbero essere configurate in un file di configurazione separato
# o passate come argomenti al tuo script Python.
TCPSERVER_PID_FILE = "/var/run/my_socket_server.pid"
TCPSERVER_IP = "0.0.0.0" # Ascolta su tutte le interfacce
TCPSERVER_PORT = 12345 # Porta del server socket
TCPSERVER_USER = "admin" # Credenziali opzionali per l'autenticazione
TCPSERVER_PWD = "password123"
# Variabili usate internamente dallo script Bash, che in Python diventano parametri o logica
RUN_FROM_TCPSERVER = False # Sarà True quando il comando è eseguito dal server socket
# Definisci i percorsi per i comandi esterni (se non sono nel PATH di sistema)
# In un ambiente di produzione, è meglio specificare percorsi assoluti.
# Ad esempio, TR_COMMAND = "/usr/bin/tr"
TR_COMMAND = "tr"
CUT_COMMAND = "cut"
READLINK_COMMAND = "readlink"
# --- FUNZIONI UTILITY (PLACEHOLDERS) ---
# Queste sono le funzioni che erano richiamate dallo script Bash
# Dovrai implementarle in Python o collegarle alle tue librerie esistenti.
def log_write(source, level, message):
"""Placeholder per la funzione di logging."""
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
print(f"[{timestamp}] [{source}] [{level.upper()}] {message}")
def json_error(code, message):
"""Placeholder per la funzione che genera un JSON di errore."""
print(f'{{"status": "error", "code": {code}, "message": "{message}"}}')
def json_status(*args):
"""Placeholder per la funzione che genera un JSON di stato."""
if args:
print(f'{{"status": "success", "data": "{", ".join(args)}"}}')
else:
print('{"status": "success"}')
def message_write(level, message):
"""Placeholder per la funzione che scrive un messaggio."""
print(f"[{level.upper()}] {message}")
def ev_open(alias, param=None):
"""Placeholder per la funzione di apertura valvola."""
log_write("socket_server", "info", f"Executing ev_open for alias: {alias}, param: {param}")
# Qui andrebbe la logica per aprire la valvola
pass
def ev_open_in(arg2, arg3, arg4, arg5):
"""Placeholder per la funzione di apertura valvola in un intervallo."""
log_write("socket_server", "info", f"Executing ev_open_in with args: {arg2}, {arg3}, {arg4}, {arg5}")
# Qui andrebbe la logica per aprire la valvola in un intervallo
pass
def ev_close(alias):
"""Placeholder per la funzione di chiusura valvola."""
log_write("socket_server", "info", f"Executing ev_close for alias: {alias}")
# Qui andrebbe la logica per chiudere la valvola
pass
def close_all():
"""Placeholder per la funzione di chiusura di tutte le valvole."""
log_write("socket_server", "info", "Executing close_all")
# Qui andrebbe la logica per chiudere tutte le valvole
pass
def cron_disable_all_open_close():
"""Placeholder per la funzione di disabilitazione scheduling cron."""
log_write("socket_server", "info", "Executing cron_disable_all_open_close")
# Qui andrebbe la logica per disabilitare lo scheduling
pass
def cron_enable_all_open_close():
"""Placeholder per la funzione di abilitazione scheduling cron."""
log_write("socket_server", "info", "Executing cron_enable_all_open_close")
# Qui andrebbe la logica per abilitare lo scheduling
pass
def set_cron_init():
"""Placeholder per la funzione set_cron_init."""
log_write("socket_server", "info", "Executing set_cron_init")
return "" # Simula output vuoto per successo
def set_cron_start_socket_server():
"""Placeholder per la funzione set_cron_start_socket_server."""
log_write("socket_server", "info", "Executing set_cron_start_socket_server")
return ""
def set_cron_check_rain_sensor():
"""Placeholder per la funzione set_cron_check_rain_sensor."""
log_write("socket_server", "info", "Executing set_cron_check_rain_sensor")
return ""
def set_cron_check_rain_online():
"""Placeholder per la funzione set_cron_check_rain_online."""
log_write("socket_server", "info", "Executing set_cron_check_rain_online")
return ""
def set_cron_close_all_for_rain():
"""Placeholder per la funzione set_cron_close_all_for_rain."""
log_write("socket_server", "info", "Executing set_cron_close_all_for_rain")
return ""
def del_cron_open(arg):
"""Placeholder per la funzione del_cron_open."""
log_write("socket_server", "info", f"Executing del_cron_open with arg: {arg}")
return ""
def del_cron_open_in(arg):
"""Placeholder per la funzione del_cron_open_in."""
log_write("socket_server", "info", f"Executing del_cron_open_in with arg: {arg}")
return ""
def del_cron_close(arg):
"""Placeholder per la funzione del_cron_close."""
log_write("socket_server", "info", f"Executing del_cron_close with arg: {arg}")
return ""
def add_cron_open(arg2, arg3, arg4, arg5, arg6, arg7, arg8):
"""Placeholder per la funzione add_cron_open."""
log_write("socket_server", "info", f"Executing add_cron_open with args: {arg2}, {arg3}, {arg4}, {arg5}, {arg6}, {arg7}, {arg8}")
return ""
def add_cron_close(arg2, arg3, arg4, arg5, arg6, arg7, arg8):
"""Placeholder per la funzione add_cron_close."""
log_write("socket_server", "info", f"Executing add_cron_close with args: {arg2}, {arg3}, {arg4}, {arg5}, {arg6}, {arg7}, {arg8}")
return ""
def cmd_pigardensched(arg2, arg3, arg4, arg5, arg6):
"""Placeholder per la funzione cmd_pigardensched."""
log_write("socket_server", "info", f"Executing cmd_pigardensched with args: {arg2}, {arg3}, {arg4}, {arg5}, {arg6}")
return ""
def reset_last_rain_sensor_timestamp():
"""Placeholder per la funzione reset_last_rain_sensor_timestamp."""
log_write("socket_server", "info", "Executing reset_last_rain_sensor_timestamp")
pass
def reset_last_rain_online_timestamp():
"""Placeholder per la funzione reset_last_rain_online_timestamp."""
log_write("socket_server", "info", "Executing reset_last_rain_online_timestamp")
pass
def sensor_status_set(arg2, arg3, arg4):
"""Placeholder per la funzione sensor_status_set."""
log_write("socket_server", "info", f"Executing sensor_status_set with args: {arg2}, {arg3}, {arg4}")
pass
# --- FUNZIONI DI GESTIONE DEI PROCESSI ---
def list_descendants(pid):
"""
Simula la logica di 'list_descendants' Bash.
In un sistema reale, dovresti usare librerie come 'psutil'
per ottenere i processi figli. Qui è solo una simulazione.
"""
try:
# psutil è l'opzione migliore, se disponibile
# import psutil
# parent = psutil.Process(pid)
# return [child.pid for child in parent.children(recursive=True)]
# Fallback semplice per simulazione (non accurato per processi reali)
# Se non hai psutil, questa funzione è difficile da replicare accuratamente in modo generico.
# Potrebbe essere necessario un approccio specifico per il tuo sistema operativo.
return [] # Nessun discendente noto senza psutil
except Exception as e:
log_write("process_manager", "error", f"Errore nel listing dei discendenti di {pid}: {e}")
return []
def get_script_path():
"""Restituisce il percorso assoluto dello script corrente."""
return os.path.abspath(sys.argv[0])
# --- CLASSE GESTORE RICHIESTE SOCKET ---
class MyTCPHandler(socketserver.BaseRequestHandler):
"""
La classe MyTCPHandler gestirà ogni nuova connessione client.
Sovrascrive il metodo handle() per implementare la logica del server.
"""
def handle(self):
global RUN_FROM_TCPSERVER
RUN_FROM_TCPSERVER = True
# TCPREMOTEIP in Python è self.client_address[0]
client_ip = self.client_address[0]
log_write("socket_server", "info", f"Nuova connessione da: {client_ip}")
try:
# Autenticazione (se configurata)
if TCPSERVER_USER and TCPSERVER_PWD:
# Leggi utente (timeout 3 secondi)
self.request.settimeout(3)
try:
user_line = self.request.recv(1024).decode('utf-8').strip()
password_line = self.request.recv(1024).decode('utf-8').strip()
except socket.timeout:
log_write("socket_server", "warning", f"socket connection from: {client_ip} - Timeout during credentials read")
json_error(0, "Authentication timeout")
return
if user_line != TCPSERVER_USER or password_line != TCPSERVER_PWD:
log_write("socket_server", "warning", f"socket connection from: {client_ip} - Bad socket server credentials - user:{user_line}")
self.request.sendall(f'{{"status": "error", "code": 0, "message": "Bad socket server credentials"}}\n'.encode('utf-8'))
return
else:
log_write("socket_server", "info", f"socket connection from: {client_ip} - Authentication successful")
# Leggi il comando
command_line = self.request.recv(4096).decode('utf-8').strip()
# Parsing del comando
args = command_line.split(' ')
arg1 = args[0] if len(args) > 0 else ""
arg2 = args[1] if len(args) > 1 else ""
arg3 = args[2] if len(args) > 2 else ""
arg4 = args[3] if len(args) > 3 else ""
arg5 = args[4] if len(args) > 4 else ""
arg6 = args[5] if len(args) > 5 else ""
arg7 = args[6] if len(args) > 6 else ""
arg8 = args[7] if len(args) > 7 else ""
log_write("socket_server", "info", f"socket connection from: {client_ip} - command: {command_line}")
# Esegui il comando
response = self.execute_command(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
# Invia la risposta al client (assumendo che le funzioni json_error/json_status stampino su stdout)
# Potresti voler catturare l'output di quelle funzioni e inviarlo qui.
# Per semplicità, qui si presuppone che inviino direttamente al client,
# ma in un sistema reale dovresti costruire la risposta JSON e inviarla.
self.request.sendall(response.encode('utf-8') + b'\n')
except socket.timeout:
log_write("socket_server", "warning", f"socket connection from: {client_ip} - Timeout waiting for command.")
self.request.sendall(f'{{"status": "error", "code": 0, "message": "Timeout waiting for command"}}\n'.encode('utf-8'))
except Exception as e:
log_write("socket_server", "error", f"Errore durante la gestione della connessione da {client_ip}: {e}")
self.request.sendall(f'{{"status": "error", "code": -1, "message": "Internal server error"}}\n'.encode('utf-8'))
finally:
self.request.close() # Chiudi la connessione
RUN_FROM_TCPSERVER = False # Reset per la prossima connessione o per operazioni interne
def execute_command(self, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8):
"""Esegue il comando ricevuto dal socket server."""
# Questo metodo replicherà la logica della case statement Bash
vret = "" # Per catturare i risultati delle funzioni
if arg1 == "status":
json_status(arg2, arg3, arg4, arg5, arg6, arg7)
elif arg1 == "open":
if not arg2: # "empty$arg2" == "empty"
json_error(0, "Alias solenoid not specified")
else:
ev_open(arg2, arg3) # &> /dev/null è gestito non catturando l'output
json_status(f"get_cron_open_in:{arg2}")
elif arg1 == "open_in":
ev_open_in(arg2, arg3, arg4, arg5)
json_status(f"get_cron_open_in:{arg4}")
elif arg1 == "close":
if not arg2:
json_error(0, "Alias solenoid not specified")
else:
ev_close(arg2)
json_status(f"get_cron_open_in:{arg2}")
elif arg1 == "close_all":
if arg2 == "disable_scheduling":
cron_disable_all_open_close()
close_all()
message_write("success", "All solenoid closed")
json_status()
elif arg1 == "cron_enable_all_open_close":
cron_enable_all_open_close()
message_write("success", "All solenoid enabled")
json_status()
elif arg1 == "set_general_cron":
# Per i comandi di set_general_cron, chiami le funzioni e concateni i risultati
# Ho ipotizzato che i risultati vuoti indichino successo e stringhe non vuote errori
funcs_to_call = {
"set_cron_init": set_cron_init,
"set_cron_start_socket_server": set_cron_start_socket_server,
"set_cron_check_rain_sensor": set_cron_check_rain_sensor,
"set_cron_check_rain_online": set_cron_check_rain_online,
"set_cron_close_all_for_rain": set_cron_close_all_for_rain,
}
# Qui si itera sugli argomenti come nello script Bash
for i_arg in [arg for arg in [arg2, arg3, arg4, arg5, arg6, arg7] if arg]:
if i_arg in funcs_to_call:
ret_val = funcs_to_call[i_arg]()
if ret_val: # Se la funzione restituisce qualcosa (un errore in Bash)
vret += ret_val
if vret: # Se c'è stato qualche errore in una delle chiamate
json_error(0, "Cron set failed")
log_write("socket_server", "error", f"Cron set failed: {vret}")
else:
message_write("success", "Cron set successful")
json_status()
elif arg1 == "del_cron_open":
vret = del_cron_open(arg2)
if vret:
json_error(0, "Cron set failed")
log_write("socket_server", "error", f"Cron del failed: {vret}")
else:
message_write("success", "Cron set successful")
json_status()
elif arg1 == "del_cron_open_in":
vret = del_cron_open_in(arg2)
if vret:
json_error(0, "Cron del failed")
log_write("socket_server", "error", f"Cron del failed: {vret}")
else:
message_write("success", "Scheduled start successfully deleted")
json_status(f"get_cron_open_in:{arg2}")
elif arg1 == "del_cron_close":
vret = del_cron_close(arg2)
if vret:
json_error(0, "Cron set failed")
log_write("socket_server", "error", f"Cron set failed: {vret}")
else:
message_write("success", "Cron set successful")
json_status()
elif arg1 == "add_cron_open":
vret = add_cron_open(arg2, arg3, arg4, arg5, arg6, arg7, arg8)
if vret:
json_error(0, "Cron set failed")
log_write("socket_server", "error", f"Cron set failed: {vret}")
else:
message_write("success", "Cron set successful")
json_status()
elif arg1 == "add_cron_close":
vret = add_cron_close(arg2, arg3, arg4, arg5, arg6, arg7, arg8)
if vret:
json_error(0, "Cron set failed")
log_write("socket_server", "error", f"Cron set failed: {vret}")
else:
message_write("success", "Cron set successful")
json_status()
elif arg1 == "cmd_pigardensched":
vret = cmd_pigardensched(arg2, arg3, arg4, arg5, arg6)
if vret:
json_error(0, "piGardenSched command failed")
log_write("socket_server", "error", f"piGardenSched command failed: {vret}")
else:
message_write("success", "Schedule set successful")
json_status()
elif arg1 == "reboot":
message_write("warning", "System reboot is started")
json_status()
current_script_path = get_script_path()
# Esegui il reboot in un sottoprocesso separato per non bloccare il server
# e con nohup-like behavior.
# Questo è un esempio, la gestione di reboot/poweroff in Python è delicata.
# Potresti voler chiamare un comando di sistema come `sudo reboot`.
subprocess.Popen([current_script_path, "reboot_system_internal_cmd"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
preexec_fn=os.setsid) # setsid per disassociare dal gruppo di processi
elif arg1 == "poweroff":
message_write("warning", "System shutdown is started")
json_status()
current_script_path = get_script_path()
subprocess.Popen([current_script_path, "poweroff_system_internal_cmd"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
preexec_fn=os.setsid) # setsid per disassociare dal gruppo di processi
elif arg1 == "reset_last_rain_sensor_timestamp":
reset_last_rain_sensor_timestamp()
message_write("success", "Timestamp of last sensor rain successful reset")
json_status()
elif arg1 == "reset_last_rain_online_timestamp":
reset_last_rain_online_timestamp()
message_write("success", "Timestamp of last online rain successful reset")
json_status()
elif arg1 == "sensor_status_set":
if not arg2:
json_error(0, "Alias sensor not specified")
else:
sensor_status_set(arg2, arg3, arg4)
json_status()
else:
json_error(0, "invalid command")
# Le funzioni json_error, json_status, message_write stampano direttamente su stdout
# In un contesto di server reale, dovresti catturare il loro output e inviarlo al client.
# Per questa conversione, sto assumendo che tu voglia replicare il comportamento Bash
# di "stampa e poi la pipeline gestisce l'invio". Potrebbe richiedere un refactoring
# delle funzioni json_error/status per restituire stringhe invece di stampare.
# Per ora, restituisco una stringa vuota o un placeholder.
return "" # Potresti voler restituire il JSON o il messaggio qui
# --- FUNZIONI PRINCIPALI DEL SERVER ---
def start_socket_server():
"""Avvia il server socket."""
# Rimuovi il file PID esistente
if os.path.exists(TCPSERVER_PID_FILE):
os.remove(TCPSERVER_PID_FILE)
# Scrivi il PID dello script principale nel file PID
# In un sistema reale, dovresti scrivere il PID del processo del server,
# che potrebbe essere diverso se usi un manager di processi come systemd.
current_pid = os.getpid()
with open(TCPSERVER_PID_FILE, "w") as f:
f.write(str(current_pid))
log_write("socket_server", "info", f"Server PID {current_pid} scritto in {TCPSERVER_PID_FILE}")
try:
# Crea il server TCP
# ThreadingTCPServer gestisce ogni richiesta in un thread separato
with socketserver.ThreadingTCPServer((TCPSERVER_IP, TCPSERVER_PORT), MyTCPHandler) as server:
log_write("socket_server", "info", f"Server socket avviato su {TCPSERVER_IP}:{TCPSERVER_PORT}")
# Avvia il server, rimarrà in ascolto indefinitamente
server.serve_forever()
except Exception as e:
log_write("socket_server", "error", f"Errore all'avvio del server socket: {e}")
if os.path.exists(TCPSERVER_PID_FILE):
os.remove(TCPSERVER_PID_FILE) # Pulisci il PID file in caso di errore
sys.exit(1)
def stop_socket_server():
"""Ferma il server socket."""
if not os.path.exists(TCPSERVER_PID_FILE):
print("Daemon is not running")
sys.exit(1)
log_write("socket_server", "info", "stop socket server")
with open(TCPSERVER_PID_FILE, "r") as f:
try:
pid = int(f.read().strip())
except ValueError:
print(f"Errore: Il file PID '{TCPSERVER_PID_FILE}' contiene un PID non valido.")
sys.exit(1)
# Tentativo di killare i processi discendenti (se list_descendants è implementato)
descendants = list_descendants(pid)
for d_pid in descendants:
try:
os.kill(d_pid, 9) # SIGKILL
log_write("socket_server", "info", f"Terminato processo discendente {d_pid}")
except ProcessLookupError:
pass # Il processo non esiste
# Tenta di killare il processo principale del server
try:
os.kill(pid, 9) # SIGKILL
log_write("socket_server", "info", f"Terminato processo server {pid}")
except ProcessLookupError:
print(f"Processo con PID {pid} non trovato.")
except Exception as e:
log_write("socket_server", "error", f"Errore durante l'uccisione del processo server {pid}: {e}")
# Rimuovi il file PID
if os.path.exists(TCPSERVER_PID_FILE):
os.remove(TCPSERVER_PID_FILE)
log_write("socket_server", "info", "File PID rimosso.")
# --- FUNZIONE PRINCIPALE PER LA GESTIONE DEGLI ARGOMENTI DELLA CLI ---
if __name__ == "__main__":
if len(sys.argv) > 1:
command = sys.argv[1]
if command == "start_socket_server":
# Per avviare in background come un vero daemon, dovresti implementare
# la demonizzazione (forking) qui o usare una libreria come `python-daemon`.
# Per ora, questo lo avvia nel terminale corrente.
log_write("main", "info", "Richiesta di avvio del socket server.")
start_socket_server()
elif command == "stop_socket_server":
log_write("main", "info", "Richiesta di stop del socket server.")
stop_socket_server()
elif command == "socket_server_command":
# Questa parte dovrebbe essere gestita dal server TCP stesso.
# Non viene chiamata direttamente dalla riga di comando in Python in questo modo.
# Se hai bisogno di testare la logica 'socket_server_command' isolatamente,
# dovresti chiamare MyTCPHandler.execute_command() con argomenti di test.
print("Errore: 'socket_server_command' non può essere chiamato direttamente come script.")
print("Questa logica è gestita internamente dal server TCP.")
sys.exit(1)
elif command == "reboot_system_internal_cmd":
# Comando interno per il riavvio effettivo
log_write("main", "warning", "Eseguo il riavvio del sistema...")
# In un sistema Linux, questo è il modo per riavviare
subprocess.run(["sudo", "reboot"])
# Assicurati che l'utente che esegue lo script abbia i permessi sudo senza password per 'reboot'
elif command == "poweroff_system_internal_cmd":
# Comando interno per lo spegnimento effettivo
log_write("main", "warning", "Eseguo lo spegnimento del sistema...")
# In un sistema Linux, questo è il modo per spegnere
subprocess.run(["sudo", "poweroff"])
# Assicurati che l'utente che esegue lo script abbia i permessi sudo senza password per 'poweroff'
else:
print(f"Comando non riconosciuto: {command}")
print("Utilizzo: python your_script_name.py [start_socket_server|stop_socket_server]")
sys.exit(1)
else:
print("Nessun comando specificato.")
print("Utilizzo: python your_script_name.py [start_socket_server|stop_socket_server]")
sys.exit(1)