move beatsaver map caching to redis
All checks were successful
deploy / deploy (push) Successful in 1m35s
All checks were successful
deploy / deploy (push) Successful in 1m35s
This commit is contained in:
parent
af707a8c79
commit
e6b169f3fc
4
.env
Normal file
4
.env
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
SENTRY_AUTH_TOKEN=hi
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
REDIS_URL=redis://:bigtitsyes7@10.0.0.203:30004
|
@ -1 +1,4 @@
|
|||||||
SENTRY_AUTH_TOKEN=hi
|
SENTRY_AUTH_TOKEN=hi
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
REDIS_URL=redis://localhost:6379/0
|
@ -39,6 +39,7 @@
|
|||||||
"react-chartjs-2": "^5.2.0",
|
"react-chartjs-2": "^5.2.0",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
"react-toastify": "^9.1.3",
|
"react-toastify": "^9.1.3",
|
||||||
|
"redis": "^4.6.10",
|
||||||
"sharp": "^0.32.6",
|
"sharp": "^0.32.6",
|
||||||
"tailwind-merge": "^2.0.0",
|
"tailwind-merge": "^2.0.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
|
73
pnpm-lock.yaml
generated
73
pnpm-lock.yaml
generated
@ -89,6 +89,9 @@ dependencies:
|
|||||||
react-toastify:
|
react-toastify:
|
||||||
specifier: ^9.1.3
|
specifier: ^9.1.3
|
||||||
version: 9.1.3(react-dom@18.2.0)(react@18.2.0)
|
version: 9.1.3(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
redis:
|
||||||
|
specifier: ^4.6.10
|
||||||
|
version: 4.6.10
|
||||||
sharp:
|
sharp:
|
||||||
specifier: ^0.32.6
|
specifier: ^0.32.6
|
||||||
version: 0.32.6
|
version: 0.32.6
|
||||||
@ -1062,6 +1065,55 @@ packages:
|
|||||||
'@babel/runtime': 7.23.2
|
'@babel/runtime': 7.23.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@redis/bloom@1.2.0(@redis/client@1.5.11):
|
||||||
|
resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==}
|
||||||
|
peerDependencies:
|
||||||
|
'@redis/client': ^1.0.0
|
||||||
|
dependencies:
|
||||||
|
'@redis/client': 1.5.11
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@redis/client@1.5.11:
|
||||||
|
resolution: {integrity: sha512-cV7yHcOAtNQ5x/yQl7Yw1xf53kO0FNDTdDU6bFIMbW6ljB7U7ns0YRM+QIkpoqTAt6zK5k9Fq0QWlUbLcq9AvA==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
dependencies:
|
||||||
|
cluster-key-slot: 1.1.2
|
||||||
|
generic-pool: 3.9.0
|
||||||
|
yallist: 4.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@redis/graph@1.1.0(@redis/client@1.5.11):
|
||||||
|
resolution: {integrity: sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==}
|
||||||
|
peerDependencies:
|
||||||
|
'@redis/client': ^1.0.0
|
||||||
|
dependencies:
|
||||||
|
'@redis/client': 1.5.11
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@redis/json@1.0.6(@redis/client@1.5.11):
|
||||||
|
resolution: {integrity: sha512-rcZO3bfQbm2zPRpqo82XbW8zg4G/w4W3tI7X8Mqleq9goQjAGLL7q/1n1ZX4dXEAmORVZ4s1+uKLaUOg7LrUhw==}
|
||||||
|
peerDependencies:
|
||||||
|
'@redis/client': ^1.0.0
|
||||||
|
dependencies:
|
||||||
|
'@redis/client': 1.5.11
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@redis/search@1.1.5(@redis/client@1.5.11):
|
||||||
|
resolution: {integrity: sha512-hPP8w7GfGsbtYEJdn4n7nXa6xt6hVZnnDktKW4ArMaFQ/m/aR7eFvsLQmG/mn1Upq99btPJk+F27IQ2dYpCoUg==}
|
||||||
|
peerDependencies:
|
||||||
|
'@redis/client': ^1.0.0
|
||||||
|
dependencies:
|
||||||
|
'@redis/client': 1.5.11
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@redis/time-series@1.0.5(@redis/client@1.5.11):
|
||||||
|
resolution: {integrity: sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg==}
|
||||||
|
peerDependencies:
|
||||||
|
'@redis/client': ^1.0.0
|
||||||
|
dependencies:
|
||||||
|
'@redis/client': 1.5.11
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@rollup/plugin-commonjs@24.0.0(rollup@2.78.0):
|
/@rollup/plugin-commonjs@24.0.0(rollup@2.78.0):
|
||||||
resolution: {integrity: sha512-0w0wyykzdyRRPHOb0cQt14mIBLujfAv6GgP6g8nvg/iBxEm112t3YPPq+Buqe2+imvElTka+bjNlJ/gB56TD8g==}
|
resolution: {integrity: sha512-0w0wyykzdyRRPHOb0cQt14mIBLujfAv6GgP6g8nvg/iBxEm112t3YPPq+Buqe2+imvElTka+bjNlJ/gB56TD8g==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@ -1719,6 +1771,11 @@ packages:
|
|||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/cluster-key-slot@1.1.2:
|
||||||
|
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/color-convert@2.0.1:
|
/color-convert@2.0.1:
|
||||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||||
engines: {node: '>=7.0.0'}
|
engines: {node: '>=7.0.0'}
|
||||||
@ -2524,6 +2581,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
|
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/generic-pool@3.9.0:
|
||||||
|
resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==}
|
||||||
|
engines: {node: '>= 4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/get-intrinsic@1.2.2:
|
/get-intrinsic@1.2.2:
|
||||||
resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==}
|
resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -3766,6 +3828,17 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
|
|
||||||
|
/redis@4.6.10:
|
||||||
|
resolution: {integrity: sha512-mmbyhuKgDiJ5TWUhiKhBssz+mjsuSI/lSZNPI9QvZOYzWvYGejtb+W3RlDDf8LD6Bdl5/mZeG8O1feUGhXTxEg==}
|
||||||
|
dependencies:
|
||||||
|
'@redis/bloom': 1.2.0(@redis/client@1.5.11)
|
||||||
|
'@redis/client': 1.5.11
|
||||||
|
'@redis/graph': 1.1.0(@redis/client@1.5.11)
|
||||||
|
'@redis/json': 1.0.6(@redis/client@1.5.11)
|
||||||
|
'@redis/search': 1.1.5(@redis/client@1.5.11)
|
||||||
|
'@redis/time-series': 1.0.5(@redis/client@1.5.11)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/reflect.getprototypeof@1.0.4:
|
/reflect.getprototypeof@1.0.4:
|
||||||
resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==}
|
resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
import { Redis } from "@/db/redis";
|
||||||
import { BeatsaverMap } from "@/schemas/beatsaver/BeatsaverMap";
|
import { BeatsaverMap } from "@/schemas/beatsaver/BeatsaverMap";
|
||||||
import { BeatsaverAPI } from "@/utils/beatsaver/api";
|
import { BeatsaverAPI } from "@/utils/beatsaver/api";
|
||||||
|
|
||||||
const mapCache = new Map<string, BeatsaverMap>();
|
await Redis.connectRedis();
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
export async function GET(request: Request) {
|
||||||
const { searchParams } = new URL(request.url);
|
const { searchParams } = new URL(request.url);
|
||||||
@ -10,24 +11,41 @@ export async function GET(request: Request) {
|
|||||||
return new Response("mapHashes parameter is required", { status: 400 });
|
return new Response("mapHashes parameter is required", { status: 400 });
|
||||||
}
|
}
|
||||||
const idOnly = searchParams.get("idonly") === "true";
|
const idOnly = searchParams.get("idonly") === "true";
|
||||||
|
let totalInCache = 0;
|
||||||
|
|
||||||
const maps: Record<string, BeatsaverMap | { id: string }> = {};
|
const maps: Record<string, BeatsaverMap | { id: string }> = {};
|
||||||
for (const mapHash of mapHashes) {
|
for (const mapHash of mapHashes) {
|
||||||
if (mapCache.has(mapHash)) {
|
const cachedMap = await (
|
||||||
maps[mapHash] = mapCache.get(mapHash)!;
|
await Redis.client
|
||||||
|
).get(`beatsaver:map:${mapHash}`);
|
||||||
|
if (cachedMap) {
|
||||||
|
maps[mapHash] = JSON.parse(cachedMap);
|
||||||
|
totalInCache++;
|
||||||
} else {
|
} else {
|
||||||
const map = await BeatsaverAPI.fetchMapByHash(mapHash);
|
const map = await BeatsaverAPI.fetchMapByHash(mapHash);
|
||||||
if (map) {
|
if (!map) {
|
||||||
maps[mapHash] = map;
|
continue;
|
||||||
mapCache.set(mapHash, map);
|
|
||||||
}
|
|
||||||
if (map && idOnly) {
|
|
||||||
maps[mapHash] = { id: map.id };
|
|
||||||
}
|
}
|
||||||
|
maps[mapHash] = map;
|
||||||
|
await (
|
||||||
|
await Redis.client
|
||||||
|
).set("beatsaver:map:" + mapHash, JSON.stringify(map), {
|
||||||
|
EX: 60 * 60 * 24 * 7, // 7 days
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idOnly) {
|
||||||
|
maps[mapHash] = { id: (maps[mapHash] as BeatsaverMap).id };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Response(JSON.stringify(maps), {
|
return new Response(
|
||||||
headers: { "content-type": "application/json;charset=UTF-8" },
|
JSON.stringify({
|
||||||
});
|
maps,
|
||||||
|
totalInCache,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
headers: { "content-type": "application/json;charset=UTF-8" },
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,14 @@ export default function BeatSaverLogo({
|
|||||||
version="1.1"
|
version="1.1"
|
||||||
className={className}
|
className={className}
|
||||||
>
|
>
|
||||||
<g fill="none" stroke="#000000" stroke-width="10">
|
<g fill="none" stroke="#000000" strokeWidth="10">
|
||||||
<path d="M 100,7 189,47 100,87 12,47 Z" stroke-linejoin="round"></path>
|
<path d="M 100,7 189,47 100,87 12,47 Z" strokeLinejoin="round"></path>
|
||||||
<path
|
<path
|
||||||
d="M 189,47 189,155 100,196 12,155 12,47"
|
d="M 189,47 189,155 100,196 12,155 12,47"
|
||||||
stroke-linejoin="round"
|
strokeLinejoin="round"
|
||||||
></path>
|
></path>
|
||||||
<path d="M 100,87 100,196" stroke-linejoin="round"></path>
|
<path d="M 100,87 100,196" strokeLinejoin="round"></path>
|
||||||
<path d="M 26,77 85,106 53,130 Z" stroke-linejoin="round"></path>
|
<path d="M 26,77 85,106 53,130 Z" strokeLinejoin="round"></path>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
31
src/db/redis.ts
Normal file
31
src/db/redis.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { createClient } from "redis";
|
||||||
|
|
||||||
|
let redisClient = connectRedis();
|
||||||
|
|
||||||
|
async function connectRedis() {
|
||||||
|
console.log("Connecting to redis");
|
||||||
|
const client = createClient({
|
||||||
|
url: process.env.REDIS_URL,
|
||||||
|
});
|
||||||
|
await client.connect();
|
||||||
|
|
||||||
|
client.on("connect", () => {
|
||||||
|
console.log("Connected to redis");
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("error", (error) => {
|
||||||
|
console.error("There was an error connecting to redis: " + error);
|
||||||
|
setTimeout(() => {
|
||||||
|
redisClient = connectRedis();
|
||||||
|
}, 5_000); // 5 seconds
|
||||||
|
});
|
||||||
|
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: add disconnect handler
|
||||||
|
|
||||||
|
export const Redis = {
|
||||||
|
client: redisClient,
|
||||||
|
connectRedis,
|
||||||
|
};
|
@ -176,7 +176,7 @@ async function fetchScoresWithBeatsaverData(
|
|||||||
});
|
});
|
||||||
const mapJson = await mapResponse.json();
|
const mapJson = await mapResponse.json();
|
||||||
for (const score of scores) {
|
for (const score of scores) {
|
||||||
const mapData = mapJson[score.leaderboard.songHash];
|
const mapData = mapJson.maps[score.leaderboard.songHash];
|
||||||
if (mapData) {
|
if (mapData) {
|
||||||
scoresWithBeatsaverData[score.leaderboard.songHash] = {
|
scoresWithBeatsaverData[score.leaderboard.songHash] = {
|
||||||
score: score.score,
|
score: score.score,
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2016",
|
"target": "ES2022",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"esnext"
|
|
||||||
],
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
@ -24,18 +20,9 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": [
|
"@/*": ["./src/*"]
|
||||||
"./src/*"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||||
"next-env.d.ts",
|
"exclude": ["node_modules"]
|
||||||
"**/*.ts",
|
|
||||||
"**/*.tsx",
|
|
||||||
".next/types/**/*.ts"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user