SFTP: Added console logging to diagnose, plus a watcher that sends the pending list when sessionId becomes available (covers the race where WS opens before sessionId is set). RDP: connectHost() was returning early for non-SSH protocols. Removed the guard and use host.protocol instead of hardcoded 'ssh'. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
102 lines
3.3 KiB
TypeScript
102 lines
3.3 KiB
TypeScript
import { ref, watch, type Ref } from 'vue'
|
|
import { useAuthStore } from '~/stores/auth.store'
|
|
|
|
export function useSftp(sessionId: Ref<string | null>) {
|
|
const auth = useAuthStore()
|
|
let ws: WebSocket | null = null
|
|
const entries = ref<any[]>([])
|
|
const currentPath = ref('/')
|
|
const fileContent = ref<{ path: string; content: string } | null>(null)
|
|
const transfers = ref<any[]>([])
|
|
|
|
let pendingList: string | null = null
|
|
|
|
function connect() {
|
|
const wsUrl = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}/api/ws/sftp?token=${auth.token}`
|
|
ws = new WebSocket(wsUrl)
|
|
|
|
ws.onopen = () => {
|
|
console.log('[SFTP] WS open, sessionId=', sessionId.value, 'pendingList=', pendingList)
|
|
if (pendingList !== null) {
|
|
// Send directly — don't rely on send() guard since we know WS is open
|
|
const path = pendingList
|
|
pendingList = null
|
|
if (sessionId.value) {
|
|
ws!.send(JSON.stringify({ type: 'list', path, sessionId: sessionId.value }))
|
|
} else {
|
|
console.warn('[SFTP] No sessionId available yet, cannot list')
|
|
pendingList = path // put it back
|
|
}
|
|
}
|
|
}
|
|
|
|
ws.onmessage = (event) => {
|
|
const msg = JSON.parse(event.data)
|
|
switch (msg.type) {
|
|
case 'list':
|
|
entries.value = msg.entries.sort((a: any, b: any) => {
|
|
if (a.isDirectory !== b.isDirectory) return a.isDirectory ? -1 : 1
|
|
return a.name.localeCompare(b.name)
|
|
})
|
|
currentPath.value = msg.path
|
|
break
|
|
case 'fileContent':
|
|
fileContent.value = { path: msg.path, content: msg.content }
|
|
break
|
|
case 'saved':
|
|
fileContent.value = null
|
|
list(currentPath.value)
|
|
break
|
|
case 'progress':
|
|
// Update transfer progress
|
|
break
|
|
case 'error':
|
|
console.error('SFTP error:', msg.message)
|
|
break
|
|
}
|
|
}
|
|
|
|
return ws
|
|
}
|
|
|
|
function send(msg: any) {
|
|
if (ws?.readyState === WebSocket.OPEN && sessionId.value) {
|
|
ws.send(JSON.stringify({ ...msg, sessionId: sessionId.value }))
|
|
}
|
|
}
|
|
|
|
function list(path: string) {
|
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
send({ type: 'list', path })
|
|
} else {
|
|
pendingList = path
|
|
}
|
|
}
|
|
function readFile(path: string) { send({ type: 'read', path }) }
|
|
function writeFile(path: string, data: string) { send({ type: 'write', path, data }) }
|
|
function mkdir(path: string) { send({ type: 'mkdir', path }) }
|
|
function rename(oldPath: string, newPath: string) { send({ type: 'rename', oldPath, newPath }) }
|
|
function remove(path: string) { send({ type: 'delete', path }) }
|
|
function chmod(path: string, mode: string) { send({ type: 'chmod', path, mode }) }
|
|
function download(path: string) { send({ type: 'download', path }) }
|
|
|
|
// If sessionId arrives after WS is already open, send any pending list
|
|
watch(sessionId, (newId) => {
|
|
if (newId && pendingList !== null && ws?.readyState === WebSocket.OPEN) {
|
|
const path = pendingList
|
|
pendingList = null
|
|
ws!.send(JSON.stringify({ type: 'list', path, sessionId: newId }))
|
|
}
|
|
})
|
|
|
|
function disconnect() {
|
|
ws?.close()
|
|
ws = null
|
|
}
|
|
|
|
return {
|
|
entries, currentPath, fileContent, transfers,
|
|
connect, disconnect, list, readFile, writeFile, mkdir, rename, remove, chmod, download,
|
|
}
|
|
}
|