UNPKG

rubiks-cube-mcp-server

Version:

MCP server for Rubik's Cube solving with real-time 3D visualization and MCP UI integration

160 lines (159 loc) 6.08 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.VisualizationServer = void 0; const express_1 = __importDefault(require("express")); const http_1 = require("http"); const path_1 = __importDefault(require("path")); const fs_1 = __importDefault(require("fs")); const cubeLogic_js_1 = require("../cubeLogic.js"); const WebSocketHandler_js_1 = require("./WebSocketHandler.js"); const APIRoutes_js_1 = require("./APIRoutes.js"); class VisualizationServer { app; server; webSocketHandler; apiRoutes; sessions; constructor() { this.app = (0, express_1.default)(); this.server = (0, http_1.createServer)(this.app); this.sessions = new Map(); this.setupTemplateEngine(); this.webSocketHandler = new WebSocketHandler_js_1.WebSocketHandler(this.server, this.sessions); this.apiRoutes = new APIRoutes_js_1.APIRoutes(this, this.webSocketHandler); this.setupRoutes(); } setupTemplateEngine() { // EJS 템플릿 엔진 설정 this.app.set('view engine', 'ejs'); // 패키지 루트 디렉토리 찾기 const packageRoot = this.findPackageRoot(); this.app.set('views', path_1.default.join(packageRoot, 'views')); // 정적 파일 서빙 this.app.use(express_1.default.static(path_1.default.join(packageRoot, 'public'))); this.app.use(express_1.default.json()); } findPackageRoot() { // 현재 실행 파일의 위치에서 package.json이 있는 디렉토리를 찾음 let currentDir = __dirname; while (currentDir !== path_1.default.dirname(currentDir)) { try { const packageJsonPath = path_1.default.join(currentDir, 'package.json'); if (fs_1.default.existsSync(packageJsonPath)) { const packageJson = require(packageJsonPath); if (packageJson.name === 'rubiks-cube-mcp-server') { return currentDir; } } } catch (e) { // continue searching } currentDir = path_1.default.dirname(currentDir); } // 기본값: 현재 디렉토리에서 2레벨 위 return path_1.default.join(__dirname, '../..'); } setupRoutes() { // API 라우트 this.app.use('/api', this.apiRoutes.getRouter()); // 테스트용 게임 생성 API this.app.post('/api/test/create-game', (req, res) => { const gameId = `test_${Date.now()}`; const cube = new cubeLogic_js_1.RubiksCube(); // 스크램블 적용 const scrambleMoves = ['U', 'R', 'F', 'L', 'D', 'B']; for (let i = 0; i < 10; i++) { const randomMove = scrambleMoves[Math.floor(Math.random() * scrambleMoves.length)]; cube.executeMove(randomMove); } const session = { id: gameId, cubeState: cube.getState(), status: 'active', createdAt: Date.now(), lastActivity: Date.now() }; this.sessions.set(gameId, session); res.json({ success: true, gameId, gameUrl: `/game/${gameId}` }); }); // 메인 페이지 this.app.get('/', (req, res) => { const games = Array.from(this.sessions.entries()).map(([id, session]) => ({ id, title: `Game ${id.split('_')[1]}`, status: session.status, moveCount: session.cubeState.moveHistory.length, createdAt: new Date(session.createdAt).toLocaleString(), statusIcon: session.status === 'completed' ? '🎉' : '🎲', statusText: session.status === 'completed' ? 'SOLVED' : 'Active' })); res.render('gameList', { games }); }); // 게임 페이지 this.app.get('/game/:gameId', (req, res) => { const { gameId } = req.params; const session = this.sessions.get(gameId); if (!session) { return res.status(404).send(` <html> <body style="font-family: Arial; text-align: center; padding: 50px;"> <h1>Game Not Found</h1> <p>Game session "${gameId}" not found.</p> <a href="/">← Back to Games</a> </body> </html> `); } res.render('gameView', { gameId, session, cubeState: session.cubeState }); }); } // 세션 등록 registerSession(session) { this.sessions.set(session.id, session); } // 세션 업데이트 updateSession(gameId, cubeState) { const session = this.sessions.get(gameId); if (session) { session.cubeState = cubeState; session.lastActivity = Date.now(); if (cubeState.solved) { session.status = 'completed'; } this.webSocketHandler.broadcastGameState(gameId, cubeState, session.status); } } // 세션 목록 조회 getSessions() { return this.sessions; } // 서버 시작 start(port = 3000) { this.server.listen(port, () => { console.error(`🎲 3D Cube visualization server running on http://localhost:${port}`); console.error(`🌐 WebSocket enabled for real-time updates`); }); } // 서버 종료 stop() { if (this.server) { this.server.close(() => { console.error("✅ Visualization server closed"); }); this.webSocketHandler.close(); } } } exports.VisualizationServer = VisualizationServer;