diff --git a/apps/client/src/app/room/[code]/game/[gameId]/game.tsx b/apps/client/src/app/room/[code]/game/[gameId]/game.tsx index d9ca192..e428899 100644 --- a/apps/client/src/app/room/[code]/game/[gameId]/game.tsx +++ b/apps/client/src/app/room/[code]/game/[gameId]/game.tsx @@ -5,7 +5,7 @@ import { EventFrom, State } from "xstate"; import { useMachine } from "@xstate/react"; import { AnimatePresence } from "framer-motion"; import { useQuery } from "@tanstack/react-query"; -import { redirect } from "next/navigation"; +import { useRouter } from "next/navigation"; import { GameInfo, @@ -36,6 +36,8 @@ export default function Game({ gameInfo, session }: GameProps) { // Socket for real-time communication const socket = useContext(SocketContext); + const router = useRouter(); + // Wait until the client mounts to avoid hydration errors const [isMounted, setIsMounted] = useState(false); @@ -138,9 +140,9 @@ export default function Game({ gameInfo, session }: GameProps) { const handlePlayAnotherGame = useCallback( (gameId: number) => { send("NEXT"); - redirect(`/room/${gameInfo.game.roomCode}/game/${gameId}`); + router.push(`/room/${gameInfo.game.roomCode}/game/${gameId}`); }, - [gameInfo.game.roomCode, send], + [gameInfo.game.roomCode, router, send], ); // Send new state to server diff --git a/apps/client/src/components/game/prompt.tsx b/apps/client/src/components/game/prompt.tsx index 6fa4974..6e7c497 100644 --- a/apps/client/src/components/game/prompt.tsx +++ b/apps/client/src/components/game/prompt.tsx @@ -50,7 +50,7 @@ const Prompt = ({ const gameId = gameInfo.game.id; const userId = session.user.id; const currRound = state.context.round; - const maxRegenerations = 3; + const maxRegenerations = 2; const userGameRoundGenerations = gameInfo.gameRoundGenerations.filter( (generation) => diff --git a/apps/client/src/utils/queries.ts b/apps/client/src/utils/queries.ts index 41653cf..664d98d 100644 --- a/apps/client/src/utils/queries.ts +++ b/apps/client/src/utils/queries.ts @@ -201,7 +201,6 @@ export async function getGameInfo(gameId: number, sessionToken: string) { export type GetGameLeaderboardResponse = { leaderboard: { user: User; points: number; standing: number }[]; - // winningGenerations: { question: Question; generation: Generation }[]; allGenerations: { question: Question; generation: Generation; user: User }[]; }; @@ -287,7 +286,7 @@ export const generateSDXLImages = async (prompt: string) => { body: JSON.stringify({ prompt }), }); - if (response.status !== 200) { + if (!response.ok) { throw new Error(`Request failed with status ${response.status}`); } diff --git a/apps/server/src/server.ts b/apps/server/src/server.ts index 46919d4..394649d 100644 --- a/apps/server/src/server.ts +++ b/apps/server/src/server.ts @@ -67,15 +67,32 @@ export function buildServer() { // Rate limiter // Based on https://redis.io/commands/incr#pattern-rate-limiter-1 app.use(async (req, res, next) => { + const isIPBlocked = await redis.get(`BLOCKED_${req.ip}`); + + if (isIPBlocked) { + res.status(429).send("Too many requests - try again tomorrow"); + return; + } + let redisIncr: number; try { redisIncr = await redis.incr(req.ip); - } catch (err) { + } catch (error) { console.error(`Could not increment rate limit key for ${req.ip}`); - throw err; + throw error; } if (redisIncr > 10) { - res.status(429).send("Too many requests - try again later"); + const today = new Date(); + const tomorrow = new Date(today); + tomorrow.setDate(tomorrow.getDate() + 1); + tomorrow.setHours(0, 0, 0, 0); + await redis.set(`BLOCKED_${req.ip}`, tomorrow.toISOString()); + await redis.expireat( + `BLOCKED_${req.ip}`, + Math.floor(tomorrow.getTime() / 1000) + ); + console.log("Blocked the IP Address:", req.ip); + res.status(429).send("Too many requests - try again tomorrow"); return; } await redis.expire(req.ip, 10);