| | <!DOCTYPE html>
|
| | <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>
|
| |
|
| | <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>
|
| |
|
| |
|
| | <div class="alerts-container" id="alerts-container"></div>
|
| |
|
| |
|
| | <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>
|
| |
|
| |
|
| | <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>
|
| |
|
| | 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>
|
| |
|
| |
|