Feature: finish the implemention of sftp manage

This commit is contained in:
萌萌哒赫萝
2023-08-21 03:12:27 -07:00
parent 19f2b18a6a
commit c7e81eb44b
4 changed files with 129 additions and 24 deletions
+1 -1
View File
@@ -68,7 +68,7 @@
"mitt": "^3.0.0", "mitt": "^3.0.0",
"node-ssh-no-cpu-features": "^1.0.1", "node-ssh-no-cpu-features": "^1.0.1",
"nodejs-file-downloader": "^4.12.1", "nodejs-file-downloader": "^4.12.1",
"piclist": "^0.8.11", "piclist": "^0.8.12",
"pinia": "^2.1.4", "pinia": "^2.1.4",
"pinia-plugin-persistedstate": "^3.1.0", "pinia-plugin-persistedstate": "^3.1.0",
"qiniu": "^7.9.0", "qiniu": "^7.9.0",
+65 -17
View File
@@ -5,7 +5,7 @@ import ManageLogger from '../utils/logger'
import SSHClient from '~/main/utils/sshClient' import SSHClient from '~/main/utils/sshClient'
// 错误格式化函数、新的下载器、并发异步任务池 // 错误格式化函数、新的下载器、并发异步任务池
import { formatError, ConcurrencyPromisePool } from '../utils/common' import { formatError } from '../utils/common'
// 是否为图片的判断函数 // 是否为图片的判断函数
import { isImage } from '@/manage/utils/common' import { isImage } from '@/manage/utils/common'
@@ -20,7 +20,7 @@ import { IWindowList } from '#/types/enum'
import { ipcMain, IpcMainEvent } from 'electron' import { ipcMain, IpcMainEvent } from 'electron'
// 上传下载任务队列 // 上传下载任务队列
import UpDownTaskQueue, { commonTaskStatus } from '../datastore/upDownTaskQueue' import UpDownTaskQueue, { commonTaskStatus, downloadTaskSpecialStatus, uploadTaskSpecialStatus } from '../datastore/upDownTaskQueue'
// 路径处理库 // 路径处理库
import path from 'path' import path from 'path'
@@ -187,7 +187,7 @@ class SftpApi {
} }
try { try {
await this.connectClient() await this.connectClient()
res = await this.ctx.execCommand(`cd ${prefix} && ls -la --time-style=long-iso`) res = await this.ctx.execCommand(`cd "${prefix}" && ls -la --time-style=long-iso`)
this.ctx.close() this.ctx.close()
if (this.isRequestSuccess(res.code)) { if (this.isRequestSuccess(res.code)) {
const formatedLSRes = this.formatLSResult(res.stdout, prefix) const formatedLSRes = this.formatLSResult(res.stdout, prefix)
@@ -258,7 +258,7 @@ class SftpApi {
} }
try { try {
await this.connectClient() await this.connectClient()
res = await this.ctx.execCommand(`cd ${prefix} && ls -la --time-style=long-iso`) res = await this.ctx.execCommand(`cd "${prefix}" && ls -la --time-style=long-iso`)
this.ctx.close() this.ctx.close()
if (this.isRequestSuccess(res.code)) { if (this.isRequestSuccess(res.code)) {
const formatedLSRes = this.formatLSResult(res.stdout, prefix) const formatedLSRes = this.formatLSResult(res.stdout, prefix)
@@ -352,14 +352,39 @@ class SftpApi {
targetFilePath: key, targetFilePath: key,
targetFileBucket: bucketName, targetFileBucket: bucketName,
targetFileRegion: region, targetFileRegion: region,
noProgress: true noProgress: false
})
instance.updateUploadTask({
id,
progress: 0,
status: commonTaskStatus.failed,
finishTime: new Date().toLocaleString()
}) })
try {
await this.connectClient()
const res = await this.ctx.putFile(filePath, `/${key.replace(/^\/+/, '')}`, {
fileMode: this.fileMode,
dirMode: this.dirMode
})
this.ctx.close()
if (res) {
instance.updateUploadTask({
id,
progress: 100,
status: uploadTaskSpecialStatus.uploaded,
finishTime: new Date().toLocaleString()
})
} else {
instance.updateUploadTask({
id,
progress: 0,
status: commonTaskStatus.failed,
finishTime: new Date().toLocaleString()
})
}
} catch (error) {
this.logParam(error, 'uploadBucketFile')
instance.updateUploadTask({
id,
progress: 0,
status: commonTaskStatus.failed,
finishTime: new Date().toLocaleString()
})
}
} }
return true return true
} }
@@ -379,9 +404,8 @@ class SftpApi {
} }
async downloadBucketFile (configMap: IStringKeyMap): Promise<boolean> { async downloadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
const { downloadPath, fileArray, maxDownloadFileCount } = configMap const { downloadPath, fileArray } = configMap
const instance = UpDownTaskQueue.getInstance() const instance = UpDownTaskQueue.getInstance()
const promises = [] as any
for (const item of fileArray) { for (const item of fileArray) {
const { alias, bucketName, region, key, fileName } = item const { alias, bucketName, region, key, fileName } = item
const savedFilePath = path.join(downloadPath, fileName) const savedFilePath = path.join(downloadPath, fileName)
@@ -396,11 +420,35 @@ class SftpApi {
sourceFileName: fileName, sourceFileName: fileName,
targetFilePath: savedFilePath targetFilePath: savedFilePath
}) })
try {
await this.connectClient()
const res = await this.ctx.getFile(savedFilePath, `/${key.replace(/^\/+/, '')}`)
this.ctx.close()
if (res) {
instance.updateDownloadTask({
id,
progress: 100,
status: downloadTaskSpecialStatus.downloaded,
finishTime: new Date().toLocaleString()
})
} else {
instance.updateDownloadTask({
id,
progress: 0,
status: commonTaskStatus.failed,
finishTime: new Date().toLocaleString()
})
}
} catch (error) {
this.logParam(error, 'downloadBucketFile')
instance.updateDownloadTask({
id,
progress: 0,
status: commonTaskStatus.failed,
finishTime: new Date().toLocaleString()
})
}
} }
const pool = new ConcurrencyPromisePool(maxDownloadFileCount)
pool.all(promises).catch((error) => {
this.logParam(error, 'downloadBucketFile')
})
return true return true
} }
} }
+59 -2
View File
@@ -1,4 +1,5 @@
import { NodeSSH, Config, SSHExecCommandResponse } from 'node-ssh-no-cpu-features' import { NodeSSH, Config, SSHExecCommandResponse } from 'node-ssh-no-cpu-features'
import path from 'path'
import { ISftpPlistConfig } from 'piclist/dist/types' import { ISftpPlistConfig } from 'piclist/dist/types'
class SSHClient { class SSHClient {
@@ -67,8 +68,9 @@ class SSHClient {
try { try {
remote = this.changeWinStylePathToUnix(remote) remote = this.changeWinStylePathToUnix(remote)
local = this.changeWinStylePathToUnix(local) local = this.changeWinStylePathToUnix(local)
console.log(`remote: ${remote}, local: ${local}`) await SSHClient.client.getFile(local, remote, undefined, {
await SSHClient.client.getFile(local, remote) concurrency: 1
})
return true return true
} catch (err: any) { } catch (err: any) {
console.log(err) console.log(err)
@@ -76,6 +78,61 @@ class SSHClient {
} }
} }
async putFile (local: string, remote: string, config: {
fileMode?: string
dirMode?: string
} = {}): Promise<boolean> {
if (!this._isConnected) {
throw new Error('SSH 未连接')
}
try {
remote = this.changeWinStylePathToUnix(remote)
await this.mkdir(path.dirname(remote).replace(/^\/+|\/+$/g, ''), config)
await SSHClient.client.putFile(local, remote)
const fileMode = config.fileMode || '0644'
if (fileMode !== '0644') {
const script = `chmod ${fileMode} "${remote}"`
return await this.exec(script)
}
return true
} catch (err: any) {
console.log(err)
return false
}
}
async mkdir (dirPath: string, config: {
dirMode?: string
} = {}): Promise<boolean> {
if (!this._isConnected) {
throw new Error('SSH 未连接')
}
try {
const directoryMode = config.dirMode || '0755'
if (directoryMode === '0755') {
const script = `mkdir -p "${dirPath}"`
return await this.exec(script)
} else {
const dirs = dirPath.split('/')
let currentPath = ''
for (const dir of dirs) {
if (dir) {
currentPath += `/${dir}`
const script = `mkdir "${currentPath}" && chmod ${directoryMode} "${currentPath}"`
const result = await this.exec(script)
if (!result) {
return false
}
}
}
return true
}
} catch (err: any) {
console.log(err)
return false
}
}
get isConnected (): boolean { get isConnected (): boolean {
return SSHClient.client.isConnected() return SSHClient.client.isConnected()
} }
+4 -4
View File
@@ -10973,10 +10973,10 @@ performance-now@^2.1.0:
resolved "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" resolved "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==
piclist@^0.8.11: piclist@^0.8.12:
version "0.8.11" version "0.8.12"
resolved "https://registry.npmjs.org/piclist/-/piclist-0.8.11.tgz#0fd6d690f9eb9099cea161d0d38d24d81df3a7cc" resolved "https://registry.npmjs.org/piclist/-/piclist-0.8.12.tgz#b9ca7311f42bf62b5d3f20f36dce0f61c93658b6"
integrity sha512-rgUw4x7gk3IpfzG8kONW7oQddWhylkWNSSucavQqlZeR6/XDPXZj+BBy0enzyi8GM/em0U456HHhP3ncJJjxnQ== integrity sha512-9I93JsOauw7I7Jen6H0RWyxW7dXtiqlU0YOsePwxfMgBSKjYJ0Gne5jkwTLZR6NdR/Z9nhM+Vn7kvmY3V0ipyw==
dependencies: dependencies:
"@picgo/i18n" "^1.0.0" "@picgo/i18n" "^1.0.0"
"@picgo/store" "^2.0.4" "@picgo/store" "^2.0.4"