|
|
<!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/[email protected]/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/[email protected]/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>
|
|
|
|
|
|
|