feat(web): 改为通过 WebSocket 推送 ttyd 状态并清理轮询与冗余接口

This commit is contained in:
mofeng-git
2026-03-27 10:49:04 +08:00
parent e20136a5ab
commit 6bcb54bd22
15 changed files with 119 additions and 84 deletions

View File

@@ -30,7 +30,6 @@ import type {
GostcConfigUpdate,
EasytierConfig,
EasytierConfigUpdate,
TtydStatus,
} from '@/types/generated'
import { request } from './request'
@@ -236,11 +235,6 @@ export const extensionsApi = {
logs: (id: string, lines = 100) =>
request<ExtensionLogs>(`/extensions/${id}/logs?lines=${lines}`),
/**
* 获取 ttyd 状态(简化版,用于控制台)
*/
getTtydStatus: () => request<TtydStatus>('/extensions/ttyd/status'),
/**
* 更新 ttyd 配置
*/

View File

@@ -118,12 +118,18 @@ export interface AudioDeviceInfo {
error: string | null
}
export interface TtydDeviceInfo {
available: boolean
running: boolean
}
export interface DeviceInfoEvent {
video: VideoDeviceInfo
hid: HidDeviceInfo
msd: MsdDeviceInfo | null
atx: AtxDeviceInfo | null
audio: AudioDeviceInfo | null
ttyd: TtydDeviceInfo
}
export const useSystemStore = defineStore('system', () => {

View File

@@ -667,12 +667,6 @@ export interface TtydConfigUpdate {
shell?: string;
}
/** Simple ttyd status for console view */
export interface TtydStatus {
available: boolean;
running: boolean;
}
export interface VideoConfigUpdate {
device?: string;
format?: string;

View File

@@ -11,7 +11,7 @@ import { useHidWebSocket } from '@/composables/useHidWebSocket'
import { useWebRTC } from '@/composables/useWebRTC'
import { useVideoSession } from '@/composables/useVideoSession'
import { getUnifiedAudio } from '@/composables/useUnifiedAudio'
import { streamApi, hidApi, atxApi, extensionsApi, atxConfigApi, authApi } from '@/api'
import { streamApi, hidApi, atxApi, atxConfigApi, authApi } from '@/api'
import { CanonicalKey } from '@/types/generated'
import type { HidKeyboardEvent, HidMouseEvent } from '@/types/hid'
import { keyboardEventToCanonicalKey, updateModifierMaskForKey } from '@/lib/keyboardMappings'
@@ -162,7 +162,6 @@ const changingPassword = ref(false)
// ttyd (web terminal) state
const ttydStatus = ref<{ available: boolean; running: boolean } | null>(null)
const showTerminalDialog = ref(false)
let ttydPollInterval: ReturnType<typeof setInterval> | null = null
// Theme
const isDark = ref(document.documentElement.classList.contains('dark'))
@@ -965,6 +964,7 @@ function handleDeviceInfo(data: any) {
const prevAudioStreaming = systemStore.audio?.streaming ?? false
const prevAudioDevice = systemStore.audio?.device ?? null
systemStore.updateFromDeviceInfo(data)
ttydStatus.value = data.ttyd ?? null
const nextAudioStreaming = systemStore.audio?.streaming ?? false
const nextAudioDevice = systemStore.audio?.device ?? null
@@ -1484,14 +1484,6 @@ async function handleChangePassword() {
}
// ttyd (web terminal) functions
async function fetchTtydStatus() {
try {
ttydStatus.value = await extensionsApi.getTtydStatus()
} catch {
ttydStatus.value = null
}
}
function openTerminal() {
if (!ttydStatus.value?.running) return
showTerminalDialog.value = true
@@ -2112,10 +2104,6 @@ onMounted(async () => {
document.documentElement.classList.add('dark')
}
// Fetch ttyd status initially and poll every 10 seconds
fetchTtydStatus()
ttydPollInterval = setInterval(fetchTtydStatus, 10000)
// Note: Video mode is now synced from server via device_info event
// The handleDeviceInfo function will automatically switch to the server's mode
// localStorage preference is only used when server mode matches
@@ -2142,12 +2130,6 @@ onUnmounted(() => {
mouseFlushTimer = null
}
// Clear ttyd poll interval
if (ttydPollInterval) {
clearInterval(ttydPollInterval)
ttydPollInterval = null
}
// Clear all timers
if (retryTimeoutId !== null) {
clearTimeout(retryTimeoutId)