ancerlop commited on
Commit
8f10eaa
verified
1 Parent(s): 193e652

First commit

Browse files
Files changed (6) hide show
  1. .env +8 -0
  2. .gitignore +54 -0
  3. Dockerfile +27 -0
  4. README.md +113 -12
  5. app.py +106 -0
  6. requirements.txt +4 -0
.env ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ # Configuraci贸n del servidor
2
+ PORT=5000
3
+
4
+ # Configuraci贸n de seguridad
5
+ MAX_EXECUTION_TIME=5
6
+
7
+ # Configuraci贸n de CORS (para desarrollo)
8
+ CORS_ORIGINS=http://localhost:3000,https://yourusername.github.io
.gitignore ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ env/
8
+ build/
9
+ develop-eggs/
10
+ dist/
11
+ downloads/
12
+ eggs/
13
+ .eggs/
14
+ lib/
15
+ lib64/
16
+ parts/
17
+ sdist/
18
+ var/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual Environment
24
+ venv/
25
+ env/
26
+ ENV/
27
+
28
+ # IDE files
29
+ .idea/
30
+ .vscode/
31
+ *.swp
32
+ *.swo
33
+
34
+ # Logs
35
+ logs/
36
+ *.log
37
+
38
+ # Temporary files
39
+ tmp/
40
+ temp/
41
+
42
+ # Environment variables
43
+ .env.local
44
+ .env.development.local
45
+ .env.test.local
46
+ .env.production.local
47
+
48
+ # Docker
49
+ .dockerignore
50
+
51
+ # Compiled C files
52
+ *.exe
53
+ *.out
54
+ *.app
Dockerfile ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9-slim
2
+
3
+ # Instalar dependencias del sistema
4
+ RUN apt-get update && apt-get install -y \
5
+ gcc \
6
+ && rm -rf /var/lib/apt/lists/*
7
+
8
+ # Crear directorio de trabajo
9
+ WORKDIR /app
10
+
11
+ # Copiar archivos de requisitos
12
+ COPY requirements.txt .
13
+
14
+ # Instalar dependencias de Python
15
+ RUN pip install --no-cache-dir -r requirements.txt
16
+
17
+ # Copiar el c贸digo de la aplicaci贸n
18
+ COPY . .
19
+
20
+ # Crear directorio temporal para archivos de c贸digo
21
+ RUN mkdir -p /tmp/42coderunner
22
+
23
+ # Exponer el puerto
24
+ EXPOSE 5000
25
+
26
+ # Comando para ejecutar la aplicaci贸n
27
+ CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
README.md CHANGED
@@ -1,12 +1,113 @@
1
- ---
2
- title: MargeCode
3
- emoji: 馃殌
4
- colorFrom: indigo
5
- colorTo: pink
6
- sdk: docker
7
- pinned: false
8
- license: mit
9
- short_description: 42 Marge Code Backend
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 42CodeRunner - Backend
2
+
3
+ Este es el backend para 42CodeRunner, un servicio que permite compilar y ejecutar c贸digo C de forma segura a trav茅s de una API REST.
4
+
5
+ ## Requisitos
6
+
7
+ - Python 3.8+
8
+ - GCC (para compilar c贸digo C)
9
+ - Docker (opcional, para ejecutar en contenedor)
10
+
11
+ ## Instalaci贸n
12
+
13
+ ### Instalaci贸n local
14
+
15
+ ```bash
16
+ # Clonar el repositorio
17
+ git clone https://github.com/yourusername/42CodeRunner.git
18
+ cd 42CodeRunner/backend
19
+
20
+ # Crear entorno virtual (opcional pero recomendado)
21
+ python -m venv venv
22
+
23
+ # Activar entorno virtual
24
+ # En Windows
25
+ venv\Scripts\activate
26
+ # En Linux/Mac
27
+ # source venv/bin/activate
28
+
29
+ # Instalar dependencias
30
+ pip install -r requirements.txt
31
+
32
+ # Ejecutar el servidor
33
+ python app.py
34
+ ```
35
+
36
+ El servidor estar谩 disponible en http://localhost:5000
37
+
38
+ ### Instalaci贸n con Docker
39
+
40
+ ```bash
41
+ # Construir la imagen
42
+ docker build -t 42coderunner-backend .
43
+
44
+ # Ejecutar el contenedor
45
+ docker run -p 5000:5000 42coderunner-backend
46
+ ```
47
+
48
+ ## API
49
+
50
+ ### Ejecutar c贸digo C
51
+
52
+ **Endpoint:** `POST /api/execute`
53
+
54
+ **Cuerpo de la solicitud:**
55
+
56
+ ```json
57
+ {
58
+ "code": "#include <stdio.h>\n\nint main() {\n printf(\"Hello, World!\\n\");\n return 0;\n}"
59
+ }
60
+ ```
61
+
62
+ **Respuesta exitosa:**
63
+
64
+ ```json
65
+ {
66
+ "success": true,
67
+ "output": "Hello, World!\n",
68
+ "error": "",
69
+ "execution_time": 0.023
70
+ }
71
+ ```
72
+
73
+ **Respuesta con error:**
74
+
75
+ ```json
76
+ {
77
+ "success": false,
78
+ "error": "main.c:3:5: error: expected ';' before 'printf'"
79
+ }
80
+ ```
81
+
82
+ ### Verificar estado del servicio
83
+
84
+ **Endpoint:** `GET /api/health`
85
+
86
+ **Respuesta:**
87
+
88
+ ```json
89
+ {
90
+ "status": "ok"
91
+ }
92
+ ```
93
+
94
+ ## Seguridad
95
+
96
+ El servicio implementa las siguientes medidas de seguridad:
97
+
98
+ 1. L铆mite de tiempo de ejecuci贸n (5 segundos por defecto)
99
+ 2. Ejecuci贸n en archivos temporales con nombres aleatorios
100
+ 3. Limpieza autom谩tica de archivos temporales
101
+
102
+ ## Despliegue en Hugging Face
103
+
104
+ Para desplegar este servicio en Hugging Face Spaces:
105
+
106
+ 1. Crea un nuevo Space en Hugging Face
107
+ 2. Selecciona Docker como tipo de espacio
108
+ 3. Sube los archivos del backend (incluyendo el Dockerfile)
109
+ 4. Configura el espacio para exponer el puerto 5000
110
+
111
+ ## Licencia
112
+
113
+ MIT
app.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify
2
+ import subprocess
3
+ import os
4
+ import tempfile
5
+ import uuid
6
+ import time
7
+ import logging
8
+ from flask_cors import CORS
9
+
10
+ app = Flask(__name__)
11
+ CORS(app) # Habilitar CORS para todas las rutas
12
+
13
+ # Configuraci贸n de logging
14
+ logging.basicConfig(level=logging.INFO)
15
+ logger = logging.getLogger(__name__)
16
+
17
+ # Directorio temporal para los archivos de c贸digo
18
+ TEMP_DIR = os.path.join(tempfile.gettempdir(), '42coderunner')
19
+ os.makedirs(TEMP_DIR, exist_ok=True)
20
+
21
+ # Tiempo m谩ximo de ejecuci贸n (en segundos)
22
+ MAX_EXECUTION_TIME = 5
23
+
24
+ @app.route('/api/execute', methods=['POST'])
25
+ def execute_code():
26
+ try:
27
+ # Obtener el c贸digo C del request
28
+ data = request.get_json()
29
+ if not data or 'code' not in data:
30
+ return jsonify({'success': False, 'error': 'No se proporcion贸 c贸digo'}), 400
31
+
32
+ code = data['code']
33
+
34
+ # Crear un ID 煤nico para este trabajo
35
+ job_id = str(uuid.uuid4())
36
+
37
+ # Crear archivos temporales para el c贸digo y la salida
38
+ code_file = os.path.join(TEMP_DIR, f"{job_id}.c")
39
+ executable = os.path.join(TEMP_DIR, f"{job_id}.exe")
40
+
41
+ # Guardar el c贸digo en un archivo temporal
42
+ with open(code_file, 'w') as f:
43
+ f.write(code)
44
+
45
+ # Compilar el c贸digo
46
+ logger.info(f"Compilando c贸digo para job {job_id}")
47
+ compile_process = subprocess.run(
48
+ ['gcc', code_file, '-o', executable],
49
+ capture_output=True,
50
+ text=True
51
+ )
52
+
53
+ # Verificar si la compilaci贸n fue exitosa
54
+ if compile_process.returncode != 0:
55
+ return jsonify({
56
+ 'success': False,
57
+ 'error': compile_process.stderr
58
+ })
59
+
60
+ # Ejecutar el c贸digo compilado
61
+ logger.info(f"Ejecutando c贸digo para job {job_id}")
62
+ try:
63
+ start_time = time.time()
64
+ run_process = subprocess.run(
65
+ [executable],
66
+ capture_output=True,
67
+ text=True,
68
+ timeout=MAX_EXECUTION_TIME
69
+ )
70
+ execution_time = time.time() - start_time
71
+
72
+ # Preparar la respuesta
73
+ result = {
74
+ 'success': run_process.returncode == 0,
75
+ 'output': run_process.stdout,
76
+ 'error': run_process.stderr,
77
+ 'execution_time': execution_time
78
+ }
79
+
80
+ except subprocess.TimeoutExpired:
81
+ result = {
82
+ 'success': False,
83
+ 'error': f'La ejecuci贸n excedi贸 el tiempo l铆mite de {MAX_EXECUTION_TIME} segundos'
84
+ }
85
+
86
+ # Limpiar archivos temporales
87
+ try:
88
+ os.remove(code_file)
89
+ if os.path.exists(executable):
90
+ os.remove(executable)
91
+ except Exception as e:
92
+ logger.error(f"Error al limpiar archivos temporales: {e}")
93
+
94
+ return jsonify(result)
95
+
96
+ except Exception as e:
97
+ logger.error(f"Error inesperado: {e}")
98
+ return jsonify({'success': False, 'error': f'Error interno del servidor: {str(e)}'}), 500
99
+
100
+ @app.route('/api/health', methods=['GET'])
101
+ def health_check():
102
+ return jsonify({'status': 'ok'})
103
+
104
+ if __name__ == '__main__':
105
+ port = int(os.environ.get('PORT', 5000))
106
+ app.run(host='0.0.0.0', port=port)
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ flask==2.0.1
2
+ flask-cors==3.0.10
3
+ gunicorn==20.1.0
4
+ python-dotenv==0.19.0