mirror of
https://github.com/GSManagerXZ/GameServerManager.git
synced 2026-06-01 18:39:35 +08:00
修复打包
This commit is contained in:
86
.env.example
86
.env.example
@@ -1,40 +1,70 @@
|
||||
# GSM3 游戏服务端管理面板环境配置
|
||||
# GSM3 游戏服务器管理系统配置
|
||||
|
||||
# 服务器配置
|
||||
PORT=3000
|
||||
HOST=localhost
|
||||
# 服务器端口配置
|
||||
# 后端API服务端口
|
||||
SERVER_PORT=3001
|
||||
|
||||
# 前端开发服务端口(仅开发环境使用)
|
||||
CLIENT_PORT=5173
|
||||
|
||||
# 环境配置
|
||||
NODE_ENV=production
|
||||
|
||||
# 前端构建路径
|
||||
CLIENT_BUILD_PATH=./public
|
||||
|
||||
# 数据存储路径
|
||||
DATA_PATH=./data
|
||||
|
||||
# 日志配置
|
||||
LOG_LEVEL=info
|
||||
LOG_PATH=./logs
|
||||
|
||||
# JWT配置
|
||||
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
|
||||
JWT_EXPIRES_IN=24h
|
||||
|
||||
# 认证配置
|
||||
MAX_LOGIN_ATTEMPTS=5
|
||||
LOCKOUT_DURATION=900000
|
||||
SESSION_TIMEOUT=86400000
|
||||
|
||||
# CORS配置
|
||||
CORS_ORIGIN=http://localhost:3000
|
||||
# 允许的前端访问地址,生产环境请修改为实际域名
|
||||
CORS_ORIGIN=*
|
||||
|
||||
# Socket.IO配置
|
||||
SOCKET_CORS_ORIGIN=*
|
||||
|
||||
# 数据目录
|
||||
DATA_DIR=./data
|
||||
|
||||
# 日志目录
|
||||
LOG_DIR=./logs
|
||||
|
||||
# PTY配置
|
||||
PTY_TIMEOUT=1800000
|
||||
PTY_MAX_SESSIONS=10
|
||||
|
||||
# 游戏服务器配置
|
||||
GAME_DATA_PATH=./data/games
|
||||
GAME_BACKUPS_PATH=./data/backups
|
||||
GAME_MAX_INSTANCES=5
|
||||
GAME_DATA_DIR=./data/games
|
||||
|
||||
# 文件上传配置
|
||||
UPLOAD_PATH=./uploads
|
||||
MAX_FILE_SIZE=100MB
|
||||
# 系统监控配置
|
||||
SYSTEM_MONITOR_INTERVAL=5000
|
||||
SYSTEM_STATS_HISTORY_SIZE=720
|
||||
|
||||
# 告警配置
|
||||
ALERT_CPU_WARNING=70
|
||||
ALERT_CPU_CRITICAL=90
|
||||
ALERT_MEMORY_WARNING=80
|
||||
ALERT_MEMORY_CRITICAL=95
|
||||
ALERT_DISK_WARNING=85
|
||||
ALERT_DISK_CRITICAL=95
|
||||
|
||||
# Java配置(用于Minecraft服务器)
|
||||
JAVA_HOME=
|
||||
JAVA_OPTS=-Xmx2G -Xms1G
|
||||
|
||||
# 安全配置
|
||||
RATE_LIMIT_WINDOW=900000
|
||||
RATE_LIMIT_MAX=100
|
||||
SESSION_SECRET=your-secret-key-here
|
||||
JWT_SECRET=your-jwt-secret-here
|
||||
|
||||
# 备份配置
|
||||
BACKUP_ENABLED=true
|
||||
BACKUP_INTERVAL=86400000
|
||||
BACKUP_RETENTION=7
|
||||
|
||||
# 网络配置
|
||||
MAX_UPLOAD_SIZE=100mb
|
||||
REQUEST_TIMEOUT=30000
|
||||
|
||||
# 说明:
|
||||
# 1. 修改 SERVER_PORT 可以更改后端服务端口
|
||||
# 2. 生产环境部署时,请将 CORS_ORIGIN 和 SOCKET_CORS_ORIGIN 设置为实际的前端访问地址
|
||||
# 3. 请务必修改 SESSION_SECRET 和 JWT_SECRET 为随机字符串
|
||||
# 4. 根据服务器配置调整 JAVA_OPTS 中的内存设置
|
||||
13
client/.env.example
Normal file
13
client/.env.example
Normal file
@@ -0,0 +1,13 @@
|
||||
# 前端环境配置
|
||||
|
||||
# 后端服务端口(生产环境使用)
|
||||
VITE_SERVER_PORT=3001
|
||||
|
||||
# 前端开发服务端口(仅开发环境使用)
|
||||
VITE_CLIENT_PORT=5173
|
||||
|
||||
# 说明:
|
||||
# 1. VITE_SERVER_PORT 用于配置前端连接的后端服务端口
|
||||
# 2. VITE_CLIENT_PORT 用于配置前端开发服务器端口
|
||||
# 3. 生产环境部署时,前端会自动根据当前页面地址和 VITE_SERVER_PORT 连接后端
|
||||
# 4. 开发环境时,Vite 会使用代理转发请求到后端服务
|
||||
45
client/src/config/index.ts
Normal file
45
client/src/config/index.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
// 前端配置文件
|
||||
|
||||
// 获取后端服务端口
|
||||
function getServerPort(): string {
|
||||
// 优先从环境变量读取(Vite会自动注入VITE_开头的环境变量)
|
||||
if (import.meta.env.VITE_SERVER_PORT) {
|
||||
return import.meta.env.VITE_SERVER_PORT
|
||||
}
|
||||
|
||||
// 从URL参数读取
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
const portParam = urlParams.get('server_port')
|
||||
if (portParam) {
|
||||
return portParam
|
||||
}
|
||||
|
||||
// 默认端口
|
||||
return '3001'
|
||||
}
|
||||
|
||||
// 获取完整的服务器URL
|
||||
function getServerUrl(): string {
|
||||
const protocol = window.location.protocol === 'https:' ? 'https:' : 'http:'
|
||||
const hostname = window.location.hostname
|
||||
const port = getServerPort()
|
||||
return `${protocol}//${hostname}:${port}`
|
||||
}
|
||||
|
||||
// 获取API基础URL
|
||||
function getApiBaseUrl(): string {
|
||||
return `${getServerUrl()}/api`
|
||||
}
|
||||
|
||||
// 导出配置
|
||||
export const config = {
|
||||
serverPort: getServerPort(),
|
||||
serverUrl: getServerUrl(),
|
||||
apiBaseUrl: getApiBaseUrl(),
|
||||
|
||||
// 其他配置
|
||||
requestTimeout: 30000,
|
||||
socketTimeout: 20000,
|
||||
}
|
||||
|
||||
export default config
|
||||
@@ -1,5 +1,6 @@
|
||||
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
|
||||
import { LoginRequest, LoginResponse, ApiResponse, User } from '@/types'
|
||||
import config from '@/config'
|
||||
|
||||
class ApiClient {
|
||||
private client: AxiosInstance
|
||||
@@ -7,8 +8,8 @@ class ApiClient {
|
||||
|
||||
constructor() {
|
||||
this.client = axios.create({
|
||||
baseURL: 'http://localhost:3001/api',
|
||||
timeout: 30000,
|
||||
baseURL: config.apiBaseUrl,
|
||||
timeout: config.requestTimeout,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { io, Socket } from 'socket.io-client'
|
||||
import { SocketEvents } from '@/types'
|
||||
import config from '@/config'
|
||||
|
||||
class SocketClient {
|
||||
private socket: Socket | null = null
|
||||
@@ -15,12 +16,12 @@ class SocketClient {
|
||||
private connect() {
|
||||
const token = localStorage.getItem('gsm3_token')
|
||||
|
||||
this.socket = io('http://localhost:3001', {
|
||||
this.socket = io(config.serverUrl, {
|
||||
auth: {
|
||||
token,
|
||||
},
|
||||
transports: ['websocket', 'polling'],
|
||||
timeout: 20000,
|
||||
timeout: config.socketTimeout,
|
||||
forceNew: true,
|
||||
})
|
||||
|
||||
|
||||
11
client/src/vite-env.d.ts
vendored
Normal file
11
client/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_SERVER_PORT?: string
|
||||
readonly VITE_CLIENT_PORT?: string
|
||||
// 更多环境变量可以在这里添加
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv
|
||||
}
|
||||
@@ -15,10 +15,10 @@
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"strict": false,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noFallthroughCasesInSwitch": false,
|
||||
|
||||
/* Path mapping */
|
||||
"baseUrl": ".",
|
||||
|
||||
@@ -2,6 +2,19 @@ import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import path from 'path'
|
||||
|
||||
// 获取后端服务端口
|
||||
const getServerPort = () => {
|
||||
return process.env.VITE_SERVER_PORT || process.env.SERVER_PORT || '3001'
|
||||
}
|
||||
|
||||
// 获取前端开发端口
|
||||
const getClientPort = () => {
|
||||
return parseInt(process.env.VITE_CLIENT_PORT || process.env.CLIENT_PORT || '5173', 10)
|
||||
}
|
||||
|
||||
const serverPort = getServerPort()
|
||||
const clientPort = getClientPort()
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
@@ -11,14 +24,14 @@ export default defineConfig({
|
||||
},
|
||||
},
|
||||
server: {
|
||||
port: 3000,
|
||||
port: clientPort,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:3001',
|
||||
target: `http://localhost:${serverPort}`,
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/socket.io': {
|
||||
target: 'http://localhost:3001',
|
||||
target: `http://localhost:${serverPort}`,
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
},
|
||||
|
||||
905
package-lock.json
generated
905
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -36,6 +36,30 @@ async function createPackage() {
|
||||
path.join(packageDir, 'server', 'PTY')
|
||||
)
|
||||
|
||||
// 复制环境变量配置文件
|
||||
await fs.copy(
|
||||
path.join(__dirname, '..', 'server', '.env.example'),
|
||||
path.join(packageDir, 'server', '.env.example')
|
||||
)
|
||||
|
||||
await fs.copy(
|
||||
path.join(__dirname, '..', '.env.example'),
|
||||
path.join(packageDir, '.env.example')
|
||||
)
|
||||
|
||||
console.log('📥 安装服务端生产依赖...')
|
||||
// 在打包的服务端目录中安装生产依赖
|
||||
try {
|
||||
execSync('npm install --production --omit=dev', {
|
||||
cwd: path.join(packageDir, 'server'),
|
||||
stdio: 'inherit'
|
||||
})
|
||||
console.log('✅ 服务端依赖安装完成')
|
||||
} catch (error) {
|
||||
console.error('❌ 服务端依赖安装失败:', error)
|
||||
throw error
|
||||
}
|
||||
|
||||
console.log('🎨 复制前端文件...')
|
||||
// 复制前端构建文件
|
||||
await fs.copy(
|
||||
@@ -48,7 +72,7 @@ async function createPackage() {
|
||||
const startScript = `@echo off
|
||||
echo 正在启动GSM3管理面板...
|
||||
cd server
|
||||
node index.js
|
||||
node_app.exe index.js
|
||||
pause`
|
||||
|
||||
await fs.writeFile(
|
||||
@@ -60,7 +84,7 @@ pause`
|
||||
const startShScript = `#!/bin/bash
|
||||
echo "正在启动GSM3管理面板..."
|
||||
cd server
|
||||
node index.js`
|
||||
/opt/node-v22.17.0-linux-x64/bin/node index.js`
|
||||
|
||||
await fs.writeFile(
|
||||
path.join(packageDir, 'start.sh'),
|
||||
@@ -81,20 +105,29 @@ node index.js`
|
||||
## 安装说明
|
||||
|
||||
1. 确保已安装 Node.js (版本 >= 18)
|
||||
2. 进入 server 目录
|
||||
3. 运行 \`npm install --production\` 安装依赖
|
||||
4. 复制 .env.example 为 .env 并配置相关参数
|
||||
5. 运行启动脚本:
|
||||
2. 解压缩包到目标目录
|
||||
3. (可选) 配置端口和其他参数:
|
||||
- 复制 .env.example 为 .env 并修改 SERVER_PORT 等配置
|
||||
- 复制 server/.env.example 为 server/.env 并配置详细参数
|
||||
4. 运行启动脚本:
|
||||
- Windows: 双击 start.bat
|
||||
- Linux/Mac: 运行 ./start.sh
|
||||
|
||||
## 默认访问地址
|
||||
|
||||
http://localhost:3000
|
||||
http://localhost:3001
|
||||
|
||||
## 端口配置
|
||||
|
||||
- 修改根目录 .env 文件中的 SERVER_PORT 可以更改服务端口
|
||||
- 修改后需要重启服务才能生效
|
||||
- 确保防火墙允许新端口访问
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 首次运行需要创建管理员账户
|
||||
- 依赖已预装,无需手动安装
|
||||
- 首次运行会自动创建默认管理员账户 (admin/admin123)
|
||||
- 请立即登录并修改默认密码
|
||||
- 确保防火墙允许相关端口访问
|
||||
- 建议在生产环境中使用 PM2 等进程管理工具
|
||||
|
||||
|
||||
@@ -8,22 +8,24 @@ import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import winston from 'winston'
|
||||
|
||||
import { TerminalManager } from './modules/terminal/TerminalManager'
|
||||
import { GameManager } from './modules/game/GameManager'
|
||||
import { SystemManager } from './modules/system/SystemManager'
|
||||
import { ConfigManager } from './modules/config/ConfigManager'
|
||||
import { AuthManager } from './modules/auth/AuthManager'
|
||||
import { setupTerminalRoutes } from './routes/terminal'
|
||||
import { setupGameRoutes } from './routes/games'
|
||||
import { setupSystemRoutes } from './routes/system'
|
||||
import { setupAuthRoutes } from './routes/auth'
|
||||
import { setAuthManager } from './middleware/auth'
|
||||
import { TerminalManager } from './modules/terminal/TerminalManager.js'
|
||||
import { GameManager } from './modules/game/GameManager.js'
|
||||
import { SystemManager } from './modules/system/SystemManager.js'
|
||||
import { ConfigManager } from './modules/config/ConfigManager.js'
|
||||
import { AuthManager } from './modules/auth/AuthManager.js'
|
||||
import { setupTerminalRoutes } from './routes/terminal.js'
|
||||
import { setupGameRoutes } from './routes/games.js'
|
||||
import { setupSystemRoutes } from './routes/system.js'
|
||||
import { setupAuthRoutes } from './routes/auth.js'
|
||||
import { setAuthManager } from './middleware/auth.js'
|
||||
|
||||
// 获取当前文件目录
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = path.dirname(__filename)
|
||||
|
||||
// 加载环境变量
|
||||
// 首先尝试加载根目录的.env文件,然后加载server目录的.env文件
|
||||
dotenv.config({ path: path.join(__dirname, '../../.env') })
|
||||
dotenv.config()
|
||||
|
||||
// 配置日志
|
||||
@@ -73,6 +75,7 @@ app.use(express.urlencoded({ extended: true, limit: '10mb' }))
|
||||
|
||||
// 静态文件服务
|
||||
app.use('/static', express.static(path.join(__dirname, '../public')))
|
||||
app.use(express.static(path.join(__dirname, '../public')))
|
||||
|
||||
// 管理器变量声明
|
||||
let configManager: ConfigManager
|
||||
@@ -175,12 +178,18 @@ async function startServer() {
|
||||
app.use('/api/game', setupGameRoutes(gameManager))
|
||||
app.use('/api/system', setupSystemRoutes(systemManager))
|
||||
|
||||
// 404处理(必须在所有路由之后)
|
||||
app.use('*', (req, res) => {
|
||||
res.status(404).json({
|
||||
error: '接口不存在',
|
||||
path: req.originalUrl
|
||||
})
|
||||
// 前端路由处理(SPA支持)
|
||||
app.get('*', (req, res) => {
|
||||
// 如果是API请求,返回404
|
||||
if (req.path.startsWith('/api/')) {
|
||||
res.status(404).json({
|
||||
error: '接口不存在',
|
||||
path: req.originalUrl
|
||||
})
|
||||
} else {
|
||||
// 其他请求返回前端页面
|
||||
res.sendFile(path.join(__dirname, '../public/index.html'))
|
||||
}
|
||||
})
|
||||
|
||||
// Socket.IO 连接处理
|
||||
@@ -250,7 +259,7 @@ async function startServer() {
|
||||
})
|
||||
})
|
||||
|
||||
const PORT = parseInt(process.env.PORT || '3001', 10)
|
||||
const PORT = parseInt(process.env.SERVER_PORT || process.env.PORT || '3001', 10)
|
||||
const HOST = process.env.HOST || '0.0.0.0'
|
||||
|
||||
server.listen(PORT, HOST, () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Request, Response, NextFunction } from 'express'
|
||||
import { AuthManager } from '../modules/auth/AuthManager'
|
||||
import logger from '../utils/logger'
|
||||
import { AuthManager } from '../modules/auth/AuthManager.js'
|
||||
import logger from '../utils/logger.js'
|
||||
|
||||
export interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
|
||||
@@ -3,7 +3,7 @@ import jwt from 'jsonwebtoken'
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
import winston from 'winston'
|
||||
import { ConfigManager } from '../config/ConfigManager'
|
||||
import { ConfigManager } from '../config/ConfigManager.js'
|
||||
|
||||
export interface User {
|
||||
id: string
|
||||
@@ -223,7 +223,7 @@ export class AuthManager {
|
||||
role: user.role
|
||||
},
|
||||
jwtConfig.secret,
|
||||
{ expiresIn: jwtConfig.expiresIn }
|
||||
{ expiresIn: jwtConfig.expiresIn as `${number}h` }
|
||||
)
|
||||
|
||||
this.logger.info(`用户 ${username} 登录成功`)
|
||||
|
||||
@@ -52,9 +52,9 @@ export class TerminalManager {
|
||||
// 根据操作系统选择PTY程序路径
|
||||
const platform = os.platform()
|
||||
if (platform === 'win32') {
|
||||
this.ptyPath = path.resolve(__dirname, '../../../PTY/pty_win32_x64.exe')
|
||||
this.ptyPath = path.resolve(__dirname, '../../PTY/pty_win32_x64.exe')
|
||||
} else {
|
||||
this.ptyPath = path.resolve(__dirname, '../../../PTY/pty_linux_x64')
|
||||
this.ptyPath = path.resolve(__dirname, '../../PTY/pty_linux_x64')
|
||||
}
|
||||
|
||||
this.logger.info(`终端管理器初始化完成,PTY路径: ${this.ptyPath}`)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Router, Request, Response } from 'express'
|
||||
import rateLimit from 'express-rate-limit'
|
||||
import { AuthManager } from '../modules/auth/AuthManager'
|
||||
import { authenticateToken, AuthenticatedRequest, requireAdmin } from '../middleware/auth'
|
||||
import logger from '../utils/logger'
|
||||
import { AuthManager } from '../modules/auth/AuthManager.js'
|
||||
import { authenticateToken, AuthenticatedRequest, requireAdmin } from '../middleware/auth.js'
|
||||
import logger from '../utils/logger.js'
|
||||
import Joi from 'joi'
|
||||
|
||||
const router = Router()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Router, Request, Response } from 'express'
|
||||
import { GameManager } from '../modules/game/GameManager'
|
||||
import logger from '../utils/logger'
|
||||
import { GameManager } from '../modules/game/GameManager.js'
|
||||
import logger from '../utils/logger.js'
|
||||
import Joi from 'joi'
|
||||
|
||||
const router = Router()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Router } from 'express'
|
||||
import terminalRoutes from './terminal'
|
||||
import gameRoutes from './games'
|
||||
import systemRoutes from './system'
|
||||
import fileRoutes from './files'
|
||||
import terminalRoutes from './terminal.js'
|
||||
import gameRoutes from './games.js'
|
||||
import systemRoutes from './system.js'
|
||||
import fileRoutes from './files.js'
|
||||
|
||||
const router = Router()
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Router, Request, Response } from 'express'
|
||||
import { SystemManager } from '../modules/system/SystemManager'
|
||||
import logger from '../utils/logger'
|
||||
import { SystemManager } from '../modules/system/SystemManager.js'
|
||||
import logger from '../utils/logger.js'
|
||||
import os from 'os'
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Router, Request, Response } from 'express'
|
||||
import { TerminalManager } from '../modules/terminal/TerminalManager'
|
||||
import logger from '../utils/logger'
|
||||
import { TerminalManager } from '../modules/terminal/TerminalManager.js'
|
||||
import logger from '../utils/logger.js'
|
||||
|
||||
const router = Router()
|
||||
|
||||
|
||||
@@ -8,20 +8,21 @@
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"allowJs": true,
|
||||
"strict": true,
|
||||
"strict": false,
|
||||
"noEmit": false,
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"removeComments": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitAny": false,
|
||||
"strictNullChecks": false,
|
||||
"strictFunctionTypes": false,
|
||||
"noImplicitThis": false,
|
||||
"noImplicitReturns": false,
|
||||
"noFallthroughCasesInSwitch": false,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
"forceConsistentCasingInFileNames": false,
|
||||
"noImplicitAny": false
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
|
||||
Reference in New Issue
Block a user