diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index 20f6c0b85..b764667f0 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -377,7 +377,9 @@ "src/data/cctvFootprint.js", "src/sources/cctvTypes.js", "src/sources/httpBody.js", - "src/i18n/marker.js" + "src/i18n/marker.js", + "server/providers/common/rate-limit.js", + "src/sources/rateLimit.js" ], "external": [] }, diff --git a/server/providers/cctv.js b/server/providers/cctv.js index 64605b985..e8e18ad51 100644 --- a/server/providers/cctv.js +++ b/server/providers/cctv.js @@ -19,9 +19,22 @@ import { admitSameSiteKeyless } from './common/same-site.js'; import { PROXY_SIGNALS } from '../../src/localRequestGate.mjs'; import { createHlsPuller } from './cctv/stream.js'; import { googleServerApiKey } from './places/google-key.js'; -import { googleRateLimiter } from './places/google.js'; -import { clientKey } from './common/rate-limit.js'; +import { clientKey, makeCostRateLimiter } from './common/rate-limit.js'; export { CCTV_FRAME_FETCH_TIMEOUT_MS, fetchCctvImageFromUpstream }; +let _streetViewRateLimiter; +/** + * Per-IP budget for the Street View fallback, on the same setting as the + * other Google routes (GEV_RATELIMIT_GOOGLE_PER_MIN; 0 disables it). + */ +function streetViewRateLimiter() { + if (_streetViewRateLimiter === undefined) + _streetViewRateLimiter = makeCostRateLimiter( + process.env.GEV_RATELIMIT_GOOGLE_PER_MIN, + 120, + ); + return _streetViewRateLimiter; +} + /** * Vite plugin: CCTV camera proxy with source registry, frame/media serving, * fallback chain (upstream -> Street View -> synthetic SVG), and health tracking. @@ -549,7 +562,9 @@ export function cctvProxy({ sourceRoot = process.cwd() } = {}) { const forwarded = PROXY_SIGNALS.some( (name) => req.headers?.[name] !== undefined, ); - const googleBudget = googleServerApiKey() ? googleRateLimiter() : null; + const googleBudget = googleServerApiKey() + ? streetViewRateLimiter() + : null; const sv = forwarded || !source || diff --git a/server/providers/places/google.js b/server/providers/places/google.js index 5b034e706..1ddaa9593 100644 --- a/server/providers/places/google.js +++ b/server/providers/places/google.js @@ -27,8 +27,8 @@ let _googleRateLimiter; */ export const GOOGLE_DEFAULT_PER_MIN = 120; -/** Google cost endpoints (nearby-places, text-search, geocoding, the CCTV Street View fallback). Null only when set to 0. */ -export function googleRateLimiter() { +/** Google cost endpoints (nearby-places, text-search, geocoding). Null only when set to 0. */ +function googleRateLimiter() { if (_googleRateLimiter === undefined) _googleRateLimiter = makeCostRateLimiter( process.env.GEV_RATELIMIT_GOOGLE_PER_MIN,