You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
5.4 KiB

// P2P 聊天程序 - Web 客户端
let ws = null;
let username = '';
let connected = false;
// DOM 元素
const connectPanel = document.getElementById('connectPanel');
const chatPanel = document.getElementById('chatPanel');
const usernameInput = document.getElementById('username');
const serverHostInput = document.getElementById('serverHost');
const serverPortInput = document.getElementById('serverPort');
const connectBtn = document.getElementById('connectBtn');
const disconnectBtn = document.getElementById('disconnectBtn');
const messageArea = document.getElementById('messageArea');
const messageInput = document.getElementById('messageInput');
const sendBtn = document.getElementById('sendBtn');
const peerList = document.getElementById('peerList');
const onlineCount = document.getElementById('onlineCount');
const userInfo = document.getElementById('userInfo');
const statusBar = document.getElementById('statusBar');
// 连接到服务器
connectBtn.addEventListener('click', () => {
username = usernameInput.value.trim();
const host = serverHostInput.value.trim();
const port = serverPortInput.value.trim();
if (!username) {
showStatus('请输入用户名', 'error');
return;
}
if (!host || !port) {
showStatus('请输入服务器地址和端口', 'error');
return;
}
connect(host, port);
});
// 断开连接
disconnectBtn.addEventListener('click', () => {
disconnect();
});
// 发送消息
sendBtn.addEventListener('click', sendMessage);
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendMessage();
}
});
function sendMessage() {
const message = messageInput.value.trim();
if (!message || !connected) return;
// 发送到服务器
ws.send('MESSAGE:' + message);
// 显示自己的消息
addMessage(username, message, true);
messageInput.value = '';
}
// 连接 WebSocket
function connect(host, port) {
try {
ws = new WebSocket(`ws://${host}:${port}`);
ws.onopen = () => {
connected = true;
ws.send('USERNAME:' + username);
connectPanel.style.display = 'none';
chatPanel.style.display = 'flex';
userInfo.textContent = `用户: ${username}`;
showStatus('连接成功!', 'success');
addSystemMessage('已连接到服务器');
};
ws.onmessage = (event) => {
handleMessage(event.data);
};
ws.onerror = (error) => {
showStatus('连接错误', 'error');
console.error('WebSocket error:', error);
};
ws.onclose = () => {
connected = false;
showStatus('连接已断开', 'error');
addSystemMessage('与服务器的连接已断开');
};
} catch (error) {
showStatus('连接失败: ' + error.message, 'error');
}
}
// 断开连接
function disconnect() {
if (ws) {
ws.close();
}
connected = false;
connectPanel.style.display = 'block';
chatPanel.style.display = 'none';
messageArea.innerHTML = '';
peerList.innerHTML = '';
}
// 处理接收到的消息
function handleMessage(data) {
if (data.startsWith('SYSTEM:')) {
const msg = data.substring(7);
addSystemMessage(msg);
} else if (data.startsWith('PEERS:')) {
const peers = data.substring(6).split(',').filter(p => p);
updatePeerList(peers);
} else if (data.startsWith('[')) {
// 格式: [用户名]: 消息
const match = data.match(/\[(.+?)\]: (.+)/);
if (match) {
addMessage(match[1], match[2], false);
}
}
}
// 添加消息到聊天区域
function addMessage(user, message, isOwn) {
const messageDiv = document.createElement('div');
messageDiv.className = 'message message-user' + (isOwn ? ' own' : '');
const header = document.createElement('div');
header.className = 'message-header';
header.textContent = user;
const content = document.createElement('div');
content.className = 'message-content';
content.textContent = message;
messageDiv.appendChild(header);
messageDiv.appendChild(content);
messageArea.appendChild(messageDiv);
// 滚动到底部
messageArea.scrollTop = messageArea.scrollHeight;
}
// 添加系统消息
function addSystemMessage(message) {
const messageDiv = document.createElement('div');
messageDiv.className = 'message message-system';
messageDiv.textContent = message;
messageArea.appendChild(messageDiv);
messageArea.scrollTop = messageArea.scrollHeight;
}
// 更新对等端列表
function updatePeerList(peers) {
peerList.innerHTML = '';
peers.forEach(peer => {
if (peer !== username) {
const peerDiv = document.createElement('div');
peerDiv.className = 'peer-item';
peerDiv.textContent = peer;
peerList.appendChild(peerDiv);
}
});
onlineCount.textContent = `在线: ${peers.length}`;
}
// 显示状态提示
function showStatus(message, type = 'success') {
statusBar.textContent = message;
statusBar.className = 'status-bar show ' + type;
setTimeout(() => {
statusBar.className = 'status-bar';
}, 3000);
}
// 页面加载完成后自动聚焦用户名输入框
window.addEventListener('load', () => {
usernameInput.focus();
});