22import subprocess
33import httpx
44import sys
5+ import uuid
6+ import shutil
57from flask import Flask , request , jsonify
68from openai import OpenAI
79from dotenv import load_dotenv
@@ -55,11 +57,13 @@ def echo():
5557 print ("❌ JSON 파싱 실패:" , e )
5658 return "Invalid JSON" , 400
5759
58- # 공통 코드 실행 함수
60+ # 공통 코드 실행 함수 (🔧 격리 디렉터리 + 정리 로직 추가)
5961def execute_code (code , input_data , lang ):
60- base_dir = '/home/ec2-user/Zivorp_Spike/server/code'
61- flask_dir = '/usr/src/app/code'
62- os .makedirs (base_dir , exist_ok = True )
62+ # 호스트 경로(왼쪽) ↔ Flask 컨테이너 경로(오른쪽) 바인드:
63+ # docker-compose.yml: /home/ec2-user/Zivorp_Spike/server/code:/usr/src/app/code
64+ base_dir = '/home/ec2-user/Zivorp_Spike/server/code' # 호스트에서 마운트되는 경로
65+ flask_dir = '/usr/src/app/code' # Flask 컨테이너 내부 경로
66+ os .makedirs (flask_dir , exist_ok = True )
6367
6468 file_map = {
6569 'c' : ('main.c' , 'c-compiler' ),
@@ -70,38 +74,39 @@ def execute_code(code, input_data, lang):
7074 if lang not in file_map :
7175 return None , f"❌ 지원하지 않는 언어입니다: { lang } "
7276
77+ # 🔹 요청별 격리 디렉터리 생성
78+ job_id = f"job-{ uuid .uuid4 ().hex [:12 ]} "
79+ job_dir_flask = os .path .join (flask_dir , job_id ) # 컨테이너 내부 경로
80+ os .makedirs (job_dir_flask , exist_ok = True )
81+
7382 filename , image = file_map [lang ]
74- code_path = os .path .join (flask_dir , filename )
75- input_path = os .path .join (flask_dir , 'input.txt' )
83+ code_path = os .path .join (job_dir_flask , filename )
84+ input_path = os .path .join (job_dir_flask , 'input.txt' )
7685
7786 with open (code_path , 'w' ) as f :
78- f .write (code )
87+ f .write (code or "" )
7988
8089 with open (input_path , 'w' ) as f :
81- f .write (input_data )
90+ f .write (input_data or "" )
8291
92+ # 언어별 실행 커맨드 (작업 디렉터리는 /code/<job_id>)
8393 if lang == 'python' :
84- docker_cmd = [
85- 'docker' , 'run' , '--rm' ,
86- '-v' , f'{ base_dir } :/code' ,
87- '-w' , '/code' , image ,
88- 'python' , filename
89- ]
94+ run_cmd = ['python' , filename ]
9095 elif lang == 'java' :
91- docker_cmd = [
92- 'docker' , 'run' , '--rm' ,
93- '-v ' , f' { base_dir } :/code' ,
94- '-w' , '/code' , image ,
95- 'sh' , '-c' , 'javac Main.java && java Main'
96- ]
97- elif lang == 'c' :
98- docker_cmd = [
99- 'docker ' , 'run' , '--rm ' ,
100- '-v ' , f'{ base_dir } : /code' ,
101- '-w' , '/code' , image ,
102- 'sh' , '-c' , 'gcc main.c -o program && ./program'
103- ]
104-
96+ run_cmd = ['sh' , '-c' , 'javac Main.java && java Main' ]
97+ else : # 'c'
98+ run_cmd = [ 'sh' , '-c ' , 'gcc main.c -o program && ./program' ]
99+
100+ # 🔹 컴파일러 컨테이너에 호스트 base_dir를 /code로 마운트하고
101+ # 작업디렉터리를 /code/<job_id>로 지정하여 격리 실행
102+ docker_cmd = [
103+ 'docker' , 'run' , '--rm' ,
104+ '-v ' , f' { base_dir } :/code ' ,
105+ '-w ' , f'/code/ { job_id } ' ,
106+ # (선택 권장 안전옵션)
107+ # '--network','none','--cpus','1','-m','256m','--pids-limit','128',
108+ image , * run_cmd
109+ ]
105110 print ("🐳 Docker 실행 명령어:" , ' ' .join (docker_cmd ))
106111
107112 try :
@@ -112,16 +117,14 @@ def execute_code(code, input_data, lang):
112117 text = True ,
113118 timeout = 10
114119 )
120+ return result , None
115121 except subprocess .TimeoutExpired :
116- return {
117- "stdout" : "" ,
118- "stderr" : "" ,
119- "exitCode" : - 1 ,
120- "success" : False ,
121- "error" : "⏰ 실행 시간이 초과되었습니다."
122- }, None
123-
124- return result , None
122+ # run_code가 CompletedProcess 형태를 기대하므로 맞춰서 반환
123+ timeout_cp = subprocess .CompletedProcess (docker_cmd , returncode = 124 , stdout = '' , stderr = '⏰ 실행 시간이 초과되었습니다.' )
124+ return timeout_cp , None
125+ finally :
126+ # 🔹 실행 후 항상 격리 디렉터리 정리 (호스트에도 반영됨)
127+ shutil .rmtree (job_dir_flask , ignore_errors = True )
125128
126129@app .route ('/run' , methods = ['POST' ])
127130def run_code ():
@@ -165,7 +168,7 @@ def visualize_code():
165168
166169 try :
167170 data = request .get_json (force = True )
168- print ("✅ JSON 파싱 성공:" , data , flush = True )
171+ print ("✅ JSON 수신 성공:" , data , flush = True )
169172 except Exception as e :
170173 print (f"❌ JSON 파싱 실패: { e } " , flush = True )
171174 return jsonify ({"error" : "JSON 파싱 오류" , "message" : str (e )}), 400
@@ -210,6 +213,5 @@ def visualize_code():
210213 }), 200 if result .returncode == 0 else 400
211214
212215
213-
214216if __name__ == '__main__' :
215217 app .run (host = "0.0.0.0" , port = 5050 )
0 commit comments