324 lines
12 KiB
HTML
324 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>WebSocket Test</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
max-width: 800px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
}
|
|
.container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20px;
|
|
}
|
|
.connection-status {
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
text-align: center;
|
|
font-weight: bold;
|
|
}
|
|
.connected {
|
|
background-color: #d4edda;
|
|
color: #155724;
|
|
}
|
|
.disconnected {
|
|
background-color: #f8d7da;
|
|
color: #721c24;
|
|
}
|
|
.connecting {
|
|
background-color: #fff3cd;
|
|
color: #856404;
|
|
}
|
|
.message-container {
|
|
border: 1px solid #ddd;
|
|
border-radius: 5px;
|
|
padding: 10px;
|
|
height: 300px;
|
|
overflow-y: auto;
|
|
}
|
|
.message {
|
|
margin-bottom: 10px;
|
|
padding: 8px;
|
|
border-radius: 5px;
|
|
}
|
|
.received {
|
|
background-color: #e9ecef;
|
|
}
|
|
.sent {
|
|
background-color: #d1ecf1;
|
|
text-align: right;
|
|
}
|
|
.controls {
|
|
display: flex;
|
|
gap: 10px;
|
|
}
|
|
input, button {
|
|
padding: 8px;
|
|
}
|
|
input {
|
|
flex-grow: 1;
|
|
}
|
|
button {
|
|
cursor: pointer;
|
|
background-color: #007bff;
|
|
color: white;
|
|
border: none;
|
|
border-radius: 5px;
|
|
}
|
|
button:hover {
|
|
background-color: #0069d9;
|
|
}
|
|
button:disabled {
|
|
background-color: #6c757d;
|
|
cursor: not-allowed;
|
|
}
|
|
.token-input {
|
|
margin-bottom: 10px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>WebSocket Test Client</h1>
|
|
|
|
<div class="token-input">
|
|
<label for="token">JWT Token:</label>
|
|
<input type="text" id="token" placeholder="Enter your JWT token" style="width: 100%;">
|
|
</div>
|
|
|
|
<div id="status" class="connection-status disconnected">Disconnected</div>
|
|
|
|
<div class="controls">
|
|
<button id="connect">Connect</button>
|
|
<button id="disconnect" disabled>Disconnect</button>
|
|
</div>
|
|
|
|
<div class="message-container" id="messages"></div>
|
|
|
|
<div class="controls">
|
|
<input type="text" id="message" placeholder="Type a message..." disabled>
|
|
<button id="send" disabled>Send</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
let socket = null;
|
|
let reconnectAttempts = 0;
|
|
const MAX_RECONNECT_ATTEMPTS = 5;
|
|
const RECONNECT_DELAY = 1000; // 1 second
|
|
let reconnectTimeout = null;
|
|
|
|
const statusElement = document.getElementById('status');
|
|
const messagesElement = document.getElementById('messages');
|
|
const messageInput = document.getElementById('message');
|
|
const tokenInput = document.getElementById('token');
|
|
const connectButton = document.getElementById('connect');
|
|
const disconnectButton = document.getElementById('disconnect');
|
|
const sendButton = document.getElementById('send');
|
|
|
|
function updateStatus(status, message) {
|
|
statusElement.className = 'connection-status ' + status;
|
|
statusElement.textContent = message;
|
|
console.log(`Status: ${status} - ${message}`);
|
|
}
|
|
|
|
function addMessage(message, type) {
|
|
const messageElement = document.createElement('div');
|
|
messageElement.className = 'message ' + type;
|
|
messageElement.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
|
|
messagesElement.appendChild(messageElement);
|
|
messagesElement.scrollTop = messagesElement.scrollHeight;
|
|
}
|
|
|
|
function setupWebSocket() {
|
|
const token = tokenInput.value.trim();
|
|
if (!token) {
|
|
alert('Please enter a JWT token');
|
|
return false;
|
|
}
|
|
|
|
// Use the current hostname and port for the WebSocket connection
|
|
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
const host = window.location.hostname;
|
|
const port = window.location.port || (window.location.protocol === 'https:' ? '443' : '80');
|
|
const wsUrl = `${protocol}//${host}:${port}`;
|
|
|
|
updateStatus('connecting', 'Connecting...');
|
|
addMessage(`Connecting to ${wsUrl}...`, 'info');
|
|
|
|
try {
|
|
// Close existing connection if any
|
|
if (socket) {
|
|
socket.onclose = null; // Remove previous onclose handler
|
|
socket.close();
|
|
}
|
|
|
|
socket = new WebSocket(wsUrl);
|
|
|
|
socket.onopen = function() {
|
|
reconnectAttempts = 0; // Reset reconnect attempts on successful connection
|
|
updateStatus('connected', 'Connected');
|
|
addMessage('Connection established', 'received');
|
|
|
|
// Send authentication message with token
|
|
const authMessage = JSON.stringify({ token });
|
|
socket.send(authMessage);
|
|
|
|
connectButton.disabled = true;
|
|
disconnectButton.disabled = false;
|
|
messageInput.disabled = false;
|
|
sendButton.disabled = false;
|
|
|
|
// Focus the message input
|
|
messageInput.focus();
|
|
};
|
|
|
|
socket.onmessage = function(event) {
|
|
try {
|
|
const data = JSON.parse(event.data);
|
|
let messageText = '';
|
|
|
|
if (data.type === 'CONNECTED') {
|
|
messageText = `Connected as user: ${data.message.split('as ')[1] || 'unknown'}`;
|
|
} else if (data.type === 'MESSAGE_RECEIVED') {
|
|
messageText = `Server: ${data.content}`;
|
|
} else if (data.type === 'ERROR') {
|
|
messageText = `Error: ${data.error}`;
|
|
} else if (data.type === 'ALERT') {
|
|
messageText = `Alert: ${JSON.stringify(data.payload)}`;
|
|
} else {
|
|
messageText = `Received: ${event.data}`;
|
|
}
|
|
|
|
addMessage(messageText, 'received');
|
|
} catch (e) {
|
|
console.error('Error processing message:', e);
|
|
addMessage(`Received invalid message: ${event.data}`, 'error');
|
|
}
|
|
};
|
|
|
|
socket.onclose = function(event) {
|
|
updateStatus('disconnected', 'Disconnected');
|
|
|
|
const reason = event.reason || 'Unknown reason';
|
|
const code = event.code || 'No code';
|
|
addMessage(`Connection closed. Code: ${code}, Reason: ${reason}`, 'received');
|
|
|
|
connectButton.disabled = false;
|
|
disconnectButton.disabled = true;
|
|
messageInput.disabled = true;
|
|
sendButton.disabled = true;
|
|
|
|
// Clear any existing reconnect timeout
|
|
if (reconnectTimeout) {
|
|
clearTimeout(reconnectTimeout);
|
|
}
|
|
|
|
// Attempt to reconnect if this wasn't a normal closure
|
|
if (event.code !== 1000 && reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
|
|
reconnectAttempts++;
|
|
const delay = RECONNECT_DELAY * Math.pow(2, reconnectAttempts); // Exponential backoff
|
|
addMessage(`Attempting to reconnect (${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS}) in ${delay/1000} seconds...`, 'info');
|
|
|
|
reconnectTimeout = setTimeout(() => {
|
|
addMessage('Reconnecting...', 'info');
|
|
setupWebSocket();
|
|
}, delay);
|
|
} else if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
|
|
addMessage('Max reconnection attempts reached. Please check your connection and try again.', 'error');
|
|
}
|
|
|
|
socket = null;
|
|
};
|
|
|
|
socket.onerror = function(error) {
|
|
console.error('WebSocket error:', error);
|
|
updateStatus('error', 'Connection Error');
|
|
addMessage(`WebSocket error: ${error.message || 'Unknown error'}`, 'error');
|
|
};
|
|
|
|
return true;
|
|
|
|
} catch (error) {
|
|
console.error('WebSocket setup error:', error);
|
|
updateStatus('error', 'Connection Failed');
|
|
addMessage(`Failed to connect: ${error.message}`, 'error');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function connect() {
|
|
if (setupWebSocket()) {
|
|
// Disable connect button while connecting
|
|
connectButton.disabled = true;
|
|
}
|
|
}
|
|
|
|
function disconnect() {
|
|
// Clear any pending reconnect attempts
|
|
if (reconnectTimeout) {
|
|
clearTimeout(reconnectTimeout);
|
|
reconnectTimeout = null;
|
|
}
|
|
|
|
if (socket) {
|
|
// Use normal closure status code (1000) to indicate intentional disconnect
|
|
socket.close(1000, 'User disconnected');
|
|
}
|
|
}
|
|
|
|
function sendMessage() {
|
|
if (!socket || socket.readyState !== WebSocket.OPEN) {
|
|
addMessage('Not connected to server', 'error');
|
|
return;
|
|
}
|
|
|
|
const message = messageInput.value.trim();
|
|
if (!message) return;
|
|
|
|
try {
|
|
// Send a custom message
|
|
const messageObj = {
|
|
type: 'MESSAGE',
|
|
content: message,
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
|
|
socket.send(JSON.stringify(messageObj));
|
|
addMessage(`You: ${message}`, 'sent');
|
|
messageInput.value = '';
|
|
} catch (error) {
|
|
console.error('Error sending message:', error);
|
|
addMessage(`Failed to send message: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
// Event listeners
|
|
connectButton.addEventListener('click', connect);
|
|
disconnectButton.addEventListener('click', disconnect);
|
|
sendButton.addEventListener('click', sendMessage);
|
|
|
|
messageInput.addEventListener('keypress', function(event) {
|
|
if (event.key === 'Enter') {
|
|
sendMessage();
|
|
}
|
|
});
|
|
|
|
// Auto-connect if there's a token in the URL hash
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const hash = window.location.hash.substring(1);
|
|
if (hash) {
|
|
tokenInput.value = hash;
|
|
// Small delay to ensure the UI is ready
|
|
setTimeout(connect, 500);
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|