From e7692e6b8225606c5da525a5c8b7dbb56607d89e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=B0=8F=E6=9C=B1?=
<10714957+xiao-zhu245@user.noreply.gitee.com>
Date: Sat, 12 Jul 2025 11:02:22 +0800
Subject: [PATCH] =?UTF-8?q?=E6=8F=92=E4=BB=B6=E5=A2=9E=E5=8A=A0=E5=88=9B?=
=?UTF-8?q?=E5=BB=BA=E5=AE=9E=E4=BE=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../data/plugins/example-plugin/gsm3-api.js | 165 ++++++
server/data/plugins/example-plugin/index.html | 551 ++++++++++++++++++
.../src/modules/terminal/TerminalManager.ts | 12 +-
server/src/routes/pluginApi.ts | 286 ++++++++-
4 files changed, 998 insertions(+), 16 deletions(-)
diff --git a/server/data/plugins/example-plugin/gsm3-api.js b/server/data/plugins/example-plugin/gsm3-api.js
index 78910f3..b1b88b8 100644
--- a/server/data/plugins/example-plugin/gsm3-api.js
+++ b/server/data/plugins/example-plugin/gsm3-api.js
@@ -140,6 +140,82 @@ class GSM3API {
return await this.request(`/instances/${instanceId}/status`)
}
+ /**
+ * 创建新实例
+ * @param {Object} instanceData 实例数据
+ * @param {string} instanceData.name 实例名称
+ * @param {string} instanceData.description 实例描述
+ * @param {string} instanceData.workingDirectory 工作目录
+ * @param {string} instanceData.startCommand 启动命令
+ * @param {boolean} instanceData.autoStart 是否自动启动
+ * @param {string} instanceData.stopCommand 停止命令
+ */
+ async createInstance(instanceData) {
+ return await this.request('/instances', {
+ method: 'POST',
+ body: instanceData
+ })
+ }
+
+ /**
+ * 更新实例
+ * @param {string} instanceId 实例ID
+ * @param {Object} instanceData 实例数据
+ */
+ async updateInstance(instanceId, instanceData) {
+ return await this.request(`/instances/${instanceId}`, {
+ method: 'PUT',
+ body: instanceData
+ })
+ }
+
+ /**
+ * 删除实例
+ * @param {string} instanceId 实例ID
+ */
+ async deleteInstance(instanceId) {
+ return await this.request(`/instances/${instanceId}`, {
+ method: 'DELETE'
+ })
+ }
+
+ /**
+ * 启动实例
+ * @param {string} instanceId 实例ID
+ */
+ async startInstance(instanceId) {
+ return await this.request(`/instances/${instanceId}/start`, {
+ method: 'POST'
+ })
+ }
+
+ /**
+ * 停止实例
+ * @param {string} instanceId 实例ID
+ */
+ async stopInstance(instanceId) {
+ return await this.request(`/instances/${instanceId}/stop`, {
+ method: 'POST'
+ })
+ }
+
+ /**
+ * 重启实例
+ * @param {string} instanceId 实例ID
+ */
+ async restartInstance(instanceId) {
+ return await this.request(`/instances/${instanceId}/restart`, {
+ method: 'POST'
+ })
+ }
+
+ /**
+ * 获取实例市场列表
+ */
+ async getMarketInstances() {
+ return await this.request('/instances/market')
+ }
+
// ==================== 终端管理API ====================
/**
@@ -149,6 +225,95 @@ class GSM3API {
return await this.request('/terminals')
}
+ /**
+ * 获取终端会话统计信息
+ */
+ async getTerminalStats() {
+ return await this.request('/terminals/stats', {
+ method: 'GET'
+ })
+ }
+
+ /**
+ * 获取终端会话详细信息
+ */
+ async getTerminalSessions() {
+ return await this.request('/terminals/sessions', {
+ method: 'GET'
+ })
+ }
+
+ /**
+ * 获取活跃终端进程信息
+ */
+ async getActiveTerminalProcesses() {
+ return await this.request('/terminals/active-processes', {
+ method: 'GET'
+ })
+ }
+
+ /**
+ * 更新终端会话名称
+ * @param {string} sessionId 会话ID
+ * @param {string} name 新的会话名称
+ */
+ async updateTerminalSessionName(sessionId, name) {
+ return await this.request(`/terminals/sessions/${sessionId}/name`, {
+ method: 'PUT',
+ body: { name }
+ })
+ }
+
+ /**
+ * 验证终端配置
+ * @param {string} workingDirectory 工作目录
+ * @param {string} shell Shell程序路径
+ */
+ async validateTerminalConfig(workingDirectory, shell) {
+ return await this.request('/terminals/validate-config', {
+ method: 'POST',
+ body: { workingDirectory, shell }
+ })
+ }
+
+ /**
+ * 获取系统默认Shell信息
+ */
+ async getDefaultShell() {
+ return await this.request('/terminals/default-shell', {
+ method: 'GET'
+ })
+ }
+
+ /**
+ * 获取终端主题配置
+ */
+ async getTerminalThemes() {
+ return await this.request('/terminals/themes', {
+ method: 'GET'
+ })
+ }
+
+ /**
+ * 获取终端字体配置
+ */
+ async getTerminalFonts() {
+ return await this.request('/terminals/fonts', {
+ method: 'GET'
+ })
+ }
+
+ /**
+ * 测试终端连接
+ * @param {string} workingDirectory 工作目录
+ */
+ async testTerminalConnection(workingDirectory) {
+ return await this.request('/terminals/test-connection', {
+ method: 'POST',
+ body: { workingDirectory }
+ })
+ }
+
// ==================== 游戏管理API ====================
/**
diff --git a/server/data/plugins/example-plugin/index.html b/server/data/plugins/example-plugin/index.html
index 21ac184..950879b 100644
--- a/server/data/plugins/example-plugin/index.html
+++ b/server/data/plugins/example-plugin/index.html
@@ -339,6 +339,85 @@
+
📊 系统信息
@@ -811,6 +890,478 @@
}
}
+ // ==================== 实例管理函数 ====================
+
+ // 显示创建实例表单
+ function showCreateInstanceForm() {
+ document.getElementById('createInstanceForm').style.display = 'block'
+ }
+
+ // 隐藏创建实例表单
+ function hideCreateInstanceForm() {
+ document.getElementById('createInstanceForm').style.display = 'none'
+ // 清空表单
+ document.getElementById('instanceName').value = ''
+ document.getElementById('instanceDescription').value = ''
+ document.getElementById('instanceWorkingDir').value = ''
+ document.getElementById('instanceStartCommand').value = ''
+ document.getElementById('instanceStopCommand').value = 'ctrl+c'
+ document.getElementById('instanceAutoStart').checked = false
+ }
+
+ // 创建实例
+ async function createInstance() {
+ try {
+ if (!window.gsm3) {
+ throw new Error('GSM3 API对象未找到')
+ }
+
+ const name = document.getElementById('instanceName').value
+ const description = document.getElementById('instanceDescription').value
+ const workingDirectory = document.getElementById('instanceWorkingDir').value
+ const startCommand = document.getElementById('instanceStartCommand').value
+ const stopCommand = document.getElementById('instanceStopCommand').value
+ const autoStart = document.getElementById('instanceAutoStart').checked
+
+ if (!name || !workingDirectory || !startCommand) {
+ showApiError('创建实例失败', new Error('请填写实例名称、工作目录和启动命令'))
+ return
+ }
+
+ const instanceData = {
+ name: name.trim(),
+ description: description.trim(),
+ workingDirectory: workingDirectory.trim(),
+ startCommand: startCommand.trim(),
+ stopCommand: stopCommand,
+ autoStart: autoStart
+ }
+
+ showApiLoading('正在初始化API...')
+ await window.gsm3.initialize()
+
+ showApiLoading('正在创建实例...')
+ const result = await window.gsm3.createInstance(instanceData)
+ showApiResult('创建实例成功', result)
+ hideCreateInstanceForm()
+ if (window.gsm3.showNotification) {
+ window.gsm3.showNotification('success', '实例创建成功')
+ }
+ } catch (error) {
+ showApiError('创建实例失败', error)
+ if (window.gsm3 && window.gsm3.showNotification) {
+ window.gsm3.showNotification('error', '创建实例失败: ' + error.message)
+ }
+ }
+ }
+
+ // 获取市场实例
+ async function getMarketInstances() {
+ try {
+ if (!window.gsm3) {
+ throw new Error('GSM3 API对象未找到')
+ }
+
+ showApiLoading('正在初始化API...')
+ await window.gsm3.initialize()
+
+ showApiLoading('正在获取市场实例列表...')
+ const result = await window.gsm3.getMarketInstances()
+ showApiResult('市场实例列表', result)
+ if (window.gsm3.showNotification) {
+ window.gsm3.showNotification('success', '市场实例列表获取成功')
+ }
+ } catch (error) {
+ showApiError('获取市场实例列表失败', error)
+ if (window.gsm3 && window.gsm3.showNotification) {
+ window.gsm3.showNotification('error', '获取市场实例列表失败: ' + error.message)
+ }
+ }
+ }
+
+ // 获取实例详情
+ async function getInstanceDetails() {
+ try {
+ if (!window.gsm3) {
+ throw new Error('GSM3 API对象未找到')
+ }
+
+ const instanceId = document.getElementById('instanceIdInput').value
+ if (!instanceId) {
+ showApiError('获取实例详情失败', new Error('请输入实例ID'))
+ return
+ }
+
+ showApiLoading('正在初始化API...')
+ await window.gsm3.initialize()
+
+ showApiLoading('正在获取实例详情...')
+ const result = await window.gsm3.getInstance(instanceId)
+ showApiResult(`实例详情: ${instanceId}`, result)
+ if (window.gsm3.showNotification) {
+ window.gsm3.showNotification('success', '实例详情获取成功')
+ }
+ } catch (error) {
+ showApiError('获取实例详情失败', error)
+ if (window.gsm3 && window.gsm3.showNotification) {
+ window.gsm3.showNotification('error', '获取实例详情失败: ' + error.message)
+ }
+ }
+ }
+
+ // 启动实例
+ async function startInstance() {
+ try {
+ if (!window.gsm3) {
+ throw new Error('GSM3 API对象未找到')
+ }
+
+ const instanceId = document.getElementById('instanceIdInput').value
+ if (!instanceId) {
+ showApiError('启动实例失败', new Error('请输入实例ID'))
+ return
+ }
+
+ showApiLoading('正在初始化API...')
+ await window.gsm3.initialize()
+
+ showApiLoading('正在启动实例...')
+ const result = await window.gsm3.startInstance(instanceId)
+ showApiResult(`启动实例: ${instanceId}`, result)
+ if (window.gsm3.showNotification) {
+ window.gsm3.showNotification('success', '实例启动成功')
+ }
+ } catch (error) {
+ showApiError('启动实例失败', error)
+ if (window.gsm3 && window.gsm3.showNotification) {
+ window.gsm3.showNotification('error', '启动实例失败: ' + error.message)
+ }
+ }
+ }
+
+ // 停止实例
+ async function stopInstance() {
+ try {
+ if (!window.gsm3) {
+ throw new Error('GSM3 API对象未找到')
+ }
+
+ const instanceId = document.getElementById('instanceIdInput').value
+ if (!instanceId) {
+ showApiError('停止实例失败', new Error('请输入实例ID'))
+ return
+ }
+
+ showApiLoading('正在初始化API...')
+ await window.gsm3.initialize()
+
+ showApiLoading('正在停止实例...')
+ const result = await window.gsm3.stopInstance(instanceId)
+ showApiResult(`停止实例: ${instanceId}`, result)
+ if (window.gsm3.showNotification) {
+ window.gsm3.showNotification('success', '实例停止成功')
+ }
+ } catch (error) {
+ showApiError('停止实例失败', error)
+ if (window.gsm3 && window.gsm3.showNotification) {
+ window.gsm3.showNotification('error', '停止实例失败: ' + error.message)
+ }
+ }
+ }
+
+ // 重启实例
+ async function restartInstance() {
+ try {
+ if (!window.gsm3) {
+ throw new Error('GSM3 API对象未找到')
+ }
+
+ const instanceId = document.getElementById('instanceIdInput').value
+ if (!instanceId) {
+ showApiError('重启实例失败', new Error('请输入实例ID'))
+ return
+ }
+
+ showApiLoading('正在初始化API...')
+ await window.gsm3.initialize()
+
+ showApiLoading('正在重启实例...')
+ const result = await window.gsm3.restartInstance(instanceId)
+ showApiResult(`重启实例: ${instanceId}`, result)
+ if (window.gsm3.showNotification) {
+ window.gsm3.showNotification('success', '实例重启成功')
+ }
+ } catch (error) {
+ showApiError('重启实例失败', error)
+ if (window.gsm3 && window.gsm3.showNotification) {
+ window.gsm3.showNotification('error', '重启实例失败: ' + error.message)
+ }
+ }
+ }
+
+ // 删除实例
+ async function deleteInstance() {
+ try {
+ if (!window.gsm3) {
+ throw new Error('GSM3 API对象未找到')
+ }
+
+ const instanceId = document.getElementById('instanceIdInput').value
+ if (!instanceId) {
+ showApiError('删除实例失败', new Error('请输入实例ID'))
+ return
+ }
+
+ if (!confirm(`确定要删除实例 ${instanceId} 吗?此操作不可撤销!`)) {
+ return
+ }
+
+ showApiLoading('正在初始化API...')
+ await window.gsm3.initialize()
+
+ showApiLoading('正在删除实例...')
+ const result = await window.gsm3.deleteInstance(instanceId)
+ showApiResult(`删除实例: ${instanceId}`, result)
+ if (window.gsm3.showNotification) {
+ window.gsm3.showNotification('success', '实例删除成功')
+ }
+ } catch (error) {
+ showApiError('删除实例失败', error)
+ if (window.gsm3 && window.gsm3.showNotification) {
+ window.gsm3.showNotification('error', '删除实例失败: ' + error.message)
+ }
+ }
+ }
+
+ // ==================== 终端管理函数 ====================
+
+ // 获取终端统计信息
+ async function getTerminalStats() {
+ try {
+ if (!window.gsm3) {
+ throw new Error('GSM3 API对象未找到')
+ }
+
+ showApiLoading('正在初始化API...')
+ await window.gsm3.initialize()
+
+ showApiLoading('正在获取终端统计信息...')
+ const result = await window.gsm3.getTerminalStats()
+ showApiResult('终端统计信息', result)
+ if (window.gsm3.showNotification) {
+ window.gsm3.showNotification('success', '终端统计信息获取成功')
+ }
+ } catch (error) {
+ showApiError('获取终端统计信息失败', error)
+ if (window.gsm3 && window.gsm3.showNotification) {
+ window.gsm3.showNotification('error', '获取终端统计信息失败: ' + error.message)
+ }
+ }
+ }
+
+ // 获取终端会话列表
+ async function getTerminalSessions() {
+ try {
+ if (!window.gsm3) {
+ throw new Error('GSM3 API对象未找到')
+ }
+
+ showApiLoading('正在初始化API...')
+ await window.gsm3.initialize()
+
+ showApiLoading('正在获取终端会话列表...')
+ const result = await window.gsm3.getTerminalSessions()
+ showApiResult('终端会话列表', result)
+ if (window.gsm3.showNotification) {
+ window.gsm3.showNotification('success', '终端会话列表获取成功')
+ }
+ } catch (error) {
+ showApiError('获取终端会话列表失败', error)
+ if (window.gsm3 && window.gsm3.showNotification) {
+ window.gsm3.showNotification('error', '获取终端会话列表失败: ' + error.message)
+ }
+ }
+ }
+
+ // 获取活跃终端进程
+ async function getActiveTerminalProcesses() {
+ try {
+ if (!window.gsm3) {
+ throw new Error('GSM3 API对象未找到')
+ }
+
+ showApiLoading('正在初始化API...')
+ await window.gsm3.initialize()
+
+ showApiLoading('正在获取活跃终端进程...')
+ const result = await window.gsm3.getActiveTerminalProcesses()
+ showApiResult('活跃终端进程', result)
+ if (window.gsm3.showNotification) {
+ window.gsm3.showNotification('success', '活跃终端进程获取成功')
+ }
+ } catch (error) {
+ showApiError('获取活跃终端进程失败', error)
+ if (window.gsm3 && window.gsm3.showNotification) {
+ window.gsm3.showNotification('error', '获取活跃终端进程失败: ' + error.message)
+ }
+ }
+ }
+
+ // 获取默认Shell
+ async function getDefaultShell() {
+ try {
+ if (!window.gsm3) {
+ throw new Error('GSM3 API对象未找到')
+ }
+
+ showApiLoading('正在初始化API...')
+ await window.gsm3.initialize()
+
+ showApiLoading('正在获取默认Shell信息...')
+ const result = await window.gsm3.getDefaultShell()
+ showApiResult('默认Shell信息', result)
+ if (window.gsm3.showNotification) {
+ window.gsm3.showNotification('success', '默认Shell信息获取成功')
+ }
+ } catch (error) {
+ showApiError('获取默认Shell信息失败', error)
+ if (window.gsm3 && window.gsm3.showNotification) {
+ window.gsm3.showNotification('error', '获取默认Shell信息失败: ' + error.message)
+ }
+ }
+ }
+
+ // 获取终端主题
+ async function getTerminalThemes() {
+ try {
+ if (!window.gsm3) {
+ throw new Error('GSM3 API对象未找到')
+ }
+
+ showApiLoading('正在初始化API...')
+ await window.gsm3.initialize()
+
+ showApiLoading('正在获取终端主题配置...')
+ const result = await window.gsm3.getTerminalThemes()
+ showApiResult('终端主题配置', result)
+ if (window.gsm3.showNotification) {
+ window.gsm3.showNotification('success', '终端主题配置获取成功')
+ }
+ } catch (error) {
+ showApiError('获取终端主题配置失败', error)
+ if (window.gsm3 && window.gsm3.showNotification) {
+ window.gsm3.showNotification('error', '获取终端主题配置失败: ' + error.message)
+ }
+ }
+ }
+
+ // 获取终端字体
+ async function getTerminalFonts() {
+ try {
+ if (!window.gsm3) {
+ throw new Error('GSM3 API对象未找到')
+ }
+
+ showApiLoading('正在初始化API...')
+ await window.gsm3.initialize()
+
+ showApiLoading('正在获取终端字体配置...')
+ const result = await window.gsm3.getTerminalFonts()
+ showApiResult('终端字体配置', result)
+ if (window.gsm3.showNotification) {
+ window.gsm3.showNotification('success', '终端字体配置获取成功')
+ }
+ } catch (error) {
+ showApiError('获取终端字体配置失败', error)
+ if (window.gsm3 && window.gsm3.showNotification) {
+ window.gsm3.showNotification('error', '获取终端字体配置失败: ' + error.message)
+ }
+ }
+ }
+
+ // 验证终端配置
+ async function validateTerminalConfig() {
+ try {
+ if (!window.gsm3) {
+ throw new Error('GSM3 API对象未找到')
+ }
+
+ showApiLoading('正在初始化API...')
+ await window.gsm3.initialize()
+
+ showApiLoading('正在验证终端配置...')
+ const workingDirectory = process.cwd ? process.cwd() : '/'
+ const shell = process.platform === 'win32' ? 'powershell.exe' : '/bin/bash'
+ const result = await window.gsm3.validateTerminalConfig(workingDirectory, shell)
+ showApiResult('验证终端配置', result)
+ if (window.gsm3.showNotification) {
+ window.gsm3.showNotification('success', '终端配置验证成功')
+ }
+ } catch (error) {
+ showApiError('验证终端配置失败', error)
+ if (window.gsm3 && window.gsm3.showNotification) {
+ window.gsm3.showNotification('error', '验证终端配置失败: ' + error.message)
+ }
+ }
+ }
+
+ // 测试终端连接
+ async function testTerminalConnection() {
+ try {
+ if (!window.gsm3) {
+ throw new Error('GSM3 API对象未找到')
+ }
+
+ showApiLoading('正在初始化API...')
+ await window.gsm3.initialize()
+
+ showApiLoading('正在测试终端连接...')
+ const workingDirectory = process.cwd ? process.cwd() : '/'
+ const result = await window.gsm3.testTerminalConnection(workingDirectory)
+ showApiResult('测试终端连接', result)
+ if (window.gsm3.showNotification) {
+ window.gsm3.showNotification('success', '终端连接测试成功')
+ }
+ } catch (error) {
+ showApiError('测试终端连接失败', error)
+ if (window.gsm3 && window.gsm3.showNotification) {
+ window.gsm3.showNotification('error', '测试终端连接失败: ' + error.message)
+ }
+ }
+ }
+
+ // 更新终端会话名称
+ async function updateTerminalSessionName() {
+ try {
+ if (!window.gsm3) {
+ throw new Error('GSM3 API对象未找到')
+ }
+
+ const sessionId = document.getElementById('sessionIdInput').value
+ const sessionName = document.getElementById('sessionNameInput').value
+
+ if (!sessionId || !sessionName) {
+ showApiError('更新会话名称失败', new Error('请输入会话ID和新名称'))
+ return
+ }
+
+ showApiLoading('正在初始化API...')
+ await window.gsm3.initialize()
+
+ showApiLoading('正在更新终端会话名称...')
+ const result = await window.gsm3.updateTerminalSessionName(sessionId, sessionName)
+ showApiResult(`更新会话名称: ${sessionId} -> ${sessionName}`, result)
+ if (window.gsm3.showNotification) {
+ window.gsm3.showNotification('success', '终端会话名称更新成功')
+ }
+ } catch (error) {
+ showApiError('更新终端会话名称失败', error)
+ if (window.gsm3 && window.gsm3.showNotification) {
+ window.gsm3.showNotification('error', '更新终端会话名称失败: ' + error.message)
+ }
+ }
+ }
+
// 控制台欢迎信息
console.log('%c🧩 GSM3 插件系统', 'color: #667eea; font-size: 20px; font-weight: bold;')
console.log('%c欢迎使用示例插件!', 'color: #764ba2; font-size: 14px;')
diff --git a/server/src/modules/terminal/TerminalManager.ts b/server/src/modules/terminal/TerminalManager.ts
index 1a10ec1..6dfeb57 100644
--- a/server/src/modules/terminal/TerminalManager.ts
+++ b/server/src/modules/terminal/TerminalManager.ts
@@ -63,16 +63,16 @@ export class TerminalManager {
const arch = os.arch()
if (platform === 'win32') {
- // this.ptyPath = path.resolve(__dirname, '../../../PTY/pty_win32_x64.exe')
- this.ptyPath = path.resolve(__dirname, '../../PTY/pty_win32_x64.exe')
+ this.ptyPath = path.resolve(__dirname, '../../../PTY/pty_win32_x64.exe')
+ // this.ptyPath = path.resolve(__dirname, '../../PTY/pty_win32_x64.exe')
} else {
// Linux平台根据架构选择对应的PTY文件
if (arch === 'arm64' || arch === 'aarch64') {
- // this.ptyPath = path.resolve(__dirname, '../../../PTY/pty_linux_arm64')
- this.ptyPath = path.resolve(__dirname, '../../PTY/pty_linux_arm64')
+ this.ptyPath = path.resolve(__dirname, '../../../PTY/pty_linux_arm64')
+ // this.ptyPath = path.resolve(__dirname, '../../PTY/pty_linux_arm64')
} else {
- // this.ptyPath = path.resolve(__dirname, '../../../PTY/pty_linux_x64')
- this.ptyPath = path.resolve(__dirname, '../../PTY/pty_linux_x64')
+ this.ptyPath = path.resolve(__dirname, '../../../PTY/pty_linux_x64')
+ // this.ptyPath = path.resolve(__dirname, '../../PTY/pty_linux_x64')
}
}
diff --git a/server/src/routes/pluginApi.ts b/server/src/routes/pluginApi.ts
index 9e75089..078ec4c 100644
--- a/server/src/routes/pluginApi.ts
+++ b/server/src/routes/pluginApi.ts
@@ -5,6 +5,7 @@ import type { SystemManager } from '../modules/system/SystemManager.js'
import type { TerminalManager } from '../modules/terminal/TerminalManager.js'
import type { GameManager } from '../modules/game/GameManager.js'
import filesRouter from './files.js'
+import { setupTerminalRoutes } from './terminal.js'
import logger from '../utils/logger.js'
const router = Router()
@@ -200,33 +201,298 @@ router.get('/instances/:id/status', async (req: Request, res: Response) => {
}
})
-// ==================== 终端管理API ====================
-
-// 获取终端会话列表
-router.get('/terminals', async (req: Request, res: Response) => {
+// 获取市场实例列表
+router.get('/instances/market', async (req: Request, res: Response) => {
try {
- if (!terminalManager) {
+ if (!instanceManager) {
return res.status(503).json({
success: false,
- message: '终端管理器未初始化'
+ message: '实例管理器未初始化'
})
}
- const terminals = terminalManager.getSessionStats()
+ const marketInstances = instanceManager.getMarketInstances()
res.json({
success: true,
- data: terminals
+ data: marketInstances
})
} catch (error) {
- logger.error('插件获取终端列表失败:', error)
+ logger.error('插件获取市场实例列表失败:', error)
res.status(500).json({
success: false,
- message: '获取终端列表失败',
+ message: '获取市场实例列表失败',
error: error instanceof Error ? error.message : '未知错误'
})
}
})
+// 创建实例
+router.post('/instances', async (req: Request, res: Response) => {
+ try {
+ if (!instanceManager) {
+ return res.status(503).json({
+ success: false,
+ message: '实例管理器未初始化'
+ })
+ }
+
+ const { name, description, workingDirectory, startCommand, stopCommand, autoStart } = req.body
+
+ // 验证必填字段
+ if (!name || !workingDirectory || !startCommand) {
+ return res.status(400).json({
+ success: false,
+ message: '缺少必填字段: name, workingDirectory, startCommand'
+ })
+ }
+
+ // 验证停止命令
+ const validStopCommands = ['ctrl+c', 'stop', 'quit', 'exit']
+ if (stopCommand && !validStopCommands.includes(stopCommand)) {
+ return res.status(400).json({
+ success: false,
+ message: `无效的停止命令。支持的命令: ${validStopCommands.join(', ')}`
+ })
+ }
+
+ const instanceData = {
+ name: name.trim(),
+ description: description?.trim() || '',
+ workingDirectory: workingDirectory.trim(),
+ startCommand: startCommand.trim(),
+ stopCommand: stopCommand || 'ctrl+c',
+ autoStart: autoStart || false
+ }
+
+ const result = await instanceManager.createInstance(instanceData)
+ res.status(201).json({
+ success: true,
+ data: result,
+ message: '实例创建成功'
+ })
+ } catch (error) {
+ logger.error('插件创建实例失败:', error)
+ res.status(500).json({
+ success: false,
+ message: '创建实例失败',
+ error: error instanceof Error ? error.message : '未知错误'
+ })
+ }
+})
+
+// 更新实例
+router.put('/instances/:id', async (req: Request, res: Response) => {
+ try {
+ const { id } = req.params
+
+ if (!instanceManager) {
+ return res.status(503).json({
+ success: false,
+ message: '实例管理器未初始化'
+ })
+ }
+
+ const instance = instanceManager.getInstance(id)
+ if (!instance) {
+ return res.status(404).json({
+ success: false,
+ message: '实例不存在'
+ })
+ }
+
+ const { name, description, workingDirectory, startCommand, stopCommand, autoStart } = req.body
+
+ // 验证必填字段
+ if (!name || !workingDirectory || !startCommand) {
+ return res.status(400).json({
+ success: false,
+ message: '缺少必填字段: name, workingDirectory, startCommand'
+ })
+ }
+
+ // 验证停止命令
+ const validStopCommands = ['ctrl+c', 'stop', 'quit', 'exit']
+ if (stopCommand && !validStopCommands.includes(stopCommand)) {
+ return res.status(400).json({
+ success: false,
+ message: `无效的停止命令。支持的命令: ${validStopCommands.join(', ')}`
+ })
+ }
+
+ const instanceData = {
+ name: name.trim(),
+ description: description?.trim() || '',
+ workingDirectory: workingDirectory.trim(),
+ startCommand: startCommand.trim(),
+ stopCommand: stopCommand || 'ctrl+c',
+ autoStart: autoStart || false
+ }
+
+ const result = await instanceManager.updateInstance(id, instanceData)
+ res.json({
+ success: true,
+ data: result,
+ message: '实例更新成功'
+ })
+ } catch (error) {
+ logger.error('插件更新实例失败:', error)
+ res.status(500).json({
+ success: false,
+ message: '更新实例失败',
+ error: error instanceof Error ? error.message : '未知错误'
+ })
+ }
+})
+
+// 删除实例
+router.delete('/instances/:id', async (req: Request, res: Response) => {
+ try {
+ const { id } = req.params
+
+ if (!instanceManager) {
+ return res.status(503).json({
+ success: false,
+ message: '实例管理器未初始化'
+ })
+ }
+
+ const instance = instanceManager.getInstance(id)
+ if (!instance) {
+ return res.status(404).json({
+ success: false,
+ message: '实例不存在'
+ })
+ }
+
+ await instanceManager.deleteInstance(id)
+ res.json({
+ success: true,
+ message: '实例删除成功'
+ })
+ } catch (error) {
+ logger.error('插件删除实例失败:', error)
+ res.status(500).json({
+ success: false,
+ message: '删除实例失败',
+ error: error instanceof Error ? error.message : '未知错误'
+ })
+ }
+})
+
+// 启动实例
+router.post('/instances/:id/start', async (req: Request, res: Response) => {
+ try {
+ const { id } = req.params
+
+ if (!instanceManager) {
+ return res.status(503).json({
+ success: false,
+ message: '实例管理器未初始化'
+ })
+ }
+
+ const instance = instanceManager.getInstance(id)
+ if (!instance) {
+ return res.status(404).json({
+ success: false,
+ message: '实例不存在'
+ })
+ }
+
+ const result = await instanceManager.startInstance(id)
+ res.json({
+ success: true,
+ data: result,
+ message: '实例启动成功'
+ })
+ } catch (error) {
+ logger.error('插件启动实例失败:', error)
+ res.status(500).json({
+ success: false,
+ message: '启动实例失败',
+ error: error instanceof Error ? error.message : '未知错误'
+ })
+ }
+})
+
+// 停止实例
+router.post('/instances/:id/stop', async (req: Request, res: Response) => {
+ try {
+ const { id } = req.params
+
+ if (!instanceManager) {
+ return res.status(503).json({
+ success: false,
+ message: '实例管理器未初始化'
+ })
+ }
+
+ const instance = instanceManager.getInstance(id)
+ if (!instance) {
+ return res.status(404).json({
+ success: false,
+ message: '实例不存在'
+ })
+ }
+
+ const result = await instanceManager.stopInstance(id)
+ res.json({
+ success: true,
+ data: result,
+ message: '实例停止成功'
+ })
+ } catch (error) {
+ logger.error('插件停止实例失败:', error)
+ res.status(500).json({
+ success: false,
+ message: '停止实例失败',
+ error: error instanceof Error ? error.message : '未知错误'
+ })
+ }
+})
+
+// 重启实例
+router.post('/instances/:id/restart', async (req: Request, res: Response) => {
+ try {
+ const { id } = req.params
+
+ if (!instanceManager) {
+ return res.status(503).json({
+ success: false,
+ message: '实例管理器未初始化'
+ })
+ }
+
+ const instance = instanceManager.getInstance(id)
+ if (!instance) {
+ return res.status(404).json({
+ success: false,
+ message: '实例不存在'
+ })
+ }
+
+ const result = await instanceManager.restartInstance(id)
+ res.json({
+ success: true,
+ data: result,
+ message: '实例重启成功'
+ })
+ } catch (error) {
+ logger.error('插件重启实例失败:', error)
+ res.status(500).json({
+ success: false,
+ message: '重启实例失败',
+ error: error instanceof Error ? error.message : '未知错误'
+ })
+ }
+})
+
+// ==================== 终端管理API ====================
+
+// 转发终端操作请求到terminal路由
+const terminalRouter = setupTerminalRoutes(terminalManager)
+router.use('/terminals', terminalRouter)
+
// ==================== 游戏管理API ====================
// 获取游戏列表