Spaces:
Sleeping
Sleeping
Fix: 장치 상태 확인 API 경로 수정 (/status -> /api/status)
Browse files- app/app_device_routes.py +148 -77
app/app_device_routes.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
"""
|
2 |
-
RAG 검색 챗봇 웹 애플리케이션 - 장치 관리 API 라우트 정의
|
3 |
"""
|
4 |
|
5 |
import logging
|
@@ -11,190 +11,261 @@ logger = logging.getLogger(__name__)
|
|
11 |
|
12 |
def register_device_routes(app, login_required, DEVICE_SERVER_URL):
|
13 |
"""Flask 애플리케이션에 장치 관리 관련 라우트 등록"""
|
|
|
14 |
@app.route('/api/device/status', methods=['GET'])
|
15 |
@login_required
|
16 |
def device_status():
|
|
|
17 |
try:
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
# 연결 타임아웃 설정
|
23 |
timeout = 5 # 5초로 타임아웃 설정
|
24 |
-
|
25 |
try:
|
26 |
-
#
|
27 |
-
|
28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
if response.status_code == 200:
|
30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
else:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
return jsonify({
|
33 |
-
"success": False,
|
34 |
-
"error":
|
35 |
}), 502 # Bad Gateway
|
36 |
-
|
37 |
except requests.exceptions.Timeout:
|
|
|
38 |
return jsonify({
|
39 |
"success": False,
|
40 |
"error": "장치 서버 연결 타임아웃. 서버 응답이 너무 느립니다."
|
41 |
}), 504 # Gateway Timeout
|
42 |
-
|
43 |
except requests.exceptions.ConnectionError:
|
|
|
44 |
return jsonify({
|
45 |
"success": False,
|
46 |
-
"error": "장치 관리 서버에 연결할 수 없습니다. 서버가 실행
|
47 |
-
}), 502 # Bad Gateway
|
48 |
-
|
49 |
except Exception as e:
|
|
|
50 |
return jsonify({
|
51 |
"success": False,
|
52 |
"error": f"장치 서버 연결 중 오류 발생: {str(e)}"
|
53 |
-
}), 500 # Internal Server Error
|
54 |
-
|
55 |
except Exception as e:
|
|
|
|
|
56 |
return jsonify({
|
57 |
"success": False,
|
58 |
-
"error": f"내부 서버
|
59 |
}), 500 # Internal Server Error
|
60 |
-
|
61 |
@app.route('/api/device/list', methods=['GET'])
|
62 |
@login_required
|
63 |
def device_list():
|
64 |
"""장치 목록 조회 API"""
|
65 |
logger.info("장치 목록 조회 요청")
|
66 |
-
|
67 |
try:
|
68 |
-
#
|
69 |
-
|
70 |
-
|
|
|
|
|
71 |
if response.status_code == 200:
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
|
|
|
|
|
|
|
|
79 |
else:
|
80 |
-
|
|
|
|
|
|
|
81 |
return jsonify({
|
82 |
"success": False,
|
83 |
-
"error":
|
84 |
}), 502
|
85 |
-
|
86 |
except requests.exceptions.Timeout:
|
87 |
logger.error("장치 목록 조회 시간 초과")
|
88 |
return jsonify({
|
89 |
"success": False,
|
90 |
"error": "장치 목록 조회 시간이 초과되었습니다."
|
91 |
}), 504
|
92 |
-
|
93 |
except requests.exceptions.ConnectionError:
|
94 |
logger.error("장치 관리 서버 연결 실패")
|
95 |
return jsonify({
|
96 |
"success": False,
|
97 |
"error": "장치 관리 서버에 연결할 수 없습니다. 서버가 실행 중인지 확인해주세요."
|
98 |
-
}), 503
|
99 |
-
|
100 |
except Exception as e:
|
101 |
-
logger.error(f"장치 목록 조회 중 오류 발생: {e}")
|
102 |
return jsonify({
|
103 |
"success": False,
|
104 |
"error": f"장치 목록 조회 중 오류 발생: {str(e)}"
|
105 |
}), 500
|
106 |
-
|
107 |
-
|
108 |
@app.route('/api/device/programs', methods=['GET'])
|
109 |
@login_required
|
110 |
def device_programs():
|
111 |
"""실행 가능한 프로그램 목록 조회 API"""
|
112 |
logger.info("프로그램 목록 조회 요청")
|
113 |
-
|
114 |
try:
|
115 |
-
#
|
116 |
-
|
117 |
-
|
|
|
|
|
|
|
118 |
if response.status_code == 200:
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
|
|
|
|
|
|
|
|
126 |
else:
|
127 |
-
|
|
|
|
|
|
|
128 |
return jsonify({
|
129 |
"success": False,
|
130 |
-
"error":
|
131 |
}), 502
|
132 |
-
|
133 |
except requests.exceptions.Timeout:
|
134 |
logger.error("프로그램 목록 조회 시간 초과")
|
135 |
return jsonify({
|
136 |
"success": False,
|
137 |
"error": "프로그램 목록 조회 시간이 초과되었습니다."
|
138 |
}), 504
|
139 |
-
|
140 |
except requests.exceptions.ConnectionError:
|
141 |
logger.error("장치 관리 서버 연결 실패")
|
142 |
return jsonify({
|
143 |
"success": False,
|
144 |
"error": "장치 관리 서버에 연결할 수 없습니다. 서버가 실행 중인지 확인해주세요."
|
145 |
}), 503
|
146 |
-
|
147 |
except Exception as e:
|
148 |
-
logger.error(f"프로그램 목록 조회 중 오류 발생: {e}")
|
149 |
return jsonify({
|
150 |
"success": False,
|
151 |
"error": f"프로그램 목록 조회 중 오류 발생: {str(e)}"
|
152 |
}), 500
|
153 |
-
|
154 |
-
|
155 |
@app.route('/api/device/programs/<program_id>/execute', methods=['POST'])
|
156 |
@login_required
|
157 |
def execute_program(program_id):
|
158 |
"""프로그램 실행 API"""
|
159 |
logger.info(f"프로그램 실행 요청: {program_id}")
|
160 |
-
|
161 |
try:
|
162 |
-
#
|
|
|
163 |
response = requests.post(
|
164 |
-
f"{DEVICE_SERVER_URL}
|
165 |
-
json={},
|
166 |
timeout=10 # 프로그램 실행에는 더 긴 시간 부여
|
167 |
)
|
168 |
-
|
|
|
|
|
169 |
if response.status_code == 200:
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
175 |
else:
|
176 |
-
|
|
|
|
|
|
|
177 |
return jsonify({
|
178 |
"success": False,
|
179 |
-
"error":
|
180 |
-
}), 502
|
181 |
-
|
182 |
except requests.exceptions.Timeout:
|
183 |
logger.error("프로그램 실행 요청 시간 초과")
|
184 |
return jsonify({
|
185 |
"success": False,
|
186 |
"error": "프로그램 실행 요청 시간이 초과되었습니다."
|
187 |
}), 504
|
188 |
-
|
189 |
except requests.exceptions.ConnectionError:
|
190 |
logger.error("장치 관리 서버 연결 실패")
|
191 |
return jsonify({
|
192 |
"success": False,
|
193 |
"error": "장치 관리 서버에 연결할 수 없습니다. 서버가 실행 중인지 확인해주세요."
|
194 |
}), 503
|
195 |
-
|
196 |
except Exception as e:
|
197 |
-
logger.error(f"프로그램 실행 중 오류 발생: {e}")
|
198 |
return jsonify({
|
199 |
"success": False,
|
200 |
"error": f"프로그램 실행 중 오류 발생: {str(e)}"
|
|
|
1 |
"""
|
2 |
+
RAG 검색 챗봇 웹 애플리케이션 - 장치 관리 API 라우트 정의 (API 경로 수정됨)
|
3 |
"""
|
4 |
|
5 |
import logging
|
|
|
11 |
|
12 |
def register_device_routes(app, login_required, DEVICE_SERVER_URL):
|
13 |
"""Flask 애플리케이션에 장치 관리 관련 라우트 등록"""
|
14 |
+
|
15 |
@app.route('/api/device/status', methods=['GET'])
|
16 |
@login_required
|
17 |
def device_status():
|
18 |
+
"""장치 관리 서버의 상태를 확인하는 API 엔드포인트"""
|
19 |
try:
|
20 |
+
# requests 라이브러리는 함수 내에서 임포트할 필요 없음 (상단 임포트 사용)
|
21 |
+
# json, jsonify도 Flask에서 이미 임포트됨 (상단 임포트 사용)
|
22 |
+
|
|
|
23 |
# 연결 타임아웃 설정
|
24 |
timeout = 5 # 5초로 타임아웃 설정
|
25 |
+
|
26 |
try:
|
27 |
+
# ================== 수정된 부분 시작 ==================
|
28 |
+
# 장치 서버 상태 확인 - 경로 수정: /status -> /api/status
|
29 |
+
api_path = "/api/status"
|
30 |
+
logger.info(f"장치 서버 상태 확인 요청: {DEVICE_SERVER_URL}{api_path}")
|
31 |
+
response = requests.get(f"{DEVICE_SERVER_URL}{api_path}", timeout=timeout)
|
32 |
+
# ================== 수정된 부분 끝 ====================
|
33 |
+
|
34 |
+
# 응답 상태 코드 및 내용 로깅 (디버깅 강화)
|
35 |
+
logger.debug(f"장치 서버 응답 상태 코드: {response.status_code}")
|
36 |
+
try:
|
37 |
+
logger.debug(f"장치 서버 응답 내용: {response.text[:200]}...") # 너무 길면 잘라서 로깅
|
38 |
+
except Exception:
|
39 |
+
logger.debug("장치 서버 응답 내용 로깅 실패 (텍스트 형식 아님?)")
|
40 |
+
|
41 |
+
|
42 |
if response.status_code == 200:
|
43 |
+
# 성공 시 응답 데이터 구조 확인 및 로깅
|
44 |
+
try:
|
45 |
+
data = response.json()
|
46 |
+
logger.info(f"장치 서버 상태 확인 성공. 응답 데이터: {data}")
|
47 |
+
return jsonify({"success": True, "status": "connected", "data": data})
|
48 |
+
except requests.exceptions.JSONDecodeError:
|
49 |
+
logger.error("장치 서버 응답 JSON 파싱 실패")
|
50 |
+
return jsonify({
|
51 |
+
"success": False,
|
52 |
+
"error": "장치 서버로부터 유효하지 않은 JSON 응답을 받았습니다."
|
53 |
+
}), 502 # Bad Gateway (업스트림 서버 오류)
|
54 |
else:
|
55 |
+
# 실패 시 오류 메시지 포함 로깅
|
56 |
+
error_message = f"장치 서버 응답 오류: {response.status_code}"
|
57 |
+
try:
|
58 |
+
# 서버에서 오류 메시지를 json으로 보내는 경우 포함
|
59 |
+
error_detail = response.json().get("error", response.text)
|
60 |
+
error_message += f" - {error_detail}"
|
61 |
+
except Exception:
|
62 |
+
error_message += f" - {response.text}" # JSON 파싱 실패 시 원본 텍스트
|
63 |
+
|
64 |
+
logger.warning(error_message) # 경고 레벨로 로깅
|
65 |
return jsonify({
|
66 |
+
"success": False,
|
67 |
+
"error": error_message
|
68 |
}), 502 # Bad Gateway
|
69 |
+
|
70 |
except requests.exceptions.Timeout:
|
71 |
+
logger.error(f"장치 서버 연결 타임아웃 ({DEVICE_SERVER_URL})")
|
72 |
return jsonify({
|
73 |
"success": False,
|
74 |
"error": "장치 서버 연결 타임아웃. 서버 응답이 너무 느립니다."
|
75 |
}), 504 # Gateway Timeout
|
76 |
+
|
77 |
except requests.exceptions.ConnectionError:
|
78 |
+
logger.error(f"장치 관리 서버 연결 실패 ({DEVICE_SERVER_URL})")
|
79 |
return jsonify({
|
80 |
"success": False,
|
81 |
+
"error": "장치 관리 서버에 연결할 수 없습니다. 서버가 실행 중인지, URL이 정확한지 확인해주세요."
|
82 |
+
}), 502 # Bad Gateway (연결 실패도 업스트림 문제로 간주)
|
83 |
+
|
84 |
except Exception as e:
|
85 |
+
logger.error(f"장치 서버 연결 중 예상치 못한 오류 발생: {e}", exc_info=True) # 상세 스택 트레이스 로깅
|
86 |
return jsonify({
|
87 |
"success": False,
|
88 |
"error": f"장치 서버 연결 중 오류 발생: {str(e)}"
|
89 |
+
}), 500 # Internal Server Error (Flask 앱 내부 또는 requests 라이브러리 문제 가능성)
|
90 |
+
|
91 |
except Exception as e:
|
92 |
+
# 이 try-except 블록은 /api/device/status 라우트 자체의 내부 오류 처리
|
93 |
+
logger.error(f"/api/device/status 처리 중 내부 서버 오류: {e}", exc_info=True)
|
94 |
return jsonify({
|
95 |
"success": False,
|
96 |
+
"error": f"내부 서버 오류 발생: {str(e)}"
|
97 |
}), 500 # Internal Server Error
|
98 |
+
|
99 |
@app.route('/api/device/list', methods=['GET'])
|
100 |
@login_required
|
101 |
def device_list():
|
102 |
"""장치 목록 조회 API"""
|
103 |
logger.info("장치 목록 조회 요청")
|
104 |
+
|
105 |
try:
|
106 |
+
api_path = "/api/devices" # 이미 올바른 경로 사용 중
|
107 |
+
logger.info(f"장치 목록 조회 요청: {DEVICE_SERVER_URL}{api_path}")
|
108 |
+
response = requests.get(f"{DEVICE_SERVER_URL}{api_path}", timeout=5)
|
109 |
+
logger.debug(f"장치 목록 응답 상태 코드: {response.status_code}")
|
110 |
+
|
111 |
if response.status_code == 200:
|
112 |
+
try:
|
113 |
+
data = response.json()
|
114 |
+
devices = data.get("devices", [])
|
115 |
+
logger.info(f"장치 목록 조회 성공: {len(devices)}개 장치")
|
116 |
+
return jsonify({
|
117 |
+
"success": True,
|
118 |
+
"devices": devices
|
119 |
+
})
|
120 |
+
except requests.exceptions.JSONDecodeError:
|
121 |
+
logger.error("장치 목록 응답 JSON 파싱 실패")
|
122 |
+
return jsonify({"success": False, "error": "장치 서버로부터 유효하지 않은 JSON 응답"}), 502
|
123 |
else:
|
124 |
+
error_message = f"장치 목록 조회 실패: {response.status_code}"
|
125 |
+
try: error_message += f" - {response.json().get('error', response.text)}"
|
126 |
+
except Exception: error_message += f" - {response.text}"
|
127 |
+
logger.warning(error_message)
|
128 |
return jsonify({
|
129 |
"success": False,
|
130 |
+
"error": error_message
|
131 |
}), 502
|
132 |
+
|
133 |
except requests.exceptions.Timeout:
|
134 |
logger.error("장치 목록 조회 시간 초과")
|
135 |
return jsonify({
|
136 |
"success": False,
|
137 |
"error": "장치 목록 조회 시간이 초과되었습니다."
|
138 |
}), 504
|
139 |
+
|
140 |
except requests.exceptions.ConnectionError:
|
141 |
logger.error("장치 관리 서버 연결 실패")
|
142 |
return jsonify({
|
143 |
"success": False,
|
144 |
"error": "장치 관리 서버에 연결할 수 없습니다. 서버가 실행 중인지 확인해주세요."
|
145 |
+
}), 503 # Service Unavailable
|
146 |
+
|
147 |
except Exception as e:
|
148 |
+
logger.error(f"장치 목록 조회 중 오류 발생: {e}", exc_info=True)
|
149 |
return jsonify({
|
150 |
"success": False,
|
151 |
"error": f"장치 목록 조회 중 오류 발생: {str(e)}"
|
152 |
}), 500
|
153 |
+
|
154 |
+
|
155 |
@app.route('/api/device/programs', methods=['GET'])
|
156 |
@login_required
|
157 |
def device_programs():
|
158 |
"""실행 가능한 프로그램 목록 조회 API"""
|
159 |
logger.info("프로그램 목록 조회 요청")
|
160 |
+
|
161 |
try:
|
162 |
+
api_path = "/api/programs" # 이미 올바른 경로 사용 중
|
163 |
+
logger.info(f"프로그램 목록 조회 요청: {DEVICE_SERVER_URL}{api_path}")
|
164 |
+
response = requests.get(f"{DEVICE_SERVER_URL}{api_path}", timeout=5)
|
165 |
+
logger.debug(f"프로그램 목록 응답 상태 코드: {response.status_code}")
|
166 |
+
|
167 |
+
|
168 |
if response.status_code == 200:
|
169 |
+
try:
|
170 |
+
data = response.json()
|
171 |
+
programs = data.get("programs", [])
|
172 |
+
logger.info(f"프로그램 목록 조회 성공: {len(programs)}개 프로그램")
|
173 |
+
return jsonify({
|
174 |
+
"success": True,
|
175 |
+
"programs": programs
|
176 |
+
})
|
177 |
+
except requests.exceptions.JSONDecodeError:
|
178 |
+
logger.error("프로그램 목록 응답 JSON 파싱 실패")
|
179 |
+
return jsonify({"success": False, "error": "장치 서버로부터 유효하지 않은 JSON 응답"}), 502
|
180 |
else:
|
181 |
+
error_message = f"프로그램 목록 조회 실패: {response.status_code}"
|
182 |
+
try: error_message += f" - {response.json().get('error', response.text)}"
|
183 |
+
except Exception: error_message += f" - {response.text}"
|
184 |
+
logger.warning(error_message)
|
185 |
return jsonify({
|
186 |
"success": False,
|
187 |
+
"error": error_message
|
188 |
}), 502
|
189 |
+
|
190 |
except requests.exceptions.Timeout:
|
191 |
logger.error("프로그램 목록 조회 시간 초과")
|
192 |
return jsonify({
|
193 |
"success": False,
|
194 |
"error": "프로그램 목록 조회 시간이 초과되었습니다."
|
195 |
}), 504
|
196 |
+
|
197 |
except requests.exceptions.ConnectionError:
|
198 |
logger.error("장치 관리 서버 연결 실패")
|
199 |
return jsonify({
|
200 |
"success": False,
|
201 |
"error": "장치 관리 서버에 연결할 수 없습니다. 서버가 실행 중인지 확인해주세요."
|
202 |
}), 503
|
203 |
+
|
204 |
except Exception as e:
|
205 |
+
logger.error(f"프로그램 목록 조회 중 오류 발생: {e}", exc_info=True)
|
206 |
return jsonify({
|
207 |
"success": False,
|
208 |
"error": f"프로그램 목록 조회 중 오류 발생: {str(e)}"
|
209 |
}), 500
|
210 |
+
|
211 |
+
|
212 |
@app.route('/api/device/programs/<program_id>/execute', methods=['POST'])
|
213 |
@login_required
|
214 |
def execute_program(program_id):
|
215 |
"""프로그램 실행 API"""
|
216 |
logger.info(f"프로그램 실행 요청: {program_id}")
|
217 |
+
|
218 |
try:
|
219 |
+
api_path = f"/api/programs/{program_id}/execute" # 이미 올바른 경로 사용 중
|
220 |
+
logger.info(f"프로그램 실행 요청: {DEVICE_SERVER_URL}{api_path}")
|
221 |
response = requests.post(
|
222 |
+
f"{DEVICE_SERVER_URL}{api_path}",
|
223 |
+
json={}, # 필요시 여기에 파라미터 추가 가능
|
224 |
timeout=10 # 프로그램 실행에는 더 긴 시간 부여
|
225 |
)
|
226 |
+
logger.debug(f"프로그램 실행 응답 상태 코드: {response.status_code}")
|
227 |
+
|
228 |
+
|
229 |
if response.status_code == 200:
|
230 |
+
try:
|
231 |
+
data = response.json()
|
232 |
+
success = data.get("success", False)
|
233 |
+
message = data.get("message", "")
|
234 |
+
logger.info(f"프로그램 실행 응답: {success}, {message}")
|
235 |
+
return jsonify(data) # 서버 응답 그대로 반환
|
236 |
+
except requests.exceptions.JSONDecodeError:
|
237 |
+
logger.error("프로그램 실행 응답 JSON 파싱 실패")
|
238 |
+
# 성공(200)했지만 응답이 비정상적인 경우
|
239 |
+
return jsonify({
|
240 |
+
"success": False, # 파싱 실패했으므로 False로 간주
|
241 |
+
"error": "프로그램 실행 서버로부터 유효하지 않은 JSON 응답"
|
242 |
+
}), 502
|
243 |
else:
|
244 |
+
error_message = f"프로그램 실행 요청 실패: {response.status_code}"
|
245 |
+
try: error_message += f" - {response.json().get('error', response.text)}"
|
246 |
+
except Exception: error_message += f" - {response.text}"
|
247 |
+
logger.warning(error_message)
|
248 |
return jsonify({
|
249 |
"success": False,
|
250 |
+
"error": error_message
|
251 |
+
}), 502 # 또는 response.status_code 를 그대로 반환하는 것도 고려
|
252 |
+
|
253 |
except requests.exceptions.Timeout:
|
254 |
logger.error("프로그램 실행 요청 시간 초과")
|
255 |
return jsonify({
|
256 |
"success": False,
|
257 |
"error": "프로그램 실행 요청 시간이 초과되었습니다."
|
258 |
}), 504
|
259 |
+
|
260 |
except requests.exceptions.ConnectionError:
|
261 |
logger.error("장치 관리 서버 연결 실패")
|
262 |
return jsonify({
|
263 |
"success": False,
|
264 |
"error": "장치 관리 서버에 연결할 수 없습니다. 서버가 실행 중인지 확인해주세요."
|
265 |
}), 503
|
266 |
+
|
267 |
except Exception as e:
|
268 |
+
logger.error(f"프로그램 실행 중 오류 발생: {e}", exc_info=True)
|
269 |
return jsonify({
|
270 |
"success": False,
|
271 |
"error": f"프로그램 실행 중 오류 발생: {str(e)}"
|