diff --git a/.gitignore b/.gitignore index bf90c0a..0cc1ced 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,9 @@ users.json favorites.json server/data/environment server/data/wallpapers/ +server/data/lib/ data/wallpapers/ +data/lib/ dist/ diff --git a/Dockerfile b/Dockerfile index 4f0c79d..5e7b8bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -275,6 +275,19 @@ RUN mkdir -p /root/data/lib && \ "https://github.com/MCSManager/Zip-Tools/releases/latest/download/${BINARY_NAME}" && \ chmod 755 /root/data/lib/${BINARY_NAME} && \ echo "Zip-Tools 下载完成: ${BINARY_NAME}" + +# 下载 PTY 二进制文件(从 GitHub Releases latest,构建时预置) +RUN if [ "$TARGETARCH" = "amd64" ]; then \ + PTY_NAME="pty_linux_x64"; \ + elif [ "$TARGETARCH" = "arm64" ]; then \ + PTY_NAME="pty_linux_arm64"; \ + fi && \ + echo "正在下载 PTY latest (${PTY_NAME})..." && \ + wget -t 3 --retry-connrefused --waitretry=2 --read-timeout=30 --timeout=15 \ + -O /root/data/lib/${PTY_NAME} \ + "https://github.com/MCSManager/PTY/releases/tag/latest/download/${PTY_NAME}" && \ + chmod 755 /root/data/lib/${PTY_NAME} && \ + echo "PTY 下载完成: ${PTY_NAME}" # 拷贝 Python 依赖清单并安装 COPY --from=builder /app/server/src/Python/requirements.txt /tmp/requirements.txt # 安装Python依赖并配置最终权限 diff --git a/README.md b/README.md index b67beb3..69e960b 100644 --- a/README.md +++ b/README.md @@ -143,8 +143,8 @@ GSManager3/ │ │ └── Python/ # Python 脚本 │ ├── data/ # 数据存储目录 │ │ ├── games/ # 游戏数据 +│ │ ├── lib/ # 运行依赖(PTY、Zip-Tools 等二进制文件) │ │ └── plugins/ # 插件数据 -│ ├── PTY/ # 伪终端程序 │ └── package.json # 后端依赖 ├── scripts/ # 构建脚本 ├── docker-compose.yml # Docker 编排文件 diff --git a/docs/PTY集成说明.md b/docs/PTY集成说明.md new file mode 100644 index 0000000..40843b4 --- /dev/null +++ b/docs/PTY集成说明.md @@ -0,0 +1,62 @@ +# PTY 集成说明 + +## 概述 + +项目使用 [MCSManager/PTY](https://github.com/MCSManager/PTY) 外部二进制工具处理终端伪终端(PTY)会话。该工具提供跨平台的终端模拟能力。 + +## 自动下载机制 + +服务端启动时会自动检测 PTY 二进制文件是否存在: + +- **已存在**:跳过下载,记录日志 `PTY 已存在,跳过下载` +- **不存在**:自动下载对应平台的二进制文件(双源策略) +- **下载失败**:记录警告日志但不阻塞服务启动,终端功能可能不可用 + +### 下载源优先级 + +1. **自建镜像(主)**:`https://download.xiaozhuhouses.asia/开源项目/GSManager/GSManager3/运行依赖/PTY/` +2. **GitHub Releases(备用)**:`https://github.com/MCSManager/PTY/releases/tag/latest/download/` + +运行时优先从自建镜像下载(国内加速),失败后自动回退到 GitHub Releases。 + +### CI/CD 构建与打包 + +打包脚本(`scripts/package.js`)和 Docker 构建(`Dockerfile`)在构建时直接从 GitHub Releases 下载 PTY 并内置到产物中,确保用户部署后无需额外下载。 + +## 支持的平台和架构 + +| 操作系统 | CPU 架构 | 二进制文件名 | +|---------|---------|-------------| +| Windows | x64 | `pty_win32_x64.exe` | +| Linux | x64 | `pty_linux_x64` | +| Linux | ARM64 | `pty_linux_arm64` | + +## 二进制文件存放位置 + +使用多路径尝试策略,按以下顺序查找: + +1. `{项目根目录}/data/lib/` — 打包后环境 +2. `{项目根目录}/server/data/lib/` — 开发环境 + +> **注意**:PTY 文件已从旧的 `server/PTY/` 目录迁移到 `data/lib/` 目录,与 Zip-Tools 统一管理。 + +## 手动放置二进制文件(离线环境) + +如果服务器无法访问外网,可以手动下载并放置二进制文件: + +1. 从 [PTY Releases](https://github.com/MCSManager/PTY/releases/tag/latest) 下载对应平台的二进制文件 +2. 将文件放置到 `server/data/lib/` 或 `data/lib/` 目录下 +3. Linux 平台需要设置可执行权限:`chmod 755 pty_linux_x64` + +## 使用的模块 + +- `PtyManager`(`server/src/utils/ptyManager.ts`)— PTY 二进制文件的路径解析、检测、下载管理 +- `TerminalManager`(`server/src/modules/terminal/TerminalManager.ts`)— 通过 PtyManager 获取 PTY 路径并创建终端会话 + +## 迁移说明(从旧版本升级) + +旧版本将 PTY 文件存放在 `server/PTY/` 目录下,新版本已迁移到 `data/lib/` 目录。升级后: + +- 旧的 `server/PTY/` 目录可以安全删除 +- 服务启动时会自动检测并下载 PTY 到新目录 +- 打包产物中不再包含 `server/PTY/` 目录 diff --git a/install-gsm3.sh b/install-gsm3.sh index ff40dbe..c1341c1 100755 --- a/install-gsm3.sh +++ b/install-gsm3.sh @@ -121,7 +121,7 @@ if test "$install_type" = "1"; then echo "下载完毕,解压中,请稍等" tar -xzf gsm3.tgz -C "$install_path" rm -rf gsm3.tgz - chmod 755 "$install_path/node/bin/node" "$install_path/start.sh" "$install_path"/server/PTY/pty* + chmod 755 "$install_path/node/bin/node" "$install_path/start.sh" "$install_path"/data/lib/pty* 2>/dev/null || true echo "SERVER_PORT=$server_port" >> "$install_path/.env" if test "$install_to_systemd" = "yes"; then mkdir -pv /usr/local/lib/systemd/system diff --git a/scripts/package.js b/scripts/package.js index 76264f1..506cfac 100644 --- a/scripts/package.js +++ b/scripts/package.js @@ -26,6 +26,9 @@ const nodeVersion = '22.17.0' // Zip-Tools GitHub 下载配置(始终使用最新版本) const ZIP_TOOLS_GITHUB_URL = 'https://github.com/MCSManager/Zip-Tools/releases/latest/download/' +// PTY GitHub 下载配置(使用 latest 标签) +const PTY_GITHUB_URL = 'https://github.com/MCSManager/PTY/releases/tag/latest/download/' + /** * 获取目标平台对应的 Zip-Tools 二进制文件名列表 * 打包时下载所有该平台支持的架构版本 @@ -115,6 +118,60 @@ async function downloadZipTools(platform) { console.log('✅ Zip-Tools 下载完成') } +/** + * 获取目标平台对应的 PTY 二进制文件名列表 + * 打包时下载所有该平台支持的架构版本 + */ +function getPtyBinaries(platform) { + if (platform === 'linux') { + return ['pty_linux_x64', 'pty_linux_arm64'] + } else if (platform === 'windows') { + return ['pty_win32_x64.exe'] + } + // 未指定平台时下载所有版本 + return [ + 'pty_linux_x64', + 'pty_linux_arm64', + 'pty_win32_x64.exe', + ] +} + +/** + * 下载 PTY 二进制文件到打包目录的 data/lib/ + * 从 GitHub Releases 下载,确保打包产物内置 PTY + */ +async function downloadPty(platform) { + const binaries = getPtyBinaries(platform) + const libDir = path.join(packageDir, 'data', 'lib') + await fs.ensureDir(libDir) + + console.log('📥 正在从 GitHub 下载 PTY (latest)...') + + for (const binaryName of binaries) { + const url = `${PTY_GITHUB_URL}${binaryName}` + const destPath = path.join(libDir, binaryName) + + console.log(` 下载: ${binaryName}`) + try { + await downloadFile(url, destPath) + // 非 Windows 二进制文件设置可执行权限 + if (!binaryName.endsWith('.exe')) { + try { + execSync(`chmod +x "${destPath}"`) + } catch (e) { + // Windows 构建环境无法 chmod,忽略 + } + } + console.log(` ✅ ${binaryName} 下载完成`) + } catch (err) { + console.error(` ❌ ${binaryName} 下载失败: ${err.message}`) + throw err + } + } + + console.log('✅ PTY 下载完成') +} + async function downloadNodejs(platform) { const nodeUrls = { linux: `https://nodejs.org/dist/v${nodeVersion}/node-v${nodeVersion}-linux-x64.tar.xz`, @@ -207,11 +264,7 @@ async function createPackage() { path.join(packageDir, 'server', 'package.json') ) - // 复制PTY文件 - await fs.copy( - path.join(__dirname, '..', 'server', 'PTY'), - path.join(packageDir, 'server', 'PTY') - ) + // PTY 文件不再从本地复制,改为从 GitHub 下载到 data/lib/ 目录 // 复制环境变量配置文件 await fs.copy( @@ -285,6 +338,14 @@ async function createPackage() { console.log(' 用户启动时会自动从镜像站下载') } + // 下载 PTY 二进制文件(从 GitHub Releases) + try { + await downloadPty(buildTarget) + } catch (error) { + console.error('⚠️ PTY 下载失败,打包产物中将不包含 PTY:', error.message) + console.log(' 用户启动时会自动从镜像站下载') + } + console.log('📝 创建启动脚本...') // 根据目标平台创建启动脚本 if (buildTarget === 'windows') { @@ -296,7 +357,7 @@ async function createPackage() { } else if (buildTarget === 'linux') { const startShScript = `#!/bin/bash echo "正在启动GSM3管理面板..." -chmod +x server/PTY/pty_linux_x64 +# PTY 文件已迁移到 data/lib/ 目录,启动时由服务端自动检测 node/bin/node server/index.js` await fs.writeFile( @@ -326,7 +387,7 @@ pause` const startShScript = `#!/bin/bash echo "正在启动GSM3管理面板..." -chmod +x server/PTY/pty_linux_x64 +# PTY 文件已迁移到 data/lib/ 目录,启动时由服务端自动检测 node server/index.js` await fs.writeFile( diff --git a/server/PTY/pty_linux_arm32 b/server/PTY/pty_linux_arm32 deleted file mode 100755 index 927d9ee..0000000 Binary files a/server/PTY/pty_linux_arm32 and /dev/null differ diff --git a/server/PTY/pty_linux_arm64 b/server/PTY/pty_linux_arm64 deleted file mode 100755 index d33a86f..0000000 Binary files a/server/PTY/pty_linux_arm64 and /dev/null differ diff --git a/server/PTY/pty_linux_x64 b/server/PTY/pty_linux_x64 deleted file mode 100755 index 7a7bfdd..0000000 Binary files a/server/PTY/pty_linux_x64 and /dev/null differ diff --git a/server/PTY/pty_win32_x64.exe b/server/PTY/pty_win32_x64.exe deleted file mode 100644 index a6ef759..0000000 Binary files a/server/PTY/pty_win32_x64.exe and /dev/null differ diff --git a/server/PTY/介绍.md b/server/PTY/介绍.md deleted file mode 100644 index 0ff01df..0000000 --- a/server/PTY/介绍.md +++ /dev/null @@ -1,67 +0,0 @@ -Pseudo-teletype App --- -- -- - -仿真终端应用程序,支持运行所有 Linux/Windows 程序,可以为您的更高层应用带来完全终端控制能力。 - -中文 | English - -terminal image - -图片中表示的是,使用仿真终端运行 Minecraft 服务器,并且按下 Tab 键来选取提示。 - - -什么是 PTY/TTY? -tty = "teletype",pty = "pseudo-teletype" - -众所周知,程序拥有输入与输出流,但是数据流与显示器之间有一个区别,那便是缺少行和高的排列维度。简而言之,PTY 的中文意义就是伪装设备终端,让我们的程序伪装成一个拥有固定高宽的显示器,接受来自程序的输出内容。 - - -使用 -开一个 PTY 并执行命令,设置固定窗口大小,IO 流直接转发。 - -注意:-cmd 接收的是一个数组, 命令的参数以数组的形式传递,且需要序列化,如:[\"java\",\"-jar\",\"ser.jar\",\"nogui\"] -go build -./pty -dir "." -cmd [\"bash\"] -size 50,50 -接下来您会得到一个设置好大小宽度的窗口,并且您可以像 SSH 终端一样,进行任何交互。 - -ping google.com -top -htop - -参数: - -cmd string - command - -coder string - Coder (default "UTF-8") - -dir string - command work path (default ".") - -size string - Initialize pty size, stdin will be forwarded directly (default "50,50") - -test - Test whether the system environment is pty compatible - -兼容性 -支持所有现代主流版本 Linux 系统。 -支持 Windows 7 到 Windows 11 所有版本系统,包括 Server 系列。 -支持 windows amd64 / linux amd64 & arm64。 - -MCSManager -MCSManager 是一款开源,分布式,开箱即用,支持 Minecraft 和其他控制台应用的程序管理面板。 - -这个程序是专门为了 MCSManager 而设计,您也可以尝试嵌入到您自己的程序中。 - -More info: https://github.com/mcsmanager - - -贡献 -此程序属于 MCSManager 的最重要的核心功能之一,非必要不新增功能。 - -如果您想为这个项目提供新功能,那您必须开一个 issue 说明此功能,并提供编程思路,我们一起经过讨论后再决定是否开发 - -如果您是修复 BUG,可以直接提交 PR 并说明情况 - - -MIT license -遵循 MIT License 开源协议。 - -版权所有 zijiren233 和贡献者们。 \ No newline at end of file diff --git a/server/src/index.ts b/server/src/index.ts index 14b473f..c5992ca 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -50,6 +50,7 @@ import networkRouter from './routes/network.js' import cloudBuildRouter from './routes/cloudBuild.js' import { consoleLogBuffer } from './utils/logger.js' import { zipToolsManager } from './utils/zipToolsManager.js' +import { ptyManager } from './utils/ptyManager.js' // 获取当前文件目录 const __filename = fileURLToPath(import.meta.url) @@ -626,6 +627,15 @@ async function startServer() { // 不阻塞启动 } + // 检测并下载 PTY + try { + await ptyManager.ensureInstalled() + logger.info('PTY 已就绪') + } catch (error: any) { + logger.warn('PTY 下载失败,终端功能可能不可用:', error.message || error) + // 不阻塞启动 + } + // 设置路由 app.use('/api/auth', setupAuthRoutes(authManager)) app.use('/api/terminal', setupTerminalRoutes(terminalManager)) diff --git a/server/src/modules/terminal/TerminalManager.ts b/server/src/modules/terminal/TerminalManager.ts index c100804..4ce2ab3 100755 --- a/server/src/modules/terminal/TerminalManager.ts +++ b/server/src/modules/terminal/TerminalManager.ts @@ -11,6 +11,7 @@ import { promisify } from 'util' import { exec } from 'child_process' import { TerminalSessionManager, PersistedTerminalSession } from './TerminalSessionManager.js' import { ConfigManager } from '../config/ConfigManager.js' +import { ptyManager } from '../../utils/ptyManager.js' const execAsync = promisify(exec) @@ -72,47 +73,8 @@ export class TerminalManager { this.configManager = configManager this.sessionManager = new TerminalSessionManager(logger) - // 根据操作系统和架构选择PTY程序路径 - const platform = os.platform() - const arch = os.arch() - const baseDir = process.cwd() - - let ptyFileName: string - if (platform === 'win32') { - ptyFileName = 'pty_win32_x64.exe' - } else { - // Linux平台根据架构选择对应的PTY文件 - if (arch === 'arm64' || arch === 'aarch64') { - ptyFileName = 'pty_linux_arm64' - } else { - ptyFileName = 'pty_linux_x64' - } - } - - // 尝试多个可能的路径来查找 PTY 文件 - const possiblePaths = [ - path.join(baseDir, 'PTY', ptyFileName), // 打包后的路径 - path.join(baseDir, 'server', 'PTY', ptyFileName), // 开发环境路径 - ] - + // PTY 路径将在 initialize() 中通过 ptyManager 异步获取 this.ptyPath = '' - for (const possiblePath of possiblePaths) { - try { - fs.accessSync(possiblePath, fs.constants.F_OK) - this.ptyPath = possiblePath - break - } catch { - // 继续尝试下一个路径 - } - } - - if (!this.ptyPath) { - this.logger.error(`无法找到 PTY 文件: ${ptyFileName}`) - // 使用默认路径作为最后的备用 - this.ptyPath = path.resolve(__dirname, '../../PTY', ptyFileName) - } - - this.logger.info(`终端管理器初始化完成,PTY路径: ${this.ptyPath}`) // 定期清理不活跃的会话 - 已禁用 // setInterval(() => { @@ -127,9 +89,26 @@ export class TerminalManager { /** * 初始化终端管理器 + * 通过 ptyManager 获取 PTY 二进制文件路径 */ async initialize(): Promise { await this.sessionManager.initialize() + + // 通过 ptyManager 获取 PTY 路径(已在启动时确保下载) + try { + this.ptyPath = await ptyManager.getPtyPath() + this.logger.info(`终端管理器初始化完成,PTY路径: ${this.ptyPath}`) + } catch (error: any) { + this.logger.error(`无法找到 PTY 文件: ${error.message}`) + // 使用 ptyManager 获取平台对应的文件名作为备用路径 + try { + const ptyFileName = ptyManager.getBinaryName() + this.ptyPath = path.join(process.cwd(), 'data', 'lib', ptyFileName) + this.logger.warn(`使用备用 PTY 路径: ${this.ptyPath}`) + } catch (nameError: any) { + this.logger.error(`无法获取 PTY 文件名: ${nameError.message}`) + } + } } /** diff --git a/server/src/utils/ptyManager.ts b/server/src/utils/ptyManager.ts new file mode 100644 index 0000000..93a68f9 --- /dev/null +++ b/server/src/utils/ptyManager.ts @@ -0,0 +1,201 @@ +import path from 'path' +import fs from 'fs/promises' +import { createWriteStream } from 'fs' +import { pipeline } from 'stream/promises' +import logger from './logger.js' + +/** + * 支持的操作系统平台列表 + */ +const SUPPORTED_PLATFORMS = new Set(['win32', 'linux']) + +/** + * 支持的 CPU 架构列表 + */ +const SUPPORTED_ARCHS = new Set(['x64', 'arm64']) + +/** + * PTY 二进制文件管理器 + * 负责 PTY 二进制文件的路径解析、检测、下载 + * 参照 ZipToolsManager 的设计模式 + */ +class PtyManager { + /** 自建镜像下载基础 URL(运行时使用,国内加速) */ + private readonly DOWNLOAD_BASE_URL = + 'https://download.xiaozhuhouses.asia/%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE/GSManager/GSManager3/%E8%BF%90%E8%A1%8C%E4%BE%9D%E8%B5%96/PTY/' + + /** GitHub Releases 备用下载 URL */ + private readonly FALLBACK_DOWNLOAD_URL = + 'https://github.com/MCSManager/PTY/releases/tag/latest/download/' + + /** + * 获取当前平台对应的 PTY 二进制文件名 + * 命名规则:pty_{platform}_{arch},Windows 追加 .exe + * + * 实际文件命名: + * - win32/x64 → pty_win32_x64.exe + * - linux/x64 → pty_linux_x64 + * - linux/arm64 → pty_linux_arm64 + */ + getBinaryName(): string { + const platform = process.platform + const arch = process.arch + + if (!SUPPORTED_PLATFORMS.has(platform)) { + throw new Error(`不支持的操作系统平台: ${platform}`) + } + if (!SUPPORTED_ARCHS.has(arch)) { + throw new Error(`不支持的 CPU 架构: ${arch}`) + } + + const name = `pty_${platform}_${arch}` + return platform === 'win32' ? `${name}.exe` : name + } + + /** + * 获取 lib 目录的候选路径列表 + * 使用多路径尝试策略,兼容打包后环境和开发环境 + */ + private getLibDirCandidates(): string[] { + const baseDir = process.cwd() + return [ + path.join(baseDir, 'data', 'lib'), // 打包后环境 + path.join(baseDir, 'server', 'data', 'lib'), // 开发环境 + ] + } + + /** + * 使用多路径尝试策略获取 PTY 二进制文件绝对路径 + * 依次尝试 data/lib/ 和 server/data/lib/ 目录 + */ + async getPtyPath(): Promise { + const binaryName = this.getBinaryName() + const candidates = this.getLibDirCandidates() + + for (const libDir of candidates) { + const fullPath = path.join(libDir, binaryName) + try { + await fs.access(fullPath) + return fullPath + } catch { + // 该路径不存在,尝试下一个 + } + } + + throw new Error( + `未找到 PTY 二进制文件 (${binaryName}),已尝试路径: ${candidates.map(d => path.join(d, binaryName)).join(', ')}` + ) + } + + /** + * 检测 PTY 二进制文件是否存在 + */ + async isInstalled(): Promise { + try { + await this.getPtyPath() + return true + } catch { + return false + } + } + + /** + * 从指定 URL 下载二进制文件到目标路径 + * 非 Windows 平台设置 chmod 0o755 + */ + private async downloadFromUrl(url: string, targetPath: string): Promise { + const axios = (await import('axios')).default + const response = await axios.get(url, { + responseType: 'stream', + timeout: 60000, // 60 秒超时 + }) + + // 使用流式写入文件 + const writer = createWriteStream(targetPath) + await pipeline(response.data, writer) + + // 检查文件大小,防止下载空文件 + const stat = await fs.stat(targetPath) + if (stat.size === 0) { + await fs.unlink(targetPath) + throw new Error('下载的文件大小为 0,已删除') + } + + // 非 Windows 平台设置可执行权限 + if (process.platform !== 'win32') { + await fs.chmod(targetPath, 0o755) + } + } + + /** + * 下载 PTY 二进制文件到第一个可写的 lib 目录 + * 优先从自建镜像下载,失败后回退到 GitHub Releases + */ + async download(): Promise { + const binaryName = this.getBinaryName() + const candidates = this.getLibDirCandidates() + + // 选择第一个可用的 lib 目录(优先打包后路径) + let targetDir: string | null = null + for (const dir of candidates) { + try { + await fs.mkdir(dir, { recursive: true }) + targetDir = dir + break + } catch { + // 无法创建该目录,尝试下一个 + } + } + + if (!targetDir) { + throw new Error(`无法创建 lib 目录,已尝试: ${candidates.join(', ')}`) + } + + const targetPath = path.join(targetDir, binaryName) + const primaryUrl = `${this.DOWNLOAD_BASE_URL}${binaryName}` + const fallbackUrl = `${this.FALLBACK_DOWNLOAD_URL}${binaryName}` + + // 优先从自建镜像下载 + logger.info(`正在从自建镜像下载 PTY: ${primaryUrl}`) + try { + await this.downloadFromUrl(primaryUrl, targetPath) + logger.info(`PTY 下载完成: ${targetPath}`) + return + } catch (primaryError: any) { + logger.warn(`自建镜像下载失败: ${primaryError.message || primaryError},尝试 GitHub 备用地址...`) + // 清理可能的残留文件 + try { await fs.unlink(targetPath) } catch { /* 忽略 */ } + } + + // 回退到 GitHub Releases + logger.info(`正在从 GitHub 下载 PTY: ${fallbackUrl}`) + try { + await this.downloadFromUrl(fallbackUrl, targetPath) + logger.info(`PTY 下载完成(GitHub 备用): ${targetPath}`) + } catch (fallbackError: any) { + // 清理可能的残留文件 + try { await fs.unlink(targetPath) } catch { /* 忽略 */ } + const message = `PTY 下载失败(两个源均不可用): ${fallbackError.message || fallbackError}` + logger.error(message) + throw new Error(message) + } + } + + /** + * 确保 PTY 二进制文件可用(检测 + 自动下载) + * 服务端启动时调用 + */ + async ensureInstalled(): Promise { + if (await this.isInstalled()) { + logger.info('PTY 已存在,跳过下载') + return + } + await this.download() + } +} + +/** 导出单例实例 */ +export const ptyManager = new PtyManager() + +/** 导出类本身(用于测试) */ +export { PtyManager } diff --git a/start.sh b/start.sh index 9534d1a..1d0be45 100644 --- a/start.sh +++ b/start.sh @@ -14,16 +14,17 @@ if [ -f "server/index.js" ]; then echo "📍 默认账户: admin / admin123" echo - # 设置PTY可执行权限(根据架构选择) + # PTY 文件已迁移到 data/lib/ 目录,启动时由服务端自动检测和下载 + # 如果 data/lib/ 中存在 PTY 文件,设置可执行权限 ARCH=$(uname -m) - if [ "$ARCH" = "x86_64" ] && [ -f "server/PTY/pty_linux_x64" ]; then - chmod +x server/PTY/pty_linux_x64 + if [ "$ARCH" = "x86_64" ] && [ -f "data/lib/pty_linux_x64" ]; then + chmod +x data/lib/pty_linux_x64 echo "✅ PTY权限设置完成 (x64)" - elif [ "$ARCH" = "aarch64" ] && [ -f "server/PTY/pty_linux_arm64" ]; then - chmod +x server/PTY/pty_linux_arm64 + elif [ "$ARCH" = "aarch64" ] && [ -f "data/lib/pty_linux_arm64" ]; then + chmod +x data/lib/pty_linux_arm64 echo "✅ PTY权限设置完成 (arm64)" else - echo "⚠️ 未找到对应架构的PTY文件,使用默认配置" + echo "ℹ️ PTY文件将在服务启动时自动下载" fi # 启动应用