feat: unify market/portfolio/system UI, improve exchange errors and asset valuation
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
# app/src/core/system_status.py
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from src.core.config import load_settings
|
||||
from src.core.constants import APP_NAME, APP_VERSION
|
||||
@@ -40,7 +44,8 @@ def _extract_postgres_version(raw: str) -> str:
|
||||
|
||||
|
||||
def _build_exchange_status(
|
||||
exchange_service: ExchangeService, default_symbol: str
|
||||
exchange_service: ExchangeService,
|
||||
default_symbol: str,
|
||||
) -> ComponentStatus:
|
||||
try:
|
||||
symbol_validation = exchange_service.validate_symbol(default_symbol)
|
||||
@@ -48,7 +53,7 @@ def _build_exchange_status(
|
||||
return ComponentStatus(
|
||||
name="Биржа",
|
||||
state="🔴",
|
||||
details=f"Не удалось проверить инструмент: {exc}",
|
||||
details=_humanize_error_message(str(exc)),
|
||||
)
|
||||
|
||||
exchange_health = exchange_service.get_health()
|
||||
@@ -60,7 +65,7 @@ def _build_exchange_status(
|
||||
return ComponentStatus(
|
||||
name="Биржа",
|
||||
state="🔴",
|
||||
details=exchange_health.message or "Ошибка подключения к API биржи.",
|
||||
details=_humanize_error_message(exchange_health.message or ""),
|
||||
)
|
||||
|
||||
return ComponentStatus(
|
||||
@@ -78,7 +83,7 @@ def _build_account_status(exchange_service: ExchangeService) -> ComponentStatus:
|
||||
return ComponentStatus(
|
||||
name="Аккаунт",
|
||||
state="🔴",
|
||||
details=private_auth_health.message or "Ошибка private API.",
|
||||
details=_humanize_error_message(private_auth_health.message or ""),
|
||||
)
|
||||
|
||||
|
||||
@@ -145,26 +150,75 @@ def get_system_snapshot() -> SystemSnapshot:
|
||||
)
|
||||
|
||||
|
||||
def has_system_alerts(snapshot: SystemSnapshot) -> bool:
|
||||
return any(component.state != "🟢" for component in snapshot.components)
|
||||
|
||||
|
||||
def _render_component(component: ComponentStatus) -> str:
|
||||
if component.state == "🟢":
|
||||
return f"{component.state} <b>{component.name}</b>"
|
||||
line = f"{component.state} {component.name}"
|
||||
|
||||
return f"{component.state} <b>{component.name}</b>\n— {component.details}"
|
||||
if component.state == "🟢" or not component.details:
|
||||
return line
|
||||
|
||||
return f"{line}\n— {component.details}"
|
||||
|
||||
|
||||
def build_system_text() -> str:
|
||||
def _now_hhmmss() -> str:
|
||||
settings = load_settings()
|
||||
tz_name = settings.tz or "UTC"
|
||||
|
||||
try:
|
||||
local_dt = datetime.now(ZoneInfo(tz_name))
|
||||
except Exception:
|
||||
local_dt = datetime.utcnow()
|
||||
|
||||
return local_dt.strftime("%H:%M:%S")
|
||||
|
||||
|
||||
def build_system_text(*, include_updated_at: bool = False) -> str:
|
||||
snapshot = get_system_snapshot()
|
||||
components_block = "\n".join(
|
||||
_render_component(component) for component in snapshot.components
|
||||
)
|
||||
|
||||
return (
|
||||
"<b>⚙️ Система</b>\n\n"
|
||||
f"{components_block}\n\n"
|
||||
"<b>🌐 Окружение</b>\n"
|
||||
f"• приложение: {snapshot.app_name} {snapshot.app_version}\n"
|
||||
f"• база данных: {snapshot.db_label}\n"
|
||||
f"• часовой пояс: {snapshot.timezone_name}\n"
|
||||
f"• режим: {snapshot.mode_label}\n"
|
||||
f"• инструмент: {snapshot.default_symbol}"
|
||||
)
|
||||
text = (
|
||||
"<b>⚙️ Система</b>\n"
|
||||
f"🔸 <b>{snapshot.mode_label}</b>\n"
|
||||
f"⏱️ {snapshot.timezone_name}\n\n"
|
||||
f"{components_block}"
|
||||
)
|
||||
|
||||
if include_updated_at:
|
||||
text += f"\n\n<i>Обновлено: {_now_hhmmss()}</i>"
|
||||
|
||||
return text
|
||||
|
||||
|
||||
def _humanize_error_message(text: str) -> str:
|
||||
t = text.lower()
|
||||
|
||||
# сеть
|
||||
if "nodename nor servname" in t or "name or service not known" in t:
|
||||
return "Нет связи с биржей"
|
||||
|
||||
if "timeout" in t or "timed out" in t:
|
||||
return "Биржа не отвечает (таймаут)"
|
||||
|
||||
if "network error" in t or "connection error" in t:
|
||||
return "Ошибка сети при обращении к бирже"
|
||||
|
||||
# API / доступ
|
||||
if "private api error" in t:
|
||||
return "Ошибка доступа к аккаунту"
|
||||
|
||||
if "invalid api key" in t or "api key" in t:
|
||||
return "Неверный API ключ"
|
||||
|
||||
if "forbidden" in t or "unauthorized" in t:
|
||||
return "Нет доступа к аккаунту"
|
||||
|
||||
# время
|
||||
if "-1021" in t or "doesn't match server time" in t:
|
||||
return "Ошибка времени (рассинхронизация)"
|
||||
|
||||
return "Не удалось получить данные с биржи"
|
||||
Reference in New Issue
Block a user