import subprocess import os import sys import webbrowser import time import shutil import signal import platform # Global variables to hold subprocesses django_process = None vite_process = None def kill_process_on_port(port): """ Kills the process running on the specified port. """ try: print(f"[KILL] Attempting to kill process on port {port}...") system_platform = platform.system() if system_platform == "Windows": # Windows: Use netstat and findstr command = f"netstat -ano | findstr :{port}" else: # Linux/Unix: Use netstat and grep command = f"netstat -tuln | grep :{port}" # Find the PID of the process using the given port result = subprocess.check_output(command, shell=True).decode() # Extract the PID from the result lines = result.strip().split("\n") if lines: for line in lines: parts = line.strip().split() if system_platform == "Windows" and len(parts) >= 5: pid = parts[-1] elif system_platform != "Windows" and len(parts) >= 7: pid = parts[-1] # Kill the process using taskkill or kill if system_platform == "Windows": subprocess.run(f"taskkill /PID {pid} /F", shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) else: subprocess.run(f"kill -9 {pid}", shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) print(f"[KILL] Killed process on port {port} with PID {pid}") else: print(f"[KILL] No process found on port {port}") except subprocess.CalledProcessError: print(f"[KILL] No process found on port {port}") except Exception as e: print(f"[KILL] Error killing process on port {port}: {e}") def run_django_server(): """ Starts the Django development server. """ global django_process try: # Determine the absolute path to the Django project directory script_dir = os.path.dirname(os.path.abspath(__file__)) django_project_path = script_dir # Assuming manage.py is in the script directory manage_py = os.path.join(django_project_path, 'manage.py') if not os.path.isfile(manage_py): print(f"[DJANGO] Error: manage.py not found in {django_project_path}.") return print(f"[DJANGO] Starting Django server in: {django_project_path}") # Start the Django server django_process = subprocess.Popen( [sys.executable, "manage.py", "runserver"], cwd=django_project_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True ) print("[DJANGO] Django server started on port 8000...") except FileNotFoundError: print("[DJANGO] Error: Python executable or manage.py not found.") except Exception as e: print(f"[DJANGO] Error starting Django server: {e}") def run_vite_server(): """ Starts the Vite development server and opens it in the default browser. """ global vite_process try: # Determine the absolute path to the frontend directory script_dir = os.path.dirname(os.path.abspath(__file__)) frontend_path = os.path.join(script_dir, "frontend") print(f"[VITE] Starting Vite server in: {frontend_path}") if not os.path.isdir(frontend_path): print(f"[VITE] Error: Frontend folder not found at {frontend_path}.") return package_json = os.path.join(frontend_path, 'package.json') if not os.path.isfile(package_json): print(f"[VITE] Error: No package.json found in {frontend_path}. Is this the correct frontend folder?") return # Verify that npm is available in the system PATH npm_path = shutil.which("npm") if not npm_path: print("[VITE] Error: npm is not installed or not found in the system PATH.") return else: print(f"[VITE] Found npm at: {npm_path}") # Install npm dependencies print(f"[VITE] Installing npm dependencies in: {frontend_path}...") install_process = subprocess.run( ["npm", "install"], cwd=frontend_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True ) if install_process.returncode != 0: print(f"[VITE] Error installing npm dependencies: {install_process.stderr.decode()}") return # Start the Vite server vite_process = subprocess.Popen( ["npm", "run", "dev"], cwd=frontend_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True ) print("[VITE] Vite frontend server started on port 5173...") # Wait a few seconds to ensure the server starts time.sleep(5) # Open the Vite server in the default web browser vite_url = "http://localhost:5173" print(f"[VITE] Opening {vite_url} in the default browser...") webbrowser.open(vite_url) except FileNotFoundError: print("[VITE] Error: npm executable not found.") except Exception as e: print(f"[VITE] Error starting Vite server: {e}") def signal_handler(sig, frame): """ Handles termination signals to gracefully shut down servers. """ print("\n[MAIN] Interrupt received. Shutting down servers...") if django_process: print("[MAIN] Terminating Django server...") django_process.terminate() try: django_process.wait(timeout=5) print("[MAIN] Django server terminated.") except subprocess.TimeoutExpired: print("[MAIN] Django server did not terminate in time. Killing it...") django_process.kill() if vite_process: print("[MAIN] Terminating Vite server...") vite_process.terminate() try: vite_process.wait(timeout=5) print("[MAIN] Vite server terminated.") except subprocess.TimeoutExpired: print("[MAIN] Vite server did not terminate in time. Killing it...") vite_process.kill() print("[MAIN] All servers shut down. Exiting.") sys.exit(0) def main(): """ Main function to manage server processes. """ # Register the signal handler for graceful shutdown signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) print("[MAIN] Starting server management script...") # Define ports django_port = 8000 vite_port = 5173 # Kill any existing processes on the ports kill_process_on_port(django_port) kill_process_on_port(vite_port) # Start the Django server run_django_server() # Start the Vite server run_vite_server() print("[MAIN] Servers are running. Press Ctrl+C to stop.") # Keep the script running to listen for interrupts try: while True: time.sleep(1) except KeyboardInterrupt: # This will be handled by the signal handler pass if __name__ == "__main__": main()