compiler

Log | Files | Refs | README

commit 36c31c229c4bd422590d9b6a83a7d38a3a7f662b
parent 756bf3c8b5ba71553ba58f1b220fa7e88e8c1231
Author: AMIT DUTTA <amitdutta4255@gmail.com>
Date:   Sat, 10 Jan 2026 20:47:42 +0530

Enhance backend for multi-language support and health check

Refactor the backend to support Python, C, and C++ code execution with health check endpoint.
Diffstat:
Mbackend.py | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 116 insertions(+), 44 deletions(-)

diff --git a/backend.py b/backend.py @@ -8,35 +8,28 @@ import platform import threading import re import importlib.util +import http # ================================================================================== -# THREADED COMPILER SERVER (Auto-Install + UTF-8) +# CLOUD COMPILER SERVER (Python, C, C++) - RENDER COMPATIBLE # ================================================================================== def install_package(package_name): - """Attempt to install a package via pip.""" + """Attempt to install a python package via pip.""" try: - # Check if already installed to save time if importlib.util.find_spec(package_name) is not None: return - print(f"Installing missing package: {package_name}...") subprocess.check_call([sys.executable, "-m", "pip", "install", package_name]) except Exception as e: print(f"Failed to install {package_name}: {e}") def check_and_install_packages(code): - """Scan code for imports and install them if missing.""" - # Regex to find 'import x' or 'from x import y' + """Scan Python code for imports and install them if missing.""" imports = re.findall(r'^\s*import\s+(\w+)', code, re.MULTILINE) from_imports = re.findall(r'^\s*from\s+(\w+)', code, re.MULTILINE) - unique_packages = set(imports + from_imports) - - # Filter out standard library modules (approximate list or just let pip handle it) - # Ideally, we just try to install. Pip is smart enough to skip if satisfied. for pkg in unique_packages: - # Skip common standard libs to save time (add more if needed) if pkg in ['os', 'sys', 'time', 'random', 'math', 'json', 'asyncio', 'threading', 'platform', 'subprocess', 're']: continue install_package(pkg) @@ -45,9 +38,11 @@ async def run_code(websocket): print(f"Client connected: {websocket.remote_address}") process = None + # Helper to read output stream in a separate thread def read_stream(stream, loop): try: while True: + # Read 1 byte/char at a time char = stream.read(1) if not char: break @@ -64,38 +59,102 @@ async def run_code(websocket): if data.get('type') == 'run': code = data.get('code') + language = data.get('language', 'python') - # 1. AUTO-INSTALL PACKAGES - await websocket.send(json.dumps({'type': 'status', 'msg': 'Checking dependencies...'})) - # Run in executor to avoid blocking the event loop - await asyncio.get_running_loop().run_in_executor(None, check_and_install_packages, code) - - # 2. WRITE FILE - filename = "temp_script.py" - with open(filename, "w", encoding="utf-8") as f: - f.write(code) - - # 3. RUN CODE - env = os.environ.copy() - env["PYTHONIOENCODING"] = "utf-8" + # --- PYTHON HANDLING --- + if language == 'python': + await websocket.send(json.dumps({'type': 'status', 'msg': 'Checking dependencies...'})) + # Run package check in executor to avoid blocking main loop + await asyncio.get_running_loop().run_in_executor(None, check_and_install_packages, code) + + filename = "temp_script.py" + with open(filename, "w", encoding="utf-8") as f: + f.write(code) + + env = os.environ.copy() + env["PYTHONIOENCODING"] = "utf-8" - process = subprocess.Popen( - [sys.executable, "-u", filename], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - text=True, - bufsize=0, - encoding='utf-8', - env=env - ) - - await websocket.send(json.dumps({'type': 'status', 'msg': 'Running...'})) + process = subprocess.Popen( + [sys.executable, "-u", filename], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + bufsize=0, + encoding='utf-8', + env=env + ) + await websocket.send(json.dumps({'type': 'status', 'msg': 'Running Python...'})) + + # --- C HANDLING --- + elif language == 'c': + filename = "temp_code.c" + executable = "./a.out" if platform.system() != "Windows" else "a.exe" + + with open(filename, "w", encoding="utf-8") as f: + f.write(code) + + await websocket.send(json.dumps({'type': 'status', 'msg': 'Compiling C...'})) + + compile_process = subprocess.run( + ["gcc", filename, "-o", executable], + capture_output=True, + text=True + ) + + if compile_process.returncode != 0: + await websocket.send(json.dumps({'type': 'stdout', 'data': f"Compilation Error:\n{compile_process.stderr}"})) + continue + + await websocket.send(json.dumps({'type': 'status', 'msg': 'Running C Binary...'})) + + process = subprocess.Popen( + [executable], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + bufsize=0, + encoding='utf-8' + ) + + # --- C++ HANDLING --- + elif language == 'cpp': + filename = "temp_code.cpp" + executable = "./a.out" if platform.system() != "Windows" else "a.exe" + + with open(filename, "w", encoding="utf-8") as f: + f.write(code) + + await websocket.send(json.dumps({'type': 'status', 'msg': 'Compiling C++...'})) + + compile_process = subprocess.run( + ["g++", filename, "-o", executable], + capture_output=True, + text=True + ) + + if compile_process.returncode != 0: + await websocket.send(json.dumps({'type': 'stdout', 'data': f"Compilation Error:\n{compile_process.stderr}"})) + continue + + await websocket.send(json.dumps({'type': 'status', 'msg': 'Running C++ Binary...'})) + + process = subprocess.Popen( + [executable], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + bufsize=0, + encoding='utf-8' + ) - loop = asyncio.get_running_loop() - thread = threading.Thread(target=read_stream, args=(process.stdout, loop)) - thread.daemon = True - thread.start() + if process: + loop = asyncio.get_running_loop() + thread = threading.Thread(target=read_stream, args=(process.stdout, loop)) + thread.daemon = True + thread.start() elif data.get('type') == 'input': if process and process.poll() is None: @@ -113,10 +172,24 @@ async def run_code(websocket): finally: if process: process.kill() +async def health_check(path, request_headers): + """ + Custom handler to intercept HTTP requests (like health checks) + before the WebSocket handshake. + """ + if path == "/healthz": + return http.HTTPStatus.OK, [], b"OK" + # Returning None tells websockets to proceed with the standard handshake + return None + async def main(): - print("Server started on port 8765...") - async with websockets.serve(run_code, "0.0.0.0", 8765): + # Use PORT env var for Render/Replit, default to 8765 + port = int(os.environ.get("PORT", 8765)) + print(f"Server started on port {port}...") + + # We pass 'process_request' to handle health checks + async with websockets.serve(run_code, "0.0.0.0", port, process_request=health_check): await asyncio.Future() if __name__ == "__main__": - asyncio.run(main())- \ No newline at end of file + asyncio.run(main())
© notamitgamer • Site Built: 2026-07-21 13:58:23 UTC • git-mirror commit: 1037f62 [view raw info]
Originally created with stagit • modified by notamitgamer
Forked from github.com/notamitgamer/git-mirror