From 988952807002aaca25d1751a7e2970b2db5273f4 Mon Sep 17 00:00:00 2001 From: chaos-zhu Date: Tue, 13 Aug 2024 15:51:14 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20SFTP=E6=94=AF=E6=8C=81=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E5=B5=8C=E5=A5=97=E6=96=87=E4=BB=B6=E5=A4=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/app/socket/sftp.js | 39 +++++++++++++--------- web/src/views/terminal/components/sftp.vue | 29 ++++++++-------- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/server/app/socket/sftp.js b/server/app/socket/sftp.js index 78b1e0e..2a9bb57 100644 --- a/server/app/socket/sftp.js +++ b/server/app/socket/sftp.js @@ -55,10 +55,12 @@ function listenInput(sftpClient, socket) { }) // socket.on('down_dir', async (path) => { // const exists = await sftpClient.exists(path) - // if(!exists) return socket.emit('not_exists_dir', '文件夹不存在或当前不可访问') + // if(!exists) return socket.emit('not_exists_dir', '目录不存在或当前不可访问') // let res = await sftpClient.downloadDir(path, sftpCacheDir) // socket.emit('down_dir_success', res) // }) + + // 下载 socket.on('down_file', async ({ path, name, size, target = 'down' }) => { // target: down or preview const exists = await sftpClient.exists(path) @@ -94,10 +96,12 @@ function listenInput(sftpClient, socket) { socket.emit('sftp_error', error.message) } }) + + // 上传 socket.on('up_file', async ({ targetPath, fullPath, name, file }) => { // console.log({ targetPath, fullPath, name, file }) const exists = await sftpClient.exists(targetPath) - if(!exists) return socket.emit('not_exists_dir', '文件夹不存在或当前不可访问') + if(!exists) return socket.emit('not_exists_dir', '目录不存在或当前不可访问') try { const localPath = rawPath.join(sftpCacheDir, name) fs.writeFileSync(localPath, file) @@ -110,30 +114,35 @@ function listenInput(sftpClient, socket) { } }) - // 上传文件夹先在目标sftp服务器创建文件夹 - socket.on('create_remote_dir', async ({ targetDirPath, folderName }) => { - let fullPath = rawPath.posix.join(targetDirPath, folderName) - consola.info('创建远程服务器文件夹:', fullPath) - const exists = await sftpClient.exists(fullPath) - if(exists) return socket.emit('is_exists_dir', '上传文件夹失败,文件夹已存在') - let res = await sftpClient.mkdir(fullPath) - consola.success('创建远程服务器文件夹成功:', fullPath) - socket.emit('create_remote_dir_success', res) + // 上传目录先在目标sftp服务器创建目录 + socket.on('create_remote_dir', async ({ targetDirPath, foldersName }) => { + let baseFolderPath = rawPath.posix.join(targetDirPath, foldersName[0].split('/')[0]) + let baseFolderPathExists = await sftpClient.exists(baseFolderPath) + if (baseFolderPathExists) return socket.emit('create_remote_dir_exists', `远程目录已存在: ${ baseFolderPath }`) + consola.info('准备创建远程服务器目录:', foldersName) + for (const folderName of foldersName) { + const fullPath = rawPath.posix.join(targetDirPath, folderName) + const exists = await sftpClient.exists(fullPath) + if (exists) continue + await sftpClient.mkdir(fullPath, true) + consola.info('创建目录:', fullPath) + } + socket.emit('create_remote_dir_success') }) /** 分片上传 */ - // 1. 创建本地缓存文件夹 + // 1. 创建本地缓存目录 let md5List = [] socket.on('create_cache_dir', async ({ targetDirPath, name }) => { // console.log({ targetDirPath, name }) const exists = await sftpClient.exists(targetDirPath) - if(!exists) return socket.emit('not_exists_dir', '文件夹不存在或当前不可访问') + if(!exists) return socket.emit('not_exists_dir', '目录不存在或当前不可访问') md5List = [] const localPath = rawPath.join(sftpCacheDir, name) fs.emptyDirSync(localPath) // 不存在会创建,存在则清空 socket.emit('create_cache_success') }) - // 2. 上传分片 + // 2. 上传分片到面板服务 socket.on('up_file_slice', async ({ name, sliceFile, fileIndex }) => { // console.log('up_file_slice:', fileIndex, name) try { @@ -147,7 +156,7 @@ function listenInput(sftpClient, socket) { socket.emit('up_file_slice_fail', error.message) } }) - // 3. 完成上传 + // 3. 合并分片上传到服务器 socket.on('up_file_slice_over', async ({ name, targetFilePath, range, size }) => { const md5CacheDirPath = rawPath.join(sftpCacheDir, name) const resultFilePath = rawPath.join(sftpCacheDir, name, name) diff --git a/web/src/views/terminal/components/sftp.vue b/web/src/views/terminal/components/sftp.vue index 7b1b312..1838ce3 100644 --- a/web/src/views/terminal/components/sftp.vue +++ b/web/src/views/terminal/components/sftp.vue @@ -459,15 +459,22 @@ const handleUploadDir = async (event) => { if (showFileProgress.value) return $message.warning('需等待当前任务完成') let { files } = event.target if(files.length === 0) return $message.warning('不允许上传空文件夹') - let folderName = files[0].webkitRelativePath.split('/')[0] - console.log(folderName) - console.log(files) + files = Array.from(files) + // console.log(files) + // 文件夹可能嵌套, 需先创建文件夹 + let foldersName = files.map(file => file.webkitRelativePath.split('/').slice(0, -1).join('/')) + if (foldersName.length === 0) return $message.warning('不允许上传空文件夹') + // console.log(foldersName) let targetDirPath = curPath.value - socket.value.emit('create_remote_dir', { targetDirPath, folderName }) - socket.value.once('is_exists_dir', (res) => { $message.error(res) }) + socket.value.emit('create_remote_dir', { targetDirPath, foldersName }) + socket.value.once('create_remote_dir_exists', (res) => { + $message.error(res) + uploadDirRef.value = null + }) socket.value.once('create_remote_dir_success', async () => { - for (let file of files) { - let fullFilePath = getPath(`${ folderName }/${ file.name }`) + for (let [index, file,] of files.entries()) { + let fullFilePath = getPath(`${ foldersName[index] }/${ file.name }`) + console.log('fullFilePath: ', fullFilePath) try { await uploadFile(file, fullFilePath) } catch (error) { @@ -481,16 +488,13 @@ const handleUploadDir = async (event) => { const uploadFile = (file, targetFilePath) => { return new Promise((resolve, reject) => { if (!file) return reject('file is not defined') - // if ((file.size / 1024 / 1024) > 1000) { - // $message.warn('用网页传这么大文件你是认真的吗?') - // } let reader = new FileReader() reader.onload = async () => { const { name } = file const targetDirPath = curPath.value curUploadFileName.value = name const size = file.size - if(size === 0) return reject('文件大小为0KB, 无法上传') + if (size === 0) return reject('文件大小为0KB, 无法上传') socket.value.emit('create_cache_dir', { targetDirPath, name }) socket.value.once('create_cache_success', async () => { let start = 0 @@ -501,7 +505,7 @@ const uploadFile = (file, targetFilePath) => { try { upFileProgress.value = 0 showFileProgress.value = true - childDirLoading.value = true + // childDirLoading.value = true const totalSliceCount = Math.ceil(size / range) while (end < size) { fileIndex++ @@ -563,7 +567,6 @@ const uploadSliceFile = (fileInfo) => { } const openDir = (path = '', tips = true) => { - if (showFileProgress.value) return $message.warning('需等待当前任务完成') childDirLoading.value = true curTarget.value = null socket.value.emit('open_dir', path || curPath.value, tips)