File size: 5,565 Bytes
5d21581
a7a9c2f
c0e8d4b
 
5d21581
 
c0e8d4b
68625cd
5d21581
c0e8d4b
5d21581
 
 
c0e8d4b
5d21581
 
 
 
 
 
 
 
8a0322c
a139f18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8a0322c
 
 
 
a139f18
8a0322c
68625cd
 
8a0322c
 
 
 
 
 
 
68625cd
 
 
8a0322c
68625cd
 
8a0322c
 
 
 
 
 
 
 
68625cd
 
 
 
a139f18
 
 
 
 
 
6888b36
c0e8d4b
7ce9f2f
c0e8d4b
7ce9f2f
c0e8d4b
7ce9f2f
c0e8d4b
7ce9f2f
8a0322c
1ffa464
8a0322c
7ce9f2f
8a0322c
c0e8d4b
 
 
 
 
 
 
5d21581
 
0f6a021
 
 
cfca35b
5d21581
 
 
 
c0e8d4b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5d21581
 
 
 
 
 
c0e8d4b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import sys
import random
import os
import subprocess
from io import StringIO
import contextlib
import tempfile
import requests
from datetime import datetime
from typing import Tuple

@contextlib.contextmanager
def capture_output():
    """Capture stdout and stderr for Python code"""
    stdout, stderr = StringIO(), StringIO()
    old_out, old_err = sys.stdout, sys.stderr
    try:
        sys.stdout, sys.stderr = stdout, stderr
        yield stdout, stderr
    finally:
        sys.stdout, sys.stderr = old_out, old_err

def _execute_with_onecompiler(code: str, stdin: str, language: str, filename: str) -> Tuple[str, str, str]:
    keys = [os.environ["ONECOMPILER_API_KEY"], os.environ["ONECOMPILER_API_KEY1"]]
    first_key = random.choice(keys)

    result = _call_onecompiler_api(first_key, code, stdin, language, filename)
    
    if _is_quota_or_invalid(result):
        # Fallback: try all keys one-by-one until one works
        for key in keys:
            if key == first_key:
                continue  # Already tried this one
            result = _call_onecompiler_api(key, code, stdin, language, filename)
            if not _is_quota_or_invalid(result):
                return result
    
    return result  # Either success, or last failed response


def _call_onecompiler_api(key: str, code: str, stdin: str, language: str, filename: str) -> Tuple[str, str, str]:
    url = "https://onecompiler-apis.p.rapidapi.com/api/v1/run"
    headers = {
        "Content-Type": "application/json",
        "x-rapidapi-host": "onecompiler-apis.p.rapidapi.com",
        "x-rapidapi-key": key
    }
    payload = {
        "language": language.lower(),
        "stdin": stdin,
        "files": [
            {
                "name": filename,
                "content": code
            }
        ]
    }

    try:
        response = requests.post(url, json=payload, headers=headers, timeout=10)
        data = response.json()

        if data.get("status") == "failed":
            return "", "", f"OneCompiler Error: {data.get('error')}"
        
        return (
            data.get("stdout", "").strip(),
            data.get("stderr", "") or "",
            data.get("exception", "")
        )
    except Exception as e:
        return "", "", str(e)


def _is_quota_or_invalid(result: Tuple[str, str, str]) -> bool:
    _, _, error = result
    if not error:
        return False
    return any(token in error.lower() for token in ["quota", "e002", "e003", "invalid", "exhausted"])

def execute_code(code: str, stdin: str = "", language: str = "cpp") -> Tuple[str, str, str]:
    try:
        if language == "Python":
            return _execute_python(code, stdin)
        elif language == "C":
            return _execute_c(code, stdin)
        elif language == "C++":
            return _execute_cpp(code, stdin)
        elif language == "Java":
            return _execute_with_onecompiler(code, stdin, language="java", filename="Main.java")
        elif language == "JavaScript":
            return _execute_with_onecompiler(code, stdin, language="javascript", filename="script.js")
        elif language == "C#":
            return _execute_with_onecompiler(code, stdin, language="csharp", filename="Program.cs")
        else:
            return "", f"Unsupported language: {language}", None
    except Exception as e:
        return "", "", str(e)


def _execute_python(code: str, stdin: str) -> Tuple[str, str, str]:
    with capture_output() as (stdout, stderr):
        try:
            inputs = iter(stdin.splitlines())
            input_override = lambda prompt='': next(inputs, '')
            local_vars = {"input": input_override}
            exec(code, {}, local_vars)
            return stdout.getvalue().strip(), stderr.getvalue().strip(), None
        except Exception as e:
            return stdout.getvalue().strip(), stderr.getvalue().strip(), str(e)


def _run_subprocess(cmd, stdin_input=None) -> Tuple[str, str, str]:
    try:
        result = subprocess.run(
            cmd,
            input=stdin_input.encode() if stdin_input else None,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            timeout=10
        )
        return result.stdout.decode(), result.stderr.decode(), None
    except Exception as e:
        return "", "", str(e)


def _execute_c(code: str, stdin: str):
    with tempfile.TemporaryDirectory() as tmp:
        source_path = os.path.join(tmp, "main.c")
        binary_path = os.path.join(tmp, "main.out")
        with open(source_path, "w") as f:
            f.write(code)
        compile_cmd = ["gcc", source_path, "-o", binary_path]
        compile_out, compile_err, exc = _run_subprocess(compile_cmd)
        if exc or compile_err:
            return compile_out, compile_err, exc
        return _run_subprocess([binary_path], stdin)


def _execute_cpp(code: str, stdin: str):
    with tempfile.TemporaryDirectory() as tmp:
        source_path = os.path.join(tmp, "main.cpp")
        binary_path = os.path.join(tmp, "main.out")
        with open(source_path, "w") as f:
            f.write(code)
        compile_cmd = ["g++", source_path, "-o", binary_path]
        compile_out, compile_err, exc = _run_subprocess(compile_cmd)
        if exc or compile_err:
            return compile_out, compile_err, exc
        return _run_subprocess([binary_path], stdin)


def export_session(code: str, output: str, error: str) -> dict:
    return {
        "timestamp": datetime.now().isoformat(),
        "code": code,
        "output": output,
        "error": error
    }