完善插件

This commit is contained in:
小朱
2025-07-12 09:50:32 +08:00
parent 21e4a6ecde
commit 85f2be55a6
6 changed files with 899 additions and 6 deletions

View File

@@ -0,0 +1,307 @@
/**
* GSM3 插件API客户端
* 提供插件与主面板通信的接口
*/
class GSM3API {
constructor() {
this.baseURL = '/api/plugin-api'
this.token = null
this.initializeToken()
}
/**
* 初始化token获取机制
*/
initializeToken() {
try {
// 检查是否已经通过脚本注入设置了全局token
if (window.gsm3Token) {
this.token = window.gsm3Token
console.log('Token已从全局变量获取:', this.token)
return
}
// 检查是否已经通过脚本注入设置了token
if (window.gsm3 && window.gsm3.token) {
this.token = window.gsm3.token
console.log('Token已从注入脚本获取')
return
}
// 尝试从父窗口获取token
if (window.parent && window.parent !== window) {
window.parent.postMessage({ type: 'gsm3-get-token' }, '*')
}
console.log('正在初始化token...')
} catch (error) {
console.warn('Token初始化失败:', error)
}
// 监听token更新
window.addEventListener('message', (event) => {
if (event.data && event.data.type === 'gsm3-token-update') {
this.token = event.data.token
console.log('通过消息更新Token:', this.token)
}
})
// 定期检查全局token变量
const checkGlobalToken = () => {
if (!this.token && window.gsm3Token) {
this.token = window.gsm3Token
console.log('从全局变量延迟获取Token:', this.token)
}
}
// 每100ms检查一次最多检查50次5秒
let checkCount = 0
const tokenChecker = setInterval(() => {
checkGlobalToken()
checkCount++
if (this.token || checkCount >= 50) {
clearInterval(tokenChecker)
}
}, 100)
}
/**
* 发送HTTP请求
*/
async request(endpoint, options = {}) {
const url = `${this.baseURL}${endpoint}`
const config = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-Plugin-Request': 'true', // 添加插件标识
...(this.token && { 'Authorization': `Bearer ${this.token}` })
},
...options
}
if (config.body && typeof config.body === 'object') {
config.body = JSON.stringify(config.body)
}
try {
const response = await fetch(url, config)
const data = await response.json()
if (!response.ok) {
throw new Error(data.message || `HTTP ${response.status}`)
}
return data
} catch (error) {
console.error('API请求失败:', error)
throw error
}
}
// ==================== 系统信息API ====================
/**
* 获取系统状态
*/
async getSystemStatus() {
return await this.request('/system/status')
}
/**
* 获取系统信息
*/
async getSystemInfo() {
return await this.request('/system/info')
}
// ==================== 实例管理API ====================
/**
* 获取所有实例列表
*/
async getInstances() {
return await this.request('/instances')
}
/**
* 获取单个实例信息
* @param {string} instanceId 实例ID
*/
async getInstance(instanceId) {
return await this.request(`/instances/${instanceId}`)
}
/**
* 获取实例状态
* @param {string} instanceId 实例ID
*/
async getInstanceStatus(instanceId) {
return await this.request(`/instances/${instanceId}/status`)
}
// ==================== 终端管理API ====================
/**
* 获取终端会话列表
*/
async getTerminals() {
return await this.request('/terminals')
}
// ==================== 游戏管理API ====================
/**
* 获取游戏列表
*/
async getGames() {
return await this.request('/games')
}
// ==================== 通用API ====================
/**
* 获取API版本信息
*/
async getVersion() {
return await this.request('/version')
}
/**
* 健康检查
*/
async healthCheck() {
return await this.request('/health')
}
// ==================== 工具方法 ====================
/**
* 显示通知消息(如果主面板支持)
* @param {string} type 消息类型: 'info', 'success', 'warning', 'error'
* @param {string} message 消息内容
*/
showNotification(type, message) {
try {
// 尝试向父窗口发送通知消息
if (window.parent && window.parent !== window) {
window.parent.postMessage({
type: 'gsm3-notification',
data: { type, message }
}, '*')
} else {
// 如果无法发送到父窗口,使用浏览器原生通知
console.log(`[${type.toUpperCase()}] ${message}`)
}
} catch (error) {
console.warn('发送通知失败:', error)
}
}
/**
* 格式化字节大小
* @param {number} bytes 字节数
* @param {number} decimals 小数位数
*/
formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes'
const k = 1024
const dm = decimals < 0 ? 0 : decimals
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
}
/**
* 格式化时间戳
* @param {string|number|Date} timestamp 时间戳
*/
formatTime(timestamp) {
const date = new Date(timestamp)
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
})
}
/**
* 格式化运行时间
* @param {number} seconds 秒数
*/
formatUptime(seconds) {
const days = Math.floor(seconds / 86400)
const hours = Math.floor((seconds % 86400) / 3600)
const minutes = Math.floor((seconds % 3600) / 60)
const secs = Math.floor(seconds % 60)
const parts = []
if (days > 0) parts.push(`${days}`)
if (hours > 0) parts.push(`${hours}小时`)
if (minutes > 0) parts.push(`${minutes}分钟`)
if (secs > 0 || parts.length === 0) parts.push(`${secs}`)
return parts.join(' ')
}
}
// 创建全局实例
window.gsm3 = new GSM3API()
// 添加初始化状态标记
window.gsm3.isInitialized = false
window.gsm3.initPromise = null
// 初始化API的Promise
window.gsm3.initialize = function() {
if (this.initPromise) {
return this.initPromise
}
this.initPromise = new Promise((resolve) => {
const checkReady = () => {
if (this.token) {
this.isInitialized = true
console.log('GSM3 API初始化完成Token:', this.token)
resolve(true)
} else {
setTimeout(checkReady, 100)
}
}
checkReady()
})
return this.initPromise
}
// 监听来自父窗口的消息
window.addEventListener('message', (event) => {
if (event.data && event.data.type === 'gsm3-token-update') {
window.gsm3.token = event.data.token
console.log('Token已更新:', event.data.token)
}
})
// 插件加载完成后的初始化
document.addEventListener('DOMContentLoaded', () => {
console.log('GSM3 插件API已加载')
// 启动初始化过程
window.gsm3.initialize().then(() => {
console.log('GSM3 API准备就绪')
// 向父窗口发送插件加载完成的消息
if (window.parent && window.parent !== window) {
window.parent.postMessage({
type: 'gsm3-plugin-loaded',
data: { timestamp: new Date().toISOString() }
}, '*')
}
})
})

View File

@@ -4,6 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>示例插件 - GSM3</title>
<script src="gsm3-api.js"></script>
<style>
* {
margin: 0;
@@ -297,6 +298,22 @@
</div>
</div>
<div class="demo-section">
<h3>🔌 API调用演示</h3>
<p>体验插件调用主面板API的功能</p>
<div class="button-group">
<button class="btn" onclick="getSystemStatus()">获取系统状态</button>
<button class="btn btn-success" onclick="getInstances()">获取实例列表</button>
<button class="btn btn-warning" onclick="getSystemInfo()">获取系统信息</button>
<button class="btn btn-info" onclick="getApiVersion()">获取API版本</button>
</div>
<div id="apiResult" class="status-display" style="max-height: 300px; overflow-y: auto; white-space: pre-wrap; font-family: 'Courier New', monospace;">
<strong>API调用结果:</strong> 点击上方按钮查看API响应
</div>
</div>
<div class="demo-section">
<h3>📊 系统信息</h3>
<div id="systemInfo">
@@ -390,10 +407,139 @@
`
document.head.appendChild(style)
// ==================== API调用演示函数 ====================
async function getSystemStatus() {
try {
if (!window.gsm3) {
throw new Error('GSM3 API对象未找到')
}
showApiLoading('正在初始化API...')
await window.gsm3.initialize()
showApiLoading('正在获取系统状态...')
const result = await window.gsm3.getSystemStatus()
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 getInstances() {
try {
if (!window.gsm3) {
throw new Error('GSM3 API对象未找到')
}
showApiLoading('正在初始化API...')
await window.gsm3.initialize()
showApiLoading('正在获取实例列表...')
const result = await window.gsm3.getInstances()
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 getSystemInfo() {
try {
if (!window.gsm3) {
throw new Error('GSM3 API对象未找到')
}
showApiLoading('正在初始化API...')
await window.gsm3.initialize()
showApiLoading('正在获取系统信息...')
const result = await window.gsm3.getSystemInfo()
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 getApiVersion() {
try {
if (!window.gsm3) {
throw new Error('GSM3 API对象未找到')
}
showApiLoading('正在初始化API...')
await window.gsm3.initialize()
showApiLoading('正在获取API版本...')
const result = await window.gsm3.getVersion()
showApiResult('API版本', result)
if (window.gsm3.showNotification) {
window.gsm3.showNotification('info', 'API版本信息获取成功')
}
} catch (error) {
showApiError('获取API版本失败', error)
if (window.gsm3 && window.gsm3.showNotification) {
window.gsm3.showNotification('error', '获取API版本失败: ' + error.message)
}
}
}
function showApiLoading(message) {
const apiResult = document.getElementById('apiResult')
apiResult.innerHTML = `<strong>API调用结果:</strong> <span class="loading"></span> ${message}`
}
function showApiResult(title, result) {
const apiResult = document.getElementById('apiResult')
apiResult.innerHTML = `<strong>API调用结果 - ${title}:</strong>\n${JSON.stringify(result, null, 2)}`
}
function showApiError(title, error) {
const apiResult = document.getElementById('apiResult')
apiResult.innerHTML = `<strong>API调用错误 - ${title}:</strong>\n${error.message || error}`
apiResult.style.borderLeft = '4px solid #ff6b6b'
}
// 控制台欢迎信息
console.log('%c🧩 GSM3 插件系统', 'color: #667eea; font-size: 20px; font-weight: bold;')
console.log('%c欢迎使用示例插件', 'color: #764ba2; font-size: 14px;')
console.log('插件开发文档: https://github.com/your-repo/gsm3-docs')
// 等待GSM3 API加载完成后进行健康检查
window.addEventListener('load', async () => {
// 等待一段时间确保gsm3-api.js完全加载
setTimeout(async () => {
if (window.gsm3) {
try {
console.log('GSM3 API对象已加载:', window.gsm3)
const health = await window.gsm3.healthCheck()
console.log('GSM3 API连接正常:', health)
} catch (error) {
console.warn('GSM3 API连接失败:', error)
}
} else {
console.error('GSM3 API对象未找到请检查gsm3-api.js是否正确加载')
console.log('当前window对象包含的gsm3相关属性:', Object.keys(window).filter(key => key.includes('gsm3')))
}
}, 1000)
})
</script>
</body>
</html>