RAG_AgenticServer_Small / app /app_device_routes.py
jeongsoo's picture
init
2c5fb15
"""
RAG ๊ฒ€์ƒ‰ ์ฑ—๋ด‡ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ - ์žฅ์น˜ ๊ด€๋ฆฌ API ๋ผ์šฐํŠธ ์ •์˜ (์‚ฌ์šฉ์ž ์ •์˜ ์‹คํ–‰, f-string ์˜ค๋ฅ˜ ์ˆ˜์ •๋จ)
"""
import logging
import requests
import uuid # ์‚ฌ์šฉ์ž ์ •์˜ ์‹คํ–‰์„ ์œ„ํ•ด ์ถ”๊ฐ€
import time # ์‚ฌ์šฉ์ž ์ •์˜ ์‹คํ–‰์„ ์œ„ํ•ด ์ถ”๊ฐ€
import shlex # ์‚ฌ์šฉ์ž ์ •์˜ ์‹คํ–‰์„ ์œ„ํ•ด ์ถ”๊ฐ€
import os # ๊ฒฝ๋กœ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ์ถ”๊ฐ€ (ํ•„์š”์‹œ)
from flask import request, jsonify
import json
# ๋กœ๊ฑฐ ๊ฐ€์ ธ์˜ค๊ธฐ
logger = logging.getLogger(__name__)
def register_device_routes(app, login_required, DEVICE_SERVER_URL):
"""Flask ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์žฅ์น˜ ๊ด€๋ฆฌ ๊ด€๋ จ ๋ผ์šฐํŠธ ๋“ฑ๋ก"""
# ์‚ฌ์šฉ์ž ์ง€์ • ์žฅ์น˜ ์„œ๋ฒ„ URL ๋ณ€์ˆ˜
custom_device_url = None
# URL ์„ค์ • ํ•จ์ˆ˜
def get_device_url():
# ์‚ฌ์šฉ์ž ์ง€์ • URL์ด ์žˆ์œผ๋ฉด ์‚ฌ์šฉ, ์—†์œผ๋ฉด ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๊ฐ’ ์‚ฌ์šฉ
return custom_device_url or DEVICE_SERVER_URL
@app.route('/api/device/connect', methods=['POST'])
@login_required
def connect_device_server():
"""์‚ฌ์šฉ์ž ์ง€์ • ์žฅ์น˜ ์„œ๋ฒ„ URL ์—ฐ๊ฒฐ API"""
nonlocal custom_device_url # ์ƒ์œ„ ์Šค์ฝ”ํ”„์˜ ๋ณ€์ˆ˜ ์ฐธ์กฐ
try:
# ์š”์ฒญ์—์„œ URL ๊ฐ€์ ธ์˜ค๊ธฐ
request_data = request.get_json()
if not request_data or 'url' not in request_data:
logger.error("URL์ด ์ œ๊ณต๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
return jsonify({
"success": False,
"error": "URL์ด ์ œ๊ณต๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค."
}), 400 # Bad Request
new_url = request_data['url'].strip()
if not new_url:
logger.error("URL์ด ๋น„์–ด ์žˆ์Šต๋‹ˆ๋‹ค.")
return jsonify({
"success": False,
"error": "URL์ด ๋น„์–ด ์žˆ์Šต๋‹ˆ๋‹ค."
}), 400 # Bad Request
# URL ์„ค์ •
logger.info(f"์‚ฌ์šฉ์ž ์ง€์ • ์žฅ์น˜ ์„œ๋ฒ„ URL ์„ค์ •: {new_url}")
custom_device_url = new_url
# ์„ค์ •๋œ URL๋กœ ์ƒํƒœ ํ™•์ธ ์‹œ๋„
try:
api_path = "/api/status"
logger.info(f"์žฅ์น˜ ์„œ๋ฒ„ ์ƒํƒœ ํ™•์ธ ์š”์ฒญ: {custom_device_url}{api_path}")
response = requests.get(f"{custom_device_url}{api_path}", timeout=5)
if response.status_code == 200:
try:
data = response.json()
logger.info(f"์‚ฌ์šฉ์ž ์ง€์ • ์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์„ฑ๊ณต. ์‘๋‹ต ๋ฐ์ดํ„ฐ: {data}")
return jsonify({
"success": True,
"message": "์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
"server_status": data.get("status", "์ •์ƒ") # ์„œ๋ฒ„ ์‘๋‹ต ๊ตฌ์กฐ์— ๋”ฐ๋ผ ํ‚ค ์กฐ์ • ํ•„์š”
})
except requests.exceptions.JSONDecodeError:
logger.error("์žฅ์น˜ ์„œ๋ฒ„ ์‘๋‹ต JSON ํŒŒ์‹ฑ ์‹คํŒจ")
return jsonify({
"success": False,
"error": "์žฅ์น˜ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์œ ํšจํ•˜์ง€ ์•Š์€ JSON ์‘๋‹ต์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."
}), 502 # Bad Gateway
else:
error_message = f"์žฅ์น˜ ์„œ๋ฒ„ ์‘๋‹ต ์˜ค๋ฅ˜: {response.status_code}"
try:
error_detail = response.json().get("error", response.text)
error_message += f" - {error_detail}"
except Exception:
error_message += f" - {response.text}"
logger.warning(error_message)
custom_device_url = None # ์—ฐ๊ฒฐ ์‹คํŒจ ์‹œ URL ์ดˆ๊ธฐํ™”
return jsonify({
"success": False,
"error": error_message
}), 502 # Bad Gateway
except requests.exceptions.Timeout:
logger.error(f"์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ํƒ€์ž„์•„์›ƒ ({custom_device_url})")
custom_device_url = None # ์—ฐ๊ฒฐ ์‹คํŒจ ์‹œ URL ์ดˆ๊ธฐํ™”
return jsonify({
"success": False,
"error": "์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ํƒ€์ž„์•„์›ƒ. ์„œ๋ฒ„ ์‘๋‹ต์ด ๋„ˆ๋ฌด ๋А๋ฆฝ๋‹ˆ๋‹ค."
}), 504 # Gateway Timeout
except requests.exceptions.ConnectionError:
logger.error(f"์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹คํŒจ ({custom_device_url})")
custom_device_url = None # ์—ฐ๊ฒฐ ์‹คํŒจ ์‹œ URL ์ดˆ๊ธฐํ™”
return jsonify({
"success": False,
"error": "์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€, URL์ด ์ •ํ™•ํ•œ์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
}), 502 # Bad Gateway
except Exception as e:
logger.error(f"์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์ค‘ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}", exc_info=True)
custom_device_url = None # ์—ฐ๊ฒฐ ์‹คํŒจ ์‹œ URL ์ดˆ๊ธฐํ™”
return jsonify({
"success": False,
"error": f"์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
}), 500 # Internal Server Error
except Exception as e:
logger.error(f"/api/device/connect ์ฒ˜๋ฆฌ ์ค‘ ๋‚ด๋ถ€ ์„œ๋ฒ„ ์˜ค๋ฅ˜: {e}", exc_info=True)
return jsonify({
"success": False,
"error": f"๋‚ด๋ถ€ ์„œ๋ฒ„ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
}), 500 # Internal Server Error
@app.route('/api/device/status', methods=['GET'])
@login_required
def device_status():
"""์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„์˜ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๋Š” API ์—”๋“œํฌ์ธํŠธ"""
try:
# ์—ฐ๊ฒฐ ํƒ€์ž„์•„์›ƒ ์„ค์ •
timeout = 5 # 5์ดˆ๋กœ ํƒ€์ž„์•„์›ƒ ์„ค์ •
try:
# ์žฅ์น˜ ์„œ๋ฒ„ ์ƒํƒœ ํ™•์ธ - ๊ฒฝ๋กœ: /api/status
current_device_url = get_device_url()
api_path = "/api/status"
logger.info(f"์žฅ์น˜ ์„œ๋ฒ„ ์ƒํƒœ ํ™•์ธ ์š”์ฒญ: {current_device_url}{api_path}")
response = requests.get(f"{current_device_url}{api_path}", timeout=timeout)
# ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ ๋ฐ ๋‚ด์šฉ ๋กœ๊น… (๋””๋ฒ„๊น… ๊ฐ•ํ™”)
logger.debug(f"์žฅ์น˜ ์„œ๋ฒ„ ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ: {response.status_code}")
try:
logger.debug(f"์žฅ์น˜ ์„œ๋ฒ„ ์‘๋‹ต ๋‚ด์šฉ: {response.text[:200]}...") # ๋„ˆ๋ฌด ๊ธธ๋ฉด ์ž˜๋ผ์„œ ๋กœ๊น…
except Exception:
logger.debug("์žฅ์น˜ ์„œ๋ฒ„ ์‘๋‹ต ๋‚ด์šฉ ๋กœ๊น… ์‹คํŒจ (ํ…์ŠคํŠธ ํ˜•์‹ ์•„๋‹˜?)")
if response.status_code == 200:
# ์„ฑ๊ณต ์‹œ ์‘๋‹ต ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ํ™•์ธ ๋ฐ ๋กœ๊น…
try:
data = response.json()
logger.info(f"์žฅ์น˜ ์„œ๋ฒ„ ์ƒํƒœ ํ™•์ธ ์„ฑ๊ณต. ์‘๋‹ต ๋ฐ์ดํ„ฐ: {data}")
return jsonify({"success": True, "status": "connected", "data": data})
except requests.exceptions.JSONDecodeError:
logger.error("์žฅ์น˜ ์„œ๋ฒ„ ์‘๋‹ต JSON ํŒŒ์‹ฑ ์‹คํŒจ")
return jsonify({
"success": False,
"error": "์žฅ์น˜ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์œ ํšจํ•˜์ง€ ์•Š์€ JSON ์‘๋‹ต์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."
}), 502 # Bad Gateway (์—…์ŠคํŠธ๋ฆผ ์„œ๋ฒ„ ์˜ค๋ฅ˜)
else:
# ์‹คํŒจ ์‹œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ํฌํ•จ ๋กœ๊น…
error_message = f"์žฅ์น˜ ์„œ๋ฒ„ ์‘๋‹ต ์˜ค๋ฅ˜: {response.status_code}"
try:
# ์„œ๋ฒ„์—์„œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ json์œผ๋กœ ๋ณด๋‚ด๋Š” ๊ฒฝ์šฐ ํฌํ•จ
error_detail = response.json().get("error", response.text)
error_message += f" - {error_detail}"
except Exception:
error_message += f" - {response.text}" # JSON ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ์›๋ณธ ํ…์ŠคํŠธ
logger.warning(error_message) # ๊ฒฝ๊ณ  ๋ ˆ๋ฒจ๋กœ ๋กœ๊น…
return jsonify({
"success": False,
"error": error_message
}), 502 # Bad Gateway
except requests.exceptions.Timeout:
logger.error(f"์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ํƒ€์ž„์•„์›ƒ ({get_device_url()})")
return jsonify({
"success": False,
"error": "์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ํƒ€์ž„์•„์›ƒ. ์„œ๋ฒ„ ์‘๋‹ต์ด ๋„ˆ๋ฌด ๋А๋ฆฝ๋‹ˆ๋‹ค."
}), 504 # Gateway Timeout
except requests.exceptions.ConnectionError:
current_device_url = get_device_url()
logger.error(f"์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹คํŒจ ({current_device_url})")
return jsonify({
"success": False,
"error": "์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€, URL์ด ์ •ํ™•ํ•œ์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
}), 502 # Bad Gateway (์—ฐ๊ฒฐ ์‹คํŒจ๋„ ์—…์ŠคํŠธ๋ฆผ ๋ฌธ์ œ๋กœ ๊ฐ„์ฃผ)
except Exception as e:
logger.error(f"์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์ค‘ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}", exc_info=True) # ์ƒ์„ธ ์Šคํƒ ํŠธ๋ ˆ์ด์Šค ๋กœ๊น…
return jsonify({
"success": False,
"error": f"์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
}), 500 # Internal Server Error (Flask ์•ฑ ๋‚ด๋ถ€ ๋˜๋Š” requests ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฌธ์ œ ๊ฐ€๋Šฅ์„ฑ)
except Exception as e:
# ์ด try-except ๋ธ”๋ก์€ /api/device/status ๋ผ์šฐํŠธ ์ž์ฒด์˜ ๋‚ด๋ถ€ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ
logger.error(f"/api/device/status ์ฒ˜๋ฆฌ ์ค‘ ๋‚ด๋ถ€ ์„œ๋ฒ„ ์˜ค๋ฅ˜: {e}", exc_info=True)
return jsonify({
"success": False,
"error": f"๋‚ด๋ถ€ ์„œ๋ฒ„ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
}), 500 # Internal Server Error
@app.route('/api/device/list', methods=['GET'])
@login_required
def device_list():
"""์žฅ์น˜ ๋ชฉ๋ก ์กฐํšŒ API"""
logger.info("์žฅ์น˜ ๋ชฉ๋ก ์กฐํšŒ ์š”์ฒญ")
try:
current_device_url = get_device_url()
api_path = "/api/devices" # LocalPCAgent API ๋ฌธ์„œ์— ๋”ฐ๋ผ ํ™•์ธ ํ•„์š”
logger.info(f"์žฅ์น˜ ๋ชฉ๋ก ์กฐํšŒ ์š”์ฒญ: {current_device_url}{api_path}")
response = requests.get(f"{current_device_url}{api_path}", timeout=5)
logger.debug(f"์žฅ์น˜ ๋ชฉ๋ก ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ: {response.status_code}")
if response.status_code == 200:
try:
data = response.json()
devices = data.get("devices", []) # LocalPCAgent ์‘๋‹ต ํ˜•์‹์— ๋งž๊ฒŒ ํ‚ค ์กฐ์ •
logger.info(f"์žฅ์น˜ ๋ชฉ๋ก ์กฐํšŒ ์„ฑ๊ณต: {len(devices)}๊ฐœ ์žฅ์น˜")
return jsonify({
"success": True,
"devices": devices
})
except requests.exceptions.JSONDecodeError:
logger.error("์žฅ์น˜ ๋ชฉ๋ก ์‘๋‹ต JSON ํŒŒ์‹ฑ ์‹คํŒจ")
return jsonify({"success": False, "error": "์žฅ์น˜ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์œ ํšจํ•˜์ง€ ์•Š์€ JSON ์‘๋‹ต"}), 502
else:
error_message = f"์žฅ์น˜ ๋ชฉ๋ก ์กฐํšŒ ์‹คํŒจ: {response.status_code}"
try: error_message += f" - {response.json().get('error', response.text)}"
except Exception: error_message += f" - {response.text}"
logger.warning(error_message)
return jsonify({
"success": False,
"error": error_message
}), 502
except requests.exceptions.Timeout:
logger.error("์žฅ์น˜ ๋ชฉ๋ก ์กฐํšŒ ์‹œ๊ฐ„ ์ดˆ๊ณผ")
return jsonify({
"success": False,
"error": "์žฅ์น˜ ๋ชฉ๋ก ์กฐํšŒ ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."
}), 504
except requests.exceptions.ConnectionError:
logger.error("์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹คํŒจ")
return jsonify({
"success": False,
"error": "์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
}), 503 # Service Unavailable
except Exception as e:
logger.error(f"์žฅ์น˜ ๋ชฉ๋ก ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}", exc_info=True)
return jsonify({
"success": False,
"error": f"์žฅ์น˜ ๋ชฉ๋ก ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
}), 500
@app.route('/api/device/programs', methods=['GET'])
@login_required
def device_programs():
"""์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ API"""
logger.info("ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ ์š”์ฒญ")
try:
current_device_url = get_device_url()
api_path = "/api/programs"
logger.info(f"ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ ์š”์ฒญ: {current_device_url}{api_path}")
response = requests.get(f"{current_device_url}{api_path}", timeout=5)
logger.debug(f"ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ: {response.status_code}")
if response.status_code == 200:
try:
data = response.json()
programs = data.get("programs", [])
logger.info(f"ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ ์„ฑ๊ณต: {len(programs)}๊ฐœ ํ”„๋กœ๊ทธ๋žจ")
return jsonify({
"success": True,
"programs": programs
})
except requests.exceptions.JSONDecodeError:
logger.error("ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์‘๋‹ต JSON ํŒŒ์‹ฑ ์‹คํŒจ")
return jsonify({"success": False, "error": "์žฅ์น˜ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์œ ํšจํ•˜์ง€ ์•Š์€ JSON ์‘๋‹ต"}), 502
else:
error_message = f"ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ ์‹คํŒจ: {response.status_code}"
try: error_message += f" - {response.json().get('error', response.text)}"
except Exception: error_message += f" - {response.text}"
logger.warning(error_message)
return jsonify({
"success": False,
"error": error_message
}), 502
except requests.exceptions.Timeout:
logger.error("ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ ์‹œ๊ฐ„ ์ดˆ๊ณผ")
return jsonify({
"success": False,
"error": "ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."
}), 504
except requests.exceptions.ConnectionError:
logger.error("์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹คํŒจ")
return jsonify({
"success": False,
"error": "์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
}), 503
except Exception as e:
logger.error(f"ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}", exc_info=True)
return jsonify({
"success": False,
"error": f"ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
}), 500
@app.route('/api/device/programs/<program_id>/execute', methods=['POST'])
@login_required
def execute_program(program_id):
"""๋“ฑ๋ก๋œ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ API"""
logger.info(f"๋“ฑ๋ก๋œ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์š”์ฒญ: {program_id}")
try:
current_device_url = get_device_url()
api_path = f"/api/programs/{program_id}/execute"
logger.info(f"ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์š”์ฒญ: {current_device_url}{api_path}")
response = requests.post(
f"{current_device_url}{api_path}",
json={}, # ํ•„์š”์‹œ ์—ฌ๊ธฐ์— ํŒŒ๋ผ๋ฏธํ„ฐ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ
timeout=10 # ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰์—๋Š” ๋” ๊ธด ์‹œ๊ฐ„ ๋ถ€์—ฌ
)
logger.debug(f"ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ: {response.status_code}")
if response.status_code == 200:
try:
data = response.json()
# LocalPCAgent ์‘๋‹ต์—์„œ ํ•„์š”ํ•œ ์ •๋ณด ์ถ”์ถœ (์˜ˆ: success, message, output ๋“ฑ)
logger.info(f"ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‘๋‹ต: {data}")
return jsonify(data) # ์„œ๋ฒ„ ์‘๋‹ต ๊ตฌ์กฐ์— ๋งž์ถฐ ๋ฐ˜ํ™˜
except requests.exceptions.JSONDecodeError:
logger.error("ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‘๋‹ต JSON ํŒŒ์‹ฑ ์‹คํŒจ")
return jsonify({
"success": False,
"error": "ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์œ ํšจํ•˜์ง€ ์•Š์€ JSON ์‘๋‹ต"
}), 502
else:
error_message = f"ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์š”์ฒญ ์‹คํŒจ: {response.status_code}"
try: error_message += f" - {response.json().get('error', response.text)}"
except Exception: error_message += f" - {response.text}"
logger.warning(error_message)
return jsonify({
"success": False,
"error": error_message
}), 502 # ๋˜๋Š” response.status_code ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ๋„ ๊ณ ๋ ค
except requests.exceptions.Timeout:
logger.error("ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์š”์ฒญ ์‹œ๊ฐ„ ์ดˆ๊ณผ")
return jsonify({
"success": False,
"error": "ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์š”์ฒญ ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."
}), 504
except requests.exceptions.ConnectionError:
logger.error("์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹คํŒจ")
return jsonify({
"success": False,
"error": "์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
}), 503
except Exception as e:
logger.error(f"ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}", exc_info=True)
return jsonify({
"success": False,
"error": f"ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
}), 500
# ================== ์‚ฌ์šฉ์ž ์ •์˜ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์—”๋“œํฌ์ธํŠธ ์ถ”๊ฐ€ ==================
@app.route('/api/device/execute-custom', methods=['POST'])
@login_required
def execute_custom_program():
"""์‚ฌ์šฉ์ž ์ •์˜ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ API - ์ž„์‹œ ID๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋“ฑ๋ก ํ›„ ์‹คํ–‰"""
logger.info("์‚ฌ์šฉ์ž ์ •์˜ ํ”„๋กœ๊ทธ๋žจ ์ž„์‹œ ๋“ฑ๋ก ๋ฐ ์‹คํ–‰ ์š”์ฒญ")
# LocalPCAgent ์„œ๋ฒ„ ์‘๋‹ต์„ ์ €์žฅํ•  ๋ณ€์ˆ˜
execute_data = None
final_response = None
temp_id = None # ์ž„์‹œ ID ์ €์žฅ ๋ณ€์ˆ˜
try:
# ์š”์ฒญ ๋ฐ์ดํ„ฐ ํ™•์ธ
request_data = request.get_json()
if not request_data or 'command' not in request_data:
logger.error("๋ช…๋ น์–ด๊ฐ€ ์ œ๊ณต๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
return jsonify({
"success": False,
"error": "์‹คํ–‰ํ•  ๋ช…๋ น์–ด๋ฅผ ์ œ๊ณตํ•ด์ฃผ์„ธ์š”."
}), 400 # Bad Request
command = request_data['command'].strip()
if not command:
logger.error("๋ช…๋ น์–ด๊ฐ€ ๋น„์–ด ์žˆ์Šต๋‹ˆ๋‹ค.")
return jsonify({
"success": False,
"error": "์‹คํ–‰ํ•  ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."
}), 400 # Bad Request
# ํ˜„์žฌ ์žฅ์น˜ ์„œ๋ฒ„ URL ๊ฐ€์ ธ์˜ค๊ธฐ
current_device_url = get_device_url()
if not current_device_url:
logger.error("์žฅ์น˜ ์„œ๋ฒ„ URL์ด ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
return jsonify({"success": False, "error": "์žฅ์น˜ ์„œ๋ฒ„ URL์ด ์„ค์ •๋˜์ง€ ์•Š์•„ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."}), 503
# --- 1. ์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ๋“ฑ๋ก ---
# ์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ID ์ƒ์„ฑ (์‹œ๊ฐ„ ๊ธฐ๋ฐ˜ uuid)
temp_id = f"temp_program_{int(time.time())}_{uuid.uuid4().hex[:8]}"
# ๋ช…๋ น์–ด ๊ฒฝ๋กœ์™€ ์ธ์ˆ˜ ๋ถ„๋ฆฌ (shlex ์‚ฌ์šฉ)
try:
# ๋”ฐ์˜ดํ‘œ๋กœ ๋ฌถ์ธ ๋ช…๋ น์–ด ์ฒ˜๋ฆฌ (Windows ๊ฒฝ๋กœ ๋“ฑ)
parts = shlex.split(command)
except Exception as parse_err:
# shlex ํŒŒ์‹ฑ ์˜ค๋ฅ˜ ์‹œ ๊ฐ„๋‹จํ•œ ๋ฐฉ์‹์œผ๋กœ ๋ถ„๋ฆฌ (์˜ˆ์™ธ ์ผ€์ด์Šค ์ฒ˜๋ฆฌ)
logger.warning(f"shlex ํŒŒ์‹ฑ ์˜ค๋ฅ˜ ({parse_err}), ๋‹จ์ˆœ ๋ถ„๋ฆฌ ์‹œ๋„: {command}")
parts = command.split(maxsplit=1) # ์‹คํ–‰ํŒŒ์ผ๊ณผ ๋‚˜๋จธ์ง€ ์ธ์ˆ˜๋กœ ๋ถ„๋ฆฌ ์‹œ๋„
if not parts: # ๋ถ„๋ฆฌ ๊ฒฐ๊ณผ๊ฐ€ ์—†์œผ๋ฉด ์˜ค๋ฅ˜
logger.error(f"๋ช…๋ น์–ด ํŒŒ์‹ฑ ์‹คํŒจ: {command}")
return jsonify({"success": False, "error": "๋ช…๋ น์–ด ํ˜•์‹์„ ์ธ์‹ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."}), 400
path = parts[0]
args = parts[1:] if len(parts) > 1 else []
# ================== ์ˆ˜์ •๋œ ๋ถ€๋ถ„ ์‹œ์ž‘ ==================
# ๊ฒฝ๋กœ์—์„œ ํŒŒ์ผ๋ช…๋งŒ ์ถ”์ถœ (๋ฐฑ์Šฌ๋ž˜์‹œ ๋ฌธ์ œ ํ•ด๊ฒฐ)
# os.path.basename ์‚ฌ์šฉ ๋˜๋Š” ๋ฌธ์ž์—ด ์ฒ˜๋ฆฌ ๋ฐฉ์‹ ์‚ฌ์šฉ
try:
# ๋ชจ๋“  ๋ฐฑ์Šฌ๋ž˜์‹œ๋ฅผ ์Šฌ๋ž˜์‹œ๋กœ ๋ณ€๊ฒฝ ํ›„ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„ ์ถ”์ถœ
filename = path.replace('\\', '/').split('/')[-1]
if not filename: # ๊ฒฝ๋กœ๊ฐ€ '/'๋‚˜ '\\'๋กœ ๋๋‚˜๋Š” ๊ฒฝ์šฐ ๋Œ€๋น„
filename = path # ์›๋ณธ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๊ธฐ๋ณธ๊ฐ’ ์„ค์ •
except Exception:
filename = "unknown" # ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ ๊ธฐ๋ณธ๊ฐ’
# ================== ์ˆ˜์ •๋œ ๋ถ€๋ถ„ ๋ ====================
# ํ”„๋กœ๊ทธ๋žจ ๋“ฑ๋ก API ํ˜ธ์ถœ ๋ฐ์ดํ„ฐ ๊ตฌ์„ฑ
logger.info(f"์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ๋“ฑ๋ก ์‹œ๋„: ID={temp_id}, ๊ฒฝ๋กœ='{path}', ์ธ์ˆ˜={args}")
register_data = {
"id": temp_id,
# ์ˆ˜์ •๋œ filename ์‚ฌ์šฉ
"name": f"์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ({filename})",
"path": path,
"args": args,
"ui_required": True, # UI๊ฐ€ ํ•„์š”ํ•œ ๊ฒƒ์œผ๋กœ ๊ฐ€์ • (ํ•„์š”์‹œ ์ˆ˜์ •)
"description": f"์ž„์‹œ ๋“ฑ๋ก๋œ ํ”„๋กœ๊ทธ๋žจ: {command}"
}
register_response = requests.post(
f"{current_device_url}/api/programs", # LocalPCAgent์˜ ํ”„๋กœ๊ทธ๋žจ ๋“ฑ๋ก ์—”๋“œํฌ์ธํŠธ
json=register_data,
timeout=5
)
if not register_response.ok:
# ๋“ฑ๋ก ์‹คํŒจ ์‹œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ
logger.error(f"์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ๋“ฑ๋ก ์‹คํŒจ: {register_response.status_code}")
try:
error_data = register_response.json()
error_message = error_data.get('error', register_response.text)
except:
error_message = register_response.text
return jsonify({
"success": False,
"error": f"์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ๋“ฑ๋ก ์‹คํŒจ({register_response.status_code}): {error_message}"
}), 502 # Bad Gateway (Upstream ์‹คํŒจ)
# --- 2. ์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ---
logger.info(f"์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‹œ๋„: {temp_id}")
execute_response = requests.post(
f"{current_device_url}/api/programs/{temp_id}/execute", # LocalPCAgent์˜ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์—”๋“œํฌ์ธํŠธ
json={},
timeout=15 # ์‹คํ–‰์€ ๋” ๊ธด ์‹œ๊ฐ„ ๋ถ€์—ฌ
)
# ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ์šฐ์„  ์ €์žฅ (์‚ญ์ œ ํ›„ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด)
if execute_response.ok:
try:
execute_data = execute_response.json()
# ์„ฑ๊ณต ์‘๋‹ต์„ ๊ธฐ๋ณธ ์‘๋‹ต์œผ๋กœ ์„ค์ •
final_response = jsonify(execute_data)
logger.info(f"์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์„ฑ๊ณต (์‘๋‹ต ์ฝ”๋“œ {execute_response.status_code}): {execute_data}")
except Exception as parse_error:
logger.error(f"์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์„ฑ๊ณต ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: {parse_error}")
# ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ์˜ค๋ฅ˜ ์‘๋‹ต ์„ค์ •
final_response = jsonify({
"success": False,
"error": f"ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‘๋‹ต(์„ฑ๊ณต:{execute_response.status_code}) ํŒŒ์‹ฑ ์‹คํŒจ: {str(parse_error)}"
}), 502
else:
# ์‹คํ–‰ ์‹คํŒจ ์‹œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ
logger.error(f"์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‹คํŒจ: {execute_response.status_code}")
try:
error_data = execute_response.json()
error_message = error_data.get('error', execute_response.text)
except:
error_message = execute_response.text
# ์‹คํ–‰ ์‹คํŒจ ์‘๋‹ต์„ ๊ธฐ๋ณธ ์‘๋‹ต์œผ๋กœ ์„ค์ •
final_response = jsonify({
"success": False,
"error": f"ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‹คํŒจ({execute_response.status_code}): {error_message}"
}), 502
# --- 3. ์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ์‚ญ์ œ (try-finally ๋ธ”๋ก์œผ๋กœ ์ด๋™) ---
# ์‹คํ–‰ ์„ฑ๊ณต/์‹คํŒจ ์—ฌ๋ถ€์™€ ๊ด€๊ณ„์—†์ด ์‚ญ์ œ ์‹œ๋„
return final_response # ์ €์žฅ๋œ ์ตœ์ข… ์‘๋‹ต ๋ฐ˜ํ™˜
except requests.exceptions.Timeout:
logger.error("์‚ฌ์šฉ์ž ์ •์˜ ํ”„๋กœ๊ทธ๋žจ ์š”์ฒญ ์‹œ๊ฐ„ ์ดˆ๊ณผ (๋“ฑ๋ก ๋˜๋Š” ์‹คํ–‰ ๋‹จ๊ณ„)")
return jsonify({
"success": False,
"error": "ํ”„๋กœ๊ทธ๋žจ ์š”์ฒญ ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋˜์—ˆ์Šต๋‹ˆ๋‹ค (LocalPCAgent ์‘๋‹ต ์—†์Œ)."
}), 504 # Gateway Timeout
except requests.exceptions.ConnectionError:
logger.error("์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹คํŒจ (๋“ฑ๋ก ๋˜๋Š” ์‹คํ–‰ ๋‹จ๊ณ„)")
return jsonify({
"success": False,
"error": "์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
}), 503 # Service Unavailable
except Exception as e:
logger.error(f"์‚ฌ์šฉ์ž ์ •์˜ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์ค‘ Flask ์ธก ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}", exc_info=True)
return jsonify({
"success": False,
"error": f"ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์ค‘ ๋‚ด๋ถ€ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
}), 500 # Internal Server Error
finally:
# --- 3. ์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ์‚ญ์ œ (finally ๋ธ”๋ก์—์„œ ์‹คํ–‰) ---
if temp_id and get_device_url(): # ์ž„์‹œ ID๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๊ณ  URL์ด ์œ ํšจํ•  ๋•Œ๋งŒ ์‚ญ์ œ ์‹œ๋„
current_device_url = get_device_url() # URL ๋‹ค์‹œ ๊ฐ€์ ธ์˜ค๊ธฐ (ํ•„์š”์‹œ)
logger.info(f"์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ์‚ญ์ œ ์‹œ๋„: {temp_id}")
try:
delete_response = requests.delete(
f"{current_device_url}/api/programs/{temp_id}", # LocalPCAgent์˜ ํ”„๋กœ๊ทธ๋žจ ์‚ญ์ œ ์—”๋“œํฌ์ธํŠธ
timeout=3
)
if delete_response.ok:
logger.info(f"์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ์‚ญ์ œ ์„ฑ๊ณต: {temp_id}")
else:
logger.warning(f"์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ์‚ญ์ œ ์‹คํŒจ ({delete_response.status_code}): {temp_id} - {delete_response.text[:100]}")
except Exception as delete_error:
logger.warning(f"์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ์‚ญ์ œ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ (๋ฌด์‹œ๋จ): {delete_error}")
elif not temp_id:
logger.debug("์ž„์‹œ ID๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์•„ ์‚ญ์ œ ๊ฑด๋„ˆ<0xEB>๋œ€.")
elif not get_device_url():
logger.warning("์žฅ์น˜ ์„œ๋ฒ„ URL์ด ์—†์–ด ์ž„์‹œ ํ”„๋กœ๊ทธ๋žจ ์‚ญ์ œ ๊ฑด๋„ˆ<0xEB>๋œ€.")
@app.route('/api/device/scan-ports', methods=['GET'])
@login_required
def scan_device_ports():
"""๋กœ์ปฌPC์— ์—ฐ๊ฒฐ๋œ ์žฅ์น˜(COM ํฌํŠธ ๋ฐ USB ์žฅ์น˜) ๋ชฉ๋ก ์กฐํšŒ API"""
logger.info("์žฅ์น˜ ํฌํŠธ ์Šค์บ” ์š”์ฒญ")
try:
# ํ”„๋กœ๊ทธ๋žจ ID (์žฅ์น˜ ์Šค์บ” ์Šคํฌ๋ฆฝํŠธ ID - scan_ports)
program_id = "scan_ports"
# ํ˜„์žฌ ์žฅ์น˜ ์„œ๋ฒ„ URL ๊ฐ€์ ธ์˜ค๊ธฐ
current_device_url = get_device_url()
if not current_device_url:
logger.error("์žฅ์น˜ ์„œ๋ฒ„ URL์ด ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
return jsonify({
"success": False,
"error": "์žฅ์น˜ ์„œ๋ฒ„ URL์ด ์„ค์ •๋˜์ง€ ์•Š์•„ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."
}), 503 # Service Unavailable
# ์žฅ์น˜ ์Šค์บ” ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ (ํ”„๋กœ๊ทธ๋žจ ID: scan_ports)
api_path = f"/api/programs/{program_id}/execute"
logger.info(f"์žฅ์น˜ ํฌํŠธ ์Šค์บ” ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์š”์ฒญ: {current_device_url}{api_path}")
# ์š”์ฒญ ์ „์†ก: ์žฅ์น˜ ์Šค์บ” ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰
response = requests.post(
f"{current_device_url}{api_path}",
json={}, # ํ•„์š”ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ์—ฌ๊ธฐ์— ์ถ”๊ฐ€
timeout=20 # ์žฅ์น˜ ์Šค์บ”์€ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ํƒ€์ž„์•„์›ƒ ์ฆ๊ฐ€
)
logger.debug(f"์žฅ์น˜ ํฌํŠธ ์Šค์บ” ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ: {response.status_code}")
if response.status_code == 200:
try:
data = response.json()
# LocalPCAgent ์‘๋‹ต์—์„œ ํ•„์š”ํ•œ ์ •๋ณด ์ถ”์ถœ
if data.get("success", False):
# ์Šค์บ” ๊ฒฐ๊ณผ ์ถœ๋ ฅ ๊ฐ€์ ธ์˜ค๊ธฐ
output = data.get("output", "")
try:
# ์ถœ๋ ฅ์ด JSON ํ˜•์‹์ธ์ง€ ํ™•์ธ ๋ฐ ํŒŒ์‹ฑ
scan_results = json.loads(output)
logger.info("์žฅ์น˜ ํฌํŠธ ์Šค์บ” ๊ฒฐ๊ณผ ํŒŒ์‹ฑ ์„ฑ๊ณต")
# ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜
return jsonify({
"success": True,
"timestamp": scan_results.get("timestamp", ""),
"system_info": scan_results.get("system_info", {}),
"devices": scan_results.get("devices", {})
})
except json.JSONDecodeError as json_err:
logger.error(f"์žฅ์น˜ ํฌํŠธ ์Šค์บ” ๊ฒฐ๊ณผ JSON ํŒŒ์‹ฑ ์‹คํŒจ: {json_err}")
return jsonify({
"success": False,
"error": "์žฅ์น˜ ํฌํŠธ ์Šค์บ” ๊ฒฐ๊ณผ๋ฅผ JSON์œผ๋กœ ํŒŒ์‹ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.",
"raw_output": output[:1000] # ๊ธด ์ถœ๋ ฅ์€ ์ž˜๋ผ์„œ ๋ฐ˜ํ™˜
}), 500
else:
# ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰์€ ์„ฑ๊ณตํ–ˆ์ง€๋งŒ ์Šค์บ” ์ž์ฒด๊ฐ€ ์‹คํŒจํ•œ ๊ฒฝ์šฐ
error_message = data.get("error", "์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜")
logger.error(f"์žฅ์น˜ ํฌํŠธ ์Šค์บ” ํ”„๋กœ๊ทธ๋žจ ์˜ค๋ฅ˜: {error_message}")
return jsonify({
"success": False,
"error": f"์žฅ์น˜ ํฌํŠธ ์Šค์บ” ํ”„๋กœ๊ทธ๋žจ ์˜ค๋ฅ˜: {error_message}"
}), 500
except Exception as parse_err:
logger.error(f"์žฅ์น˜ ํฌํŠธ ์Šค์บ” ์‘๋‹ต ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜: {parse_err}")
return jsonify({
"success": False,
"error": f"์žฅ์น˜ ํฌํŠธ ์Šค์บ” ์‘๋‹ต ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜: {str(parse_err)}"
}), 500
else:
# API ์š”์ฒญ ์ž์ฒด๊ฐ€ ์‹คํŒจํ•œ ๊ฒฝ์šฐ
error_message = f"์žฅ์น˜ ํฌํŠธ ์Šค์บ” API ์š”์ฒญ ์‹คํŒจ (์ƒํƒœ ์ฝ”๋“œ: {response.status_code})"
try:
error_data = response.json()
if 'error' in error_data:
error_message += f": {error_data['error']}"
except:
if response.text:
error_message += f": {response.text[:200]}"
logger.error(error_message)
return jsonify({
"success": False,
"error": error_message
}), response.status_code
except requests.exceptions.Timeout:
error_message = "์žฅ์น˜ ํฌํŠธ ์Šค์บ” ์š”์ฒญ ์‹œ๊ฐ„ ์ดˆ๊ณผ"
logger.error(error_message)
return jsonify({
"success": False,
"error": error_message
}), 504 # Gateway Timeout
except requests.exceptions.ConnectionError:
error_message = f"์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹คํŒจ ({get_device_url()})"
logger.error(error_message)
return jsonify({
"success": False,
"error": "์žฅ์น˜ ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
}), 502 # Bad Gateway
except Exception as e:
logger.error(f"์žฅ์น˜ ํฌํŠธ ์Šค์บ” ์š”์ฒญ ์ฒ˜๋ฆฌ ์ค‘ ์˜ˆ์™ธ ๋ฐœ์ƒ: {e}", exc_info=True)
return jsonify({
"success": False,
"error": f"์žฅ์น˜ ํฌํŠธ ์Šค์บ” ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜: {str(e)}"
}), 500 # Internal Server Error
# register_device_routes ํ•จ์ˆ˜์˜ ๋