初始化SSE服务端项目

This commit is contained in:
2025-07-01 20:07:24 +08:00
commit 2f899e8792
11 changed files with 1199 additions and 0 deletions

74
lib/clients.js Normal file
View File

@ -0,0 +1,74 @@
/**
* @file 管理所有 SSE 客户端连接的模块
* @author Yk <yk_9001@icloud.com>
* @date 2025-07-01
* @description 提供客户端连接的添加、移除、获取及广播消息功能
*/
class SSEClientsManager {
/**
* 构造函数,初始化一个 Map 来存储客户端连接
*/
constructor() {
this.clients = new Map(); // 使用 Map 存储 clientId 到响应对象的映射
}
/**
* 添加一个新的客户端连接
* @param {string} clientId - 客户端唯一标识
* @param {Object} res - HTTP 响应对象,用于后续通信
* @returns {number} 当前客户端数量
*/
add(clientId, res) {
this.clients.set(clientId, res);
return this.clients.size;
}
/**
* 移除指定的客户端连接
* @param {string} clientId - 要移除的客户端 ID
* @returns {number} 移除后剩余的客户端数量
*/
remove(clientId) {
this.clients.delete(clientId);
return this.clients.size;
}
/**
* 获取指定的客户端响应对象
* @param {string} clientId - 客户端 ID
* @returns {Object} 对应的响应对象,或 undefined
*/
get(clientId) {
return this.clients.get(clientId);
}
/**
* 向所有客户端广播数据
* @param {*} data - 要广播的数据,将被序列化为 JSON
* @returns {number} 成功发送的客户端数量
*/
broadcast(data) {
let successCount = 0;
for (const [id, res] of this.clients.entries()) {
try {
res.write(`data: ${JSON.stringify(data)}\n\n`); // 发送标准的 SSE 格式数据
successCount++;
} catch (err) {
this.remove(id); // 如果发送失败,移除该客户端连接
}
}
return successCount;
}
/**
* 获取当前连接的客户端总数
* @returns {number}
*/
size() {
return this.clients.size;
}
}
// 导出单例实例,确保全局共享同一组客户端连接
module.exports = new SSEClientsManager();

39
lib/sse.js Normal file
View File

@ -0,0 +1,39 @@
/**
* @file 处理SSE请求
* @author Yk <yk_9001@icloud.com>
* @createdAt 2025-07-01
* @lastModifiedAt 2025-07-01
* @description 维护链接的客户端
*/
// 引入客户端管理模块,用于维护连接的客户端
const clients = require('./clients');
/**
* 设置 SSEServer-Sent Events响应头确保客户端能够正确接收事件流
* @param {Object} res - HTTP 响应对象
*/
function setupSSEHeaders(res) {
res.setHeader('Content-Type', 'text/event-stream'); // 指定内容类型为事件流
res.setHeader('Cache-Control', 'no-cache'); // 禁止缓存
res.setHeader('Connection', 'keep-alive'); // 保持长连接
res.flushHeaders(); // 立即发送响应头
}
/**
* 发送心跳事件给所有连接的客户端,用于保持连接活跃并传递服务器时间
* @returns {void}
*/
function sendHeartbeat() {
const data = {
event: 'heartbeat', // 事件类型为 heartbeat
time: new Date().toISOString() // 当前时间的 ISO 字符串格式
};
return clients.broadcast(data); // 广播给所有连接的客户端
}
// 导出函数,供其他模块使用
module.exports = {
setupSSEHeaders,
sendHeartbeat
};