更改ws为http
This commit is contained in:
@@ -157,8 +157,7 @@ const fileInputRef = ref<HTMLInputElement>()
|
||||
const monacoEditorRef = ref()
|
||||
|
||||
const handleReload = (resolve: () => void, reject: (msg?: string) => void) => {
|
||||
server
|
||||
.fetchFiles()
|
||||
withTimeout(server.fetchFiles(), 10000)
|
||||
.then((response) => {
|
||||
files.value = response
|
||||
nextTick(() => {
|
||||
@@ -168,75 +167,97 @@ const handleReload = (resolve: () => void, reject: (msg?: string) => void) => {
|
||||
resolve()
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
reject(e.message)
|
||||
const errorMessage = e.message.includes('超时') ? '文件列表请求超时,请检查网络连接' : e.message
|
||||
reject(errorMessage)
|
||||
})
|
||||
}
|
||||
|
||||
const handleSaveFile = (path: string, content: string, resolve: () => void, reject: (msg?: string) => void) => {
|
||||
server
|
||||
.createOrSaveFile(path, content)
|
||||
withTimeout(server.createOrSaveFile(path, content), 10000)
|
||||
.then((_response) => {
|
||||
resolve()
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
reject(e.message)
|
||||
const errorMessage = e.message.includes('超时') ? '保存文件请求超时,请重试' : e.message
|
||||
reject(errorMessage)
|
||||
})
|
||||
}
|
||||
|
||||
const handleDeleteFile = (path: string, resolve: () => void, reject: (msg?: string) => void) => {
|
||||
server
|
||||
.deleteFile(path)
|
||||
withTimeout(server.deleteFile(path), 10000)
|
||||
.then((_response) => {
|
||||
resolve()
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
reject(e.message)
|
||||
const errorMessage = e.message.includes('超时') ? '删除文件请求超时,请重试' : e.message
|
||||
reject(errorMessage)
|
||||
})
|
||||
}
|
||||
|
||||
const handleDeleteFolder = (path: string, resolve: () => void, reject: (msg?: string) => void) => {
|
||||
server
|
||||
.deleteFile(path)
|
||||
withTimeout(server.deleteFile(path), 10000)
|
||||
.then((_response) => {
|
||||
resolve()
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
reject(e.message)
|
||||
const errorMessage = e.message.includes('超时') ? '删除文件夹请求超时,请重试' : e.message
|
||||
reject(errorMessage)
|
||||
})
|
||||
}
|
||||
|
||||
const handleNewFile = (path: string, resolve: Function, reject: Function) => {
|
||||
server
|
||||
.newFile(path)
|
||||
withTimeout(server.newFile(path), 10000)
|
||||
.then((_response) => {
|
||||
resolve()
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
reject(e.message)
|
||||
const errorMessage = e.message.includes('超时') ? '新建文件请求超时,请重试' : e.message
|
||||
reject(errorMessage)
|
||||
})
|
||||
}
|
||||
|
||||
const handleNewFolder = (path: string, resolve: Function, reject: Function) => {
|
||||
server
|
||||
.newFolder(path)
|
||||
withTimeout(server.newFolder(path), 10000)
|
||||
.then((_response) => {
|
||||
resolve()
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
reject(e.message)
|
||||
const errorMessage = e.message.includes('超时') ? '新建文件夹请求超时,请重试' : e.message
|
||||
reject(errorMessage)
|
||||
})
|
||||
}
|
||||
|
||||
const handleRename = (path: string, newPath: string, resolve: () => void, reject: (msg?: string) => void) => {
|
||||
server
|
||||
.rename(path, newPath)
|
||||
withTimeout(server.rename(path, newPath), 10000)
|
||||
.then((_response) => {
|
||||
resolve()
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
reject(e.message)
|
||||
const errorMessage = e.message.includes('超时') ? '重命名请求超时,请重试' : e.message
|
||||
reject(errorMessage)
|
||||
})
|
||||
}
|
||||
// ================ 超时处理工具函数 =================
|
||||
const withTimeout = async <T>(promise: Promise<T>, timeoutMs: number = 10000): Promise<T> => {
|
||||
const abortController = new AbortController()
|
||||
const timeoutId = setTimeout(() => abortController.abort(), timeoutMs)
|
||||
|
||||
try {
|
||||
const response = await Promise.race([
|
||||
promise,
|
||||
new Promise<T>((_, reject) => {
|
||||
abortController.signal.addEventListener('abort', () => {
|
||||
reject(new Error('请求超时'))
|
||||
})
|
||||
}),
|
||||
])
|
||||
clearTimeout(timeoutId)
|
||||
return response
|
||||
} catch (e) {
|
||||
clearTimeout(timeoutId)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 自定义菜单 =================
|
||||
const fileMenu = ref([{ label: '下载文件', value: 'download' }])
|
||||
@@ -262,7 +283,10 @@ const downloadFile = (path: string) => {
|
||||
|
||||
try {
|
||||
const content = file.content || ''
|
||||
const fileName = path.split('\\').pop() || 'file'
|
||||
|
||||
// 提取纯文件名(不包含路径)
|
||||
let fileName = path.split(/[/\\]/).pop() || 'file' // 同时支持 / 和 \ 分隔符
|
||||
fileName = fileName.replace(/[:*?"<>|]/g, '_') // 移除Windows非法字符
|
||||
|
||||
// 创建Blob对象
|
||||
const blob = new Blob([content], { type: 'text/plain;charset=utf-8' })
|
||||
@@ -271,7 +295,7 @@ const downloadFile = (path: string) => {
|
||||
// 创建下载链接
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = fileName
|
||||
link.download = fileName // 只使用文件名
|
||||
link.style.display = 'none'
|
||||
|
||||
document.body.appendChild(link)
|
||||
@@ -442,16 +466,20 @@ const extractUrlParams = () => {
|
||||
|
||||
try {
|
||||
const url = new URL(currentUrl)
|
||||
const host = url.host // 提取host(包含端口号)
|
||||
const protocol = url.protocol // http: 或 https:
|
||||
const host = url.host // 主机地址(包含端口号)
|
||||
const id = url.searchParams.get('id') || '未找到ID'
|
||||
const ws = url.searchParams.get('ws') || '未找到WS'
|
||||
|
||||
// 生成CC: Tweaked命令
|
||||
const ccTweakedCommand = `wget run http://${host}/Client/cc/main.lua ${ws} ${id}`
|
||||
// 构建完整的HTTP地址(包含协议)
|
||||
const httpAddress = `${protocol}//${host}`
|
||||
|
||||
// 生成CC: Tweaked命令 - 使用HTTP地址而不是WebSocket
|
||||
const ccTweakedCommand = `wget run http://${host}/Client/cc/main.lua ${httpAddress} ${id}`
|
||||
|
||||
// 添加CC: Tweaked命令
|
||||
commandManager.add('CC: Tweaked连接命令', ccTweakedCommand)
|
||||
|
||||
console.log('生成的命令:', ccTweakedCommand)
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('URL解析错误:', error)
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
import type { Files } from 'monaco-tree-editor'
|
||||
|
||||
// WebSocket 连接管理
|
||||
let ws: WebSocket | null = null
|
||||
let roomId: string | null = null
|
||||
let wsServer: string | null = null
|
||||
let isConnected = false
|
||||
let clientId: string | null = null
|
||||
let reconnectAttempts = 0
|
||||
let heartbeatInterval: number | null = null
|
||||
const maxReconnectAttempts = 5
|
||||
const reconnectDelay = 2000
|
||||
const heartbeatIntervalMs = 30000 // 30秒发送一次心跳
|
||||
let isDisconnecting = false
|
||||
let serverUrl: string | null = null
|
||||
let pollIntervalMs = 1000
|
||||
let isPolling = false
|
||||
let pollingTimeout: number | null = null
|
||||
|
||||
// 请求回调映射
|
||||
const pendingRequests = new Map<
|
||||
string,
|
||||
{
|
||||
@@ -23,7 +15,6 @@ const pendingRequests = new Map<
|
||||
}
|
||||
>()
|
||||
|
||||
// 待处理初始请求队列
|
||||
const pendingInitialRequests: Array<{
|
||||
operation: string
|
||||
data?: any
|
||||
@@ -31,245 +22,97 @@ const pendingInitialRequests: Array<{
|
||||
reject: (error: Error) => void
|
||||
}> = []
|
||||
|
||||
// 生成唯一请求ID
|
||||
function generateRequestId(): string {
|
||||
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
||||
}
|
||||
|
||||
// 从URL获取房间ID和WebSocket服务器地址
|
||||
function getParamsFromUrl(): { roomId: string | null; wsServer: string | null } {
|
||||
function getParamsFromUrl(): { roomId: string | null } {
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
const roomId = urlParams.get('id')
|
||||
const wsServer = urlParams.get('ws') || urlParams.get('server')
|
||||
|
||||
return { roomId, wsServer }
|
||||
return { roomId }
|
||||
}
|
||||
|
||||
// 处理页面关闭前的清理
|
||||
function handleBeforeUnload() {
|
||||
if (!isDisconnecting && isConnected && ws && ws.readyState === WebSocket.OPEN) {
|
||||
isDisconnecting = true
|
||||
try {
|
||||
// 发送离开房间消息
|
||||
sendMessage({
|
||||
type: 'leave_room',
|
||||
room_id: roomId,
|
||||
client_id: clientId,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('发送离开消息失败:', error)
|
||||
async function httpPost(path: string, data: any): Promise<any> {
|
||||
const url = `${serverUrl}${path}`
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP错误: ${response.status} ${response.statusText}`)
|
||||
}
|
||||
|
||||
// 断开连接
|
||||
disconnect()
|
||||
return await response.json()
|
||||
} catch (error) {
|
||||
console.error('HTTP请求失败:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化WebSocket连接
|
||||
export async function initWebSocketConnection(): Promise<void> {
|
||||
const params = getParamsFromUrl()
|
||||
roomId = params.roomId
|
||||
wsServer = params.wsServer
|
||||
|
||||
if (!roomId) {
|
||||
throw new Error('未找到房间ID,请通过有效的URL访问(URL应包含?id=房间ID参数)')
|
||||
throw new Error('未找到房间ID')
|
||||
}
|
||||
|
||||
// 如果没有提供ws服务器地址,使用默认值
|
||||
const serverUrl = (wsServer || 'ws://localhost:8081').replace(/^http/, 'ws')
|
||||
serverUrl = window.location.origin
|
||||
console.log('HTTP连接已初始化,服务器:', serverUrl)
|
||||
console.log('房间ID:', roomId)
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
|
||||
// 创建WebSocket连接
|
||||
ws = new WebSocket(serverUrl)
|
||||
|
||||
// 连接事件
|
||||
ws.onopen = () => {
|
||||
isConnected = true
|
||||
reconnectAttempts = 0
|
||||
console.log('WebSocket连接已建立,服务器:', serverUrl)
|
||||
|
||||
// 启动心跳
|
||||
startHeartbeat()
|
||||
|
||||
// 发送加入房间消息
|
||||
sendMessage({
|
||||
type: 'join_room',
|
||||
room_id: roomId,
|
||||
client_type: 'frontend',
|
||||
})
|
||||
|
||||
// 添加页面关闭监听
|
||||
if (typeof window !== 'undefined') {
|
||||
window.addEventListener('beforeunload', handleBeforeUnload)
|
||||
}
|
||||
}
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data)
|
||||
handleMessage(data)
|
||||
} catch (error) {
|
||||
console.error('消息解析错误:', error)
|
||||
}
|
||||
}
|
||||
|
||||
ws.onclose = (event) => {
|
||||
isConnected = false
|
||||
console.log('WebSocket连接已断开:', event.code, event.reason)
|
||||
|
||||
// 停止心跳
|
||||
stopHeartbeat()
|
||||
|
||||
// 移除事件监听
|
||||
if (typeof window !== 'undefined') {
|
||||
window.removeEventListener('beforeunload', handleBeforeUnload)
|
||||
}
|
||||
|
||||
// 拒绝所有待处理的请求
|
||||
for (const [requestId, { reject }] of pendingRequests) {
|
||||
reject(new Error('WebSocket连接已断开'))
|
||||
pendingRequests.delete(requestId)
|
||||
}
|
||||
|
||||
// 自动重连(除非是主动断开)
|
||||
if (!isDisconnecting && reconnectAttempts < maxReconnectAttempts) {
|
||||
setTimeout(() => {
|
||||
reconnectAttempts++
|
||||
console.log(`尝试重新连接 (${reconnectAttempts}/${maxReconnectAttempts})`)
|
||||
initWebSocketConnection().catch(console.error)
|
||||
}, reconnectDelay)
|
||||
}
|
||||
}
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('WebSocket错误:', error)
|
||||
reject(new Error('WebSocket连接失败'))
|
||||
}
|
||||
|
||||
// 设置连接超时
|
||||
setTimeout(() => {
|
||||
if (!isConnected) {
|
||||
reject(new Error('WebSocket连接超时'))
|
||||
}
|
||||
}, 10000)
|
||||
})
|
||||
startPolling()
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
// 启动心跳
|
||||
function startHeartbeat() {
|
||||
stopHeartbeat() // 先停止可能存在的旧心跳
|
||||
|
||||
heartbeatInterval = setInterval(() => {
|
||||
if (isConnected && ws && ws.readyState === WebSocket.OPEN) {
|
||||
sendMessage({
|
||||
type: 'ping',
|
||||
timestamp: new Date().toISOString(),
|
||||
})
|
||||
}
|
||||
}, heartbeatIntervalMs)
|
||||
function startPolling() {
|
||||
if (isPolling) return
|
||||
isPolling = true
|
||||
pollForResponses()
|
||||
}
|
||||
|
||||
// 停止心跳
|
||||
function stopHeartbeat() {
|
||||
if (heartbeatInterval) {
|
||||
clearInterval(heartbeatInterval)
|
||||
heartbeatInterval = null
|
||||
function stopPolling() {
|
||||
isPolling = false
|
||||
if (pollingTimeout) {
|
||||
clearTimeout(pollingTimeout)
|
||||
pollingTimeout = null
|
||||
}
|
||||
}
|
||||
|
||||
async function pollForResponses() {
|
||||
if (!isPolling || !roomId) return
|
||||
|
||||
try {
|
||||
const response = await httpPost('/api/frontend/receive', {
|
||||
room_id: roomId,
|
||||
})
|
||||
|
||||
if (response.success && response.message) {
|
||||
handleMessage(response.message)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('轮询消息失败:', error)
|
||||
}
|
||||
|
||||
if (isPolling) {
|
||||
pollingTimeout = window.setTimeout(() => pollForResponses(), pollIntervalMs)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理接收到的消息
|
||||
function handleMessage(data: any): void {
|
||||
const messageType = data.type
|
||||
|
||||
switch (messageType) {
|
||||
case 'connected':
|
||||
clientId = data.client_id
|
||||
console.log('连接成功:', data.message)
|
||||
console.log('客户端ID:', clientId)
|
||||
break
|
||||
|
||||
case 'joined_room':
|
||||
console.log('加入房间成功:', data.message)
|
||||
console.log('客户端数量:', data.client_count)
|
||||
|
||||
// 连接成功后处理所有待处理的初始请求
|
||||
processPendingInitialRequests()
|
||||
break
|
||||
|
||||
case 'file_operation_response':
|
||||
handleFileOperationResponse(data)
|
||||
break
|
||||
|
||||
case 'user_joined':
|
||||
console.log('新用户加入:', data.client_id, data.client_type)
|
||||
|
||||
break
|
||||
|
||||
case 'user_left':
|
||||
console.log('用户离开:', data.client_id)
|
||||
break
|
||||
|
||||
case 'pong':
|
||||
// 心跳响应,不需要处理
|
||||
break
|
||||
|
||||
case 'error':
|
||||
console.error('错误:', data.message)
|
||||
// 处理文件操作错误
|
||||
if (data.requestId && pendingRequests.has(data.requestId)) {
|
||||
const { reject, timeout } = pendingRequests.get(data.requestId)!
|
||||
clearTimeout(timeout)
|
||||
reject(new Error(data.message || '请求失败'))
|
||||
pendingRequests.delete(data.requestId)
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
console.log('未知消息类型:', messageType, data)
|
||||
if (messageType === 'file_operation_response') {
|
||||
handleFileOperationResponse(data)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理所有待处理的初始请求
|
||||
function processPendingInitialRequests() {
|
||||
while (pendingInitialRequests.length > 0) {
|
||||
const request = pendingInitialRequests.shift()!
|
||||
const { operation, data, resolve, reject } = request
|
||||
|
||||
try {
|
||||
// 重新发送请求
|
||||
sendFileOperationInternal(operation, data).then(resolve).catch(reject)
|
||||
} catch (error) {
|
||||
reject(error instanceof Error ? error : new Error(String(error)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
function sendMessage(message: any): void {
|
||||
if (!isConnected || !ws || ws.readyState !== WebSocket.OPEN) {
|
||||
if (message.type !== 'leave_room') {
|
||||
// 离开房间消息可以在关闭时发送
|
||||
throw new Error('WebSocket未连接')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
ws.send(JSON.stringify(message))
|
||||
} catch (error) {
|
||||
if (message.type !== 'leave_room') {
|
||||
// 忽略离开消息的发送错误
|
||||
throw new Error(`发送消息失败: ${error}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理文件操作响应
|
||||
function handleFileOperationResponse(data: any): void {
|
||||
const requestId = data.requestId
|
||||
|
||||
@@ -287,12 +130,11 @@ function handleFileOperationResponse(data: any): void {
|
||||
}
|
||||
}
|
||||
|
||||
// 内部发送文件操作请求(不处理连接状态)
|
||||
function sendFileOperationInternal(operationType: string, data?: any, timeoutMs: number = 10000): Promise<any> {
|
||||
function sendFileOperationInternal(operationType: string, data?: any, timeoutMs: number = 30000): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const requestId = generateRequestId()
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
const timeout = window.setTimeout(() => {
|
||||
if (pendingRequests.has(requestId)) {
|
||||
pendingRequests.delete(requestId)
|
||||
reject(new Error('请求超时'))
|
||||
@@ -301,26 +143,33 @@ function sendFileOperationInternal(operationType: string, data?: any, timeoutMs:
|
||||
|
||||
pendingRequests.set(requestId, { resolve, reject, timeout })
|
||||
|
||||
try {
|
||||
sendMessage({
|
||||
httpPost('/api/frontend/send', {
|
||||
room_id: roomId,
|
||||
message: {
|
||||
type: 'file_operation',
|
||||
requestId: requestId,
|
||||
operation_type: operationType,
|
||||
data: data,
|
||||
room_id: roomId,
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response.success) {
|
||||
pendingRequests.delete(requestId)
|
||||
clearTimeout(timeout)
|
||||
reject(new Error(response.message || '发送请求失败'))
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
pendingRequests.delete(requestId)
|
||||
clearTimeout(timeout)
|
||||
reject(error)
|
||||
})
|
||||
} catch (error) {
|
||||
pendingRequests.delete(requestId)
|
||||
clearTimeout(timeout)
|
||||
reject(new Error(`发送请求失败: ${error}`))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 发送文件操作请求(处理连接状态)
|
||||
async function sendFileOperation(operationType: string, data?: any, timeoutMs: number = 10000): Promise<any> {
|
||||
if (!isConnected) {
|
||||
// 如果未连接,将请求加入待处理队列
|
||||
async function sendFileOperation(operationType: string, data?: any, timeoutMs: number = 30000): Promise<any> {
|
||||
if (!roomId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
pendingInitialRequests.push({
|
||||
operation: operationType,
|
||||
@@ -328,150 +177,66 @@ async function sendFileOperation(operationType: string, data?: any, timeoutMs: n
|
||||
resolve,
|
||||
reject,
|
||||
})
|
||||
|
||||
// 如果还没有连接,尝试初始化连接
|
||||
if (!ws) {
|
||||
initWebSocketConnection().catch((error) => {
|
||||
console.error('初始化连接失败:', error)
|
||||
reject(error instanceof Error ? error : new Error(String(error)))
|
||||
})
|
||||
}
|
||||
initWebSocketConnection().catch(reject)
|
||||
})
|
||||
}
|
||||
|
||||
return sendFileOperationInternal(operationType, data, timeoutMs)
|
||||
}
|
||||
|
||||
|
||||
// 文件操作函数
|
||||
export const fetchFiles = async (): Promise<Files> => {
|
||||
|
||||
|
||||
try {
|
||||
console.log('开始获取文件列表...')
|
||||
const filesData = await sendFileOperation('fetch_files')
|
||||
console.log('成功获取文件列表,文件数量:', Object.keys(filesData).length)
|
||||
console.log(filesData)
|
||||
return filesData
|
||||
} catch (error) {
|
||||
console.error('获取文件列表失败:', error)
|
||||
throw new Error(`获取文件列表失败: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
export const createOrSaveFile = async (path: string, content: string) => {
|
||||
|
||||
|
||||
try {
|
||||
await sendFileOperation('create_or_save_file', { path, content })
|
||||
} catch (error) {
|
||||
throw new Error(`保存文件失败: ${error}`)
|
||||
}
|
||||
await sendFileOperation('create_or_save_file', { path, content })
|
||||
}
|
||||
|
||||
export const newFile = async (path: string) => {
|
||||
|
||||
|
||||
try {
|
||||
await sendFileOperation('new_file', { path })
|
||||
} catch (error) {
|
||||
throw new Error(`创建新文件失败: ${error}`)
|
||||
}
|
||||
await sendFileOperation('new_file', { path })
|
||||
}
|
||||
|
||||
export const newFolder = async (path: string) => {
|
||||
|
||||
|
||||
try {
|
||||
await sendFileOperation('new_folder', { path })
|
||||
} catch (error) {
|
||||
throw new Error(`创建新文件夹失败: ${error}`)
|
||||
}
|
||||
await sendFileOperation('new_folder', { path })
|
||||
}
|
||||
|
||||
export const rename = async (path: string, newPath: string) => {
|
||||
|
||||
try {
|
||||
await sendFileOperation('rename', { path, newPath })
|
||||
return true
|
||||
} catch (error) {
|
||||
throw new Error(`重命名失败: ${error}`)
|
||||
}
|
||||
await sendFileOperation('rename', { path, newPath })
|
||||
return true
|
||||
}
|
||||
|
||||
export const deleteFile = async (path: string) => {
|
||||
|
||||
try {
|
||||
await sendFileOperation('delete_file', { path })
|
||||
return true
|
||||
} catch (error) {
|
||||
throw new Error(`删除失败: ${error}`)
|
||||
}
|
||||
await sendFileOperation('delete_file', { path })
|
||||
return true
|
||||
}
|
||||
|
||||
// 工具函数
|
||||
export const getConnectionStatus = () => ({
|
||||
isConnected,
|
||||
isConnected: isPolling,
|
||||
roomId,
|
||||
clientId,
|
||||
wsServer,
|
||||
serverUrl,
|
||||
})
|
||||
|
||||
export const disconnect = () => {
|
||||
isDisconnecting = true
|
||||
|
||||
// 发送离开房间消息
|
||||
if (ws && isConnected && ws.readyState === WebSocket.OPEN) {
|
||||
try {
|
||||
sendMessage({
|
||||
type: 'leave_room',
|
||||
room_id: roomId,
|
||||
client_id: clientId,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('发送离开消息失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
if (ws) {
|
||||
ws.close()
|
||||
ws = null
|
||||
}
|
||||
|
||||
isConnected = false
|
||||
stopPolling()
|
||||
roomId = null
|
||||
wsServer = null
|
||||
clientId = null
|
||||
isDisconnecting = false
|
||||
|
||||
// 停止心跳
|
||||
stopHeartbeat()
|
||||
|
||||
// 清空待处理请求
|
||||
serverUrl = null
|
||||
pendingInitialRequests.length = 0
|
||||
|
||||
// 移除事件监听
|
||||
if (typeof window !== 'undefined') {
|
||||
window.removeEventListener('beforeunload', handleBeforeUnload)
|
||||
}
|
||||
}
|
||||
|
||||
export const getShareableUrl = (includeWs: boolean = true): string => {
|
||||
export const getShareableUrl = (): string => {
|
||||
if (!roomId) {
|
||||
throw new Error('未加入任何房间')
|
||||
}
|
||||
|
||||
const currentUrl = new URL(window.location.href)
|
||||
currentUrl.searchParams.set('id', roomId)
|
||||
|
||||
if (includeWs && wsServer) {
|
||||
currentUrl.searchParams.set('ws', wsServer)
|
||||
}
|
||||
|
||||
return currentUrl.toString()
|
||||
}
|
||||
|
||||
// 设置WebSocket服务器地址
|
||||
export const setWsServer = (serverUrl: string) => {
|
||||
wsServer = serverUrl
|
||||
export const setPollInterval = (intervalMs: number) => {
|
||||
pollIntervalMs = intervalMs
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user