mirror of
https://github.com/Kuingsmile/PicList.git
synced 2025-01-23 06:38:13 -05:00
🚧 WIP: sftp manage
This commit is contained in:
parent
1629dcaef0
commit
e89b3ca6d1
@ -4,6 +4,7 @@ import ImgurApi from './imgur'
|
||||
import LocalApi from './local'
|
||||
import QiniuApi from './qiniu'
|
||||
import S3plistApi from './s3plist'
|
||||
import SftpApi from './sftp'
|
||||
import SmmsApi from './smms'
|
||||
import TcyunApi from './tcyun'
|
||||
import UpyunApi from './upyun'
|
||||
@ -16,6 +17,7 @@ export default {
|
||||
LocalApi,
|
||||
QiniuApi,
|
||||
S3plistApi,
|
||||
SftpApi,
|
||||
SmmsApi,
|
||||
TcyunApi,
|
||||
UpyunApi,
|
||||
|
@ -0,0 +1,409 @@
|
||||
// 日志记录器
|
||||
import ManageLogger from '../utils/logger'
|
||||
|
||||
// SSH 客户端
|
||||
import SSHClient from '~/main/utils/sshClient'
|
||||
|
||||
// 错误格式化函数、新的下载器、并发异步任务池
|
||||
import { formatError, ConcurrencyPromisePool } from '../utils/common'
|
||||
|
||||
// 是否为图片的判断函数
|
||||
import { isImage } from '@/manage/utils/common'
|
||||
|
||||
// 窗口管理器
|
||||
import windowManager from 'apis/app/window/windowManager'
|
||||
|
||||
// 枚举类型声明
|
||||
import { IWindowList } from '#/types/enum'
|
||||
|
||||
// Electron 相关
|
||||
import { ipcMain, IpcMainEvent } from 'electron'
|
||||
|
||||
// 上传下载任务队列
|
||||
import UpDownTaskQueue, { commonTaskStatus } from '../datastore/upDownTaskQueue'
|
||||
|
||||
// 路径处理库
|
||||
import path from 'path'
|
||||
|
||||
// 取消下载任务的加载文件列表、刷新下载文件传输列表
|
||||
import { cancelDownloadLoadingFileList, refreshDownloadFileTransferList } from '@/manage/utils/static'
|
||||
import { Undefinable } from '~/universal/types/manage'
|
||||
|
||||
interface listDirResult {
|
||||
permissions: string
|
||||
isDir: boolean
|
||||
owner: string
|
||||
group: string
|
||||
size: number
|
||||
mtime: string
|
||||
filename: string
|
||||
key: string
|
||||
}
|
||||
|
||||
class SftpApi {
|
||||
host: string
|
||||
port: number
|
||||
username: string
|
||||
password: string
|
||||
privateKey: string
|
||||
passphrase: string
|
||||
fileMode: string
|
||||
dirMode: string
|
||||
logger: ManageLogger
|
||||
ctx: SSHClient
|
||||
config: {
|
||||
host: string
|
||||
port: number
|
||||
username: string
|
||||
password: string
|
||||
privateKey: string
|
||||
passphrase: string
|
||||
}
|
||||
|
||||
constructor (
|
||||
host: string,
|
||||
port: Undefinable<number>,
|
||||
username: Undefinable<string>,
|
||||
password: Undefinable<string>,
|
||||
privateKey: Undefinable<string>,
|
||||
passphrase: Undefinable<string>,
|
||||
fileMode: Undefinable<string>,
|
||||
dirMode: Undefinable<string>,
|
||||
logger: ManageLogger
|
||||
) {
|
||||
this.host = host
|
||||
this.port = Number(port) || 22
|
||||
this.username = username || ''
|
||||
this.password = password || ''
|
||||
this.privateKey = privateKey || ''
|
||||
this.passphrase = passphrase || ''
|
||||
this.fileMode = fileMode || '0664'
|
||||
this.dirMode = dirMode || '0775'
|
||||
this.logger = logger
|
||||
this.ctx = SSHClient.instance
|
||||
this.config = {
|
||||
host: this.host,
|
||||
port: this.port,
|
||||
username: this.username,
|
||||
password: this.password,
|
||||
privateKey: this.privateKey,
|
||||
passphrase: this.passphrase
|
||||
}
|
||||
}
|
||||
|
||||
logParam = (error:any, method: string) =>
|
||||
this.logger.error(formatError(error, { class: 'SftpApi', method }))
|
||||
|
||||
transFormPermission = (permissionsStr: string) => {
|
||||
const permissions = permissionsStr.length === 10 ? permissionsStr.slice(1) : permissionsStr
|
||||
let result = ''
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const chunk = permissions.slice(i * 3, i * 3 + 3)
|
||||
let value = 0
|
||||
|
||||
if (chunk[0] === 'r') value += 4
|
||||
if (chunk[1] === 'w') value += 2
|
||||
if (chunk[2] === 'x') value += 1
|
||||
|
||||
result += value
|
||||
}
|
||||
|
||||
return `0${result}`
|
||||
}
|
||||
|
||||
formatFolder (item: listDirResult, urlPrefix: string, isWebPath = false) {
|
||||
const key = item.key
|
||||
let url: string
|
||||
if (isWebPath) {
|
||||
url = urlPrefix
|
||||
} else {
|
||||
if (this.username && this.password) {
|
||||
url = `sfpt://${this.username}:${this.password}@${urlPrefix}${item.filename}`
|
||||
} else {
|
||||
url = `${urlPrefix}${item.filename}`
|
||||
}
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
key,
|
||||
fileName: item.filename,
|
||||
fileSize: 0,
|
||||
Key: key,
|
||||
formatedTime: '',
|
||||
isDir: true,
|
||||
checked: false,
|
||||
isImage: false,
|
||||
match: false,
|
||||
url
|
||||
}
|
||||
}
|
||||
|
||||
formatFile (item: listDirResult, urlPrefix: string, isWebPath = false) {
|
||||
const key = item.key
|
||||
return {
|
||||
...item,
|
||||
key,
|
||||
fileName: item.filename,
|
||||
fileSize: item.size,
|
||||
Key: key,
|
||||
formatedTime: new Date(item.mtime).toLocaleString(),
|
||||
isDir: false,
|
||||
checked: false,
|
||||
match: false,
|
||||
isImage: isImage(item.filename),
|
||||
url: isWebPath ? urlPrefix : `${urlPrefix}${item.filename}`
|
||||
}
|
||||
}
|
||||
|
||||
isRequestSuccess = (code: number | null) => code === 0
|
||||
|
||||
connectClient = async () => {
|
||||
try {
|
||||
await this.ctx.connect(this.config)
|
||||
if (!this.ctx.isConnected) {
|
||||
throw new Error('SSH 未连接')
|
||||
}
|
||||
} catch (error) {
|
||||
this.logParam(error, 'connectClient')
|
||||
}
|
||||
}
|
||||
|
||||
async getBucketListRecursively (configMap: IStringKeyMap): Promise<any> {
|
||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||
const { prefix, customUrl, cancelToken } = configMap
|
||||
const urlPrefix = customUrl || `${this.host}:${this.port}`
|
||||
const cancelTask = [false]
|
||||
ipcMain.on(cancelDownloadLoadingFileList, (_evt: IpcMainEvent, token: string) => {
|
||||
if (token === cancelToken) {
|
||||
cancelTask[0] = true
|
||||
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
||||
}
|
||||
})
|
||||
let res = {} as any
|
||||
const result = {
|
||||
fullList: <any>[],
|
||||
success: false,
|
||||
finished: false
|
||||
}
|
||||
try {
|
||||
await this.connectClient()
|
||||
res = await this.ctx.execCommand(`cd ${prefix} && ls -la --time-style=long-iso`)
|
||||
this.ctx.close()
|
||||
if (this.isRequestSuccess(res.code)) {
|
||||
const formatedLSRes = this.formatLSResult(res.stdout, prefix)
|
||||
if (formatedLSRes.length) {
|
||||
formatedLSRes.forEach((item: listDirResult) => {
|
||||
if (!item.isDir) {
|
||||
result.fullList.push(this.formatFile(item, urlPrefix))
|
||||
}
|
||||
})
|
||||
}
|
||||
result.success = true
|
||||
}
|
||||
} catch (error) {
|
||||
this.logParam(error, 'getBucketListRecursively')
|
||||
}
|
||||
result.finished = true
|
||||
window.webContents.send(refreshDownloadFileTransferList, result)
|
||||
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
||||
}
|
||||
|
||||
formatLSResult (res: string, cwd: string): listDirResult[] {
|
||||
const result = [] as listDirResult[]
|
||||
const resArray = res.trim().split('\n')
|
||||
resArray.slice(resArray[0].startsWith('total') ? 1 : 0).forEach((item: string) => {
|
||||
const [permissions, , owner, group, size, date, time, ...name] = item.trim().split(/\s+/)
|
||||
const filename = name.join(' ')
|
||||
if (filename === '.' || filename === '..') {
|
||||
return
|
||||
}
|
||||
const isDir = permissions.startsWith('d')
|
||||
const mtime = `${date} ${time}`
|
||||
const key = path.join(cwd, filename).replace(/\\/g, '/').replace(/^\/+/, '')
|
||||
result.push({
|
||||
permissions,
|
||||
isDir,
|
||||
owner,
|
||||
group,
|
||||
size: Number(size) || 0,
|
||||
mtime,
|
||||
filename,
|
||||
key
|
||||
})
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
async getBucketListBackstage (configMap: IStringKeyMap): Promise<any> {
|
||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||
const { prefix, customUrl, cancelToken, baseDir } = configMap
|
||||
let urlPrefix = customUrl || `${this.host}:${this.port}`
|
||||
urlPrefix = urlPrefix.replace(/\/+$/, '')
|
||||
let webPath = configMap.webPath || ''
|
||||
if (webPath && customUrl && webPath !== '/') {
|
||||
webPath = webPath.replace(/^\/+|\/+$/, '')
|
||||
}
|
||||
const cancelTask = [false]
|
||||
ipcMain.on('cancelLoadingFileList', (_evt: IpcMainEvent, token: string) => {
|
||||
if (token === cancelToken) {
|
||||
cancelTask[0] = true
|
||||
ipcMain.removeAllListeners('cancelLoadingFileList')
|
||||
}
|
||||
})
|
||||
let res = {} as any
|
||||
const result = {
|
||||
fullList: <any>[],
|
||||
success: false,
|
||||
finished: false
|
||||
}
|
||||
try {
|
||||
await this.connectClient()
|
||||
res = await this.ctx.execCommand(`cd ${prefix} && ls -la --time-style=long-iso`)
|
||||
this.ctx.close()
|
||||
if (this.isRequestSuccess(res.code)) {
|
||||
const formatedLSRes = this.formatLSResult(res.stdout, prefix)
|
||||
console.log(formatedLSRes)
|
||||
if (formatedLSRes.length) {
|
||||
formatedLSRes.forEach((item: listDirResult) => {
|
||||
const relativePath = path.relative(baseDir, item.key)
|
||||
const relative = webPath && urlPrefix + `/${path.join(webPath, relativePath)}`.replace(/\\/g, '/').replace(/\/+/g, '/')
|
||||
if (item.isDir) {
|
||||
result.fullList.push(this.formatFolder(item, webPath ? relative : urlPrefix, !!webPath))
|
||||
} else {
|
||||
result.fullList.push(this.formatFile(item, webPath ? relative : urlPrefix, !!webPath))
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
result.finished = true
|
||||
window.webContents.send('refreshFileTransferList', result)
|
||||
ipcMain.removeAllListeners('cancelLoadingFileList')
|
||||
return
|
||||
}
|
||||
} catch (error) {
|
||||
this.logParam(error, 'getBucketListBackstage')
|
||||
result.finished = true
|
||||
window.webContents.send('refreshFileTransferList', result)
|
||||
ipcMain.removeAllListeners('cancelLoadingFileList')
|
||||
return
|
||||
}
|
||||
result.success = true
|
||||
result.finished = true
|
||||
window.webContents.send('refreshFileTransferList', result)
|
||||
ipcMain.removeAllListeners('cancelLoadingFileList')
|
||||
}
|
||||
|
||||
async renameBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
||||
const { oldKey, newKey } = configMap
|
||||
let result = false
|
||||
try {
|
||||
await this.connectClient()
|
||||
const res = await this.ctx.execCommand(`mv -f ${oldKey} ${newKey}`)
|
||||
this.ctx.close()
|
||||
result = this.isRequestSuccess(res.code)
|
||||
} catch (error) {
|
||||
this.logParam(error, 'renameBucketFile')
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
async deleteBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
||||
const { key } = configMap
|
||||
let result = false
|
||||
try {
|
||||
await this.connectClient()
|
||||
const res = await this.ctx.execCommand(`rm -f ${key}`)
|
||||
this.ctx.close()
|
||||
result = this.isRequestSuccess(res.code)
|
||||
} catch (error) {
|
||||
this.logParam(error, 'deleteBucketFile')
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
async deleteBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
||||
const { key } = configMap
|
||||
let result = false
|
||||
try {
|
||||
await this.connectClient()
|
||||
const res = await this.ctx.execCommand(`rm -rf ${key}`)
|
||||
this.ctx.close()
|
||||
result = this.isRequestSuccess(res.code)
|
||||
} catch (error) {
|
||||
this.logParam(error, 'deleteBucketFolder')
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
async uploadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
||||
const { fileArray } = configMap
|
||||
const instance = UpDownTaskQueue.getInstance()
|
||||
for (const item of fileArray) {
|
||||
const { alias, bucketName, region, key, filePath, fileName } = item
|
||||
const id = `${alias}-${bucketName}-${key}-${filePath}`
|
||||
if (instance.getUploadTask(id)) {
|
||||
continue
|
||||
}
|
||||
instance.addUploadTask({
|
||||
id,
|
||||
progress: 0,
|
||||
status: commonTaskStatus.queuing,
|
||||
sourceFileName: fileName,
|
||||
sourceFilePath: filePath,
|
||||
targetFilePath: key,
|
||||
targetFileBucket: bucketName,
|
||||
targetFileRegion: region,
|
||||
noProgress: true
|
||||
})
|
||||
instance.updateUploadTask({
|
||||
id,
|
||||
progress: 0,
|
||||
status: commonTaskStatus.failed,
|
||||
finishTime: new Date().toLocaleString()
|
||||
})
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
async createBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
||||
const { key } = configMap
|
||||
let result = false
|
||||
try {
|
||||
await this.connectClient()
|
||||
const res = await this.ctx.execCommand(`mkdir -p ${key}`)
|
||||
this.ctx.close()
|
||||
result = this.isRequestSuccess(res.code)
|
||||
} catch (error) {
|
||||
this.logParam(error, 'createBucketFolder')
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
async downloadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
||||
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
||||
const instance = UpDownTaskQueue.getInstance()
|
||||
const promises = [] as any
|
||||
for (const item of fileArray) {
|
||||
const { alias, bucketName, region, key, fileName } = item
|
||||
const savedFilePath = path.join(downloadPath, fileName)
|
||||
const id = `${alias}-${bucketName}-${region}-${key}`
|
||||
if (instance.getDownloadTask(id)) {
|
||||
continue
|
||||
}
|
||||
instance.addDownloadTask({
|
||||
id,
|
||||
progress: 0,
|
||||
status: commonTaskStatus.queuing,
|
||||
sourceFileName: fileName,
|
||||
targetFilePath: savedFilePath
|
||||
})
|
||||
}
|
||||
const pool = new ConcurrencyPromisePool(maxDownloadFileCount)
|
||||
pool.all(promises).catch((error) => {
|
||||
this.logParam(error, 'downloadBucketFile')
|
||||
})
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
export default SftpApi
|
@ -68,6 +68,8 @@ export class ManageApi extends EventEmitter implements ManageApiType {
|
||||
return new API.SmmsApi(this.currentPicBedConfig.token, this.logger)
|
||||
case 's3plist':
|
||||
return new API.S3plistApi(this.currentPicBedConfig.accessKeyId, this.currentPicBedConfig.secretAccessKey, this.currentPicBedConfig.endpoint, this.currentPicBedConfig.sslEnabled, this.currentPicBedConfig.s3ForcePathStyle, this.currentPicBedConfig.proxy, this.logger)
|
||||
case 'sftp':
|
||||
return new API.SftpApi(this.currentPicBedConfig.host, this.currentPicBedConfig.port, this.currentPicBedConfig.username, this.currentPicBedConfig.password, this.currentPicBedConfig.privateKey, this.currentPicBedConfig.passphrase, this.currentPicBedConfig.fileMode, this.currentPicBedConfig.dirMode, this.logger)
|
||||
case 'tcyun':
|
||||
return new API.TcyunApi(this.currentPicBedConfig.secretId, this.currentPicBedConfig.secretKey, this.logger)
|
||||
case 'upyun':
|
||||
@ -174,6 +176,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
|
||||
case 'smms':
|
||||
case 'webdavplist':
|
||||
case 'local':
|
||||
case 'sftp':
|
||||
return [{
|
||||
Name: name,
|
||||
Location: name,
|
||||
@ -313,6 +316,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
|
||||
case 's3plist':
|
||||
case 'webdavplist':
|
||||
case 'local':
|
||||
case 'sftp':
|
||||
try {
|
||||
client = this.createClient() as any
|
||||
return await client.getBucketListRecursively(param!)
|
||||
@ -357,6 +361,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
|
||||
case 's3plist':
|
||||
case 'webdavplist':
|
||||
case 'local':
|
||||
case 'sftp':
|
||||
try {
|
||||
client = this.createClient() as any
|
||||
return await client.getBucketListBackstage(param!)
|
||||
@ -428,6 +433,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
|
||||
case 's3plist':
|
||||
case 'webdavplist':
|
||||
case 'local':
|
||||
case 'sftp':
|
||||
try {
|
||||
client = this.createClient() as any
|
||||
const res = await client.deleteBucketFile(param!)
|
||||
@ -454,6 +460,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
|
||||
case 's3plist':
|
||||
case 'webdavplist':
|
||||
case 'local':
|
||||
case 'sftp':
|
||||
try {
|
||||
client = this.createClient() as any
|
||||
return await client.deleteBucketFolder(param!)
|
||||
@ -478,6 +485,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
|
||||
case 's3plist':
|
||||
case 'webdavplist':
|
||||
case 'local':
|
||||
case 'sftp':
|
||||
try {
|
||||
client = this.createClient() as any
|
||||
return await client.renameBucketFile(param!)
|
||||
@ -505,6 +513,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
|
||||
case 's3plist':
|
||||
case 'webdavplist':
|
||||
case 'local':
|
||||
case 'sftp':
|
||||
try {
|
||||
client = this.createClient() as any
|
||||
const res = await client.downloadBucketFile(param!)
|
||||
@ -538,6 +547,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
|
||||
case 's3plist':
|
||||
case 'webdavplist':
|
||||
case 'local':
|
||||
case 'sftp':
|
||||
try {
|
||||
client = this.createClient() as any
|
||||
return await client.createBucketFolder(param!)
|
||||
@ -565,6 +575,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
|
||||
case 's3plist':
|
||||
case 'webdavplist':
|
||||
case 'local':
|
||||
case 'sftp':
|
||||
try {
|
||||
client = this.createClient() as any
|
||||
return await client.uploadBucketFile(param!)
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { NodeSSH, Config } from 'node-ssh-no-cpu-features'
|
||||
import { NodeSSH, Config, SSHExecCommandResponse } from 'node-ssh-no-cpu-features'
|
||||
import { ISftpPlistConfig } from 'piclist/dist/types'
|
||||
|
||||
class SSHClient {
|
||||
@ -55,6 +55,31 @@ class SSHClient {
|
||||
return execResult.code === 0
|
||||
}
|
||||
|
||||
async execCommand (script: string): Promise<SSHExecCommandResponse> {
|
||||
const execResult = await SSHClient.client.execCommand(script)
|
||||
return execResult || { code: 1, stdout: '', stderr: '' }
|
||||
}
|
||||
|
||||
async getFile (local: string, remote: string): Promise<boolean> {
|
||||
if (!this._isConnected) {
|
||||
throw new Error('SSH 未连接')
|
||||
}
|
||||
try {
|
||||
remote = this.changeWinStylePathToUnix(remote)
|
||||
local = this.changeWinStylePathToUnix(local)
|
||||
console.log(`remote: ${remote}, local: ${local}`)
|
||||
await SSHClient.client.getFile(local, remote)
|
||||
return true
|
||||
} catch (err: any) {
|
||||
console.log(err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
get isConnected (): boolean {
|
||||
return SSHClient.client.isConnected()
|
||||
}
|
||||
|
||||
public close (): void {
|
||||
SSHClient.client.dispose()
|
||||
this._isConnected = false
|
||||
|
@ -497,7 +497,7 @@ https://www.baidu.com/img/bd_logo1.png"
|
||||
shadow="hover"
|
||||
>
|
||||
<el-image
|
||||
v-if="!item.isDir && currentPicBedName !== 'webdavplist'"
|
||||
v-if="!item.isDir && currentPicBedName !== 'webdavplist' && currentPicBedName !== 'sftp'"
|
||||
:src="isShowThumbnail && item.isImage ?
|
||||
item.url
|
||||
: require(`./assets/icons/${getFileIconPath(item.fileName ?? '')}`)"
|
||||
@ -519,13 +519,20 @@ https://www.baidu.com/img/bd_logo1.png"
|
||||
</template>
|
||||
</el-image>
|
||||
<ImageWebdav
|
||||
v-else-if="!item.isDir && currentPicBedName === 'webdavplist'"
|
||||
v-else-if="!item.isDir && currentPicBedName === 'webdavplist' && item.isImage"
|
||||
:is-show-thumbnail="isShowThumbnail"
|
||||
:item="item"
|
||||
:headers="getBase64ofWebdav()"
|
||||
:url="item.url"
|
||||
@click="handleClickFile(item)"
|
||||
/>
|
||||
<el-image
|
||||
v-else-if="!item.isDir"
|
||||
:src="require(`./assets/icons/${getFileIconPath(item.fileName ?? '')}`)"
|
||||
fit="contain"
|
||||
style="height: 100px;width: 100%;margin: 0 auto;"
|
||||
@click="handleClickFile(item)"
|
||||
/>
|
||||
<el-image
|
||||
v-else
|
||||
:src="require('./assets/icons/folder.webp')"
|
||||
@ -1578,7 +1585,7 @@ const lastChoosed = ref<number>(-1)
|
||||
const customDomainList = ref([] as any[])
|
||||
const currentCustomDomain = ref('')
|
||||
const isShowCustomDomainSelectList = computed(() => ['tcyun', 'aliyun', 'qiniu', 'github'].includes(currentPicBedName.value))
|
||||
const isShowCustomDomainInput = computed(() => ['aliyun', 'qiniu', 'tcyun', 's3plist', 'webdavplist', 'local'].includes(currentPicBedName.value))
|
||||
const isShowCustomDomainInput = computed(() => ['aliyun', 'qiniu', 'tcyun', 's3plist', 'webdavplist', 'local', 'sftp'].includes(currentPicBedName.value))
|
||||
const isAutoCustomDomain = computed(() => manageStore.config.picBed[configMap.alias].isAutoCustomUrl === undefined ? true : manageStore.config.picBed[configMap.alias].isAutoCustomUrl)
|
||||
// 文件预览相关
|
||||
const isShowMarkDownDialog = ref(false)
|
||||
@ -1589,7 +1596,7 @@ const isShowVideoFileDialog = ref(false)
|
||||
const videoFileUrl = ref('')
|
||||
const videoPlayerHeaders = ref({})
|
||||
// 重命名相关
|
||||
const isShowRenameFileIcon = computed(() => ['tcyun', 'aliyun', 'qiniu', 'upyun', 's3plist', 'webdavplist', 'local'].includes(currentPicBedName.value))
|
||||
const isShowRenameFileIcon = computed(() => ['tcyun', 'aliyun', 'qiniu', 'upyun', 's3plist', 'webdavplist', 'local', 'sftp'].includes(currentPicBedName.value))
|
||||
const isShowBatchRenameDialog = ref(false)
|
||||
const batchRenameMatch = ref('')
|
||||
const batchRenameReplace = ref('')
|
||||
@ -1607,9 +1614,9 @@ const isAutoRefresh = computed(() => manageStore.config.settings.isAutoRefresh ?
|
||||
const isIgnoreCase = computed(() => manageStore.config.settings.isIgnoreCase ?? false)
|
||||
|
||||
// 新建文件夹相关
|
||||
const isShowCreateNewFolder = computed(() => ['aliyun', 'github', 'local', 'qiniu', 'tcyun', 's3plist', 'upyun', 'webdavplist'].includes(currentPicBedName.value))
|
||||
const isShowCreateNewFolder = computed(() => ['aliyun', 'github', 'local', 'qiniu', 'tcyun', 's3plist', 'upyun', 'webdavplist', 'sftp'].includes(currentPicBedName.value))
|
||||
|
||||
const isShowPresignedUrl = computed(() => ['aliyun', 'github', 'qiniu', 's3plist', 'tcyun', 'webdavplist'].includes(currentPicBedName.value))
|
||||
const isShowPresignedUrl = computed(() => ['aliyun', 'github', 'qiniu', 's3plist', 'tcyun', 'webdavplist', 'sftp'].includes(currentPicBedName.value))
|
||||
|
||||
// 上传相关函数
|
||||
|
||||
@ -2000,7 +2007,7 @@ async function handleChangeCustomUrl () {
|
||||
isShowLoadingPage.value = true
|
||||
await resetParam(true)
|
||||
isShowLoadingPage.value = false
|
||||
} else if (['aliyun', 'tcyun', 'qiniu', 's3plist', 'webdavplist'].includes(currentPicBedName.value)) {
|
||||
} else if (['aliyun', 'tcyun', 'qiniu', 's3plist', 'webdavplist', 'local', 'sftp'].includes(currentPicBedName.value)) {
|
||||
const currentConfigs = await getConfig<any>('picBed')
|
||||
const currentConfig = currentConfigs[configMap.alias]
|
||||
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
||||
@ -2105,7 +2112,7 @@ async function initCustomDomainList () {
|
||||
currentCustomDomain.value = endpoint
|
||||
}
|
||||
handleChangeCustomUrl()
|
||||
} else if (currentPicBedName.value === 'local') {
|
||||
} else if (currentPicBedName.value === 'local' || currentPicBedName.value === 'sftp') {
|
||||
const currentConfigs = await getConfig<any>('picBed')
|
||||
const currentConfig = currentConfigs[configMap.alias]
|
||||
const currentTransformedConfig = JSON.parse(currentConfig.transformedConfig ?? '{}')
|
||||
@ -2799,7 +2806,8 @@ async function getBucketFileListBackStage () {
|
||||
const fileTransferStore = useFileTransferStore()
|
||||
fileTransferStore.resetFileTransferList()
|
||||
if (currentPicBedName.value === 'webdavplist' ||
|
||||
currentPicBedName.value === 'local') {
|
||||
currentPicBedName.value === 'local' ||
|
||||
currentPicBedName.value === 'sftp') {
|
||||
param.baseDir = configMap.baseDir
|
||||
param.webPath = configMap.webPath
|
||||
}
|
||||
|
@ -730,7 +730,14 @@ async function transUpToManage (config: IUploaderConfigListItem, picBedName: str
|
||||
...commonConfig,
|
||||
baseDir: config.path,
|
||||
webPath: config.webpath || '',
|
||||
customUrl: config.customUrl || ''
|
||||
customUrl: config.customUrl || '',
|
||||
transformedConfig: JSON.stringify({
|
||||
local: {
|
||||
customUrl: config.customUrl || '',
|
||||
baseDir: config.path,
|
||||
webPath: config.webpath || ''
|
||||
}
|
||||
})
|
||||
})
|
||||
delete resultMap.paging
|
||||
break
|
||||
@ -739,6 +746,19 @@ async function transUpToManage (config: IUploaderConfigListItem, picBedName: str
|
||||
Object.assign(resultMap, {
|
||||
...commonConfig,
|
||||
picBedName: 'sftp',
|
||||
host: config.host,
|
||||
port: config.port || 22,
|
||||
username: config.username,
|
||||
password: config.password,
|
||||
privateKey: config.privateKey,
|
||||
passphrase: config.passphrase,
|
||||
baseDir: config.uploadPath || '/',
|
||||
webPath: config.webPath || '',
|
||||
customUrl: config.customUrl || '',
|
||||
fileMode: config.fileMode || '0664',
|
||||
dirMode: config.dirMode || '0775',
|
||||
transformedConfig: JSON.stringify({
|
||||
sftp: {
|
||||
host: config.host,
|
||||
port: config.port || 22,
|
||||
username: config.username,
|
||||
@ -750,6 +770,8 @@ async function transUpToManage (config: IUploaderConfigListItem, picBedName: str
|
||||
customUrl: config.customUrl || '',
|
||||
fileMode: config.fileMode || '0664',
|
||||
dirMode: config.dirMode || '0775'
|
||||
}
|
||||
})
|
||||
})
|
||||
delete resultMap.paging
|
||||
break
|
||||
|
@ -27,19 +27,19 @@ export class FileCacheDb extends Dexie {
|
||||
qiniu: Table<IFileCache, string>
|
||||
smms: Table<IFileCache, string>
|
||||
s3plist: Table<IFileCache, string>
|
||||
sftpplist: Table<IFileCache, string>
|
||||
sftp: Table<IFileCache, string>
|
||||
upyun: Table<IFileCache, string>
|
||||
webdavplist: Table<IFileCache, string>
|
||||
|
||||
constructor () {
|
||||
super('bucketFileDb')
|
||||
const tableNames = ['aliyun', 'github', 'imgur', 'local', 'qiniu', 's3plist', 'sftpplist', 'smms', 'tcyun', 'upyun', 'webdavplist']
|
||||
const tableNames = ['aliyun', 'github', 'imgur', 'local', 'qiniu', 's3plist', 'sftp', 'smms', 'tcyun', 'upyun', 'webdavplist']
|
||||
|
||||
const tableNamesMap = tableNames.reduce((acc, cur) => {
|
||||
acc[cur] = '&key, value'
|
||||
return acc
|
||||
}, {} as IStringKeyMap)
|
||||
this.version(4).stores(tableNamesMap)
|
||||
this.version(5).stores(tableNamesMap)
|
||||
this.aliyun = this.table('aliyun')
|
||||
this.github = this.table('github')
|
||||
this.imgur = this.table('imgur')
|
||||
@ -47,7 +47,7 @@ export class FileCacheDb extends Dexie {
|
||||
this.qiniu = this.table('qiniu')
|
||||
this.tcyun = this.table('tcyun')
|
||||
this.s3plist = this.table('s3plist')
|
||||
this.sftpplist = this.table('sftpplist')
|
||||
this.sftp = this.table('sftp')
|
||||
this.smms = this.table('smms')
|
||||
this.upyun = this.table('upyun')
|
||||
this.webdavplist = this.table('webdavplist')
|
||||
|
Loading…
Reference in New Issue
Block a user