diff --git a/moderation/backend-py/Dockerfile b/moderation/backend-py/Dockerfile index 970d3f3..2409858 100644 --- a/moderation/backend-py/Dockerfile +++ b/moderation/backend-py/Dockerfile @@ -24,5 +24,6 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:3001/health')" # Run application -CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "3001"] +# Используем wrapped_app для поддержки Socket.IO +CMD ["python", "-m", "uvicorn", "main:wrapped_app", "--host", "0.0.0.0", "--port", "3001"] diff --git a/moderation/backend-py/main.py b/moderation/backend-py/main.py index c33f8ac..98f02ad 100644 --- a/moderation/backend-py/main.py +++ b/moderation/backend-py/main.py @@ -79,25 +79,20 @@ async def root(): app.include_router(mod_app_router, prefix="/api/mod-app", tags=["moderation"]) app.include_router(moderation_auth_router, prefix="/api/moderation-auth", tags=["auth"]) -# Mount Socket.IO app for WebSocket -# Socket.IO ASGI app needs to wrap FastAPI app to handle both HTTP and WebSocket +# Socket.IO будет обернут в uvicorn.run() для правильной работы +# Здесь просто инициализируем для проверки try: socketio_app = get_socketio_app() - # Socket.IO will handle /socket.io and /mod-chat paths - # We need to mount it so it can intercept WebSocket connections - # But FastAPI routes should still work - # The Socket.IO ASGI app will handle its own paths and pass others to FastAPI - app.mount("/socket.io", socketio_app) - app.mount("/mod-chat", socketio_app) # Also mount at /mod-chat for namespace - print("✅ WebSocket (Socket.IO) настроен") + print("✅ WebSocket (Socket.IO) инициализирован") print(" 📡 Namespace /mod-chat доступен для чата модераторов") + print(" 🔌 WebSocket endpoint: /socket.io") + print(" 💡 Подключение: wss://your-domain/socket.io с namespace='/mod-chat'") except Exception as e: - print(f"⚠️ Ошибка настройки WebSocket: {e}") + print(f"⚠️ Ошибка инициализации WebSocket: {e}") import traceback traceback.print_exc() print(" Чат модераторов будет недоступен") - if __name__ == "__main__": print("\n" + "=" * 60) print("✅ Сервер модерации запущен (Python)") @@ -107,7 +102,7 @@ if __name__ == "__main__": print("=" * 60 + "\n") uvicorn.run( - "main:app", + wrapped_app, # Используем обернутое приложение host="0.0.0.0", port=settings.MODERATION_PORT, reload=settings.IS_DEVELOPMENT, diff --git a/moderation/backend-py/routes/moderation_auth.py b/moderation/backend-py/routes/moderation_auth.py index e208c2f..629049c 100644 --- a/moderation/backend-py/routes/moderation_auth.py +++ b/moderation/backend-py/routes/moderation_auth.py @@ -484,9 +484,9 @@ async def get_config(): """Get configuration for frontend""" bot_username = settings.MODERATION_BOT_USERNAME - # If not set, try to get from Bot API (simplified - can add full implementation) + # If not set, use default if not bot_username: - bot_username = "moderation_bot" + bot_username = "rbachbot" # Default bot username return {"botUsername": bot_username} diff --git a/moderation/frontend/src/App.jsx b/moderation/frontend/src/App.jsx index 421c718..7bcce3f 100644 --- a/moderation/frontend/src/App.jsx +++ b/moderation/frontend/src/App.jsx @@ -128,7 +128,7 @@ export default function App() { const [commentsLoading, setCommentsLoading] = useState(false); // Конфигурация (bot username) - const [moderationBotUsername, setModerationBotUsername] = useState('moderation_bot'); + const [moderationBotUsername, setModerationBotUsername] = useState('rbachbot'); // Форма авторизации const [authForm, setAuthForm] = useState({ @@ -316,9 +316,12 @@ export default function App() { script.setAttribute('data-onauth', 'onTelegramAuth'); script.setAttribute('data-radius', '10'); // Добавить auth-url для валидации домена - const API_URL = getApiUrl(); - const fullApiUrl = API_URL.startsWith('http') ? API_URL : `${window.location.origin}${API_URL}`; - script.setAttribute('data-auth-url', `${fullApiUrl}/moderation-auth/telegram-widget`); + // Telegram требует, чтобы auth-url был на том же домене, где размещен виджет + const authUrl = `${window.location.origin}/api/moderation-auth/telegram-widget`; + script.setAttribute('data-auth-url', authUrl); + console.log('[Telegram Widget] Bot username:', moderationBotUsername); + console.log('[Telegram Widget] Auth URL:', authUrl); + console.log('[Telegram Widget] Current origin:', window.location.origin); script.onload = () => { console.log('[Telegram Widget] Скрипт загружен'); @@ -515,9 +518,14 @@ export default function App() { hasUsername: !!user.username, hasTelegramId: !!user.telegramId }); - console.log('[Chat] Подключение к:', `${socketBase}/mod-chat`); + // Socket.IO подключается к /socket.io, но использует namespace /mod-chat + // В production Socket.IO слушает на /socket.io, namespace указывается отдельно + const socketUrl = socketBase.endsWith('/socket.io') ? socketBase : `${socketBase}/socket.io`; + console.log('[Chat] Подключение к Socket.IO:', socketUrl); + console.log('[Chat] Использование namespace: /mod-chat'); - const socket = io(`${socketBase}/mod-chat`, { + const socket = io(socketUrl, { + namespace: '/mod-chat', transports: ['websocket', 'polling'], reconnection: true, reconnectionDelay: 1000,