feat(opencode): 改进 XCOpenCodeWeb 服务管理和健康检查

This commit is contained in:
2026-03-14 20:44:15 +08:00
parent b5343bcd9d
commit 88d42b37a6
4 changed files with 80 additions and 49 deletions

View File

@@ -1,14 +1,15 @@
import React, { useEffect, useState } from 'react'
import React, { useEffect, useState, useRef } from 'react'
export const OpenCodePage: React.FC = () => {
const [isRunning, setIsRunning] = useState(false)
const [error, setError] = useState<string | null>(null)
const [port, setPort] = useState<number>(3002)
const [isHealthy, setIsHealthy] = useState(false)
const [port, setPort] = useState<number>(9999)
const startedRef = useRef(false)
const restartingRef = useRef(false)
useEffect(() => {
let mounted = true
const init = async () => {
const start = async () => {
try {
const portResult = await window.electronAPI.xcOpenCodeWebGetPort()
if (mounted) {
@@ -16,47 +17,64 @@ export const OpenCodePage: React.FC = () => {
}
const result = await window.electronAPI.xcOpenCodeWebStart()
if (!result.success && mounted) {
console.error('Failed to start XCOpenCodeWeb:', result.error)
}
restartingRef.current = false
} catch (err) {
console.error('Failed to start XCOpenCodeWeb:', err)
restartingRef.current = false
}
}
const checkStatus = async () => {
try {
const status = await window.electronAPI.xcOpenCodeWebGetStatus()
if (mounted) {
if (result.success) {
setIsRunning(true)
setError(null)
} else {
setError(result.error || '启动失败')
setIsHealthy(status.running)
if (!status.running && !restartingRef.current) {
restartingRef.current = true
start()
}
}
} catch (err) {
if (mounted) {
setError(err instanceof Error ? err.message : '启动失败')
setIsHealthy(false)
if (!restartingRef.current) {
restartingRef.current = true
start()
}
}
}
}
init()
if (!startedRef.current) {
startedRef.current = true
start()
}
const interval = setInterval(checkStatus, 2000)
return () => {
mounted = false
clearInterval(interval)
window.electronAPI.xcOpenCodeWebStop()
setIsRunning(false)
startedRef.current = false
}
}, [])
return (
<div className="h-full w-full flex flex-col">
<div className="max-w-4xl mx-auto w-full px-14 py-4 flex items-center gap-4">
<h1 className="text-2xl font-bold text-gray-800 dark:text-gray-200">
OpenCode
</h1>
<span className={`px-2 py-1 text-xs rounded ${isRunning ? 'bg-green-100 text-green-700' : 'bg-yellow-100 text-yellow-700'}`}>
{isRunning ? '运行中' : '启动中...'}
</span>
{error && (
<span className="text-red-500 text-sm">{error}</span>
)}
</div>
{isRunning && (
<div className="h-full w-full relative">
<span className={`absolute bottom-2 right-2 z-10 w-1.5 h-1.5 rounded-full ${isHealthy ? 'bg-green-500' : 'bg-red-500'}`} />
{!isHealthy && (
<div className="absolute inset-0 flex items-center justify-center">
<div className="w-8 h-8 border-2 border-gray-300 border-t-blue-500 rounded-full animate-spin" />
</div>
)}
{isHealthy && (
<iframe
src={`http://localhost:${port}`}
className="flex-1 w-full border-0"
className="h-full w-full border-0"
title="XCOpenCodeWeb"
/>
)}