Skip to content

Commit

Permalink
Merge pull request #54 from sweatpotato13/develop
Browse files Browse the repository at this point in the history
Merge to main
  • Loading branch information
sweatpotato13 authored Feb 23, 2025
2 parents 5aebdfd + e391b28 commit 23b324d
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 111 deletions.
64 changes: 46 additions & 18 deletions src/app/api/auction/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,57 @@ export async function GET(request: Request) {
const auctionItemCategory = searchParams.get("auction_item_category");
const itemName = searchParams.get("item_name");

let url = `${NXOPEN_API_URL}/mabinogi/v1/auction/list?`;
if (auctionItemCategory) {
url += `auction_item_category=${auctionItemCategory}&`;
}
if (itemName) {
url += `item_name=${encodeURIComponent(itemName)}`;
}
let allItems: any[] = [];
let nextCursor: string | null = "";

try {
do {
let url = `${NXOPEN_API_URL}/mabinogi/v1/auction/list?`;
if (auctionItemCategory) {
url += `auction_item_category=${auctionItemCategory}&`;
}
if (itemName) {
url += `item_name=${encodeURIComponent(itemName)}&`;
}
if (nextCursor) {
url += `cursor=${nextCursor}`;
}

const response = await fetch(url, {
headers: {
"Content-Type": "application/json",
"x-nxopen-api-key": NXOPEN_API_KEY || "",
},
});

const response = await fetch(url, {
headers: {
"Content-Type": "application/json",
"x-nxopen-api-key": NXOPEN_API_KEY || "",
},
});
if (!response.ok) {
console.error(await response.json());
return NextResponse.json(
{ error: "Failed to fetch data" },
{ status: 500 }
);
}

if (!response.ok) {
console.error(await response.json());
const data = await response.json();

// 결과 데이터 누적
if (data.auction_item.length > 0) {
allItems = [...allItems, ...data.auction_item];
}

// 다음 페이지를 위한 cursor 업데이트
nextCursor = data.next_cursor;
} while (nextCursor !== null);

// 전체 데이터 반환
return NextResponse.json({
items: allItems,
});
} catch (error) {
console.error("Error fetching auction data:", error);
return NextResponse.json(
{ error: "Failed to fetch data" },
{ status: 500 }
);
}

const data = await response.json();
return NextResponse.json(data);
}
4 changes: 2 additions & 2 deletions src/app/auction/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ export default function AuctionPage() {
}
const data = await response.json();

data.auction_item.sort(
data.items.sort(
(a: any, b: any) =>
a.auction_price_per_unit - b.auction_price_per_unit
);
setFilteredItems(data.auction_item);
setFilteredItems(data.items);
setErrorMessage(null);
} catch (error) {
console.error("API 호출 중 오류가 발생했습니다:", error);
Expand Down
27 changes: 24 additions & 3 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,42 @@ import "@/styles/globals.css";

import { Analytics } from "@vercel/analytics/next";
import { SpeedInsights } from "@vercel/speed-insights/next";
import { Metadata } from "next";

import Footer from "@/components/footer";
import { Providers } from "@/components/providers";
import Topbar from "@/components/topbar";
import { metadata as defaultMetadata } from "@/constant/metadata";

export const metadata = defaultMetadata;
export const metadata: Metadata = {
title: "마비노기 경매장 - 실시간 아이템 시세 검색 | Erinn.me",
description:
"마비노기 경매장의 실시간 아이템 시세를 검색하고 가격을 비교해보세요. 카테고리별 검색과 아이템 이름 검색을 지원합니다. 실시간 가격 정보와 아이템 옵션을 확인할 수 있습니다.",
keywords:
"마비노기, 경매장, 아이템 시세, 마비노기 경매장, 마비노기 시세, 마비노기 아이템, Erinn.me",
openGraph: {
title: "마비노기 경매장 - 실시간 아이템 시세 검색 | Erinn.me",
description:
"마비노기 경매장의 실시간 아이템 시세를 검색하고 가격을 비교해보세요. 카테고리별 검색과 아이템 이름 검색을 지원합니다.",
type: "website",
locale: "ko_KR",
siteName: "Erinn.me",
},
robots: {
index: true,
follow: true,
},
alternates: {
canonical: "https://erinn.me",
},
};

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html data-theme="light" lang="en">
<html data-theme="light" lang="ko">
<body className="pt-16 font-custom">
<Topbar />
<main className="min-h-screen">
Expand Down
100 changes: 12 additions & 88 deletions src/lib/api/auction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,99 +25,30 @@ export interface AuctionResponse {
next_cursor: string;
}

// API 호출 간 딜레이를 위한 sleep 함수
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

async function fetchAllAuctionPages(params: {
item_name?: string;
auction_item_category?: string;
}): Promise<AuctionItem[]> {
let allItems: AuctionItem[] = [];
let nextCursor = "";
let prevCursor = ""; // 이전 cursor 저장
let retryCount = 0;
const MAX_RETRIES = 2;

try {
do {
try {
// API 호출 간 1초 딜레이 추가
await sleep(1000);

const queryParams = new URLSearchParams();
if (params.item_name) {
queryParams.append("item_name", params.item_name);
}
if (params.auction_item_category) {
queryParams.append(
"auction_item_category",
params.auction_item_category
);
}
if (nextCursor) {
queryParams.append("cursor", nextCursor);
}

const response = await fetch(
`/api/auction?${queryParams.toString()}`
);
if (!response.ok) {
throw new Error("경매장 API 호출 중 오류가 발생했습니다.");
}

const data: AuctionResponse = await response.json();

// 새로운 아이템이 없거나 이전과 같은 cursor가 반환되면 중단
if (
data.auction_item.length === 0 ||
data.next_cursor === prevCursor
) {
break;
}

allItems = [...allItems, ...data.auction_item];
prevCursor = nextCursor; // 현재 cursor를 이전 cursor로 저장
nextCursor = data.next_cursor;
retryCount = 0;
} catch (error) {
retryCount++;
if (retryCount >= MAX_RETRIES || allItems.length === 0) {
throw error;
}
console.warn(
`데이터 조회 중 오류 발생 (${retryCount}번째 시도): `,
error
);
break;
}
} while (nextCursor);

return allItems;
} catch (error) {
if (allItems.length > 0) {
console.warn("일부 데이터만 조회되었습니다:", error);
return allItems;
}
throw error;
}
}

export async function getItemPrice(
itemName: string
): Promise<ItemPriceResponse> {
try {
const allItems = await fetchAllAuctionPages({ item_name: itemName });
let url = "/api/auction?";
if (itemName !== "") {
url += `&item_name=${encodeURIComponent(itemName).replace(/\+/g, "%2B")}`;
}
const response = await fetch(url);
const data = await response.json();

if (allItems.length === 0) {
if (data.items === undefined) {
return {
unitPrice: 0,
averagePrice: 0,
};
}

const prices = allItems.map(item => item.auction_price_per_unit);
const prices = data.items.map(
(item: any) => item.auction_price_per_unit
);
const unitPrice = Math.min(...prices);
const averagePrice = prices.reduce((a, b) => a + b, 0) / prices.length;
const averagePrice =
prices.reduce((a: any, b: any) => a + b, 0) / prices.length;

return {
unitPrice: unitPrice || 0,
Expand All @@ -131,10 +62,3 @@ export async function getItemPrice(
};
}
}

export async function searchAuctionItems(params: {
item_name?: string;
auction_item_category?: string;
}): Promise<AuctionItem[]> {
return fetchAllAuctionPages(params);
}

0 comments on commit 23b324d

Please sign in to comment.