mirror of
https://github.com/EDeev/compile-hub.git
synced 2026-06-15 19:11:10 +03:00
116 lines
No EOL
4 KiB
Python
116 lines
No EOL
4 KiB
Python
import asyncio, tempfile, os, shutil
|
|
import subprocess, uuid
|
|
|
|
from typing import Dict, Any, Optional
|
|
|
|
|
|
class CompilerBase:
|
|
def __init__(self, language: str, timeout: int = 5):
|
|
self.language = language
|
|
self.timeout = timeout
|
|
self.max_output_size = 1000000 # 1MB
|
|
|
|
async def compile_and_run(self, code: str, input_data: str = "") -> Dict[str, Any]:
|
|
temp_dir = None
|
|
try:
|
|
temp_dir = tempfile.mkdtemp(prefix="compile_")
|
|
result = await self._execute(code, input_data, temp_dir)
|
|
return result
|
|
except Exception as e:
|
|
return {
|
|
"success": False,
|
|
"error": f"Compilation error: {str(e)}"
|
|
}
|
|
finally:
|
|
if temp_dir and os.path.exists(temp_dir):
|
|
try:
|
|
shutil.rmtree(temp_dir, ignore_errors=True)
|
|
except:
|
|
pass
|
|
|
|
async def _execute(self, code: str, input_data: str, temp_dir: str) -> Dict[str, Any]:
|
|
raise NotImplementedError("Subclass must implement _execute method")
|
|
|
|
async def _run_process(self, cmd: list, input_data: str = "",
|
|
cwd: Optional[str] = None) -> Dict[str, Any]:
|
|
try:
|
|
process = await asyncio.create_subprocess_exec(
|
|
*cmd,
|
|
stdin=asyncio.subprocess.PIPE,
|
|
stdout=asyncio.subprocess.PIPE,
|
|
stderr=asyncio.subprocess.PIPE,
|
|
cwd=cwd
|
|
)
|
|
|
|
stdout, stderr = await asyncio.wait_for(
|
|
process.communicate(input=input_data.encode() if input_data else None),
|
|
timeout=self.timeout
|
|
)
|
|
|
|
stdout_str = stdout.decode('utf-8', errors='replace')[:self.max_output_size]
|
|
stderr_str = stderr.decode('utf-8', errors='replace')[:self.max_output_size]
|
|
|
|
if process.returncode != 0:
|
|
return {
|
|
"success": False,
|
|
"error": stderr_str or "Execution failed",
|
|
"output": stdout_str
|
|
}
|
|
|
|
return {
|
|
"success": True,
|
|
"output": stdout_str,
|
|
"error": stderr_str if stderr_str else None
|
|
}
|
|
|
|
except asyncio.TimeoutError:
|
|
if 'process' in locals():
|
|
process.kill()
|
|
return {
|
|
"success": False,
|
|
"error": f"Execution timeout ({self.timeout}s exceeded)"
|
|
}
|
|
except Exception as e:
|
|
return {
|
|
"success": False,
|
|
"error": f"Execution error: {str(e)}"
|
|
}
|
|
|
|
def _sanitize_code(self, code: str) -> str:
|
|
# Базовая очистка кода
|
|
dangerous_patterns = [
|
|
"system(", "exec(", "eval(", "__import__",
|
|
"subprocess", "os.system", "popen"
|
|
]
|
|
|
|
for pattern in dangerous_patterns:
|
|
if pattern in code:
|
|
return ""
|
|
|
|
return code
|
|
|
|
def _check_input_requirements(self, code: str) -> Dict[str, Any]:
|
|
# Проверка требований к вводу
|
|
input_keywords = {
|
|
"cpp": ["cin", "scanf", "getline"],
|
|
"python": ["input(", "raw_input"],
|
|
"javascript": ["readline", "prompt"]
|
|
}
|
|
|
|
keywords = input_keywords.get(self.language, [])
|
|
for keyword in keywords:
|
|
if keyword in code:
|
|
return {
|
|
"requiresInput": True,
|
|
"inputDescription": {
|
|
"variables": [
|
|
{
|
|
"name": "input",
|
|
"type": "string",
|
|
"description": "Program input data"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
|
|
return {"requiresInput": False} |