diff --git a/README.md b/README.md index 75dc884..7930a81 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Prerequisite: bun installed The environment variables `API_HOST` and `AUTH_HOST` will need to be set for the middleware. Example `.env` in web's root: ``` -API_HOST="http://localhost:8082/v1/" +API_HOST="http://localhost:8082/" AUTH_HOST="http://localhost:8083/" ``` diff --git a/web/src/app/mapfixes/page.tsx b/web/src/app/mapfixes/page.tsx index 98b31e2..e4674b6 100644 --- a/web/src/app/mapfixes/page.tsx +++ b/web/src/app/mapfixes/page.tsx @@ -11,29 +11,10 @@ import "./(styles)/page.scss"; import { ListSortConstants } from "../ts/Sort"; export default function MapfixInfoPage() { - const [mapfixes, setMapfixes] = useState({Total:0,Mapfixes:[]}) + const [mapfixes, setMapfixes] = useState(null) const [currentPage, setCurrentPage] = useState(1); const cardsPerPage = 24; // built to fit on a 1920x1080 monitor - const totalPages = Math.ceil(mapfixes.Total / cardsPerPage); - - const currentCards = mapfixes.Mapfixes.slice( - (currentPage - 1) * cardsPerPage, - currentPage * cardsPerPage - ); - - const nextPage = () => { - if (currentPage < totalPages) { - setCurrentPage(currentPage + 1); - } - }; - - const prevPage = () => { - if (currentPage > 1) { - setCurrentPage(currentPage - 1); - } - }; - useEffect(() => { async function fetchMapfixes() { const res = await fetch(`/api/mapfixes?Page=${currentPage}&Limit=${cardsPerPage}&Sort=${ListSortConstants.ListSortDateDescending}`) @@ -55,7 +36,26 @@ export default function MapfixInfoPage() { } - if (mapfixes && mapfixes.Total == 0) { + const totalPages = Math.ceil(mapfixes.Total / cardsPerPage); + + const currentCards = mapfixes.Mapfixes.slice( + (currentPage - 1) * cardsPerPage, + currentPage * cardsPerPage + ); + + const nextPage = () => { + if (currentPage < totalPages) { + setCurrentPage(currentPage + 1); + } + }; + + const prevPage = () => { + if (currentPage > 1) { + setCurrentPage(currentPage - 1); + } + }; + + if (mapfixes.Total == 0) { return
Mapfixes list is empty. diff --git a/web/src/app/submissions/page.tsx b/web/src/app/submissions/page.tsx index 8a7c017..bd67b33 100644 --- a/web/src/app/submissions/page.tsx +++ b/web/src/app/submissions/page.tsx @@ -9,29 +9,10 @@ import "./(styles)/page.scss"; import { ListSortConstants } from "../ts/Sort"; export default function SubmissionInfoPage() { - const [submissions, setSubmissions] = useState({Total:0,Submissions:[]}) + const [submissions, setSubmissions] = useState(null) const [currentPage, setCurrentPage] = useState(1); const cardsPerPage = 24; // built to fit on a 1920x1080 monitor - const totalPages = Math.ceil(submissions.Total / cardsPerPage); - - const currentCards = submissions.Submissions.slice( - (currentPage - 1) * cardsPerPage, - currentPage * cardsPerPage - ); - - const nextPage = () => { - if (currentPage < totalPages) { - setCurrentPage(currentPage + 1); - } - }; - - const prevPage = () => { - if (currentPage > 1) { - setCurrentPage(currentPage - 1); - } - }; - useEffect(() => { async function fetchSubmissions() { const res = await fetch(`/api/submissions?Page=${currentPage}&Limit=${cardsPerPage}&Sort=${ListSortConstants.ListSortDateDescending}`) @@ -53,7 +34,26 @@ export default function SubmissionInfoPage() { } - if (submissions && submissions.Total == 0) { + const totalPages = Math.ceil(submissions.Total / cardsPerPage); + + const currentCards = submissions.Submissions.slice( + (currentPage - 1) * cardsPerPage, + currentPage * cardsPerPage + ); + + const nextPage = () => { + if (currentPage < totalPages) { + setCurrentPage(currentPage + 1); + } + }; + + const prevPage = () => { + if (currentPage > 1) { + setCurrentPage(currentPage - 1); + } + }; + + if (submissions.Total == 0) { return
Submissions list is empty. diff --git a/web/src/app/thumbnails/asset/[assetId]/route.tsx b/web/src/app/thumbnails/asset/[assetId]/route.tsx index b7992f4..e7232d8 100644 --- a/web/src/app/thumbnails/asset/[assetId]/route.tsx +++ b/web/src/app/thumbnails/asset/[assetId]/route.tsx @@ -1,5 +1,8 @@ import { NextRequest, NextResponse } from 'next/server'; +const cache = new Map(); +const CACHE_TTL = 15 * 60 * 1000; + export async function GET( request: NextRequest, context: { params: Promise<{ assetId: number }> } @@ -27,6 +30,19 @@ export async function GET( } } catch { } + const now = Date.now(); + const cached = cache.get(finalAssetId); + + if (cached && cached.expires > now) { + return new NextResponse(cached.buffer, { + headers: { + 'Content-Type': 'image/png', + 'Content-Length': cached.buffer.length.toString(), + 'Cache-Control': `public, max-age=${CACHE_TTL / 1000}`, + }, + }); + } + try { const response = await fetch( `https://thumbnails.roblox.com/v1/assets?format=png&size=512x512&assetIds=${finalAssetId}` @@ -54,10 +70,13 @@ export async function GET( const arrayBuffer = await imageResponse.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); + cache.set(finalAssetId, { buffer, expires: now + CACHE_TTL }); + return new NextResponse(buffer, { headers: { 'Content-Type': 'image/png', 'Content-Length': buffer.length.toString(), + 'Cache-Control': `public, max-age=${CACHE_TTL / 1000}`, }, }); } catch { diff --git a/web/src/app/thumbnails/maps/[mapId]/route.tsx b/web/src/app/thumbnails/maps/[mapId]/route.tsx index 174feee..a923d21 100644 --- a/web/src/app/thumbnails/maps/[mapId]/route.tsx +++ b/web/src/app/thumbnails/maps/[mapId]/route.tsx @@ -5,9 +5,12 @@ export async function GET( context: { params: Promise<{ mapId: string }> } ): Promise { // TODO: implement this, we need a cdn for in-game map thumbnails... - + const { mapId } = await context.params; - const baseUrl = request.nextUrl.origin; // Gets the current base URL - return NextResponse.redirect(`${baseUrl}/thumbnails/asset/${mapId}`); + const protocol = request.headers.get("x-forwarded-proto") || "https"; + const host = request.headers.get("host"); + const origin = `${protocol}://${host}`; + + return NextResponse.redirect(`${origin}/thumbnails/asset/${mapId}`); } \ No newline at end of file diff --git a/web/src/middleware.ts b/web/src/middleware.ts index 0a25a76..61da104 100644 --- a/web/src/middleware.ts +++ b/web/src/middleware.ts @@ -1,29 +1,32 @@ import { NextRequest, NextResponse } from "next/server" export const config = { - matcher: ["/api/:path*", "/auth/:path*"], + matcher: ["/api/:path*", "/auth/:path*"], } export function middleware(request: NextRequest) { - const { pathname, search } = request.nextUrl + const { pathname, search } = request.nextUrl - if (pathname.startsWith("/api")) { - if (!process.env.API_HOST) { - throw new Error('env variable "API_HOST" is not set') - } - const apiUrl = new URL(process.env.API_HOST + pathname.replace(/^\/api/, '') + search) - return NextResponse.rewrite(apiUrl, { request }) - } else if (pathname.startsWith("/auth")) { + if (pathname.startsWith("/api")) { + if (!process.env.API_HOST) { + throw new Error('env variable "API_HOST" is not set') + } + + const baseUrl = process.env.API_HOST.replace(/\/$/, ""); + const apiUrl = new URL(baseUrl + pathname + search); + + return NextResponse.rewrite(apiUrl, { request }); + } else if (pathname.startsWith("/auth")) { if (!process.env.AUTH_HOST) { throw new Error('env variable "AUTH_HOST" is not set') } - - const authHost = process.env.AUTH_HOST.replace(/\/$/, "") - const path = pathname.replace(/^\/auth/, "") - const redirectUrl = new URL(authHost + path + search) - - return NextResponse.redirect(redirectUrl, 302) - } - return NextResponse.next() -} \ No newline at end of file + const authHost = process.env.AUTH_HOST.replace(/\/$/, ""); + const path = pathname.replace(/^\/auth/, ""); + const redirectUrl = new URL(authHost + path + search); + + return NextResponse.redirect(redirectUrl, 302); + } + + return NextResponse.next() +}