chore: 初始化仓库

中华文明全图鉴——文物全图系统(PC Web 地图 + NestJS API + 管理后台)。
含三大 IP(文物南迁北归 / 国宝海外回归 / 博物馆手艺人)、AI 文物对话、
文物地图与详情、以及 demo-video-kit 演示视频生成工具。
This commit is contained in:
selfrelease
2026-06-13 20:55:44 +08:00
commit 2d847e154f
161 changed files with 22629 additions and 0 deletions
+44
View File
@@ -0,0 +1,44 @@
import {
CanActivate,
ExecutionContext,
HttpException,
HttpStatus,
Injectable,
} from "@nestjs/common";
import { Request } from "express";
/**
* 简单的内存级 IP 限流守卫:滑动窗口。
* 用于保护成本敏感的 AI 接口,防止被刷爆额度。
*/
@Injectable()
export class RateLimitGuard implements CanActivate {
private static readonly WINDOW_MS = 60_000;
private static readonly MAX_REQUESTS = 20;
private static readonly buckets = new Map<string, number[]>();
canActivate(context: ExecutionContext): boolean {
const req = context.switchToHttp().getRequest<Request>();
const forwarded = req.headers["x-forwarded-for"];
const ip =
(Array.isArray(forwarded) ? forwarded[0] : forwarded?.split(",")[0])?.trim() ||
req.ip ||
"unknown";
const now = Date.now();
const recent = (RateLimitGuard.buckets.get(ip) ?? []).filter(
(t) => now - t < RateLimitGuard.WINDOW_MS
);
if (recent.length >= RateLimitGuard.MAX_REQUESTS) {
throw new HttpException(
"请求过于频繁,请稍后再试",
HttpStatus.TOO_MANY_REQUESTS
);
}
recent.push(now);
RateLimitGuard.buckets.set(ip, recent);
return true;
}
}