Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,8 @@ COPY backend/ /app/
# Install dependencies
RUN uv sync --no-dev

# Copy preprocess output (tileset static data)
# tileset.py resolves 6 parent dirs up from its location to reach project root
COPY preprocess/output/ /preprocess/output/

# Create required runtime directories
RUN mkdir -p /app/output /app/logs /app/static
RUN mkdir -p /app/output /app/logs

EXPOSE 8000

Expand Down
37 changes: 0 additions & 37 deletions backend/app/api/v1/endpoints/tileset.py

This file was deleted.

26 changes: 1 addition & 25 deletions backend/app/main.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from app.api.v1.endpoints import map, user, tileset
from app.api.v1.endpoints import map, user
from app.core.w_logging import get_logger, setup_logging
from fastapi.responses import JSONResponse
from firebase_admin import auth as firebase_auth
from firebase_admin._auth_utils import InvalidIdTokenError
from starlette.responses import Response

setup_logging()

Expand All @@ -29,27 +27,6 @@
allow_headers=["*"],
)


class StaticFilesCache(StaticFiles):
"""Cached Static Files, see https://stackoverflow.com/questions/66093397/how-to-disable-starlette-static-files-caching"""

def __init__(
self,
*args,
cachecontrol="public, max-age=31536000, s-maxage=31536000, immutable",
**kwargs,
):
self.cachecontrol = cachecontrol
super().__init__(*args, **kwargs)

def file_response(self, *args, **kwargs) -> Response:
resp: Response = super().file_response(*args, **kwargs)
resp.headers.setdefault("Cache-Control", self.cachecontrol)
return resp


app.mount("/static", StaticFilesCache(directory="static"), name="static")

logger = get_logger("fastapi")


Expand Down Expand Up @@ -85,7 +62,6 @@ async def log_reqeust(request: Request, call_next):

app.include_router(map.router, prefix="/api/v1/maps", tags=["Maps"])
app.include_router(user.router, prefix="/api/v1/user", tags=["User"])
app.include_router(tileset.router, prefix="/api/v1/tileset", tags=["Tileset"])


@app.get("/")
Expand Down
5 changes: 5 additions & 0 deletions frontend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ NEXT_PUBLIC_FIREBASE_APP_ID=
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=
```

3. Add static file URL in .env
```jsx
NEXT_PUBLIC_STATIC_BASE_URL=
```

### Note: Is it safe to expose Firebase apiKey to the public?

See this Q&A: [Is it safe to expose Firebase apiKey to the public?](https://stackoverflow.com/questions/37482366/is-it-safe-to-expose-firebase-apikey-to-the-public)
Expand Down
27 changes: 15 additions & 12 deletions frontend/hooks/useImage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import api from "@/lib/api";
import { useQueries, useQuery } from "@tanstack/react-query";
import {
SCImageBundle,
Expand All @@ -8,6 +7,7 @@ import {
ImageVersion,
} from "@/types/SCImage";
import axios from "axios";
import { globalConfig } from "@/utils/globalConfig";
import { useUsemapStore } from "@/components/pages/editor-page";
import useTileGroup from "./useTileGroup";
import useTilesetData from "./useTilesetData";
Expand Down Expand Up @@ -43,18 +43,18 @@ export function useImage({ version, imageIndex }: SCImage) {
imageIndex: imageIndex,
});

const base = `/static/anim/${v}/${idx}`;
const base = `${globalConfig.STATIC_BASE_URL}/anim/${v}/${idx}`;

const { data, isLoading, isSuccess } = useQuery<SCImageBundle>({
queryKey: ["scImage", v, idx],
queryFn: async () => {
const [diffuse, teamColor, meta] = await Promise.all([
(await api.get<Blob>(`${base}/diffuse.png`, { responseType: "blob" }))
(await axios.get<Blob>(`${base}/diffuse.png`, { responseType: "blob" }))
.data,
safeGet(
api.get<Blob>(`${base}/team_color.png`, { responseType: "blob" }),
axios.get<Blob>(`${base}/team_color.png`, { responseType: "blob" }),
),
(await api.get<FrameMeta>(`${base}/meta.json`)).data,
(await axios.get<FrameMeta>(`${base}/meta.json`)).data,
]);

return { diffuse, teamColor, meta };
Expand All @@ -70,9 +70,9 @@ export function useImageManifest(version: ImageVersion) {
return useQuery<Manifest>({
queryKey: [version, "manifest"],
queryFn: async () => {
const res = await api.get<
const res = await axios.get<
Record<string, { diffuse: boolean; team_color: boolean }>
>(`/static/anim/${version}/manifest.json`);
>(`${globalConfig.STATIC_BASE_URL}/anim/${version}/manifest.json`);
const obj = res.data; // already parsed JSON

return new Map(
Expand All @@ -91,20 +91,23 @@ export function useImages(imageIDs: Set<number>, version: ImageVersion) {
enabled: !!manifest?.get(id)?.diffuse, // skip if diffuse missing
queryKey: ["unitImage", version, id],
queryFn: async () => {
const base = `/static/anim/${version}/${id}`;
const base = `${globalConfig.STATIC_BASE_URL}/anim/${version}/${id}`;

// ① diffuse + meta (필수)
const [diffuse, meta] = await Promise.all([
(await api.get<Blob>(`${base}/diffuse.png`, { responseType: "blob" }))
.data,
(await api.get<FrameMeta>(`${base}/meta.json`)).data,
(
await axios.get<Blob>(`${base}/diffuse.png`, {
responseType: "blob",
})
).data,
(await axios.get<FrameMeta>(`${base}/meta.json`)).data,
]);

// ② team_color (선택)
let teamColor: Blob | undefined;
if (manifest?.get(id)?.team_color) {
teamColor = await safeGet(
api.get<Blob>(`${base}/team_color.png`, { responseType: "blob" }),
axios.get<Blob>(`${base}/team_color.png`, { responseType: "blob" }),
);
}

Expand Down
11 changes: 6 additions & 5 deletions frontend/hooks/useTileGroup.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import api from "@/lib/api";
import { globalConfig } from "@/utils/globalConfig";
import axios from "axios";
import { useEffect, useState } from "react";

type TileGroup = number[][];

export default function useTileGroup(): TileGroup | null {
export default function useTileGroup(): TileGroup | null {
const [tileGroup, setTileGroup] = useState<TileGroup | null>(null);

useEffect(() => {
(async () => {
const response = await api.get<TileGroup>("/api/v1/tileset/cv5/badlands");
const response = await axios.get<TileGroup>(`${globalConfig.STATIC_BASE_URL}/terrain/badlands/cv5_group.json`);
setTileGroup(response.data);
})();
}, []);

return tileGroup;
}
7 changes: 4 additions & 3 deletions frontend/hooks/useTilesetData.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import api from "@/lib/api";
import { globalConfig } from "@/utils/globalConfig";
import axios from "axios";
import { decompressSync } from "fflate";
import { useEffect, useState } from "react";

Expand All @@ -8,8 +9,8 @@ export default function useTilesetData(): Uint8Array | null {
useEffect(() => {
(async () => {
try {
const response = await api.get(
"/static/terrain/badlands/megatile_color.gz",
const response = await axios.get(
`${globalConfig.STATIC_BASE_URL}/terrain/badlands/megatile_color.gz`,
{
responseType: "arraybuffer",
},
Expand Down
1 change: 1 addition & 0 deletions frontend/utils/globalConfig.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const globalConfig = {
BASE_URL: process.env.NEXT_PUBLIC_API_BASE_URL,
STATIC_BASE_URL: process.env.NEXT_PUBLIC_STATIC_BASE_URL,
};