feat: configure cloud API endpoints by stand

This commit is contained in:
2026-10-25 17:43:42 +03:00
parent 5b19094a4d
commit 1f8e00e4f9
7 changed files with 53 additions and 79 deletions
+16 -35
View File
@@ -20,7 +20,7 @@ Cookie (устанавливаются main.py:action=set_mode):
get_client() — HttpClient с учётом режима и стенда
get_real_client() — алиас get_client() (историческая совместимость)
get_client_id() — ClientID из JWT (base64url, без проверки подписи)
get_stand() — "polygon_test" / "dev" / "test"
get_stand() — "polygon_{stand}" / "dev" / "test" / "prod"
get_token_info() — {email, company, client_id} из JWT для UI
get_token_masked() — маскированный токен (abc...xyz) для placeholder
"""
@@ -29,7 +29,7 @@ import base64
import json
from flask import request, current_app, g
from api.http_client import HttpClient, detect_endpoint, stand_name, STANDS
from api.http_client import DEFAULT_ENDPOINT, HttpClient, detect_endpoint, stand_name
def _cached_detect(token):
@@ -41,18 +41,7 @@ def _cached_detect(token):
if cache is None:
g._detected_endpoint = cache = {}
if token not in cache:
endpoint = current_app.config["NUBES_API_ENDPOINT"].rstrip("/")
endpoints = [url.rstrip("/") for url in STANDS]
for configured_endpoint in (
current_app.config.get("NUBES_API_PROD_ENDPOINT", ""),
endpoint,
):
configured_endpoint = configured_endpoint.rstrip("/")
if configured_endpoint and configured_endpoint not in endpoints:
endpoints.append(configured_endpoint)
if endpoint in endpoints:
endpoint = detect_endpoint(token, endpoints=endpoints) or endpoint
cache[token] = endpoint
cache[token] = detect_endpoint(token) or DEFAULT_ENDPOINT
return cache[token]
@@ -89,25 +78,21 @@ def get_token():
return request.cookies.get("token") or current_app.config["NUBES_API_TOKEN"]
def get_endpoint():
"""Вернуть URL текущего API: выбранный Polygon stand или облако по токену."""
if get_mode() == "polygon":
polygon = current_app.config.get("POLYGON_ENDPOINT", "")
stand = get_polygon_stand()
return polygon.replace("/api/v1/svc", f"/{stand}/api/v1/svc")
return _cached_detect(get_token())
def get_client():
"""HttpClient с учётом режима и стенда.
Эмуляция: polygon_url + "/" + stand → https://polygon.../{stand}/api/v1/svc
Облако: реальный API с автоопределением стенда (dev/test по токену)."""
token = get_token()
mode = get_mode()
if mode == "polygon":
polygon = current_app.config.get("POLYGON_ENDPOINT", "")
stand = get_polygon_stand()
# POLYGON_ENDPOINT = "https://polygon.../api/v1/svc"
# Стенд ВСТАВЛЯЕТСЯ перед /api/v1/svc:
# "https://polygon.../api/v1/svc" → "https://polygon.../test/api/v1/svc"
# Простая замена "/api/v1/svc" → "/{stand}/api/v1/svc"
return HttpClient(polygon.replace("/api/v1/svc", f"/{stand}/api/v1/svc"), token)
# Облако: NUBES_API_ENDPOINT с автоопределением (кешированным)
return HttpClient(_cached_detect(token), token)
Облако: реальный API с автоопределением стенда (dev/test/prod по токену)."""
return HttpClient(get_endpoint(), get_token())
def get_client_id():
@@ -139,16 +124,12 @@ def get_stand():
"""Определить стенд.
Эмуляция: "polygon_{dev|test|prod}" — для load_service_ids и трекера.
Облако: автоопределение или stand_name (dev/test/mock)."""
Облако: автоопределение или stand_name (dev/test/prod/mock)."""
mode = get_mode()
if mode == "polygon":
return f"polygon_{get_polygon_stand()}"
token = get_token()
endpoint = _cached_detect(token).rstrip("/")
prod_endpoint = current_app.config.get("NUBES_API_PROD_ENDPOINT", "").rstrip("/")
if prod_endpoint and endpoint == prod_endpoint:
return "prod"
endpoint = _cached_detect(get_token())
s = stand_name(endpoint)
return s if s != "?" else "mock"
+14 -10
View File
@@ -11,7 +11,7 @@ HttpClient:
Функции автоопределения стенда:
- detect_endpoint(token) — пробует настроенные API стенды по токену
- stand_name(endpoint) — "dev" / "test" по URL
- stand_name(endpoint) — возвращает имя стенда по URL
- create_client(token) — HttpClient + endpoint одним вызовом
Зачем автоопределение: пользователь вводит токен, мы не знаем его стенд.
@@ -20,12 +20,16 @@ HttpClient:
import requests
# Список стендов для автоопределения.
# Порядок ВАЖЕН: dev первый — он быстрее (меньше нагрузка), test — резервный.
STANDS = [
"https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc",
"https://lk-api-gateway-test.ngcloud.ru/api/v1/svc",
]
# Источник истины для URL облачных API. Меняй значения здесь и передеплой,
# а не через NUBES_API_ENDPOINT в параметрах сервиса.
API_ENDPOINTS = {
"dev": "https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc",
"test": "https://lk-api-gateway-test.ngcloud.ru/api/v1/svc",
"prod": "https://lk-api-gateway.ngcloud.ru/api/v1/svc",
}
DEFAULT_STAND = "test"
DEFAULT_ENDPOINT = API_ENDPOINTS[DEFAULT_STAND]
STANDS = list(API_ENDPOINTS.values())
def detect_endpoint(token, endpoints=None):
@@ -54,8 +58,8 @@ def detect_endpoint(token, endpoints=None):
def stand_name(endpoint):
"""Определить имя стенда по URL — точное совпадение endpoint.
Возвращает 'dev'/'test' или '?' если не совпало."""
for name, url in (("dev", STANDS[0]), ("test", STANDS[1])):
Возвращает имя стенда или '?' если URL неизвестен."""
for name, url in API_ENDPOINTS.items():
if (endpoint or "").rstrip("/") == url.rstrip("/"):
return name
return "?"
@@ -64,7 +68,7 @@ def stand_name(endpoint):
def create_client(token, fallback_endpoint=None):
"""HttpClient с автоопределением стенда.
Сначала detect_endpoint(token) — dev→test.
Сначала detect_endpoint(token) — dev→test→prod.
Если не сработало — fallback_endpoint (из конфига).
Возвращает (HttpClient, endpoint_url) или None."""
ep = detect_endpoint(token) or fallback_endpoint