Spaces:
Sleeping
Sleeping
fix
Browse files
app.py
CHANGED
|
@@ -104,16 +104,40 @@ def get_devices():
|
|
| 104 |
"""장치 목록 조회"""
|
| 105 |
global SERVER_URL
|
| 106 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
if not SERVER_URL:
|
| 108 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
|
| 110 |
-
|
| 111 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
loading_html += f"<p>이 작업은 최대 {REQUEST_TIMEOUT}초가 소요될 수 있습니다.</p>"
|
| 116 |
-
loading_html += "</div>"
|
| 117 |
|
| 118 |
try:
|
| 119 |
# 타임아웃 증가 및 헤더 추가
|
|
@@ -124,12 +148,15 @@ def get_devices():
|
|
| 124 |
"Connection": "keep-alive"
|
| 125 |
}
|
| 126 |
|
|
|
|
| 127 |
response = session.get(
|
| 128 |
f"{SERVER_URL}/api/devices",
|
| 129 |
headers=headers,
|
| 130 |
timeout=REQUEST_TIMEOUT
|
| 131 |
)
|
| 132 |
|
|
|
|
|
|
|
| 133 |
if response.status_code == 200:
|
| 134 |
result_json = response.json()
|
| 135 |
devices = result_json.get("devices", [])
|
|
@@ -179,64 +206,121 @@ def get_devices():
|
|
| 179 |
return error_html, []
|
| 180 |
except RequestException as e:
|
| 181 |
# 오류 상세 로그
|
| 182 |
-
print(f"
|
| 183 |
error_type = type(e).__name__
|
| 184 |
error_detail = str(e)
|
| 185 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 186 |
# 타임아웃일 경우 더 상세한 오류 메시지
|
| 187 |
if "timeout" in error_detail.lower() or "timed out" in error_detail.lower():
|
| 188 |
error_html = f"<div style='padding: 15px; background-color: #f8d7da; border-radius: 5px; border-left: 5px solid #dc3545;'>"
|
| 189 |
error_html += f"<h3 style='margin-top: 0; color: #721c24;'>장치 목록 조회 타임아웃</h3>"
|
| 190 |
error_html += f"<p>서버가 {REQUEST_TIMEOUT}초 내에 응답하지 않았습니다.</p>"
|
| 191 |
-
error_html += f"<p
|
| 192 |
-
error_html += f"<
|
| 193 |
-
error_html += f"<
|
| 194 |
-
error_html += f"<li>서버가 많은 장치 목록을 처리하는 중입니다.</li>"
|
| 195 |
-
error_html += f"<li>네트워크 연결이 불안정합니다.</li>"
|
| 196 |
-
error_html += f"</ul>"
|
| 197 |
-
error_html += f"<p><strong>해결 방법:</strong></p>"
|
| 198 |
-
error_html += f"<ol>"
|
| 199 |
-
error_html += f"<li>한번 더 시도해보세요.</li>"
|
| 200 |
-
error_html += f"<li>서버 연결 상태를 다시 확인하고 다시 연결해보세요.</li>"
|
| 201 |
-
error_html += f"<li>ngrok을 다시 시작하고 새 URL로 연결해보세요.</li>"
|
| 202 |
-
error_html += f"</ol>"
|
| 203 |
-
error_html += f"<p><strong>오류 상세 정보:</strong> {error_type} - {error_detail}</p>"
|
| 204 |
error_html += "</div>"
|
| 205 |
else:
|
| 206 |
error_html = f"<div style='padding: 15px; background-color: #f8d7da; border-radius: 5px; border-left: 5px solid #dc3545;'>"
|
| 207 |
error_html += f"<h3 style='margin-top: 0; color: #721c24;'>장치 목록 조회 중 오류 발생</h3>"
|
| 208 |
error_html += f"<p>{str(e)}</p>"
|
| 209 |
error_html += f"<p><strong>오류 유형:</strong> {error_type}</p>"
|
| 210 |
-
error_html += f"<p
|
| 211 |
-
error_html += f"<
|
| 212 |
-
error_html += f"<li>서버 응답 시간이 너무 깃니다. 서버가 혼잡한지 확인하세요.</li>"
|
| 213 |
-
error_html += f"<li>네트워크 연결이 불안정합니다.</li>"
|
| 214 |
-
error_html += f"<li>ngrok 세션이 만료되었습니다. 서버를 다시 시작해보세요.</li>"
|
| 215 |
-
error_html += f"</ul>"
|
| 216 |
-
error_html += f"<p><strong>해결 방법:</strong> 서버를 다시 시작하거나, 새로운 ngrok 세션을 생성한 후 다시 연결해보세요.</p>"
|
| 217 |
error_html += "</div>"
|
| 218 |
|
| 219 |
-
return error_html,
|
| 220 |
|
| 221 |
def get_device_info(device_id):
|
| 222 |
"""장치 상세 정보 조회"""
|
| 223 |
global SERVER_URL
|
| 224 |
|
| 225 |
-
|
| 226 |
-
|
| 227 |
|
| 228 |
if not device_id:
|
| 229 |
return "장치를 선택해주세요."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
|
| 231 |
-
|
| 232 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 233 |
|
| 234 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 235 |
response = session.get(
|
| 236 |
f"{SERVER_URL}/api/device/{device_id}/info",
|
|
|
|
| 237 |
timeout=REQUEST_TIMEOUT
|
| 238 |
)
|
| 239 |
|
|
|
|
|
|
|
| 240 |
if response.status_code == 200:
|
| 241 |
result_json = response.json()
|
| 242 |
device_info = result_json.get("device_info", {})
|
|
@@ -281,68 +365,86 @@ def get_device_info(device_id):
|
|
| 281 |
error_html += "</div>"
|
| 282 |
return error_html
|
| 283 |
except RequestException as e:
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 288 |
return error_html
|
| 289 |
|
| 290 |
def get_programs():
|
| 291 |
"""프로그램 목록 조회"""
|
| 292 |
global SERVER_URL
|
| 293 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 294 |
if not SERVER_URL:
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
# 디버그 정보 기록 - 여기서 모든 오류 상황을 축적해보자
|
| 298 |
-
print(f"[DEBUG] 시작: 프로그램 목록 조회 시도 - {SERVER_URL}/api/programs")
|
| 299 |
-
|
| 300 |
-
try:
|
| 301 |
-
# 임시 테스트 - 응답을 시뮬레이션해보자
|
| 302 |
-
print(f"[DEBUG] 헤더 구성 및 요청 준비 중")
|
| 303 |
-
|
| 304 |
-
# 헤더 추가
|
| 305 |
-
headers = {
|
| 306 |
-
"User-Agent": "LocalPCAgent-Client/1.0",
|
| 307 |
-
"Accept": "application/json",
|
| 308 |
-
"Cache-Control": "no-cache",
|
| 309 |
-
"Connection": "keep-alive"
|
| 310 |
-
}
|
| 311 |
-
|
| 312 |
-
# ���롭다운 배열 설정 오류 테스트
|
| 313 |
test_programs = [
|
| 314 |
{"id": "test1", "name": "테스트 프로그램 1", "description": "테스트 설명 1", "path": "C:\\test\\program1.exe"},
|
| 315 |
{"id": "test2", "name": "테스트 프로그램 2", "description": "테스트 설명 2", "path": "C:\\test\\program2.exe"}
|
| 316 |
]
|
| 317 |
|
| 318 |
-
#
|
| 319 |
-
print(f"[DEBUG] 테스트 데이터 생성 완료")
|
| 320 |
-
|
| 321 |
-
# 프로그램 목록을 바로 만들기
|
| 322 |
program_options = []
|
| 323 |
for program in test_programs:
|
| 324 |
program_id = program.get("id", "")
|
| 325 |
program_name = program.get("name", "Unknown Program")
|
| 326 |
program_desc = program.get("description", "")
|
| 327 |
-
|
| 328 |
-
program_options.append(entry)
|
| 329 |
-
print(f"[DEBUG] 드롭다운 옵션 추가: {entry}")
|
| 330 |
|
| 331 |
# 디버그 정보 추가
|
| 332 |
-
print(f"[DEBUG] 프로그램
|
| 333 |
|
| 334 |
# HTML 생성
|
| 335 |
-
html_output = "<div style='padding:
|
| 336 |
-
html_output += "<
|
| 337 |
-
html_output += "<
|
| 338 |
-
|
| 339 |
-
html_output += f"<li><strong>{program['name']}</strong> - {program['description']}</li>"
|
| 340 |
-
html_output += "</ul>"
|
| 341 |
html_output += "</div>"
|
| 342 |
|
| 343 |
-
print(f"[DEBUG] HTML 생성 완료, 결과 반환 준비 완료")
|
| 344 |
return html_output, program_options
|
| 345 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 346 |
if response.status_code == 200:
|
| 347 |
result_json = response.json()
|
| 348 |
programs = result_json.get("programs", [])
|
|
@@ -391,28 +493,34 @@ def get_programs():
|
|
| 391 |
return error_html, []
|
| 392 |
except RequestException as e:
|
| 393 |
# 오류 상세 로그
|
| 394 |
-
print(f"
|
| 395 |
error_type = type(e).__name__
|
| 396 |
error_detail = str(e)
|
| 397 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 398 |
# 타임아웃일 경우 더 상세한 오류 메시지
|
| 399 |
if "timeout" in error_detail.lower() or "timed out" in error_detail.lower():
|
| 400 |
error_html = f"<div style='padding: 15px; background-color: #f8d7da; border-radius: 5px; border-left: 5px solid #dc3545;'>"
|
| 401 |
error_html += f"<h3 style='margin-top: 0; color: #721c24;'>프로그램 목록 조회 ��임아웃</h3>"
|
| 402 |
error_html += f"<p>서버가 {REQUEST_TIMEOUT}초 내에 응답하지 않았습니다.</p>"
|
| 403 |
-
error_html += f"<p
|
| 404 |
-
error_html += f"<
|
| 405 |
-
error_html += f"<
|
| 406 |
-
error_html += f"<li>서버가 매우 많은 프로그램 목록을 처리하는 중입니다.</li>"
|
| 407 |
-
error_html += f"<li>네트워크 연결이 불안정합니다.</li>"
|
| 408 |
-
error_html += f"</ul>"
|
| 409 |
-
error_html += f"<p><strong>해결 방법:</strong></p>"
|
| 410 |
-
error_html += f"<ol>"
|
| 411 |
-
error_html += f"<li>한번 더 시도해보세요.</li>"
|
| 412 |
-
error_html += f"<li>서버 연결 상태를 다시 확인하고 다시 연결해보세요.</li>"
|
| 413 |
-
error_html += f"<li>ngrok을 다시 시작하고 새 URL로 연결해보세요.</li>"
|
| 414 |
-
error_html += f"</ol>"
|
| 415 |
-
error_html += f"<p><strong>오류 상세 정보:</strong> {error_type} - {error_detail}</p>"
|
| 416 |
error_html += "</div>"
|
| 417 |
else:
|
| 418 |
error_html = f"<div style='padding: 15px; background-color: #f8d7da; border-radius: 5px; border-left: 5px solid #dc3545;'>"
|
|
@@ -420,22 +528,42 @@ def get_programs():
|
|
| 420 |
error_html += f"<p>{str(e)}</p>"
|
| 421 |
error_html += f"<p><strong>오류 유형:</strong> {error_type}</p>"
|
| 422 |
error_html += f"<p><strong>해결 방법:</strong> 서버 연결을 확인하고 다시 시도해보세요.</p>"
|
|
|
|
| 423 |
error_html += "</div>"
|
| 424 |
|
| 425 |
-
return error_html,
|
| 426 |
|
| 427 |
def execute_program(program_id):
|
| 428 |
"""프로그램 실행"""
|
| 429 |
global SERVER_URL
|
| 430 |
|
| 431 |
-
|
| 432 |
-
|
| 433 |
|
| 434 |
if not program_id:
|
| 435 |
return "프로그램을 선택해주세요."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 436 |
|
| 437 |
# 디버그 정보 기록
|
| 438 |
-
print(f"
|
| 439 |
|
| 440 |
try:
|
| 441 |
# 로딩 표시
|
|
@@ -450,6 +578,7 @@ def execute_program(program_id):
|
|
| 450 |
"Content-Type": "application/json"
|
| 451 |
}
|
| 452 |
|
|
|
|
| 453 |
response = session.post(
|
| 454 |
f"{SERVER_URL}/api/programs/{program_id}/execute",
|
| 455 |
headers=headers,
|
|
@@ -457,6 +586,8 @@ def execute_program(program_id):
|
|
| 457 |
timeout=REQUEST_TIMEOUT
|
| 458 |
)
|
| 459 |
|
|
|
|
|
|
|
| 460 |
if response.status_code == 200:
|
| 461 |
result = response.json()
|
| 462 |
|
|
@@ -483,11 +614,26 @@ def execute_program(program_id):
|
|
| 483 |
|
| 484 |
return html_output
|
| 485 |
except RequestException as e:
|
| 486 |
-
# 오류
|
| 487 |
-
|
| 488 |
-
|
| 489 |
-
|
| 490 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 491 |
|
| 492 |
return html_output
|
| 493 |
|
|
|
|
| 104 |
"""장치 목록 조회"""
|
| 105 |
global SERVER_URL
|
| 106 |
|
| 107 |
+
# 디버그 정보 기록
|
| 108 |
+
print(f"[DEBUG] 장치 목록 조회 함수 시작")
|
| 109 |
+
|
| 110 |
+
# 서버 URL이 없을 경우 테스트 데이터 사용
|
| 111 |
if not SERVER_URL:
|
| 112 |
+
print(f"[DEBUG] 서버 URL이 설정되지 않았습니다. 테스트 데이터를 사용합니다.")
|
| 113 |
+
# 테스트 장치 데이터
|
| 114 |
+
test_devices = [
|
| 115 |
+
{"id": "device1", "name": "테스트 PC", "type": "PC", "status": "online"},
|
| 116 |
+
{"id": "device2", "name": "테스트 모바일", "type": "Mobile", "status": "online"}
|
| 117 |
+
]
|
| 118 |
|
| 119 |
+
# 테스트 드롭다운 옵션 생성
|
| 120 |
+
device_options = []
|
| 121 |
+
for device in test_devices:
|
| 122 |
+
device_id = device.get("id", "")
|
| 123 |
+
device_name = device.get("name", "Unknown Device")
|
| 124 |
+
device_type = device.get("type", "Unknown")
|
| 125 |
+
device_options.append((f"{device_name} ({device_type})", device_id))
|
| 126 |
+
|
| 127 |
+
# 디버그 정보 추가
|
| 128 |
+
print(f"[DEBUG] 테스트 장치 옵션: {device_options}")
|
| 129 |
+
|
| 130 |
+
# HTML 생성
|
| 131 |
+
html_output = "<div style='padding: 15px; background-color: #fffaeb; border-radius: 5px; border-left: 5px solid #ffcc00;'>"
|
| 132 |
+
html_output += "<h3 style='margin-top: 0; color: #856404;'>서버 연결 필요</h3>"
|
| 133 |
+
html_output += "<p>서버에 연결되지 않았습니다. 먼저 페이지 상단의 '서버 연결' 탭에서 ngrok URL을 입력하고 연결하세요.</p>"
|
| 134 |
+
html_output += "<p>* 테스트용 장치 목록이 생성되었으니 테스트를 진행해보세요.</p>"
|
| 135 |
+
html_output += "</div>"
|
| 136 |
+
|
| 137 |
+
return html_output, device_options
|
| 138 |
|
| 139 |
+
# 서버 URL이 있는 경우 API 호출
|
| 140 |
+
print(f"[DEBUG] 서버 URL이 있습니다. API 호출을 시도합니다: {SERVER_URL}/api/devices")
|
|
|
|
|
|
|
| 141 |
|
| 142 |
try:
|
| 143 |
# 타임아웃 증가 및 헤더 추가
|
|
|
|
| 148 |
"Connection": "keep-alive"
|
| 149 |
}
|
| 150 |
|
| 151 |
+
print(f"[DEBUG] API 요청 전송 - 타임아웃: {REQUEST_TIMEOUT}")
|
| 152 |
response = session.get(
|
| 153 |
f"{SERVER_URL}/api/devices",
|
| 154 |
headers=headers,
|
| 155 |
timeout=REQUEST_TIMEOUT
|
| 156 |
)
|
| 157 |
|
| 158 |
+
print(f"[DEBUG] API 응답 받음 - 상태코드: {response.status_code}")
|
| 159 |
+
|
| 160 |
if response.status_code == 200:
|
| 161 |
result_json = response.json()
|
| 162 |
devices = result_json.get("devices", [])
|
|
|
|
| 206 |
return error_html, []
|
| 207 |
except RequestException as e:
|
| 208 |
# 오류 상세 로그
|
| 209 |
+
print(f"[DEBUG] 장치 목록 조회 중 오류: {str(e)}")
|
| 210 |
error_type = type(e).__name__
|
| 211 |
error_detail = str(e)
|
| 212 |
|
| 213 |
+
# 테스트 드롭다운 데이터 생성 (오류 시에도 테스트 가능하게)
|
| 214 |
+
test_devices = [
|
| 215 |
+
{"id": "device1", "name": "테스트 PC", "type": "PC", "status": "offline"},
|
| 216 |
+
{"id": "device2", "name": "테스트 모바일", "type": "Mobile", "status": "offline"}
|
| 217 |
+
]
|
| 218 |
+
|
| 219 |
+
# 드롭다운 옵션 생성
|
| 220 |
+
device_options = []
|
| 221 |
+
for device in test_devices:
|
| 222 |
+
device_id = device.get("id", "")
|
| 223 |
+
device_name = device.get("name", "Unknown Device")
|
| 224 |
+
device_type = device.get("type", "Unknown")
|
| 225 |
+
device_options.append((f"{device_name} ({device_type})", device_id))
|
| 226 |
+
|
| 227 |
+
print(f"[DEBUG] 테스트 용 장치 옵션 추가: {device_options}")
|
| 228 |
+
|
| 229 |
# 타임아웃일 경우 더 상세한 오류 메시지
|
| 230 |
if "timeout" in error_detail.lower() or "timed out" in error_detail.lower():
|
| 231 |
error_html = f"<div style='padding: 15px; background-color: #f8d7da; border-radius: 5px; border-left: 5px solid #dc3545;'>"
|
| 232 |
error_html += f"<h3 style='margin-top: 0; color: #721c24;'>장치 목록 조회 타임아웃</h3>"
|
| 233 |
error_html += f"<p>서버가 {REQUEST_TIMEOUT}초 내에 응답하지 않았습니다.</p>"
|
| 234 |
+
error_html += f"<p><strong>해결 방법:</strong> 서버 연결을 다시 확인하고, ngrok을 다시 시작해보세요.</p>"
|
| 235 |
+
error_html += f"<p><strong>오류 정보:</strong> {error_type} - {error_detail}</p>"
|
| 236 |
+
error_html += f"<p style='margin-top: 15px;'><strong>테스트 모드:</strong> 임시 테스트용 데이터가 로드되었습니다. 장치 정보 해붙기가 가능하도록 드롭다운이 테스트 데이터로 채워졌습니다.</p>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 237 |
error_html += "</div>"
|
| 238 |
else:
|
| 239 |
error_html = f"<div style='padding: 15px; background-color: #f8d7da; border-radius: 5px; border-left: 5px solid #dc3545;'>"
|
| 240 |
error_html += f"<h3 style='margin-top: 0; color: #721c24;'>장치 목록 조회 중 오류 발생</h3>"
|
| 241 |
error_html += f"<p>{str(e)}</p>"
|
| 242 |
error_html += f"<p><strong>오류 유형:</strong> {error_type}</p>"
|
| 243 |
+
error_html += f"<p><strong>해결 방법:</strong> 서버 연결을 확인하고 다시 시도해보세요.</p>"
|
| 244 |
+
error_html += f"<p style='margin-top: 15px;'><strong>테스트 모드:</strong> 임시 테스트용 데이터가 로드되었습니다. 장치 정보 해붙기가 가능하도록 드롭다운이 테스트 데이터로 채워졌습니다.</p>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 245 |
error_html += "</div>"
|
| 246 |
|
| 247 |
+
return error_html, device_options
|
| 248 |
|
| 249 |
def get_device_info(device_id):
|
| 250 |
"""장치 상세 정보 조회"""
|
| 251 |
global SERVER_URL
|
| 252 |
|
| 253 |
+
# 디버그 정보 기록
|
| 254 |
+
print(f"[DEBUG] 장치 상세 정보 조회 시도: {device_id}")
|
| 255 |
|
| 256 |
if not device_id:
|
| 257 |
return "장치를 선택해주세요."
|
| 258 |
+
|
| 259 |
+
# 테스트 데이터 확인 (테스트 데이터의 경우 테스트 정보 반환)
|
| 260 |
+
if device_id.startswith("device"):
|
| 261 |
+
print(f"[DEBUG] 테스트 장치 확인됨. 테스트 모드로 정보 생성")
|
| 262 |
+
# 장치 정보 HTML 테이블로 표시
|
| 263 |
+
html_output = "<div style='max-height: 400px; overflow-y: auto;'>"
|
| 264 |
+
html_output += "<h3 style='margin-top: 0;'>테스트 장치 정보</h3>"
|
| 265 |
+
html_output += "<div style='padding: 10px; background-color: #e6f7ff; border-radius: 5px; margin-bottom: 10px;'>"
|
| 266 |
+
html_output += "<p style='margin: 0;'><strong>주의:</strong> 현재 테스트 모드입니다. 실제 서버에 연결하려면 페이지 상단의 '서버 연결' 탭에서 ngrok URL을 입력하고 연결하세요.</p>"
|
| 267 |
+
html_output += "</div>"
|
| 268 |
+
html_output += "<table style='width: 100%; border-collapse: collapse;'>"
|
| 269 |
|
| 270 |
+
# 기본 정보
|
| 271 |
+
html_output += "<tr style='background-color: #f2f2f2;'><th colspan='2' style='padding: 8px; text-align: left; border-bottom: 1px solid #ddd;'>기본 정보</th></tr>"
|
| 272 |
+
|
| 273 |
+
# 테스트 기존 정보
|
| 274 |
+
if device_id == "device1":
|
| 275 |
+
device_info = {"name": "테스트 PC", "type": "PC", "status": "offline", "details": {"ip": "192.168.0.100", "os": "Windows 10", "cpu": "Intel Core i5"}}
|
| 276 |
+
else:
|
| 277 |
+
device_info = {"name": "테스트 모바일", "type": "Mobile", "status": "offline", "details": {"ip": "192.168.0.101", "os": "Android 12", "model": "Galaxy S21"}}
|
| 278 |
+
|
| 279 |
+
# 기본 정보 표시
|
| 280 |
+
for key in ['name', 'type', 'status']:
|
| 281 |
+
if key in device_info:
|
| 282 |
+
html_output += f"<tr style='border-bottom: 1px solid #ddd;'>"
|
| 283 |
+
html_output += f"<td style='padding: 8px; font-weight: bold; width: 30%;'>{key.capitalize()}</td>"
|
| 284 |
+
html_output += f"<td style='padding: 8px;'>{device_info.get(key, '')}</td>"
|
| 285 |
+
html_output += "</tr>"
|
| 286 |
+
|
| 287 |
+
# 상세 정보가 있으면 추가
|
| 288 |
+
if 'details' in device_info and isinstance(device_info['details'], dict):
|
| 289 |
+
html_output += "<tr style='background-color: #f2f2f2;'><th colspan='2' style='padding: 8px; text-align: left; border-bottom: 1px solid #ddd;'>상세 정보</th></tr>"
|
| 290 |
+
for key, value in device_info['details'].items():
|
| 291 |
+
html_output += f"<tr style='border-bottom: 1px solid #ddd;'>"
|
| 292 |
+
html_output += f"<td style='padding: 8px; font-weight: bold; width: 30%;'>{key.upper()}</td>"
|
| 293 |
+
html_output += f"<td style='padding: 8px;'>{value}</td>"
|
| 294 |
+
html_output += "</tr>"
|
| 295 |
+
|
| 296 |
+
html_output += "</table></div>"
|
| 297 |
+
return html_output
|
| 298 |
+
|
| 299 |
+
if not SERVER_URL:
|
| 300 |
+
# 서버 URL이 없을 경우 오류 메시지 반환
|
| 301 |
+
html_output = "<div style='padding: 15px; background-color: #fff3cd; border-radius: 5px; border-left: 5px solid #ffc107;'>"
|
| 302 |
+
html_output += "<h3 style='margin-top: 0; color: #856404;'>서버 연결 필요</h3>"
|
| 303 |
+
html_output += "장치 정보를 조회하려면 먼저 서버에 연결해야 합니다. 페이지 상단의 '서버 연결' 탭에서 ngrok URL을 입력하고 연결하세요."
|
| 304 |
+
html_output += "</div>"
|
| 305 |
+
return html_output
|
| 306 |
|
| 307 |
try:
|
| 308 |
+
# API 요청 전송
|
| 309 |
+
print(f"[DEBUG] API 요청 전송 - 타임아웃: {REQUEST_TIMEOUT}")
|
| 310 |
+
headers = {
|
| 311 |
+
"User-Agent": "LocalPCAgent-Client/1.0",
|
| 312 |
+
"Accept": "application/json",
|
| 313 |
+
"Cache-Control": "no-cache"
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
response = session.get(
|
| 317 |
f"{SERVER_URL}/api/device/{device_id}/info",
|
| 318 |
+
headers=headers,
|
| 319 |
timeout=REQUEST_TIMEOUT
|
| 320 |
)
|
| 321 |
|
| 322 |
+
print(f"[DEBUG] API 응답 받음 - 상태코드: {response.status_code}")
|
| 323 |
+
|
| 324 |
if response.status_code == 200:
|
| 325 |
result_json = response.json()
|
| 326 |
device_info = result_json.get("device_info", {})
|
|
|
|
| 365 |
error_html += "</div>"
|
| 366 |
return error_html
|
| 367 |
except RequestException as e:
|
| 368 |
+
# 오류 상세 로그
|
| 369 |
+
print(f"[DEBUG] 장치 정보 조회 중 오류: {str(e)}")
|
| 370 |
+
error_type = type(e).__name__
|
| 371 |
+
error_detail = str(e)
|
| 372 |
+
|
| 373 |
+
# 타임아웃 오류 확인
|
| 374 |
+
if "timeout" in error_detail.lower() or "timed out" in error_detail.lower():
|
| 375 |
+
error_html = "<div style='padding: 15px; background-color: #f8d7da; border-radius: 5px; border-left: 5px solid #dc3545;'>"
|
| 376 |
+
error_html += f"<h3 style='margin-top: 0; color: #721c24;'>장치 정보 조회 타임아웃</h3>"
|
| 377 |
+
error_html += f"<p>서버가 {REQUEST_TIMEOUT}초 내에 응답하지 않았습니다.</p>"
|
| 378 |
+
error_html += f"<p><strong>해결 방법:</strong> 서버 연결을 다시 확인하고, ngrok을 다시 시작해보세요.</p>"
|
| 379 |
+
error_html += "</div>"
|
| 380 |
+
else:
|
| 381 |
+
error_html = "<div style='padding: 15px; background-color: #f8d7da; border-radius: 5px; border-left: 5px solid #dc3545;'>"
|
| 382 |
+
error_html += f"<h3 style='margin-top: 0; color: #721c24;'>장치 정보 조회 중 오류 발생</h3>"
|
| 383 |
+
error_html += f"<p>{str(e)}</p>"
|
| 384 |
+
error_html += f"<p><strong>오류 유형:</strong> {error_type}</p>"
|
| 385 |
+
error_html += f"<p><strong>해결 방법:</strong> 서버 연결을 확인하고 다시 시도해보세요.</p>"
|
| 386 |
+
error_html += "</div>"
|
| 387 |
+
|
| 388 |
return error_html
|
| 389 |
|
| 390 |
def get_programs():
|
| 391 |
"""프로그램 목록 조회"""
|
| 392 |
global SERVER_URL
|
| 393 |
|
| 394 |
+
# 디버그 정보 기록
|
| 395 |
+
print(f"[DEBUG] 프로그램 목록 조회 함수 시작")
|
| 396 |
+
|
| 397 |
+
# 서버 URL이 없을 경우 테스트 데이터 사용
|
| 398 |
if not SERVER_URL:
|
| 399 |
+
print(f"[DEBUG] 서버 URL이 설정되지 않았습니다. 테스트 데이터를 사용합니다.")
|
| 400 |
+
# 테스트 프로그램 데이터
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 401 |
test_programs = [
|
| 402 |
{"id": "test1", "name": "테스트 프로그램 1", "description": "테스트 설명 1", "path": "C:\\test\\program1.exe"},
|
| 403 |
{"id": "test2", "name": "테스트 프로그램 2", "description": "테스트 설명 2", "path": "C:\\test\\program2.exe"}
|
| 404 |
]
|
| 405 |
|
| 406 |
+
# 테스트 드롭다운 옵션 생성
|
|
|
|
|
|
|
|
|
|
| 407 |
program_options = []
|
| 408 |
for program in test_programs:
|
| 409 |
program_id = program.get("id", "")
|
| 410 |
program_name = program.get("name", "Unknown Program")
|
| 411 |
program_desc = program.get("description", "")
|
| 412 |
+
program_options.append((f"{program_name} - {program_desc}", program_id))
|
|
|
|
|
|
|
| 413 |
|
| 414 |
# 디버그 정보 추가
|
| 415 |
+
print(f"[DEBUG] 테스트 프로그램 옵션: {program_options}")
|
| 416 |
|
| 417 |
# HTML 생성
|
| 418 |
+
html_output = "<div style='padding: 15px; background-color: #fffaeb; border-radius: 5px; border-left: 5px solid #ffcc00;'>"
|
| 419 |
+
html_output += "<h3 style='margin-top: 0; color: #856404;'>서버 연결 필요</h3>"
|
| 420 |
+
html_output += "<p>서버에 연결되지 않았습니다. 먼저 페이지 상단의 '서버 연결' 탭에서 ngrok URL을 입력하고 연결하세요.</p>"
|
| 421 |
+
html_output += "<p>* 테스트용 프로그램 목록이 생성되었으니 테스트를 진행해보세요.</p>"
|
|
|
|
|
|
|
| 422 |
html_output += "</div>"
|
| 423 |
|
|
|
|
| 424 |
return html_output, program_options
|
| 425 |
|
| 426 |
+
# 서버 URL이 있는 경우 API 호출
|
| 427 |
+
print(f"[DEBUG] 서버 URL이 있습니다. API 호출을 시도합니다: {SERVER_URL}/api/programs")
|
| 428 |
+
|
| 429 |
+
try:
|
| 430 |
+
# 헤더 추가
|
| 431 |
+
headers = {
|
| 432 |
+
"User-Agent": "LocalPCAgent-Client/1.0",
|
| 433 |
+
"Accept": "application/json",
|
| 434 |
+
"Cache-Control": "no-cache",
|
| 435 |
+
"Connection": "keep-alive"
|
| 436 |
+
}
|
| 437 |
+
|
| 438 |
+
# API 요청 실행
|
| 439 |
+
print(f"[DEBUG] API 요청 시도 - 타임아웃: {REQUEST_TIMEOUT}")
|
| 440 |
+
response = session.get(
|
| 441 |
+
f"{SERVER_URL}/api/programs",
|
| 442 |
+
headers=headers,
|
| 443 |
+
timeout=REQUEST_TIMEOUT
|
| 444 |
+
)
|
| 445 |
+
|
| 446 |
+
print(f"[DEBUG] API 응답 받음 - 상태코드: {response.status_code}")
|
| 447 |
+
|
| 448 |
if response.status_code == 200:
|
| 449 |
result_json = response.json()
|
| 450 |
programs = result_json.get("programs", [])
|
|
|
|
| 493 |
return error_html, []
|
| 494 |
except RequestException as e:
|
| 495 |
# 오류 상세 로그
|
| 496 |
+
print(f"[DEBUG] API 요청 오류: {str(e)}")
|
| 497 |
error_type = type(e).__name__
|
| 498 |
error_detail = str(e)
|
| 499 |
|
| 500 |
+
# 테스트 드롭다운 데이터 생성 (오류 시에도 테스트 가능하게)
|
| 501 |
+
test_programs = [
|
| 502 |
+
{"id": "test1", "name": "테스트 프로그램 1", "description": "테스트 설명 1", "path": "C:\\test\\program1.exe"},
|
| 503 |
+
{"id": "test2", "name": "테스트 프로그램 2", "description": "테스트 설명 2", "path": "C:\\test\\program2.exe"}
|
| 504 |
+
]
|
| 505 |
+
|
| 506 |
+
# 드롭다운 옵션 생성
|
| 507 |
+
program_options = []
|
| 508 |
+
for program in test_programs:
|
| 509 |
+
program_id = program.get("id", "")
|
| 510 |
+
program_name = program.get("name", "Unknown Program")
|
| 511 |
+
program_desc = program.get("description", "")
|
| 512 |
+
program_options.append((f"{program_name} - {program_desc}", program_id))
|
| 513 |
+
|
| 514 |
+
print(f"[DEBUG] 테스트 용 드롭다운 옵션 추가: {program_options}")
|
| 515 |
+
|
| 516 |
# 타임아웃일 경우 더 상세한 오류 메시지
|
| 517 |
if "timeout" in error_detail.lower() or "timed out" in error_detail.lower():
|
| 518 |
error_html = f"<div style='padding: 15px; background-color: #f8d7da; border-radius: 5px; border-left: 5px solid #dc3545;'>"
|
| 519 |
error_html += f"<h3 style='margin-top: 0; color: #721c24;'>프로그램 목록 조회 ��임아웃</h3>"
|
| 520 |
error_html += f"<p>서버가 {REQUEST_TIMEOUT}초 내에 응답하지 않았습니다.</p>"
|
| 521 |
+
error_html += f"<p><strong>해결 방법:</strong> 서버 연결을 다시 확인하고, ngrok을 다시 시작해보세요.</p>"
|
| 522 |
+
error_html += f"<p><strong>오류 정보:</strong> {error_type} - {error_detail}</p>"
|
| 523 |
+
error_html += f"<p style='margin-top: 15px;'><strong>테스트 모드:</strong> 임시 테스트용 데이터가 로드되었습니다. 프로그램 실행 해붙기가 가능하도록 드롭다운이 테스트 데이터로 채워졌습니다.</p>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 524 |
error_html += "</div>"
|
| 525 |
else:
|
| 526 |
error_html = f"<div style='padding: 15px; background-color: #f8d7da; border-radius: 5px; border-left: 5px solid #dc3545;'>"
|
|
|
|
| 528 |
error_html += f"<p>{str(e)}</p>"
|
| 529 |
error_html += f"<p><strong>오류 유형:</strong> {error_type}</p>"
|
| 530 |
error_html += f"<p><strong>해결 방법:</strong> 서버 연결을 확인하고 다시 시도해보세요.</p>"
|
| 531 |
+
error_html += f"<p style='margin-top: 15px;'><strong>테스트 모드:</strong> 임시 테스트용 데이터가 로드되었습니다. 프로그램 실행 해붙기가 가능하도록 드롭다운이 테스트 데이터로 채워졌습니다.</p>"
|
| 532 |
error_html += "</div>"
|
| 533 |
|
| 534 |
+
return error_html, program_options
|
| 535 |
|
| 536 |
def execute_program(program_id):
|
| 537 |
"""프로그램 실행"""
|
| 538 |
global SERVER_URL
|
| 539 |
|
| 540 |
+
# 디버그 정보 기록
|
| 541 |
+
print(f"[DEBUG] 프로그램 실행 시도: {program_id}")
|
| 542 |
|
| 543 |
if not program_id:
|
| 544 |
return "프로그램을 선택해주세요."
|
| 545 |
+
|
| 546 |
+
# 테스트 데이터 확인 (테스트 데이터의 경우 테스트 성공 반환)
|
| 547 |
+
if program_id.startswith("test"):
|
| 548 |
+
print(f"[DEBUG] 테스트 프로그램 확인됨. 테스트 모드로 성공 응답 생성")
|
| 549 |
+
# 성공 메시지 HTML로 표시
|
| 550 |
+
html_output = "<div style='padding: 15px; background-color: #d4edda; border-radius: 5px; border-left: 5px solid #28a745;'>"
|
| 551 |
+
html_output += f"<h3 style='margin-top: 0; color: #155724;'>테스트 실행 성공</h3>"
|
| 552 |
+
html_output += f"<p style='margin-bottom: 0;'>테스트 프로그램 {program_id}가 시뮬레이션되었습니다.</p>"
|
| 553 |
+
html_output += f"<p style='margin-top: 10px;'><strong>주의:</strong> 현재 테스트 모드입니다. 실제 서버에 연결하여 실행하시려면 서버 URL을 입력하고 연결해주세요.</p>"
|
| 554 |
+
html_output += "</div>"
|
| 555 |
+
return html_output
|
| 556 |
+
|
| 557 |
+
if not SERVER_URL:
|
| 558 |
+
# 서버 URL이 없을 경우 오류 메시지 반환
|
| 559 |
+
html_output = "<div style='padding: 15px; background-color: #fff3cd; border-radius: 5px; border-left: 5px solid #ffc107;'>"
|
| 560 |
+
html_output += "<h3 style='margin-top: 0; color: #856404;'>서버 연결 필요</h3>"
|
| 561 |
+
html_output += "프로그램을 실행하려면 먼저 서버에 연결해야 합니다. 페이지 상단의 '서버 연결' 탭에서 ngrok URL을 입력하고 연결하세요."
|
| 562 |
+
html_output += "</div>"
|
| 563 |
+
return html_output
|
| 564 |
|
| 565 |
# 디버그 정보 기록
|
| 566 |
+
print(f"[DEBUG] 서버에 실행 요청 전송: {SERVER_URL}/api/programs/{program_id}/execute")
|
| 567 |
|
| 568 |
try:
|
| 569 |
# 로딩 표시
|
|
|
|
| 578 |
"Content-Type": "application/json"
|
| 579 |
}
|
| 580 |
|
| 581 |
+
print(f"[DEBUG] API 요청 전송 - 타임아웃: {REQUEST_TIMEOUT}")
|
| 582 |
response = session.post(
|
| 583 |
f"{SERVER_URL}/api/programs/{program_id}/execute",
|
| 584 |
headers=headers,
|
|
|
|
| 586 |
timeout=REQUEST_TIMEOUT
|
| 587 |
)
|
| 588 |
|
| 589 |
+
print(f"[DEBUG] API 응답 받음 - 상태코드: {response.status_code}")
|
| 590 |
+
|
| 591 |
if response.status_code == 200:
|
| 592 |
result = response.json()
|
| 593 |
|
|
|
|
| 614 |
|
| 615 |
return html_output
|
| 616 |
except RequestException as e:
|
| 617 |
+
# 오류 상세 로그
|
| 618 |
+
print(f"[DEBUG] 프로그램 실행 중 오류: {str(e)}")
|
| 619 |
+
error_type = type(e).__name__
|
| 620 |
+
error_detail = str(e)
|
| 621 |
+
|
| 622 |
+
# 타임아웃 오류 확인
|
| 623 |
+
if "timeout" in error_detail.lower() or "timed out" in error_detail.lower():
|
| 624 |
+
html_output = "<div style='padding: 15px; background-color: #f8d7da; border-radius: 5px; border-left: 5px solid #dc3545;'>"
|
| 625 |
+
html_output += f"<h3 style='margin-top: 0; color: #721c24;'>프로그램 실행 타임아웃</h3>"
|
| 626 |
+
html_output += f"<p style='margin-bottom: 10px;'>서버가 {REQUEST_TIMEOUT}초 내에 응답하지 않았습니다.</p>"
|
| 627 |
+
html_output += f"<p><strong>해결 방법:</strong> 서버 연결을 확인하고 다시 시도해보세요. 서버가 다른 작업을 처리하고 있을 수 있습니다.</p>"
|
| 628 |
+
html_output += f"<p><strong>오류 정보:</strong> {error_type} - {error_detail}</p>"
|
| 629 |
+
html_output += "</div>"
|
| 630 |
+
else:
|
| 631 |
+
# 오류 메시지 HTML로 표시
|
| 632 |
+
html_output = "<div style='padding: 15px; background-color: #f8d7da; border-radius: 5px; border-left: 5px solid #dc3545;'>"
|
| 633 |
+
html_output += f"<h3 style='margin-top: 0; color: #721c24;'>오류 발생</h3>"
|
| 634 |
+
html_output += f"<p style='margin-bottom: 10px;'>{str(e)}</p>"
|
| 635 |
+
html_output += f"<p><strong>오류 유형:</strong> {error_type}</p>"
|
| 636 |
+
html_output += "</div>"
|
| 637 |
|
| 638 |
return html_output
|
| 639 |
|