217 lines
7.3 KiB
HTML
217 lines
7.3 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>SSE Test</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
max-width: 800px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
}
|
|
.status {
|
|
padding: 10px;
|
|
margin: 10px 0;
|
|
border-radius: 5px;
|
|
}
|
|
.connected {
|
|
background-color: #d4edda;
|
|
color: #155724;
|
|
border: 1px solid #c3e6cb;
|
|
}
|
|
.disconnected {
|
|
background-color: #f8d7da;
|
|
color: #721c24;
|
|
border: 1px solid #f5c6cb;
|
|
}
|
|
.notification {
|
|
background-color: #fff3cd;
|
|
color: #856404;
|
|
border: 1px solid #ffeaa7;
|
|
padding: 10px;
|
|
margin: 10px 0;
|
|
border-radius: 5px;
|
|
}
|
|
#notifications {
|
|
max-height: 400px;
|
|
overflow-y: auto;
|
|
border: 1px solid #ddd;
|
|
padding: 10px;
|
|
margin: 10px 0;
|
|
}
|
|
button {
|
|
background-color: #007bff;
|
|
color: white;
|
|
border: none;
|
|
padding: 10px 20px;
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
margin: 5px;
|
|
}
|
|
button:hover {
|
|
background-color: #0056b3;
|
|
}
|
|
button:disabled {
|
|
background-color: #6c757d;
|
|
cursor: not-allowed;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>SSE Notification Test</h1>
|
|
|
|
<div id="status" class="status disconnected">
|
|
Disconnected
|
|
</div>
|
|
|
|
<div>
|
|
<button id="connectBtn" onclick="connectSSE()">Connect</button>
|
|
<button id="disconnectBtn" onclick="disconnectSSE()" disabled>Disconnect</button>
|
|
<button onclick="clearNotifications()">Clear Notifications</button>
|
|
</div>
|
|
|
|
<h3>Notifications:</h3>
|
|
<div id="notifications">
|
|
<p>No notifications yet...</p>
|
|
</div>
|
|
|
|
<h3>Test Instructions:</h3>
|
|
<ol>
|
|
<li>Click "Connect" to start the SSE connection</li>
|
|
<li>Run the test script: <code>python test_sse_notifications.py</code></li>
|
|
<li>Watch for real-time notifications to appear below</li>
|
|
<li>Check the browser console for debug information</li>
|
|
</ol>
|
|
|
|
<script>
|
|
let eventSource = null;
|
|
let reconnectAttempts = 0;
|
|
const maxReconnectAttempts = 5;
|
|
const reconnectDelay = 3000;
|
|
|
|
function updateStatus(message, isConnected) {
|
|
const statusDiv = document.getElementById('status');
|
|
statusDiv.textContent = message;
|
|
statusDiv.className = `status ${isConnected ? 'connected' : 'disconnected'}`;
|
|
|
|
document.getElementById('connectBtn').disabled = isConnected;
|
|
document.getElementById('disconnectBtn').disabled = !isConnected;
|
|
}
|
|
|
|
function addNotification(message) {
|
|
const notificationsDiv = document.getElementById('notifications');
|
|
const notification = document.createElement('div');
|
|
notification.className = 'notification';
|
|
notification.innerHTML = `
|
|
<strong>${new Date().toLocaleTimeString()}</strong><br>
|
|
${message}
|
|
`;
|
|
|
|
// Clear the "No notifications yet" message if it exists
|
|
if (notificationsDiv.querySelector('p')) {
|
|
notificationsDiv.innerHTML = '';
|
|
}
|
|
|
|
notificationsDiv.appendChild(notification);
|
|
notificationsDiv.scrollTop = notificationsDiv.scrollHeight;
|
|
}
|
|
|
|
function connectSSE() {
|
|
if (eventSource) {
|
|
eventSource.close();
|
|
}
|
|
|
|
updateStatus('Connecting...', false);
|
|
|
|
// Get CSRF token from cookies
|
|
function getCookie(name) {
|
|
let cookieValue = null;
|
|
if (document.cookie && document.cookie !== '') {
|
|
const cookies = document.cookie.split(';');
|
|
for (let i = 0; i < cookies.length; i++) {
|
|
const cookie = cookies[i].trim();
|
|
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
|
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return cookieValue;
|
|
}
|
|
|
|
const csrftoken = getCookie('csrftoken');
|
|
|
|
eventSource = new EventSource('/api/notifications/stream/');
|
|
|
|
eventSource.onopen = function(event) {
|
|
console.log('SSE connection opened:', event);
|
|
updateStatus('Connected - Waiting for notifications...', true);
|
|
reconnectAttempts = 0;
|
|
addNotification('SSE connection established successfully!');
|
|
};
|
|
|
|
eventSource.onmessage = function(event) {
|
|
console.log('SSE message received:', event.data);
|
|
try {
|
|
const data = JSON.parse(event.data);
|
|
addNotification(`Notification: ${data.message || 'No message'}`);
|
|
} catch (e) {
|
|
addNotification(`Raw message: ${event.data}`);
|
|
}
|
|
};
|
|
|
|
eventSource.onerror = function(event) {
|
|
console.error('SSE error:', event);
|
|
updateStatus('Connection error', false);
|
|
|
|
if (eventSource.readyState === EventSource.CLOSED) {
|
|
addNotification('SSE connection closed');
|
|
} else {
|
|
addNotification('SSE connection error');
|
|
}
|
|
|
|
// Attempt to reconnect
|
|
if (reconnectAttempts < maxReconnectAttempts) {
|
|
reconnectAttempts++;
|
|
addNotification(`Attempting to reconnect (${reconnectAttempts}/${maxReconnectAttempts})...`);
|
|
setTimeout(connectSSE, reconnectDelay);
|
|
} else {
|
|
addNotification('Max reconnection attempts reached');
|
|
}
|
|
};
|
|
|
|
eventSource.addEventListener('notification', function(event) {
|
|
console.log('Custom notification event:', event.data);
|
|
try {
|
|
const data = JSON.parse(event.data);
|
|
addNotification(`Custom Notification: ${data.message || 'No message'}`);
|
|
} catch (e) {
|
|
addNotification(`Custom notification: ${event.data}`);
|
|
}
|
|
});
|
|
}
|
|
|
|
function disconnectSSE() {
|
|
if (eventSource) {
|
|
eventSource.close();
|
|
eventSource = null;
|
|
}
|
|
updateStatus('Disconnected', false);
|
|
addNotification('SSE connection closed by user');
|
|
}
|
|
|
|
function clearNotifications() {
|
|
const notificationsDiv = document.getElementById('notifications');
|
|
notificationsDiv.innerHTML = '<p>No notifications yet...</p>';
|
|
}
|
|
|
|
// Auto-connect when page loads
|
|
window.addEventListener('load', function() {
|
|
addNotification('Page loaded. Click "Connect" to start SSE connection.');
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|