mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-09-07 16:36:57 +08:00
✨ Feature: finish the implemention of sftp manage
This commit is contained in:
+1
-1
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user