add passenger telemetry

This commit is contained in:
2026-05-21 00:09:11 +03:00
parent 66c84ecdeb
commit e57fea321f
15 changed files with 1411 additions and 6 deletions

View File

@@ -0,0 +1,83 @@
const { hashValue } = require('../services/passengerTelemetryAggregator');
const buckets = new Map();
function cleanupBucket(key, now) {
const bucket = buckets.get(key);
if (bucket && bucket.resetAt <= now) {
buckets.delete(key);
}
}
function incrementBucket(key, now, windowMs) {
cleanupBucket(key, now);
const existing = buckets.get(key);
if (existing) {
existing.count += 1;
return existing;
}
const bucket = {
count: 1,
resetAt: now + windowMs
};
buckets.set(key, bucket);
return bucket;
}
function normalizeKeyPart(value, fallback) {
if (value === undefined || value === null || value === '') {
return fallback;
}
return hashValue(String(value).trim());
}
function createPassengerTelemetryRateLimiter({
maxRequests = 60,
windowMs = 60 * 1000,
nowProvider = () => Date.now()
} = {}) {
return (req, res, next) => {
const now = nowProvider();
const sessionId = req.body?.session_id ?? req.body?.sessionId;
const sessionKey = normalizeKeyPart(sessionId, 'missing-session');
const ipKey = normalizeKeyPart(req.ip || req.socket?.remoteAddress, 'unknown-ip');
const keys = [
`passenger-telemetry:session:${sessionKey}`,
`passenger-telemetry:ip:${ipKey}`
];
if (req.apiKeyInfo?.id) {
keys.push(`passenger-telemetry:api-key:${normalizeKeyPart(req.apiKeyInfo.id, 'api-key')}`);
}
const exceeded = keys
.map((key) => incrementBucket(key, now, windowMs))
.find((bucket) => bucket.count > maxRequests);
if (exceeded) {
return res.status(429).json({
error: 'Too many passenger telemetry samples',
message: 'Rate limit exceeded. Please try again later.',
retryAfter: Math.ceil((exceeded.resetAt - now) / 1000)
});
}
return next();
};
}
function resetPassengerTelemetryRateLimitersForTesting() {
buckets.clear();
}
module.exports = {
createPassengerTelemetryRateLimiter,
resetPassengerTelemetryRateLimitersForTesting
};