Spaces:
Sleeping
Sleeping
| <html lang="fa" dir="rtl"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>تست اتصال WebSocket</title> | |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> | |
| <link rel="stylesheet" href="/static/css/connection-status.css"> | |
| <style> | |
| body { | |
| padding-top: 50px; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| min-height: 100vh; | |
| } | |
| .main-container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| } | |
| .stats-card { | |
| background: white; | |
| border-radius: 15px; | |
| padding: 30px; | |
| box-shadow: 0 10px 40px rgba(0,0,0,0.15); | |
| margin-bottom: 20px; | |
| } | |
| .big-stat { | |
| text-align: center; | |
| padding: 30px; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| border-radius: 15px; | |
| color: white; | |
| margin-bottom: 20px; | |
| } | |
| .big-stat-value { | |
| font-size: 72px; | |
| font-weight: bold; | |
| margin: 0; | |
| animation: scaleIn 0.5s ease; | |
| } | |
| .big-stat-label { | |
| font-size: 20px; | |
| opacity: 0.9; | |
| margin-top: 10px; | |
| } | |
| @keyframes scaleIn { | |
| from { transform: scale(0.5); opacity: 0; } | |
| to { transform: scale(1); opacity: 1; } | |
| } | |
| .message-log { | |
| background: #f8f9fa; | |
| border-radius: 10px; | |
| padding: 20px; | |
| max-height: 400px; | |
| overflow-y: auto; | |
| font-family: 'Courier New', monospace; | |
| font-size: 13px; | |
| } | |
| .message-item { | |
| padding: 8px; | |
| margin-bottom: 5px; | |
| border-radius: 5px; | |
| animation: fadeIn 0.3s ease; | |
| } | |
| .message-sent { | |
| background: #e3f2fd; | |
| border-left: 3px solid #2196f3; | |
| } | |
| .message-received { | |
| background: #e8f5e9; | |
| border-left: 3px solid #4caf50; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(-10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .control-panel { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
| gap: 10px; | |
| margin-top: 20px; | |
| } | |
| .btn-action { | |
| padding: 12px 20px; | |
| font-weight: 600; | |
| border-radius: 8px; | |
| transition: all 0.3s ease; | |
| } | |
| .btn-action:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 5px 15px rgba(0,0,0,0.2); | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- Connection Status Bar --> | |
| <div class="connection-status-bar" id="ws-connection-status"> | |
| <div class="ws-connection-info"> | |
| <span class="status-dot status-dot-offline" id="ws-status-dot"></span> | |
| <span class="ws-status-text" id="ws-status-text">در حال اتصال...</span> | |
| <span class="connection-spinner"></span> | |
| </div> | |
| <div class="online-users-widget"> | |
| <div class="online-users-count"> | |
| <span class="users-icon">👥</span> | |
| <span class="count-number" id="active-users-count">0</span> | |
| <span class="count-label">کاربر آنلاین</span> | |
| </div> | |
| <div class="online-users-count"> | |
| <span class="users-icon">📊</span> | |
| <span class="count-number" id="total-sessions-count">0</span> | |
| <span class="count-label">جلسات کل</span> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Alerts Container --> | |
| <div class="alerts-container" id="alerts-container"></div> | |
| <!-- Main Content --> | |
| <div class="main-container"> | |
| <div class="big-stat"> | |
| <div class="big-stat-value" id="active-users-big">0</div> | |
| <div class="big-stat-label">کاربر در حال حاضر آنلاین هستند</div> | |
| </div> | |
| <div class="row"> | |
| <div class="col-md-6"> | |
| <div class="stats-card"> | |
| <h3>📊 آمار اتصالات</h3> | |
| <hr> | |
| <table class="table"> | |
| <tr> | |
| <td>اتصالات فعال:</td> | |
| <td><strong id="stat-active">0</strong></td> | |
| </tr> | |
| <tr> | |
| <td>جلسات کل:</td> | |
| <td><strong id="stat-total">0</strong></td> | |
| </tr> | |
| <tr> | |
| <td>پیامهای ارسالی:</td> | |
| <td><strong id="stat-sent">0</strong></td> | |
| </tr> | |
| <tr> | |
| <td>پیامهای دریافتی:</td> | |
| <td><strong id="stat-received">0</strong></td> | |
| </tr> | |
| <tr> | |
| <td>Session ID:</td> | |
| <td><code id="session-id">-</code></td> | |
| </tr> | |
| </table> | |
| <h5>انواع کلاینتها:</h5> | |
| <div id="client-types-list"></div> | |
| </div> | |
| </div> | |
| <div class="col-md-6"> | |
| <div class="stats-card"> | |
| <h3>🎮 کنترلها</h3> | |
| <hr> | |
| <div class="control-panel"> | |
| <button class="btn btn-primary btn-action" onclick="requestStats()"> | |
| 📊 درخواست آمار | |
| </button> | |
| <button class="btn btn-success btn-action" onclick="subscribeToMarket()"> | |
| ✅ Subscribe به Market | |
| </button> | |
| <button class="btn btn-warning btn-action" onclick="unsubscribeFromMarket()"> | |
| ❌ Unsubscribe از Market | |
| </button> | |
| <button class="btn btn-info btn-action" onclick="sendPing()"> | |
| 🏓 ارسال Ping | |
| </button> | |
| <button class="btn btn-danger btn-action" onclick="disconnect()"> | |
| 🔌 قطع اتصال | |
| </button> | |
| <button class="btn btn-secondary btn-action" onclick="reconnect()"> | |
| 🔄 اتصال مجدد | |
| </button> | |
| </div> | |
| </div> | |
| <div class="stats-card"> | |
| <h3>📝 لاگ پیامها</h3> | |
| <hr> | |
| <div class="message-log" id="message-log"></div> | |
| <button class="btn btn-sm btn-outline-secondary mt-2" onclick="clearLog()"> | |
| 🗑️ پاک کردن لاگ | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Scripts --> | |
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> | |
| <script src="/static/js/websocket-client.js"></script> | |
| <script> | |
| // تنظیم handler برای Session ID | |
| if (window.wsClient) { | |
| window.wsClient.on('welcome', (message) => { | |
| document.getElementById('session-id').textContent = message.session_id; | |
| logMessage('دریافت', message); | |
| }); | |
| window.wsClient.on('stats_update', (message) => { | |
| updateStatsDisplay(message.data); | |
| logMessage('دریافت', message); | |
| }); | |
| window.wsClient.on('subscribed', (message) => { | |
| logMessage('دریافت', message); | |
| }); | |
| window.wsClient.on('pong', (message) => { | |
| logMessage('دریافت', message); | |
| }); | |
| } | |
| // توابع کنترلی | |
| function requestStats() { | |
| if (window.wsClient) { | |
| window.wsClient.requestStats(); | |
| logMessage('ارسال', { type: 'get_stats' }); | |
| } | |
| } | |
| function subscribeToMarket() { | |
| if (window.wsClient) { | |
| window.wsClient.subscribe('market'); | |
| logMessage('ارسال', { type: 'subscribe', group: 'market' }); | |
| } | |
| } | |
| function unsubscribeFromMarket() { | |
| if (window.wsClient) { | |
| window.wsClient.unsubscribe('market'); | |
| logMessage('ارسال', { type: 'unsubscribe', group: 'market' }); | |
| } | |
| } | |
| function sendPing() { | |
| if (window.wsClient) { | |
| window.wsClient.send({ type: 'ping' }); | |
| logMessage('ارسال', { type: 'ping' }); | |
| } | |
| } | |
| function disconnect() { | |
| if (window.wsClient) { | |
| window.wsClient.close(); | |
| logMessage('سیستم', 'قطع اتصال توسط کاربر'); | |
| } | |
| } | |
| function reconnect() { | |
| if (window.wsClient) { | |
| window.wsClient.reconnectAttempts = 0; | |
| window.wsClient.connect(); | |
| logMessage('سیستم', 'تلاش برای اتصال مجدد'); | |
| } | |
| } | |
| function updateStatsDisplay(data) { | |
| document.getElementById('stat-active').textContent = data.active_connections || 0; | |
| document.getElementById('stat-total').textContent = data.total_sessions || 0; | |
| document.getElementById('stat-sent').textContent = data.messages_sent || 0; | |
| document.getElementById('stat-received').textContent = data.messages_received || 0; | |
| // آپدیت عدد بزرگ | |
| const bigValue = document.getElementById('active-users-big'); | |
| bigValue.textContent = data.active_connections || 0; | |
| bigValue.style.animation = 'none'; | |
| setTimeout(() => bigValue.style.animation = 'scaleIn 0.5s ease', 10); | |
| } | |
| function logMessage(direction, message) { | |
| const log = document.getElementById('message-log'); | |
| const item = document.createElement('div'); | |
| item.className = `message-item ${direction === 'ارسال' ? 'message-sent' : 'message-received'}`; | |
| const time = new Date().toLocaleTimeString('fa-IR'); | |
| const content = typeof message === 'string' ? message : JSON.stringify(message, null, 2); | |
| item.innerHTML = ` | |
| <strong>[${time}] ${direction}:</strong><br> | |
| <pre style="margin:5px 0 0 0">${content}</pre> | |
| `; | |
| log.appendChild(item); | |
| log.scrollTop = log.scrollHeight; | |
| } | |
| function clearLog() { | |
| document.getElementById('message-log').innerHTML = ''; | |
| } | |
| // آپدیت خودکار هر ۵ ثانیه | |
| setInterval(() => { | |
| if (window.wsClient && window.wsClient.isConnected) { | |
| requestStats(); | |
| } | |
| }, 5000); | |
| </script> | |
| </body> | |
| </html> | |