minecraft-web/backend/server.js

109 lines
2.9 KiB
JavaScript

import express from "express";
import { createServer } from "http";
import { Server } from "socket.io";
import path from "path";
import { fileURLToPath } from "url";
// 모듈 import
import { loadTranslations } from "./lib/db.js";
import {
MOD_API_URL,
refreshData,
fetchPlayerDetail,
getCachedStatus,
getCachedPlayers,
} from "./lib/minecraft.js";
import apiRoutes from "./routes/api.js";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: {
origin: "*",
methods: ["GET", "POST"],
},
});
const PORT = process.env.PORT || 80;
// dist 디렉토리에서 정적 파일 제공
app.use(express.static(path.join(__dirname, "dist")));
// API 라우트
app.use("/api", apiRoutes);
// Socket.IO 연결 처리
io.on("connection", (socket) => {
console.log("클라이언트 연결됨:", socket.id);
// 연결 시 즉시 캐시된 데이터 전송
const cachedStatus = getCachedStatus();
const cachedPlayers = getCachedPlayers();
if (cachedStatus) socket.emit("status", cachedStatus);
if (cachedPlayers.length > 0) socket.emit("players", cachedPlayers);
// 특정 플레이어 정보 요청 처리
socket.on("get_player", async (uuid) => {
const player = await fetchPlayerDetail(uuid);
if (player) socket.emit("player_detail", player);
});
// 월드 정보 요청 처리
socket.on("get_worlds", async () => {
try {
const response = await fetch(`${MOD_API_URL}/worlds`);
if (response.ok) {
const data = await response.json();
socket.emit("worlds", data);
}
} catch (error) {
console.error("[ModAPI] 월드 조회 실패:", error.message);
}
});
// 플레이어 통계 요청 처리
socket.on("get_player_stats", async (uuid) => {
try {
const response = await fetch(`${MOD_API_URL}/player/${uuid}/stats`);
if (response.ok) {
const data = await response.json();
socket.emit("player_stats", data);
}
} catch (error) {
console.error("[ModAPI] 통계 조회 실패:", error.message);
}
});
socket.on("disconnect", () => {
console.log("클라이언트 연결 해제:", socket.id);
});
});
// 주기적 데이터 갱신 및 브로드캐스트
async function refreshAndBroadcast() {
const { cachedStatus, cachedPlayers } = await refreshData();
io.emit("status", cachedStatus);
io.emit("players", cachedPlayers);
}
// 1초마다 데이터 갱신
setInterval(refreshAndBroadcast, 1000);
refreshAndBroadcast();
// SPA 라우팅 - 모든 경로에 대해 index.html 제공
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "dist", "index.html"));
});
// 서버 시작
httpServer.listen(PORT, async () => {
console.log(`[Server] 웹 서버 시작: 포트 ${PORT}`);
console.log(`[Server] 모드 API URL: ${MOD_API_URL}`);
// 번역 데이터 로드
await loadTranslations();
});