修改推送数据格式
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
.idea
|
||||
node_modules
|
||||
.DS_Store
|
||||
.env
|
4
app.js
4
app.js
@ -14,6 +14,8 @@ const pushRouter = require('./routes/push');
|
||||
const {sendHeartbeat} = require('./lib/sse');
|
||||
const config = require('./config');
|
||||
|
||||
const timestamp = require('./utils/timeFormatter');
|
||||
|
||||
const app = express();
|
||||
|
||||
// 中间件
|
||||
@ -33,7 +35,7 @@ const errorHandler = (err, req, res, next) => {
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
error: 'Internal Server Error',
|
||||
timestamp: new Date().toISOString()
|
||||
timestamp: timestamp.formatTime()
|
||||
});
|
||||
};
|
||||
app.use(errorHandler);
|
||||
|
@ -12,11 +12,19 @@ module.exports = {
|
||||
env: process.env.NODE_ENV || 'development'
|
||||
},
|
||||
sse: {
|
||||
heartbeatInterval: 15000, // 15秒
|
||||
heartbeatInterval: 30000, // 30秒
|
||||
allowedOrigins: '*', //process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:3001']
|
||||
},
|
||||
rateLimit: {
|
||||
windowMs: 15 * 60 * 1000, // 15分钟
|
||||
max: 100 // 每个IP限制100个请求
|
||||
},
|
||||
redis: {
|
||||
url: process.env.REDIS_URL || 'redis://localhost:6379',
|
||||
database: process.env.REDIS_DB || 1, // 默认使用DB1
|
||||
socket: {
|
||||
reconnectStrategy: (retries) => Math.min(retries * 100, 5000)
|
||||
},
|
||||
ttl: 86400
|
||||
}
|
||||
};
|
@ -8,6 +8,7 @@
|
||||
|
||||
// 引入客户端管理模块,用于维护连接的客户端
|
||||
const clients = require('./clients');
|
||||
const timestamp = require('../utils/timeFormatter');
|
||||
|
||||
/**
|
||||
* 设置 SSE(Server-Sent Events)响应头,确保客户端能够正确接收事件流
|
||||
@ -27,7 +28,7 @@ function setupSSEHeaders(res) {
|
||||
function sendHeartbeat() {
|
||||
const data = {
|
||||
event: 'heartbeat', // 事件类型为 heartbeat
|
||||
time: new Date().toISOString() // 当前时间的 ISO 字符串格式
|
||||
time: timestamp.formatTime() // 当前时间的 ISO 字符串格式
|
||||
};
|
||||
return clients.broadcast(data); // 广播给所有连接的客户端
|
||||
}
|
||||
|
86
package-lock.json
generated
86
package-lock.json
generated
@ -15,9 +15,70 @@
|
||||
"express-sse": "^1.0.0",
|
||||
"helmet": "^8.1.0",
|
||||
"moment-timezone": "^0.6.0",
|
||||
"redis": "^5.5.6",
|
||||
"uuid": "^11.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/bloom": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.5.6.tgz",
|
||||
"integrity": "sha512-bNR3mxkwtfuCxNOzfV8B3R5zA1LiN57EH6zK4jVBIgzMzliNuReZXBFGnXvsi80/SYohajn78YdpYI+XNpqL+A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^5.5.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/client": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@redis/client/-/client-5.5.6.tgz",
|
||||
"integrity": "sha512-M3Svdwt6oSfyfQdqEr0L2HOJH2vK7GgCFx1NfAQvpWAT4+ljoT1L5S5cKT3dA9NJrxrOPDkdoTPWJnIrGCOcmw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cluster-key-slot": "1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/json": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@redis/json/-/json-5.5.6.tgz",
|
||||
"integrity": "sha512-AIsoe3SsGQagqAmSQHaqxEinm5oCWr7zxPWL90kKaEdLJ+zw8KBznf2i9oK0WUFP5pFssSQUXqnscQKe2amfDQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^5.5.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/search": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@redis/search/-/search-5.5.6.tgz",
|
||||
"integrity": "sha512-JSqasYqO0mVcHL7oxvbySRBBZYRYhFl3W7f0Da7BW8M/r0Z9wCiVrdjnN4/mKBpWZkoJT/iuisLUdPGhpKxBew==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^5.5.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/time-series": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-5.5.6.tgz",
|
||||
"integrity": "sha512-jkpcgq3NOI3TX7xEAJ3JgesJTxAx7k0m6lNxNsYdEM8KOl+xj7GaB/0CbLkoricZDmFSEAz7ClA1iK9XkGHf+Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^5.5.6"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
||||
@ -89,6 +150,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/cluster-key-slot": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
|
||||
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
|
||||
@ -690,6 +760,22 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/redis": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/redis/-/redis-5.5.6.tgz",
|
||||
"integrity": "sha512-hbpqBfcuhWHOS9YLNcXcJ4akNr7HFX61Dq3JuFZ9S7uU7C7kvnzuH2PDIXOP62A3eevvACoG8UacuXP3N07xdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@redis/bloom": "5.5.6",
|
||||
"@redis/client": "5.5.6",
|
||||
"@redis/json": "5.5.6",
|
||||
"@redis/search": "5.5.6",
|
||||
"@redis/time-series": "5.5.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/router": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
|
||||
|
@ -10,6 +10,7 @@
|
||||
"express-sse": "^1.0.0",
|
||||
"helmet": "^8.1.0",
|
||||
"moment-timezone": "^0.6.0",
|
||||
"redis": "^5.5.6",
|
||||
"uuid": "^11.1.0"
|
||||
}
|
||||
}
|
||||
|
@ -8,33 +8,38 @@
|
||||
|
||||
const express = require('express');
|
||||
const clients = require('../lib/clients');
|
||||
const moment = require('moment-timezone')
|
||||
const timeFormat = require('../utils/timeFormatter');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.post('/', (req, res) => {
|
||||
const {message, clientId} = req.body;
|
||||
const { id, type, data, timestamp: ts, client_id } = req.body;
|
||||
|
||||
if (!message) {
|
||||
return res.status(400).json({error: 'Message is required'});
|
||||
if (!type || !data) {
|
||||
return res.status(400).json({ error: 'Missing required fields: type or data' });
|
||||
}
|
||||
|
||||
const shanghaiTime = moment().tz('Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss');
|
||||
const payload = {
|
||||
id: id || crypto.randomUUID(),
|
||||
type,
|
||||
data,
|
||||
timestamp: ts || Math.floor(Date.now() / 1000),
|
||||
client_id: client_id || null,
|
||||
server_time: timeFormat.formatTime()
|
||||
};
|
||||
|
||||
const data = {message, time: shanghaiTime};
|
||||
|
||||
if (clientId) {
|
||||
const clientRes = clients.get(clientId);
|
||||
if (client_id) {
|
||||
const clientRes = clients.get(client_id);
|
||||
if (!clientRes) {
|
||||
return res.status(404).json({error: 'Client not found'});
|
||||
return res.status(404).json({ error: `Client ${client_id} not found` });
|
||||
}
|
||||
|
||||
clientRes.write(`data: ${JSON.stringify(data)}\n\n`);
|
||||
return res.json({message: 'Message delivered', clientId});
|
||||
clientRes.write(`data: ${JSON.stringify(payload)}\n\n`);
|
||||
return res.json({ message: 'Message delivered', client_id });
|
||||
}
|
||||
|
||||
const count = clients.broadcast(data);
|
||||
return res.json({message: 'Message broadcasted', clients: count});
|
||||
const count = clients.broadcast(payload);
|
||||
return res.json({ message: 'Message broadcasted', delivered_to: count });
|
||||
});
|
||||
|
||||
module.exports = router;
|
@ -10,7 +10,7 @@ const express = require('express');
|
||||
const { v4: uuidV4 } = require('uuid');
|
||||
const { setupSSEHeaders } = require('../lib/sse');
|
||||
const clients = require('../lib/clients');
|
||||
const moment = require('moment-timezone');
|
||||
const timestamp = require('../utils/timeFormatter');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
@ -19,13 +19,11 @@ router.get('/', (req, res) => {
|
||||
|
||||
setupSSEHeaders(res);
|
||||
|
||||
const shanghaiTime = moment().tz('Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
// 立即发送确认
|
||||
res.write(`data: ${JSON.stringify({
|
||||
status: 'connected',
|
||||
clientId,
|
||||
time: shanghaiTime
|
||||
time: timestamp.formatTime()
|
||||
})}\n\n`);
|
||||
|
||||
clients.add(clientId, res);
|
||||
|
13
utils/timeFormatter.js
Normal file
13
utils/timeFormatter.js
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 时间格式化工具
|
||||
* @author Yk <yk_9001@icloud.com>
|
||||
* @param {string} timezone - 时区
|
||||
* @returns {string} 格式化后的时间字符串
|
||||
*/
|
||||
function formatTime(timezone = 'Asia/Shanghai') {
|
||||
const moment = require('moment-timezone');
|
||||
|
||||
return moment().tz(timezone).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
|
||||
module.exports = {formatTime};
|
Reference in New Issue
Block a user