Feature: add support for dogeCloud manage

ISSUES CLOSED: #73
This commit is contained in:
萌萌哒赫萝 2023-08-21 08:53:01 -07:00
parent 10da6a92d1
commit 3040f4bfbb
8 changed files with 87 additions and 17 deletions

View File

@ -576,6 +576,8 @@ MANAGE_CONSTANT_S3_BUCKET_DESC: Bucket name - Optional
MANAGE_CONSTANT_S3_BUCKET_PLACEHOLDER: English comma-separated list, e.g. bucket1,bucket2
MANAGE_CONSTANT_S3_BASE_DIR_DESC: Base directory - Optional
MANAGE_CONSTANT_S3_BASE_DIR_PLACEHOLDER: English comma-separated list, e.g. /dir1,/dir2
MANAGE_CONSTANT_S3_DOGE_CLOUD_SUPPORT_DESC: Enable Doge Cloud API
MANAGE_CONSTANT_S3_DOGE_CLOUD_SUPPORT_TOOLTIP: Support Doge Cloud API
MANAGE_CONSTANT_S3_PAGING_DESC: Enable pagination
MANAGE_CONSTANT_S3_ITEMS_PAGE_DESC: Items per page
MANAGE_CONSTANT_S3_EXPLAIN: When configuring bucket name and base directory, they can be set using English comma separation. The order must be consistent and missing or empty items will use the default value.

View File

@ -579,6 +579,8 @@ MANAGE_CONSTANT_S3_BUCKET_DESC: 存储桶名-可选
MANAGE_CONSTANT_S3_BUCKET_PLACEHOLDER: 英文逗号分隔例如bucket1,bucket2
MANAGE_CONSTANT_S3_BASE_DIR_DESC: 起始目录-可选
MANAGE_CONSTANT_S3_BASE_DIR_PLACEHOLDER: '英文逗号分隔,例如:/dir1,/dir2'
MANAGE_CONSTANT_S3_DOGE_CLOUD_SUPPORT_DESC: 是否使用Doge Cloud
MANAGE_CONSTANT_S3_DOGE_CLOUD_SUPPORT_TOOLTIP: 开启后将使用Doge Cloud的API
MANAGE_CONSTANT_S3_PAGING_DESC: 是否开启分页
MANAGE_CONSTANT_S3_ITEMS_PAGE_DESC: 每页显示数量
MANAGE_CONSTANT_S3_EXPLAIN: 存储桶名和起始目录配置时可通过英文逗号分隔不同存储桶的设置,顺序必须一致,逗号间留空或缺失项使用默认值

View File

@ -576,6 +576,8 @@ MANAGE_CONSTANT_S3_BUCKET_DESC: 存儲桶名-可選
MANAGE_CONSTANT_S3_BUCKET_PLACEHOLDER: 英文逗號分隔例如bucket1,bucket2
MANAGE_CONSTANT_S3_BASE_DIR_DESC: 起始目錄-可選
MANAGE_CONSTANT_S3_BASE_DIR_PLACEHOLDER: '英文逗號分隔,例如:/dir1,/dir2'
MANAGE_CONSTANT_S3_DOGE_CLOUD_SUPPORT_DESC: 啟用 Doge Cloud 支援
MANAGE_CONSTANT_S3_DOGE_CLOUD_SUPPORT_TOOLTIP: 啟用後將會啟用Doge Cloud API
MANAGE_CONSTANT_S3_PAGING_DESC: 是否開啟分頁
MANAGE_CONSTANT_S3_ITEMS_PAGE_DESC: 每頁顯示數量
MANAGE_CONSTANT_S3_EXPLAIN: 存儲桶名和起始目錄配置時可通過英文逗號分隔不同存儲桶的設置,順序必須一致,逗號間留空或缺失項使用默認值

View File

@ -56,11 +56,18 @@ import path from 'path'
// 取消下载任务的加载文件列表、刷新下载文件传输列表
import { cancelDownloadLoadingFileList, refreshDownloadFileTransferList } from '@/manage/utils/static'
// dogecloudApi
import { dogecloudApi, DogecloudToken, getTempToken } from '../utils/dogeAPI'
class S3plistApi {
baseOptions: S3ClientConfig
logger: ManageLogger
agent: any
proxy: string | undefined
dogeCloudSupport: boolean
accessKeyId: string
secretAccessKey: string
bucketName: string
constructor (
accessKeyId: string,
@ -69,8 +76,14 @@ class S3plistApi {
sslEnabled: boolean,
s3ForcePathStyle: boolean,
proxy: string | undefined,
logger: ManageLogger
logger: ManageLogger,
dogeCloudSupport: boolean = false,
bucketName: string = ''
) {
this.accessKeyId = accessKeyId
this.secretAccessKey = secretAccessKey
this.dogeCloudSupport = dogeCloudSupport
this.bucketName = bucketName
this.baseOptions = {
credentials: {
accessKeyId,
@ -85,6 +98,19 @@ class S3plistApi {
this.proxy = formatHttpProxy(proxy, 'string') as string | undefined
}
async getDogeCloudToken () {
if (!this.dogeCloudSupport) return
const token = await getTempToken(this.accessKeyId, this.secretAccessKey) as DogecloudToken
if (Object.keys(token).length === 0) {
throw new Error('manage.setting.dogeCloudTokenError')
}
this.baseOptions.credentials = {
accessKeyId: token.accessKeyId,
secretAccessKey: token.secretAccessKey,
sessionToken: token.sessionToken
}
}
setAgent (proxy: string | undefined, sslEnabled: boolean) : NodeHttpHandler {
const agent = getAgent(proxy, sslEnabled)
const commonOptions: AgentOptions = {
@ -149,6 +175,26 @@ class S3plistApi {
*
*/
async getBucketList (): Promise<any> {
if (this.dogeCloudSupport) {
try {
const res = await dogecloudApi('/oss/bucket/list.json', {}, false, this.accessKeyId, this.secretAccessKey)
for (const item of res.buckets) {
if (item.name === this.bucketName || item.s3Bucket === this.bucketName) {
return [
{
Name: item.s3Bucket,
CreationDate: item.ctime,
Location: item.region
}
]
}
}
return []
} catch (error) {
this.logParam(error, 'getBucketList')
}
return []
}
const options = Object.assign({}, this.baseOptions) as S3ClientConfig
const result: IStringKeyMap[] = []
const endpoint = options.endpoint as string || ''
@ -216,7 +262,7 @@ class S3plistApi {
try {
do {
const options = Object.assign({}, this.baseOptions) as S3ClientConfig
options.region = region || 'us-east-1'
options.region = String(region) || 'us-east-1'
const client = new S3Client(options)
const command = new ListObjectsV2Command({
Bucket: bucket,
@ -255,6 +301,7 @@ class S3plistApi {
async getBucketListBackstage (configMap: IStringKeyMap): Promise<any> {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const { bucketName: bucket, bucketConfig: { Location: region }, prefix, cancelToken } = configMap
await this.getDogeCloudToken()
const slicedPrefix = prefix.slice(1)
const urlPrefix = configMap.customUrl || `https://${bucket}.s3.amazonaws.com`
let marker
@ -274,7 +321,7 @@ class S3plistApi {
try {
do {
const options = Object.assign({}, this.baseOptions) as S3ClientConfig
options.region = region || 'us-east-1'
options.region = String(region) || 'us-east-1'
const client = new S3Client(options)
const command = new ListObjectsV2Command({
Bucket: bucket,
@ -316,6 +363,7 @@ class S3plistApi {
async getBucketFileList (configMap: IStringKeyMap): Promise<any> {
const { bucketName: bucket, bucketConfig: { Location: region }, prefix, marker, itemsPerPage } = configMap
await this.getDogeCloudToken()
const slicedPrefix = prefix.slice(1)
const urlPrefix = configMap.customUrl || `https://${bucket}.s3.amazonaws.com`
const result = {
@ -325,7 +373,7 @@ class S3plistApi {
success: false
}
try {
const options = Object.assign({}, { ...this.baseOptions, region: region || 'us-east-1' }) as S3ClientConfig
const options = Object.assign({}, { ...this.baseOptions, region: String(region) || 'us-east-1' }) as S3ClientConfig
const client = new S3Client(options)
const command = new ListObjectsV2Command({
Bucket: bucket,
@ -362,9 +410,10 @@ class S3plistApi {
*/
async renameBucketFile (configMap: IStringKeyMap): Promise<boolean> {
const { bucketName, region, oldKey, newKey } = configMap
await this.getDogeCloudToken()
let result = false
try {
const options = Object.assign({}, { ...this.baseOptions, region: region || 'us-east-1' }) as S3ClientConfig
const options = Object.assign({}, { ...this.baseOptions, region: String(region) || 'us-east-1' }) as S3ClientConfig
const client = new S3Client(options)
const command = new CopyObjectCommand({
Bucket: bucketName,
@ -403,10 +452,11 @@ class S3plistApi {
*/
async deleteBucketFile (configMap: IStringKeyMap): Promise<boolean> {
const { bucketName, region, key } = configMap
await this.getDogeCloudToken()
let result = false
try {
const options = Object.assign({}, this.baseOptions) as S3ClientConfig
options.region = region || 'us-east-1'
options.region = String(region) || 'us-east-1'
const client = new S3Client(options)
const command = new DeleteObjectCommand({
Bucket: bucketName,
@ -430,6 +480,7 @@ class S3plistApi {
*/
async deleteBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
const { bucketName, region, key } = configMap
await this.getDogeCloudToken()
let marker
let result = false
let IsTruncated
@ -441,7 +492,7 @@ class S3plistApi {
try {
do {
const options = Object.assign({}, this.baseOptions) as S3ClientConfig
options.region = region || 'us-east-1'
options.region = String(region) || 'us-east-1'
const client = new S3Client(options)
const command = new ListObjectsV2Command({
Bucket: bucketName,
@ -476,7 +527,7 @@ class S3plistApi {
if (allFileList.Contents.length > 0) {
const cycle = Math.ceil(allFileList.Contents.length / 1000)
const options = Object.assign({}, this.baseOptions) as S3ClientConfig
options.region = region || 'us-east-1'
options.region = String(region) || 'us-east-1'
const client = new S3Client(options)
for (let i = 0; i < cycle; i++) {
const deleteList = allFileList.Contents.slice(i * 1000, (i + 1) * 1000)
@ -518,9 +569,10 @@ class S3plistApi {
*/
async getPreSignedUrl (configMap: IStringKeyMap): Promise<string> {
const { bucketName, region, key, expires } = configMap
await this.getDogeCloudToken()
try {
const options = Object.assign({}, this.baseOptions) as S3ClientConfig
options.region = region || 'us-east-1'
options.region = String(region) || 'us-east-1'
const client = new S3Client(options)
const signedUrl = await getSignedUrl(client, new GetObjectCommand({
Bucket: bucketName,
@ -541,10 +593,11 @@ class S3plistApi {
*/
async createBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
const { bucketName, region, key } = configMap
await this.getDogeCloudToken()
let result = false
try {
const options = Object.assign({}, this.baseOptions) as S3ClientConfig
options.region = region || 'us-east-1'
options.region = String(region) || 'us-east-1'
const client = new S3Client(options)
const command = new PutObjectCommand({
Bucket: bucketName,
@ -582,10 +635,11 @@ class S3plistApi {
const allowedAcl = ['private', 'public-read', 'public-read-write', 'aws-exec-read', 'authenticated-read', 'bucket-owner-read', 'bucket-owner-full-control']
for (const item of fileArray) {
const { bucketName, region, key, filePath, fileName, aclForUpload } = item
await this.getDogeCloudToken()
const options = Object.assign({}, this.baseOptions) as S3ClientConfig
options.region = region || 'us-east-1'
options.region = String(region) || 'us-east-1'
const client = new S3Client(options)
const id = `${bucketName}-${region}-${key}-${filePath}`
const id = `${bucketName}-${String(region)}-${key}-${filePath}`
if (instance.getUploadTask(id)) {
continue
}
@ -598,7 +652,7 @@ class S3plistApi {
sourceFilePath: filePath,
targetFilePath: key,
targetFileBucket: bucketName,
targetFileRegion: region
targetFileRegion: String(region)
})
const parallelUploads3 = new Upload({
client,
@ -661,7 +715,7 @@ class S3plistApi {
for (const item of fileArray) {
const { bucketName, region, key, fileName, customUrl } = item
const savedFilePath = path.join(downloadPath, fileName)
const id = `${bucketName}-${region}-${key}-${savedFilePath}`
const id = `${bucketName}-${String(region)}-${key}-${savedFilePath}`
if (instance.getDownloadTask(id)) {
continue
}
@ -674,7 +728,7 @@ class S3plistApi {
})
const preSignedUrl = await this.getPreSignedUrl({
bucketName,
region,
region: String(region),
key,
expires: 36000,
customUrl

View File

@ -67,7 +67,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
case 'smms':
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)
return new API.S3plistApi(this.currentPicBedConfig.accessKeyId, this.currentPicBedConfig.secretAccessKey, this.currentPicBedConfig.endpoint, this.currentPicBedConfig.sslEnabled, this.currentPicBedConfig.s3ForcePathStyle, this.currentPicBedConfig.proxy, this.logger, this.currentPicBedConfig.dogeCloudSupport || false, this.currentPicBedConfig.bucketName || '')
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':

View File

@ -790,6 +790,7 @@ async function transUpToManage (config: IUploaderConfigListItem, picBedName: str
sslEnabled: config.endpoint ? config.endpoint.startsWith('https') : false,
aclForUpload: 'public-read',
s3ForcePathStyle: config.pathStyleAccess,
dogeCloudSupport: false,
transformedConfig: JSON.stringify(
config.urlPrefix
? {

View File

@ -642,6 +642,13 @@ export const supportedPicBedList: IStringKeyMap = {
default: '/',
tooltip: baseDirTooltip
},
dogeCloudSupport: {
required: false,
description: $T('MANAGE_CONSTANT_S3_DOGE_CLOUD_SUPPORT_DESC'),
default: false,
type: 'boolean',
tooltip: $T('MANAGE_CONSTANT_S3_DOGE_CLOUD_SUPPORT_TOOLTIP')
},
paging: {
required: true,
description: $T('MANAGE_CONSTANT_S3_PAGING_DESC'),
@ -659,7 +666,7 @@ export const supportedPicBedList: IStringKeyMap = {
}
},
explain: $T('MANAGE_CONSTANT_S3_EXPLAIN'),
options: ['alias', 'accessKeyId', 'secretAccessKey', 'endpoint', 'sslEnabled', 's3ForcePathStyle', 'proxy', 'aclForUpload', 'bucketName', 'baseDir', 'paging', 'itemsPerPage'],
options: ['alias', 'accessKeyId', 'secretAccessKey', 'endpoint', 'sslEnabled', 's3ForcePathStyle', 'proxy', 'aclForUpload', 'bucketName', 'baseDir', 'dogeCloudSupport', 'paging', 'itemsPerPage'],
refLink: 'https://github.com/wayjam/picgo-plugin-s3',
referenceText: $T('MANAGE_CONSTANT_S3_REFER_TEXT')
},

View File

@ -539,6 +539,8 @@ interface ILocales {
MANAGE_CONSTANT_S3_BUCKET_PLACEHOLDER: string
MANAGE_CONSTANT_S3_BASE_DIR_DESC: string
MANAGE_CONSTANT_S3_BASE_DIR_PLACEHOLDER: string
MANAGE_CONSTANT_S3_DOGE_CLOUD_SUPPORT_DESC: string
MANAGE_CONSTANT_S3_DOGE_CLOUD_SUPPORT_TOOLTIP: string
MANAGE_CONSTANT_S3_PAGING_DESC: string
MANAGE_CONSTANT_S3_ITEMS_PAGE_DESC: string
MANAGE_CONSTANT_S3_EXPLAIN: string