diff --git a/server/__pycache__/flask_app.cpython-313.pyc b/server/__pycache__/flask_app.cpython-313.pyc index 0b8392e..ab35a93 100644 Binary files a/server/__pycache__/flask_app.cpython-313.pyc and b/server/__pycache__/flask_app.cpython-313.pyc differ diff --git a/server/core/config.py b/server/core/config.py index 3b62e57..60742ad 100644 --- a/server/core/config.py +++ b/server/core/config.py @@ -28,3 +28,8 @@ ELEVATION_PROBE_TTL_SEC = float( ELEVATION_CONNECT_TIMEOUT = float( os.environ.get("LORATESTER_ELEVATION_TIMEOUT", "8") ) +RF_API_URL = os.environ.get( + "LORATESTER_RF_API_URL", + "http://127.0.0.1:5603", +).rstrip("/") +RF_API_TIMEOUT = float(os.environ.get("LORATESTER_RF_API_TIMEOUT", "30")) diff --git a/server/flask_app.py b/server/flask_app.py index dba4bfb..17926a9 100644 --- a/server/flask_app.py +++ b/server/flask_app.py @@ -3,11 +3,12 @@ import time from pathlib import Path -from flask import Flask, jsonify, request, send_from_directory +import httpx +from flask import Flask, Response, jsonify, request, send_from_directory from flask_cors import CORS from core.auth import ANDROID_CLIENT_HEADER, is_android_client -from core.config import HOST, PORT +from core.config import HOST, PORT, RF_API_TIMEOUT, RF_API_URL from core.models import ChatIn, TelemetryIn from core import storage from core.telemetry_body import telemetry_from_body @@ -27,6 +28,38 @@ def index(): return resp +@app.route("/api/rf/", methods=["GET", "POST"]) +def rf_api_proxy(rf_path: str): + target = f"{RF_API_URL}/{rf_path.lstrip('/')}" + if request.query_string: + target = f"{target}?{request.query_string.decode('utf-8', errors='ignore')}" + try: + with httpx.Client(timeout=RF_API_TIMEOUT) as client: + upstream = client.request( + request.method, + target, + content=request.get_data() if request.method != "GET" else None, + headers={ + "Accept": request.headers.get("Accept", "application/json"), + "Content-Type": request.headers.get( + "Content-Type", "application/json" + ), + }, + ) + except httpx.RequestError as e: + return jsonify({ + "error": "RF API unavailable", + "detail": str(e), + "target": target, + }), 502 + + return Response( + upstream.content, + status=upstream.status_code, + content_type=upstream.headers.get("content-type", "application/json"), + ) + + @app.post("/api/telemetry") def post_telemetry(): if not is_android_client(request.headers): diff --git a/server/static/index.html b/server/static/index.html index ff3213c..1aca53d 100644 --- a/server/static/index.html +++ b/server/static/index.html @@ -2054,8 +2054,7 @@ } function defaultApiDebugBase() { - const port = location.port === '5603' ? '' : ':5603'; - return `${location.protocol}//${location.hostname}${port}`; + return '/api/rf'; } function apiDebugNumber(id, fallback = null) { @@ -2299,7 +2298,7 @@ } catch (e) { apiDebugSetStatus(`Ошибка запроса: ${e.message || e}`, true); apiDebugSetOutput(e.response || - 'Проверьте API base URL, доступность порта и CORS. Для API на том же сервере обычно подходит порт 5603.'); + 'Проверьте API base URL. По умолчанию используется same-origin proxy /api/rf.'); apiDebugSetSummary('Расчёт не выполнен.'); } } @@ -2407,7 +2406,7 @@ } catch (e) { apiDebugSetStatus(`Ошибка расчёта линии: ${e.message || e}`, true); apiDebugSetOutput(e.response || - 'Проверьте API base URL, доступность порта и CORS. Для API на том же сервере обычно подходит порт 5603.'); + 'Проверьте API base URL. По умолчанию используется same-origin proxy /api/rf.'); apiDebugSetSummary('Расчёт линии не выполнен.'); } }