东丽网口版透析机 socket- server 通讯
chenyc
20 小时以前 55c8181bbe4c198f9bda5520ea0d8ba148933f9e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// rateLimiter.js - 请求频率限制管理
const logger = require('./logger');
 
class RateLimiter {
    constructor() {
        // 存储请求记录
        // key: identifier (设备号或IP), value: { lastRequestTime, count }
        this.requestMap = new Map();
    }
 
    /**
     * 检查是否允许请求
     * @param {string} identifier - 标识符(设备号、IP 等)
     * @param {number} intervalMs - 时间间隔(毫秒)
     * @returns {object} { allowed: boolean, remainingTime: number }
     */
    checkLimit(identifier, intervalMs = 5000) {
        if (!identifier) {
            logger.warn('限流检查: 标识符为空');
            return { allowed: true, remainingTime: 0 };
        }
 
        const now = Date.now();
        const record = this.requestMap.get(identifier);
 
        if (!record) {
            // 第一次请求,允许
            this.requestMap.set(identifier, {
                lastRequestTime: now,
                count: 1
            });
            logger.info(`✅ 限流: 首次请求 ${identifier}`);
            return { allowed: true, remainingTime: 0 };
        }
 
        const timeSinceLastRequest = now - record.lastRequestTime;
 
        if (timeSinceLastRequest < intervalMs) {
            // 请求过于频繁
            const remainingTime = intervalMs - timeSinceLastRequest;
            logger.warn(`⏱️ 限流: ${identifier} 请求过于频繁,需等待 ${remainingTime}ms`);
            
            return {
                allowed: false,
                remainingTime: Math.ceil(remainingTime)
            };
        }
 
        // 允许请求,更新记录
        this.requestMap.set(identifier, {
            lastRequestTime: now,
            count: record.count + 1
        });
        logger.info(`✅ 限流: ${identifier} 请求已允许 (第 ${record.count + 1} 次)`);
 
        return { allowed: true, remainingTime: 0 };
    }
 
    /**
     * 获取限流状态
     */
    getStatus(identifier) {
        return this.requestMap.get(identifier) || null;
    }
 
    /**
     * 获取所有限流记录
     */
    getAllStatus() {
        const result = {};
        for (const [key, value] of this.requestMap.entries()) {
            result[key] = value;
        }
        return result;
    }
 
    /**
     * 清空特定标识符的限流记录
     */
    clearIdentifier(identifier) {
        if (this.requestMap.has(identifier)) {
            this.requestMap.delete(identifier);
            logger.info(`🗑️ 已清空限流记录: ${identifier}`);
            return true;
        }
        return false;
    }
 
    /**
     * 清空所有限流记录
     */
    clearAll() {
        const count = this.requestMap.size;
        this.requestMap.clear();
        logger.info(`🗑️ 已清空所有限流记录 (共 ${count} 条)`);
    }
 
    /**
     * 获取限流统计信息
     */
    getStats() {
        return {
            totalIdentifiers: this.requestMap.size,
            records: this.getAllStatus()
        };
    }
 
    /**
     * 清理过期的限流记录(可选)
     * @param {number} maxAgeMs - 最大保留时间(毫秒)
     */
    cleanupExpired(maxAgeMs = 3600000) { // 默认 1 小时
        const now = Date.now();
        let cleanedCount = 0;
 
        for (const [identifier, record] of this.requestMap.entries()) {
            if (now - record.lastRequestTime > maxAgeMs) {
                this.requestMap.delete(identifier);
                cleanedCount++;
            }
        }
 
        if (cleanedCount > 0) {
            logger.info(`🧹 已清理过期限流记录: ${cleanedCount} 条`);
        }
 
        return cleanedCount;
    }
}
 
// 导出单例
module.exports = new RateLimiter();