mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-09-05 23:47:43 +08:00
🔨 Refactor: refactored of some manage api
This commit is contained in:
@@ -47,7 +47,6 @@ class RemoteNoticeHandler {
|
|||||||
const localCountStorage: IRemoteNoticeLocalCountStorage = fs.readJSONSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH, 'utf8')
|
const localCountStorage: IRemoteNoticeLocalCountStorage = fs.readJSONSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH, 'utf8')
|
||||||
this.remoteNoticeLocalCountStorage = localCountStorage
|
this.remoteNoticeLocalCountStorage = localCountStorage
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
|
||||||
this.remoteNoticeLocalCountStorage = localCountStorage
|
this.remoteNoticeLocalCountStorage = localCountStorage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+107
-133
@@ -1,18 +1,37 @@
|
|||||||
|
// Axios
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
|
// 加密函数、获取文件 MIME 类型、错误格式化函数、新的下载器、并发异步任务池
|
||||||
import { hmacSha1Base64, getFileMimeType, formatError, NewDownloader, ConcurrencyPromisePool } from '../utils/common'
|
import { hmacSha1Base64, getFileMimeType, formatError, NewDownloader, ConcurrencyPromisePool } from '../utils/common'
|
||||||
|
|
||||||
|
// Electron 相关
|
||||||
import { ipcMain, IpcMainEvent } from 'electron'
|
import { ipcMain, IpcMainEvent } from 'electron'
|
||||||
|
|
||||||
|
// 快速 XML 解析器
|
||||||
import { XMLParser } from 'fast-xml-parser'
|
import { XMLParser } from 'fast-xml-parser'
|
||||||
|
|
||||||
|
// 阿里云 OSS 客户端库
|
||||||
import OSS from 'ali-oss'
|
import OSS from 'ali-oss'
|
||||||
|
|
||||||
|
// 路径处理库
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
|
||||||
|
// 是否为图片的判断函数
|
||||||
import { isImage } from '~/renderer/manage/utils/common'
|
import { isImage } from '~/renderer/manage/utils/common'
|
||||||
|
|
||||||
|
// 窗口管理器
|
||||||
import windowManager from 'apis/app/window/windowManager'
|
import windowManager from 'apis/app/window/windowManager'
|
||||||
|
|
||||||
|
// 枚举类型声明
|
||||||
import { IWindowList } from '#/types/enum'
|
import { IWindowList } from '#/types/enum'
|
||||||
import UpDownTaskQueue,
|
|
||||||
{
|
// 上传下载任务队列
|
||||||
uploadTaskSpecialStatus,
|
import UpDownTaskQueue, { uploadTaskSpecialStatus, commonTaskStatus } from '../datastore/upDownTaskQueue'
|
||||||
commonTaskStatus
|
|
||||||
} from '../datastore/upDownTaskQueue'
|
// 日志记录器
|
||||||
import { ManageLogger } from '../utils/logger'
|
import { ManageLogger } from '../utils/logger'
|
||||||
|
|
||||||
|
// 取消下载任务的加载文件列表、刷新下载文件传输列表
|
||||||
import { cancelDownloadLoadingFileList, refreshDownloadFileTransferList } from '@/manage/utils/static'
|
import { cancelDownloadLoadingFileList, refreshDownloadFileTransferList } from '@/manage/utils/static'
|
||||||
|
|
||||||
// 坑爹阿里云 返回数据类型标注和实际各种不一致
|
// 坑爹阿里云 返回数据类型标注和实际各种不一致
|
||||||
@@ -49,22 +68,20 @@ class AliyunApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
formatFile (item: OSS.ObjectMeta, slicedPrefix: string, urlPrefix: string): any {
|
formatFile (item: OSS.ObjectMeta, slicedPrefix: string, urlPrefix: string): any {
|
||||||
const result = {
|
const fileName = item.name.replace(slicedPrefix, '')
|
||||||
|
return {
|
||||||
...item,
|
...item,
|
||||||
key: item.name,
|
key: item.name,
|
||||||
rawUrl: `${urlPrefix}/${item.name}`,
|
fileName,
|
||||||
fileName: item.name.replace(slicedPrefix, ''),
|
|
||||||
fileSize: item.size,
|
fileSize: item.size,
|
||||||
formatedTime: new Date(item.lastModified).toLocaleString(),
|
formatedTime: new Date(item.lastModified).toLocaleString(),
|
||||||
isDir: false,
|
isDir: false,
|
||||||
checked: false,
|
checked: false,
|
||||||
match: false,
|
match: false,
|
||||||
isImage: isImage(item.name.replace(slicedPrefix, ''))
|
isImage: isImage(fileName),
|
||||||
|
rawUrl: item.url,
|
||||||
|
url: `${urlPrefix}/${item.name}`
|
||||||
}
|
}
|
||||||
const temp = result.rawUrl
|
|
||||||
result.rawUrl = result.url
|
|
||||||
result.url = temp
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getCanonicalizedOSSHeaders (headers: IStringKeyMap) {
|
getCanonicalizedOSSHeaders (headers: IStringKeyMap) {
|
||||||
@@ -100,47 +117,30 @@ class AliyunApi {
|
|||||||
* 获取存储桶列表
|
* 获取存储桶列表
|
||||||
*/
|
*/
|
||||||
async getBucketList (): Promise<any> {
|
async getBucketList (): Promise<any> {
|
||||||
const formatItem = (item: OSS.Bucket) => {
|
const getBuckets = async (marker?: string) => {
|
||||||
return {
|
const res = await this.ctx.listBuckets({
|
||||||
|
marker,
|
||||||
|
'max-keys': 1000
|
||||||
|
}) as IStringKeyMap
|
||||||
|
if (res.res.statusCode !== 200 || !res.buckets) return { result: [], isTruncated: false }
|
||||||
|
const formattedBuckets = res.buckets.map((item: OSS.Bucket) => ({
|
||||||
Name: item.name,
|
Name: item.name,
|
||||||
Location: item.region,
|
Location: item.region,
|
||||||
CreationDate: item.creationDate
|
CreationDate: item.creationDate
|
||||||
}
|
}))
|
||||||
}
|
return { result: formattedBuckets, isTruncated: res.isTruncated, nextMarker: res.nextMarker }
|
||||||
const res = await this.ctx.listBuckets({
|
|
||||||
'max-keys': 1000
|
|
||||||
}) as IStringKeyMap
|
|
||||||
const result = [] as IStringKeyMap[]
|
|
||||||
let NextMarker = ''
|
|
||||||
if (res.res.statusCode === 200) {
|
|
||||||
if (res.buckets) {
|
|
||||||
result.push(...res.buckets.map((item: OSS.Bucket) => formatItem(item)))
|
|
||||||
let isTruncated = res.isTruncated
|
|
||||||
NextMarker = res.nextMarker
|
|
||||||
while (isTruncated) {
|
|
||||||
const res = await this.ctx.listBuckets({
|
|
||||||
marker: NextMarker,
|
|
||||||
'max-keys': 1000
|
|
||||||
}) as IStringKeyMap
|
|
||||||
if (res.res.statusCode === 200) {
|
|
||||||
if (res.buckets) {
|
|
||||||
result.push(...res.buckets.map((item: OSS.Bucket) => formatItem(item)))
|
|
||||||
isTruncated = res.isTruncated
|
|
||||||
NextMarker = res.nextMarker
|
|
||||||
} else {
|
|
||||||
isTruncated = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
isTruncated = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
} else {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
const result: IStringKeyMap[] = []
|
||||||
|
let NextMarker: string | undefined
|
||||||
|
let isTruncated: boolean
|
||||||
|
do {
|
||||||
|
const { result: buckets, isTruncated: truncated, nextMarker } = await getBuckets(NextMarker)
|
||||||
|
result.push(...buckets)
|
||||||
|
NextMarker = nextMarker
|
||||||
|
isTruncated = truncated
|
||||||
|
} while (isTruncated)
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -151,6 +151,7 @@ class AliyunApi {
|
|||||||
Date: new Date().toUTCString()
|
Date: new Date().toUTCString()
|
||||||
}
|
}
|
||||||
const authorization = this.authorization('GET', `/${param.bucketName}/?cname`, headers, '', '')
|
const authorization = this.authorization('GET', `/${param.bucketName}/?cname`, headers, '', '')
|
||||||
|
|
||||||
const res = await axios({
|
const res = await axios({
|
||||||
url: `https://${param.bucketName}.${param.region}.aliyuncs.com/?cname`,
|
url: `https://${param.bucketName}.${param.region}.aliyuncs.com/?cname`,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
@@ -159,25 +160,22 @@ class AliyunApi {
|
|||||||
Authorization: authorization
|
Authorization: authorization
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
const parser = new XMLParser()
|
const parser = new XMLParser()
|
||||||
const result = parser.parse(res.data)
|
const result = parser.parse(res.data)
|
||||||
if (result.ListCnameResult && result.ListCnameResult.Cname) {
|
|
||||||
if (Array.isArray(result.ListCnameResult.Cname)) {
|
if (result.ListCnameResult?.Cname) {
|
||||||
const cnameList = [] as string[]
|
const cnames = Array.isArray(result.ListCnameResult.Cname)
|
||||||
result.ListCnameResult.Cname.forEach((item: IStringKeyMap) => {
|
? result.ListCnameResult.Cname
|
||||||
item.Status === 'Enabled' && cnameList.push(item.Domain)
|
: [result.ListCnameResult.Cname]
|
||||||
})
|
|
||||||
return cnameList
|
return cnames
|
||||||
} else {
|
.filter((item: IStringKeyMap) => item.Status === 'Enabled')
|
||||||
return result.ListCnameResult.Cname.Status === 'Enabled' ? [result.ListCnameResult.Cname.Domain] : []
|
.map((item: IStringKeyMap) => item.Domain)
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -329,16 +327,10 @@ class AliyunApi {
|
|||||||
const { bucketName: bucket, bucketConfig: { Location: region }, prefix, marker, itemsPerPage } = configMap
|
const { bucketName: bucket, bucketConfig: { Location: region }, prefix, marker, itemsPerPage } = configMap
|
||||||
const slicedPrefix = prefix.slice(1)
|
const slicedPrefix = prefix.slice(1)
|
||||||
const urlPrefix = configMap.customUrl || `https://${bucket}.${region}.aliyuncs.com`
|
const urlPrefix = configMap.customUrl || `https://${bucket}.${region}.aliyuncs.com`
|
||||||
let res = {} as any
|
|
||||||
const result = {
|
|
||||||
fullList: <any>[],
|
|
||||||
isTruncated: false,
|
|
||||||
nextMarker: '',
|
|
||||||
success: false
|
|
||||||
}
|
|
||||||
const client = this.getNewCtx(region, bucket)
|
const client = this.getNewCtx(region, bucket)
|
||||||
res = await client.listV2({
|
const res = await client.listV2({
|
||||||
prefix: slicedPrefix === '' ? undefined : slicedPrefix,
|
prefix: slicedPrefix || undefined,
|
||||||
delimiter: '/',
|
delimiter: '/',
|
||||||
'max-keys': itemsPerPage.toString(),
|
'max-keys': itemsPerPage.toString(),
|
||||||
'continuation-token': marker
|
'continuation-token': marker
|
||||||
@@ -347,18 +339,24 @@ class AliyunApi {
|
|||||||
}) as any
|
}) as any
|
||||||
// prefixes can be null
|
// prefixes can be null
|
||||||
// objects will be [] when no file
|
// objects will be [] when no file
|
||||||
if (res && res.res.statusCode === 200) {
|
if (res?.res.statusCode !== 200) {
|
||||||
res.prefixes && res.prefixes.forEach((item: string) => {
|
return {
|
||||||
result.fullList.push(this.formatFolder(item, slicedPrefix))
|
fullList: [],
|
||||||
})
|
isTruncated: false,
|
||||||
res.objects && res.objects.forEach((item: OSS.ObjectMeta) => {
|
nextMarker: '',
|
||||||
item.size !== 0 && result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix))
|
success: false
|
||||||
})
|
}
|
||||||
result.isTruncated = res.isTruncated
|
}
|
||||||
result.nextMarker = res.nextContinuationToken || ''
|
const fullList = [
|
||||||
result.success = true
|
...(res.prefixes?.map((item: string) => this.formatFolder(item, slicedPrefix)) || []),
|
||||||
|
...(res.objects?.filter((item: OSS.ObjectMeta) => item.size !== 0).map((item: OSS.ObjectMeta) => this.formatFile(item, slicedPrefix, urlPrefix)) || [])
|
||||||
|
]
|
||||||
|
return {
|
||||||
|
fullList,
|
||||||
|
isTruncated: res.isTruncated,
|
||||||
|
nextMarker: res.nextContinuationToken || '',
|
||||||
|
success: true
|
||||||
}
|
}
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -374,16 +372,15 @@ class AliyunApi {
|
|||||||
async renameBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async renameBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, region, oldKey, newKey } = configMap
|
const { bucketName, region, oldKey, newKey } = configMap
|
||||||
const client = this.getNewCtx(region, bucketName)
|
const client = this.getNewCtx(region, bucketName)
|
||||||
const res = await client.copy(
|
const copyRes = await client.copy(
|
||||||
newKey,
|
newKey,
|
||||||
oldKey
|
oldKey
|
||||||
) as any
|
) as any
|
||||||
if (res && res.res.statusCode === 200) {
|
if (copyRes?.res.statusCode === 200) {
|
||||||
const res2 = await client.delete(oldKey) as any
|
const deleteRes = await client.delete(oldKey) as any
|
||||||
return res2 && res2.res.statusCode === 204
|
return deleteRes?.res.statusCode === 204
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -399,7 +396,7 @@ class AliyunApi {
|
|||||||
const { bucketName, region, key } = configMap
|
const { bucketName, region, key } = configMap
|
||||||
const client = this.getNewCtx(region, bucketName)
|
const client = this.getNewCtx(region, bucketName)
|
||||||
const res = await client.delete(key) as any
|
const res = await client.delete(key) as any
|
||||||
return res && res.res.statusCode === 204
|
return res?.res.statusCode === 204
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -415,62 +412,39 @@ class AliyunApi {
|
|||||||
CommonPrefixes: [] as any[],
|
CommonPrefixes: [] as any[],
|
||||||
Contents: [] as any[]
|
Contents: [] as any[]
|
||||||
}
|
}
|
||||||
let res = await client.listV2({
|
do {
|
||||||
prefix: key,
|
const res = await client.listV2({
|
||||||
delimiter: '/',
|
prefix: key,
|
||||||
'max-keys': '1000'
|
delimiter: '/',
|
||||||
}, {
|
'max-keys': '1000',
|
||||||
timeout: this.timeOut
|
'continuation-token': marker
|
||||||
}) as any
|
}, {
|
||||||
if (res && res.res.statusCode === 200) {
|
timeout: this.timeOut
|
||||||
|
}) as any
|
||||||
|
if (res?.res.statusCode !== 200) return false
|
||||||
|
|
||||||
res.prefixes !== null && allFileList.CommonPrefixes.push(...res.prefixes)
|
res.prefixes !== null && allFileList.CommonPrefixes.push(...res.prefixes)
|
||||||
res.objects.length > 0 && allFileList.Contents.push(...res.objects)
|
res.objects?.length > 0 && allFileList.Contents.push(...res.objects)
|
||||||
isTruncated = res.isTruncated
|
isTruncated = res.isTruncated
|
||||||
marker = res.nextContinuationToken
|
marker = res.nextContinuationToken
|
||||||
while (isTruncated) {
|
} while (isTruncated)
|
||||||
res = await client.listV2({
|
|
||||||
prefix: key,
|
|
||||||
delimiter: '/',
|
|
||||||
'max-keys': '1000',
|
|
||||||
'continuation-token': marker
|
|
||||||
}, {
|
|
||||||
timeout: this.timeOut
|
|
||||||
}) as any
|
|
||||||
if (res && res.res.statusCode === 200) {
|
|
||||||
res.prefixes !== null && allFileList.CommonPrefixes.push(...res.prefixes)
|
|
||||||
res.objects.length > 0 && allFileList.Contents.push(...res.objects)
|
|
||||||
isTruncated = res.isTruncated
|
|
||||||
marker = res.nextContinuationToken
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (allFileList.CommonPrefixes.length > 0) {
|
if (allFileList.CommonPrefixes.length > 0) {
|
||||||
for (const item of allFileList.CommonPrefixes) {
|
for (const item of allFileList.CommonPrefixes) {
|
||||||
res = await this.deleteBucketFolder({
|
const successfully = await this.deleteBucketFolder({
|
||||||
bucketName,
|
bucketName,
|
||||||
region,
|
region,
|
||||||
key: item
|
key: item
|
||||||
})
|
})
|
||||||
if (!res) {
|
if (!successfully) return false
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (allFileList.Contents.length > 0) {
|
if (allFileList.Contents.length > 0) {
|
||||||
const cycle = Math.ceil(allFileList.Contents.length / 1000)
|
const cycle = Math.ceil(allFileList.Contents.length / 1000)
|
||||||
for (let i = 0; i < cycle; i++) {
|
for (let i = 0; i < cycle; i++) {
|
||||||
res = await client.deleteMulti(
|
const deleteRes = await client.deleteMulti(
|
||||||
allFileList.Contents.slice(i * 1000, (i + 1) * 1000).map((item: any) => {
|
allFileList.Contents.slice(i * 1000, (i + 1) * 1000).map((item: any) => item.name)) as any
|
||||||
return item.name
|
if (deleteRes?.res.statusCode !== 200) return false
|
||||||
})
|
|
||||||
) as any
|
|
||||||
if (!(res && res.res.statusCode === 200)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import UpyunApi from './upyun'
|
|||||||
import WebdavplistApi from './webdavplist'
|
import WebdavplistApi from './webdavplist'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
TcyunApi,
|
|
||||||
AliyunApi,
|
AliyunApi,
|
||||||
QiniuApi,
|
|
||||||
UpyunApi,
|
|
||||||
SmmsApi,
|
|
||||||
GithubApi,
|
GithubApi,
|
||||||
ImgurApi,
|
ImgurApi,
|
||||||
|
QiniuApi,
|
||||||
S3plistApi,
|
S3plistApi,
|
||||||
|
SmmsApi,
|
||||||
|
TcyunApi,
|
||||||
|
UpyunApi,
|
||||||
WebdavplistApi
|
WebdavplistApi
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,34 @@
|
|||||||
|
// HTTP 请求库
|
||||||
import got from 'got'
|
import got from 'got'
|
||||||
|
|
||||||
|
// 日志记录器
|
||||||
import { ManageLogger } from '../utils/logger'
|
import { ManageLogger } from '../utils/logger'
|
||||||
|
|
||||||
|
// HTTP 代理格式化函数、是否为图片的判断函数
|
||||||
import { formatHttpProxy, isImage } from '~/renderer/manage/utils/common'
|
import { formatHttpProxy, isImage } from '~/renderer/manage/utils/common'
|
||||||
|
|
||||||
|
// 窗口管理器
|
||||||
import windowManager from 'apis/app/window/windowManager'
|
import windowManager from 'apis/app/window/windowManager'
|
||||||
|
|
||||||
|
// 枚举类型声明
|
||||||
import { IWindowList } from '#/types/enum'
|
import { IWindowList } from '#/types/enum'
|
||||||
|
|
||||||
|
// Electron 相关
|
||||||
import { ipcMain, IpcMainEvent } from 'electron'
|
import { ipcMain, IpcMainEvent } from 'electron'
|
||||||
|
|
||||||
|
// got 上传函数、路径处理函数、新的下载器、获取请求代理、获取请求选项、并发异步任务池、错误格式化函数
|
||||||
import { gotUpload, trimPath, NewDownloader, getAgent, getOptions, ConcurrencyPromisePool, formatError } from '../utils/common'
|
import { gotUpload, trimPath, NewDownloader, getAgent, getOptions, ConcurrencyPromisePool, formatError } from '../utils/common'
|
||||||
import UpDownTaskQueue,
|
|
||||||
{
|
// 上传下载任务队列
|
||||||
commonTaskStatus
|
import UpDownTaskQueue, { commonTaskStatus } from '../datastore/upDownTaskQueue'
|
||||||
} from '../datastore/upDownTaskQueue'
|
|
||||||
|
// 文件系统库
|
||||||
import fs from 'fs-extra'
|
import fs from 'fs-extra'
|
||||||
|
|
||||||
|
// 路径处理库
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
|
||||||
|
// 取消下载任务的加载文件列表、刷新下载文件传输列表
|
||||||
import { cancelDownloadLoadingFileList, refreshDownloadFileTransferList } from '@/manage/utils/static'
|
import { cancelDownloadLoadingFileList, refreshDownloadFileTransferList } from '@/manage/utils/static'
|
||||||
|
|
||||||
class GithubApi {
|
class GithubApi {
|
||||||
@@ -252,34 +270,32 @@ class GithubApi {
|
|||||||
*/
|
*/
|
||||||
async deleteBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName: repo, githubBranch: branch, key } = configMap
|
const { bucketName: repo, githubBranch: branch, key } = configMap
|
||||||
|
// get sha of the branch
|
||||||
const refRes = await got(
|
const refRes = await got(
|
||||||
`${this.baseUrl}/repos/${this.username}/${repo}/git/refs/heads/${branch}`,
|
`${this.baseUrl}/repos/${this.username}/${repo}/git/refs/heads/${branch}`,
|
||||||
getOptions('GET', this.commonHeaders, undefined, 'json', undefined, undefined, this.proxy)
|
getOptions('GET', this.commonHeaders, undefined, 'json', undefined, undefined, this.proxy)
|
||||||
) as any
|
) as any
|
||||||
if (refRes.statusCode !== 200) {
|
if (refRes.statusCode !== 200) return false
|
||||||
return false
|
|
||||||
}
|
|
||||||
const refSha = refRes.body.object.sha
|
const refSha = refRes.body.object.sha
|
||||||
|
// get sha of the root tree
|
||||||
const rootRes = await got(
|
const rootRes = await got(
|
||||||
`${this.baseUrl}/repos/${this.username}/${repo}/branches/${branch}`,
|
`${this.baseUrl}/repos/${this.username}/${repo}/branches/${branch}`,
|
||||||
getOptions('GET', undefined, undefined, 'json', undefined, undefined, this.proxy)
|
getOptions('GET', undefined, undefined, 'json', undefined, undefined, this.proxy)
|
||||||
) as any
|
) as any
|
||||||
if (rootRes.statusCode !== 200) {
|
if (rootRes.statusCode !== 200) return false
|
||||||
return false
|
|
||||||
}
|
|
||||||
const rootSha = rootRes.body.commit.commit.tree.sha
|
const rootSha = rootRes.body.commit.commit.tree.sha
|
||||||
// TODO: if there are more than 10000 files in the folder, it will be truncated
|
// TODO: if there are more than 10000 files in the folder, it will be truncated
|
||||||
// Rare cases, not considered for now
|
// Rare cases, not considered for now
|
||||||
|
// get sha of the folder tree
|
||||||
const treeRes = await got(
|
const treeRes = await got(
|
||||||
`${this.baseUrl}/repos/${this.username}/${repo}/git/trees/${branch}:${key.replace(/(^\/+|\/+$)/g, '')}`,
|
`${this.baseUrl}/repos/${this.username}/${repo}/git/trees/${branch}:${key.replace(/(^\/+|\/+$)/g, '')}`,
|
||||||
getOptions('GET', this.commonHeaders, {
|
getOptions('GET', this.commonHeaders, {
|
||||||
recursive: true
|
recursive: true
|
||||||
}, 'json', undefined, undefined, this.proxy)
|
}, 'json', undefined, undefined, this.proxy)
|
||||||
) as any
|
) as any
|
||||||
if (treeRes.statusCode !== 200) {
|
if (treeRes.statusCode !== 200) return false
|
||||||
return false
|
|
||||||
}
|
|
||||||
const oldTree = treeRes.body.tree
|
const oldTree = treeRes.body.tree
|
||||||
|
// create a new tree
|
||||||
const newTree = oldTree.filter((item: any) => item.type === 'blob')
|
const newTree = oldTree.filter((item: any) => item.type === 'blob')
|
||||||
.map((item:any) => ({
|
.map((item:any) => ({
|
||||||
path: `${key.replace(/(^\/+|\/+$)/g, '')}/${item.path}`,
|
path: `${key.replace(/(^\/+|\/+$)/g, '')}/${item.path}`,
|
||||||
@@ -294,10 +310,9 @@ class GithubApi {
|
|||||||
tree: newTree
|
tree: newTree
|
||||||
}), undefined, this.proxy)
|
}), undefined, this.proxy)
|
||||||
) as any
|
) as any
|
||||||
if (newTreeShaRes.statusCode !== 201) {
|
if (newTreeShaRes.statusCode !== 201) return false
|
||||||
return false
|
|
||||||
}
|
|
||||||
const newTreeSha = newTreeShaRes.body.sha
|
const newTreeSha = newTreeShaRes.body.sha
|
||||||
|
// create a new commit
|
||||||
const commitRes = await got(
|
const commitRes = await got(
|
||||||
`${this.baseUrl}/repos/${this.username}/${repo}/git/commits`,
|
`${this.baseUrl}/repos/${this.username}/${repo}/git/commits`,
|
||||||
getOptions('POST', this.commonHeaders, undefined, 'json', JSON.stringify({
|
getOptions('POST', this.commonHeaders, undefined, 'json', JSON.stringify({
|
||||||
@@ -306,10 +321,9 @@ class GithubApi {
|
|||||||
parents: [refSha]
|
parents: [refSha]
|
||||||
}), undefined, this.proxy)
|
}), undefined, this.proxy)
|
||||||
) as any
|
) as any
|
||||||
if (commitRes.statusCode !== 201) {
|
if (commitRes.statusCode !== 201) return false
|
||||||
return false
|
|
||||||
}
|
|
||||||
const commitSha = commitRes.body.sha
|
const commitSha = commitRes.body.sha
|
||||||
|
// update the branch
|
||||||
const updateRefRes = await got(
|
const updateRefRes = await got(
|
||||||
`${this.baseUrl}/repos/${this.username}/${repo}/git/refs/heads/${branch}`,
|
`${this.baseUrl}/repos/${this.username}/${repo}/git/refs/heads/${branch}`,
|
||||||
getOptions('PATCH', this.commonHeaders, undefined, 'json', JSON.stringify({
|
getOptions('PATCH', this.commonHeaders, undefined, 'json', JSON.stringify({
|
||||||
|
|||||||
@@ -81,16 +81,12 @@ class ImgurApi {
|
|||||||
result.push(...res.body.data)
|
result.push(...res.body.data)
|
||||||
initPage++
|
initPage++
|
||||||
} while (res.body.data.length > 0)
|
} while (res.body.data.length > 0)
|
||||||
const finalResult = [] as any[]
|
const finalResult = result.map((item: any) => ({
|
||||||
for (let i = 0; i < result.length; i++) {
|
...item,
|
||||||
const item = result[i]
|
Name: item.title,
|
||||||
finalResult.push({
|
Location: item.id,
|
||||||
...item,
|
CreationDate: item.datetime
|
||||||
Name: item.title,
|
})) as any[]
|
||||||
Location: item.id,
|
|
||||||
CreationDate: item.datetime
|
|
||||||
})
|
|
||||||
}
|
|
||||||
finalResult.push({
|
finalResult.push({
|
||||||
Name: '全部',
|
Name: '全部',
|
||||||
Location: 'unclassified',
|
Location: 'unclassified',
|
||||||
|
|||||||
@@ -1,17 +1,34 @@
|
|||||||
|
// Axios
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
|
// 加密函数、获取文件 MIME 类型、新的下载器、错误格式化函数、并发异步任务池
|
||||||
import { hmacSha1Base64, getFileMimeType, NewDownloader, formatError, ConcurrencyPromisePool } from '../utils/common'
|
import { hmacSha1Base64, getFileMimeType, NewDownloader, formatError, ConcurrencyPromisePool } from '../utils/common'
|
||||||
|
|
||||||
|
// 七牛云客户端库
|
||||||
import qiniu from 'qiniu/index'
|
import qiniu from 'qiniu/index'
|
||||||
|
|
||||||
|
// 路径处理库
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
|
||||||
|
// 是否为图片的判断函数
|
||||||
import { isImage } from '~/renderer/manage/utils/common'
|
import { isImage } from '~/renderer/manage/utils/common'
|
||||||
|
|
||||||
|
// 窗口管理器
|
||||||
import windowManager from 'apis/app/window/windowManager'
|
import windowManager from 'apis/app/window/windowManager'
|
||||||
|
|
||||||
|
// 枚举类型声明
|
||||||
import { IWindowList } from '#/types/enum'
|
import { IWindowList } from '#/types/enum'
|
||||||
|
|
||||||
|
// Electron 相关
|
||||||
import { ipcMain, IpcMainEvent } from 'electron'
|
import { ipcMain, IpcMainEvent } from 'electron'
|
||||||
import UpDownTaskQueue,
|
|
||||||
{
|
// 上传下载任务队列
|
||||||
uploadTaskSpecialStatus,
|
import UpDownTaskQueue, { uploadTaskSpecialStatus, commonTaskStatus } from '../datastore/upDownTaskQueue'
|
||||||
commonTaskStatus
|
|
||||||
} from '../datastore/upDownTaskQueue'
|
// 日志记录器
|
||||||
import { ManageLogger } from '../utils/logger'
|
import { ManageLogger } from '../utils/logger'
|
||||||
|
|
||||||
|
// 取消下载任务的加载文件列表、刷新下载文件传输列表
|
||||||
import { cancelDownloadLoadingFileList, refreshDownloadFileTransferList } from '@/manage/utils/static'
|
import { cancelDownloadLoadingFileList, refreshDownloadFileTransferList } from '@/manage/utils/static'
|
||||||
|
|
||||||
class QiniuApi {
|
class QiniuApi {
|
||||||
@@ -49,16 +66,17 @@ class QiniuApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
formatFile (item: any, slicedPrefix: string, urlPrefix: string) {
|
formatFile (item: any, slicedPrefix: string, urlPrefix: string) {
|
||||||
|
const fileName = item.key.replace(slicedPrefix, '')
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
fileName: item.key.replace(slicedPrefix, ''),
|
fileName,
|
||||||
url: `${urlPrefix}/${item.key}`,
|
url: `${urlPrefix}/${item.key}`,
|
||||||
fileSize: item.fsize,
|
fileSize: item.fsize,
|
||||||
formatedTime: new Date(parseInt(item.putTime.toString().slice(0, -4), 10)).toLocaleString(),
|
formatedTime: new Date(parseInt(item.putTime.toString().slice(0, -4), 10)).toLocaleString(),
|
||||||
isDir: false,
|
isDir: false,
|
||||||
checked: false,
|
checked: false,
|
||||||
match: false,
|
match: false,
|
||||||
isImage: isImage(item.key.replace(slicedPrefix, ''))
|
isImage: isImage(fileName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,22 +89,20 @@ class QiniuApi {
|
|||||||
contentType: string,
|
contentType: string,
|
||||||
xQiniuHeaders?: IStringKeyMap
|
xQiniuHeaders?: IStringKeyMap
|
||||||
) {
|
) {
|
||||||
let signStr = `${method.toUpperCase()} ${urlPath}`
|
let signStr = `${method.toUpperCase()} ${urlPath}${query ? `?${query}` : ''}\nHost: ${host}`
|
||||||
query && (signStr += `?${query}`)
|
|
||||||
signStr += `\nHost: ${host}`
|
|
||||||
contentType && (signStr += `\nContent-Type: ${contentType}`)
|
contentType && (signStr += `\nContent-Type: ${contentType}`)
|
||||||
let xQiniuHeaderStr = ''
|
|
||||||
if (xQiniuHeaders) {
|
if (xQiniuHeaders) {
|
||||||
const xQiniuHeaderKeys = Object.keys(xQiniuHeaders).sort()
|
const xQiniuHeaderStr = Object.keys(xQiniuHeaders)
|
||||||
xQiniuHeaderKeys.forEach((key) => {
|
.sort()
|
||||||
xQiniuHeaderStr += `\n${key}:${xQiniuHeaders[key]}`
|
.map((key) => `\n${key}:${xQiniuHeaders[key]}`)
|
||||||
})
|
.join('')
|
||||||
signStr += xQiniuHeaderStr
|
signStr += xQiniuHeaderStr
|
||||||
}
|
}
|
||||||
|
|
||||||
signStr += '\n\n'
|
signStr += '\n\n'
|
||||||
if (contentType !== 'application/octet-stream' && body) {
|
|
||||||
signStr += body
|
if (contentType !== 'application/octet-stream' && body) signStr += body
|
||||||
}
|
|
||||||
return `Qiniu ${this.accessKey}:${hmacSha1Base64(this.secretKey, signStr).replace(/\+/g, '-').replace(/\//g, '_')}`
|
return `Qiniu ${this.accessKey}:${hmacSha1Base64(this.secretKey, signStr).replace(/\+/g, '-').replace(/\//g, '_')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,28 +119,21 @@ class QiniuApi {
|
|||||||
},
|
},
|
||||||
timeout: this.timeout
|
timeout: this.timeout
|
||||||
})
|
})
|
||||||
if (res && res.status === 200) {
|
if (res?.status === 200 && res?.data?.length) {
|
||||||
if (res.data && res.data.length) {
|
const result = [] as any[]
|
||||||
const result = [] as any[]
|
for (let i = 0; i < res.data.length; i++) {
|
||||||
for (let i = 0; i < res.data.length; i++) {
|
const info = await this.getBucketInfo({ bucketName: res.data[i] })
|
||||||
const info = await this.getBucketInfo({ bucketName: res.data[i] })
|
if (!info.success) return []
|
||||||
if (!info.success) {
|
result.push({
|
||||||
return []
|
Name: res.data[i],
|
||||||
}
|
Location: info.zone,
|
||||||
result.push({
|
CreationDate: new Date().toISOString(),
|
||||||
Name: res.data[i],
|
Private: info.private
|
||||||
Location: info.zone,
|
})
|
||||||
CreationDate: new Date().toISOString(),
|
|
||||||
Private: info.private
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
} else {
|
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
} else {
|
return result
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -148,17 +157,15 @@ class QiniuApi {
|
|||||||
},
|
},
|
||||||
timeout: this.timeout
|
timeout: this.timeout
|
||||||
})
|
})
|
||||||
if (res && res.status === 200) {
|
return res?.status === 200
|
||||||
return {
|
? {
|
||||||
success: true,
|
success: true,
|
||||||
private: res.data.private,
|
private: res.data.private,
|
||||||
zone: res.data.zone
|
zone: res.data.zone
|
||||||
}
|
}
|
||||||
} else {
|
: {
|
||||||
return {
|
|
||||||
success: false
|
success: false
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -178,11 +185,7 @@ class QiniuApi {
|
|||||||
},
|
},
|
||||||
timeout: this.timeout
|
timeout: this.timeout
|
||||||
})
|
})
|
||||||
if (res && res.status === 200) {
|
return res?.status === 200 && res?.data?.length ? res.data : []
|
||||||
return res.data && res.data.length ? res.data : []
|
|
||||||
} else {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -209,7 +212,7 @@ class QiniuApi {
|
|||||||
},
|
},
|
||||||
timeout: this.timeout
|
timeout: this.timeout
|
||||||
})
|
})
|
||||||
return res && res.status === 200
|
return res?.status === 200
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -222,8 +225,7 @@ class QiniuApi {
|
|||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async createBucket (configMap: IStringKeyMap): Promise<boolean> {
|
async createBucket (configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { BucketName, region } = configMap
|
const { BucketName, region, acl } = configMap
|
||||||
const { acl } = configMap
|
|
||||||
const urlPath = `/mkbucketv3/${BucketName}/region/${region}`
|
const urlPath = `/mkbucketv3/${BucketName}/region/${region}`
|
||||||
const authorization = this.authorization('POST', urlPath, this.host, '', '', 'application/json')
|
const authorization = this.authorization('POST', urlPath, this.host, '', '', 'application/json')
|
||||||
const res = await axios({
|
const res = await axios({
|
||||||
@@ -236,15 +238,12 @@ class QiniuApi {
|
|||||||
},
|
},
|
||||||
timeout: this.timeout
|
timeout: this.timeout
|
||||||
})
|
})
|
||||||
if (res && res.status === 200) {
|
return res?.status === 200
|
||||||
const changeAclRes = await this.setBucketAclPolicy({
|
? await this.setBucketAclPolicy({
|
||||||
bucketName: BucketName,
|
bucketName: BucketName,
|
||||||
isPrivate: !acl
|
isPrivate: !acl
|
||||||
})
|
})
|
||||||
return changeAclRes
|
: false
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListRecursively (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListRecursively (configMap: IStringKeyMap): Promise<any> {
|
||||||
@@ -407,19 +406,19 @@ class QiniuApi {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
if (res && res.respInfo.statusCode === 200) {
|
if (res?.respInfo?.statusCode === 200) {
|
||||||
if (res.respBody && res.respBody.commonPrefixes) {
|
if (res.respBody?.commonPrefixes) {
|
||||||
res.respBody.commonPrefixes.forEach((item: string) => {
|
res.respBody.commonPrefixes.forEach((item: string) => {
|
||||||
result.fullList.push(this.formatFolder(item, slicedPrefix))
|
result.fullList.push(this.formatFolder(item, slicedPrefix))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (res.respBody && res.respBody.items) {
|
if (res.respBody?.items) {
|
||||||
res.respBody.items.forEach((item: any) => {
|
res.respBody.items.forEach((item: any) => {
|
||||||
item.fsize !== 0 && result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix))
|
item.fsize !== 0 && result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
result.isTruncated = !!(res.respBody && res.respBody.marker)
|
result.isTruncated = !!(res.respBody?.marker)
|
||||||
result.nextMarker = res.respBody && res.respBody.marker ? res.respBody.marker : ''
|
result.nextMarker = res.respBody?.marker ? res.respBody.marker : ''
|
||||||
result.success = true
|
result.success = true
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
@@ -450,11 +449,7 @@ class QiniuApi {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}) as any
|
}) as any
|
||||||
if (res && res.respInfo.statusCode === 200) {
|
return res?.respInfo?.statusCode === 200
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -487,12 +482,12 @@ class QiniuApi {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}) as any
|
}) as any
|
||||||
if (res && res.respInfo.statusCode === 200) {
|
if (res?.respInfo?.statusCode === 200) {
|
||||||
if (res.respBody && res.respBody.items) {
|
if (res.respBody?.items) {
|
||||||
allFileList.Contents = allFileList.Contents.concat(res.respBody.items)
|
allFileList.Contents = allFileList.Contents.concat(res.respBody.items)
|
||||||
}
|
}
|
||||||
isTruncated = !!(res.respBody && res.respBody.marker)
|
isTruncated = !!(res.respBody?.marker)
|
||||||
marker = res.respBody && res.respBody.marker ? res.respBody.marker : ''
|
marker = res.respBody?.marker ? res.respBody.marker : ''
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -514,9 +509,7 @@ class QiniuApi {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}) as any
|
}) as any
|
||||||
if (!(res && res.respInfo.statusCode === 200)) {
|
if (res?.respInfo?.statusCode !== 200) return false
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -549,7 +542,7 @@ class QiniuApi {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}) as any
|
}) as any
|
||||||
return res && res.respInfo.statusCode === 200
|
return res?.respInfo?.statusCode === 200
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -671,11 +664,7 @@ class QiniuApi {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}) as any
|
}) as any
|
||||||
if (res && res.respInfo.statusCode === 200) {
|
return res?.respInfo?.statusCode === 200
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// AWS S3 相关
|
||||||
import {
|
import {
|
||||||
S3Client,
|
S3Client,
|
||||||
ListBucketsCommand,
|
ListBucketsCommand,
|
||||||
@@ -13,24 +14,48 @@ import {
|
|||||||
DeleteObjectsCommand,
|
DeleteObjectsCommand,
|
||||||
PutObjectCommand
|
PutObjectCommand
|
||||||
} from '@aws-sdk/client-s3'
|
} from '@aws-sdk/client-s3'
|
||||||
|
|
||||||
|
// AWS S3 上传和进度
|
||||||
import { Upload, Progress } from '@aws-sdk/lib-storage'
|
import { Upload, Progress } from '@aws-sdk/lib-storage'
|
||||||
|
|
||||||
|
// AWS S3 请求签名
|
||||||
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
|
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
|
||||||
|
|
||||||
|
// HTTP 和 HTTPS 模块
|
||||||
import https from 'https'
|
import https from 'https'
|
||||||
import http from 'http'
|
import http from 'http'
|
||||||
|
|
||||||
|
// 日志记录器
|
||||||
import { ManageLogger } from '../utils/logger'
|
import { ManageLogger } from '../utils/logger'
|
||||||
|
|
||||||
|
// 端点地址格式化函数、错误格式化函数、获取请求代理、获取文件 MIME 类型、新的下载器、并发异步任务池
|
||||||
import { formatEndpoint, formatError, getAgent, getFileMimeType, NewDownloader, ConcurrencyPromisePool } from '../utils/common'
|
import { formatEndpoint, formatError, getAgent, getFileMimeType, NewDownloader, ConcurrencyPromisePool } from '../utils/common'
|
||||||
|
|
||||||
|
// 是否为图片的判断函数、HTTP 代理格式化函数
|
||||||
import { isImage, formatHttpProxy } from '@/manage/utils/common'
|
import { isImage, formatHttpProxy } from '@/manage/utils/common'
|
||||||
|
|
||||||
|
// HTTP 和 HTTPS 代理库
|
||||||
import { HttpsProxyAgent, HttpProxyAgent } from 'hpagent'
|
import { HttpsProxyAgent, HttpProxyAgent } from 'hpagent'
|
||||||
|
|
||||||
|
// 窗口管理器
|
||||||
import windowManager from 'apis/app/window/windowManager'
|
import windowManager from 'apis/app/window/windowManager'
|
||||||
|
|
||||||
|
// 枚举类型声明
|
||||||
import { IWindowList } from '#/types/enum'
|
import { IWindowList } from '#/types/enum'
|
||||||
|
|
||||||
|
// Electron 相关
|
||||||
import { ipcMain, IpcMainEvent } from 'electron'
|
import { ipcMain, IpcMainEvent } from 'electron'
|
||||||
import UpDownTaskQueue,
|
|
||||||
{
|
// 上传下载任务队列
|
||||||
uploadTaskSpecialStatus,
|
import UpDownTaskQueue, { uploadTaskSpecialStatus, commonTaskStatus } from '../datastore/upDownTaskQueue'
|
||||||
commonTaskStatus
|
|
||||||
} from '../datastore/upDownTaskQueue'
|
// 文件系统库
|
||||||
import fs from 'fs-extra'
|
import fs from 'fs-extra'
|
||||||
|
|
||||||
|
// 路径处理库
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
|
||||||
|
// 取消下载任务的加载文件列表、刷新下载文件传输列表
|
||||||
import { cancelDownloadLoadingFileList, refreshDownloadFileTransferList } from '@/manage/utils/static'
|
import { cancelDownloadLoadingFileList, refreshDownloadFileTransferList } from '@/manage/utils/static'
|
||||||
|
|
||||||
interface S3plistApiOptions {
|
interface S3plistApiOptions {
|
||||||
@@ -79,18 +104,14 @@ class S3plistApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setAgent (proxy: string | undefined, sslEnabled: boolean) : HttpProxyAgent | HttpsProxyAgent | undefined {
|
setAgent (proxy: string | undefined, sslEnabled: boolean) : HttpProxyAgent | HttpsProxyAgent | undefined {
|
||||||
if (sslEnabled) {
|
const protocol = sslEnabled ? 'https' : 'http'
|
||||||
const agent = getAgent(proxy, true).https
|
const agent = getAgent(proxy, sslEnabled)[protocol]
|
||||||
return agent ?? new https.Agent({
|
const commonOptions = { keepAlive: true }
|
||||||
keepAlive: true,
|
const extraOptions = sslEnabled ? { rejectUnauthorized: false } : {}
|
||||||
rejectUnauthorized: false
|
return agent ?? new (sslEnabled ? https.Agent : http.Agent)({
|
||||||
})
|
...commonOptions,
|
||||||
} else {
|
...extraOptions
|
||||||
const agent = getAgent(proxy, false).http
|
})
|
||||||
return agent ?? new http.Agent({
|
|
||||||
keepAlive: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logParam = (error:any, method: string) =>
|
logParam = (error:any, method: string) =>
|
||||||
@@ -111,17 +132,18 @@ class S3plistApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
formatFile (item: _Object, slicedPrefix: string, urlPrefix: string): any {
|
formatFile (item: _Object, slicedPrefix: string, urlPrefix: string): any {
|
||||||
|
const fileName = item.Key?.replace(slicedPrefix, '')
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
key: item.Key,
|
key: item.Key,
|
||||||
url: `${urlPrefix}/${item.Key}`,
|
url: `${urlPrefix}/${item.Key}`,
|
||||||
fileName: item.Key?.replace(slicedPrefix, ''),
|
fileName,
|
||||||
fileSize: item.Size,
|
fileSize: item.Size,
|
||||||
formatedTime: new Date(item.LastModified!).toLocaleString(),
|
formatedTime: new Date(item.LastModified!).toLocaleString(),
|
||||||
isDir: false,
|
isDir: false,
|
||||||
checked: false,
|
checked: false,
|
||||||
match: false,
|
match: false,
|
||||||
isImage: isImage(item.Key?.replace(slicedPrefix, '') || '')
|
isImage: isImage(fileName || '')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,50 +152,43 @@ class S3plistApi {
|
|||||||
*/
|
*/
|
||||||
async getBucketList (): Promise<any> {
|
async getBucketList (): Promise<any> {
|
||||||
const options = Object.assign({}, this.baseOptions) as S3ClientConfig
|
const options = Object.assign({}, this.baseOptions) as S3ClientConfig
|
||||||
const result = [] as IStringKeyMap[]
|
const result: IStringKeyMap[] = []
|
||||||
const endpoint = options.endpoint as string || '' as string
|
const endpoint = options.endpoint as string || ''
|
||||||
options.region = endpoint.indexOf('cloudflarestorage') !== -1 ? 'auto' : 'us-east-1'
|
options.region = endpoint.includes('cloudflarestorage') ? 'auto' : 'us-east-1'
|
||||||
try {
|
try {
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new ListBucketsCommand({})
|
const data = await client.send(new ListBucketsCommand({}))
|
||||||
const data = await client.send(command)
|
|
||||||
if (data.$metadata.httpStatusCode === 200) {
|
if (data.$metadata.httpStatusCode !== 200) {
|
||||||
if (data.Buckets) {
|
this.logParam(data, 'getBucketList')
|
||||||
if (endpoint.indexOf('cloudflarestorage') !== -1) {
|
return result
|
||||||
data.Buckets.forEach((bucket) => {
|
}
|
||||||
result.push({
|
|
||||||
Name: bucket.Name,
|
if (data.Buckets) {
|
||||||
CreationDate: bucket.CreationDate,
|
if (endpoint.includes('cloudflarestorage')) {
|
||||||
Location: 'auto'
|
result.push(...data.Buckets.map(bucket => ({
|
||||||
})
|
Name: bucket.Name,
|
||||||
|
CreationDate: bucket.CreationDate,
|
||||||
|
Location: 'auto'
|
||||||
|
})))
|
||||||
|
} else {
|
||||||
|
for (const bucket of data.Buckets) {
|
||||||
|
const bucketName = bucket.Name
|
||||||
|
const bucketConfig = await client.send(new GetBucketLocationCommand({
|
||||||
|
Bucket: bucketName
|
||||||
|
}))
|
||||||
|
result.push({
|
||||||
|
Name: bucketName,
|
||||||
|
CreationDate: bucket.CreationDate,
|
||||||
|
Location: bucketConfig.$metadata.httpStatusCode === 200
|
||||||
|
? bucketConfig.LocationConstraint?.toLowerCase() || 'us-east-1'
|
||||||
|
: 'us-east-1'
|
||||||
})
|
})
|
||||||
} else {
|
if (bucketConfig.$metadata.httpStatusCode !== 200) {
|
||||||
for (let i = 0; i < data.Buckets.length; i++) {
|
this.logParam(bucketConfig, 'getBucketList')
|
||||||
const bucket = data.Buckets[i]
|
|
||||||
const bucketName = bucket.Name
|
|
||||||
const command = new GetBucketLocationCommand({
|
|
||||||
Bucket: bucketName
|
|
||||||
})
|
|
||||||
const bucketConfig = await client.send(command)
|
|
||||||
if (bucketConfig.$metadata.httpStatusCode === 200) {
|
|
||||||
result.push({
|
|
||||||
Name: bucketName,
|
|
||||||
CreationDate: bucket.CreationDate,
|
|
||||||
Location: bucketConfig.LocationConstraint?.toLowerCase() || 'us-east-1'
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.logParam(bucketConfig, 'getBucketList')
|
|
||||||
result.push({
|
|
||||||
Name: bucketName,
|
|
||||||
CreationDate: bucket.CreationDate,
|
|
||||||
Location: 'us-east-1'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
this.logParam(data, 'getBucketList')
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logParam(error, 'getBucketList')
|
this.logParam(error, 'getBucketList')
|
||||||
@@ -312,8 +327,7 @@ class S3plistApi {
|
|||||||
success: false
|
success: false
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const options = Object.assign({}, this.baseOptions) as S3ClientConfig
|
const options = Object.assign({}, { ...this.baseOptions, region: region || 'us-east-1' }) as S3ClientConfig
|
||||||
options.region = region || 'us-east-1'
|
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new ListObjectsV2Command({
|
const command = new ListObjectsV2Command({
|
||||||
Bucket: bucket,
|
Bucket: bucket,
|
||||||
@@ -324,12 +338,10 @@ class S3plistApi {
|
|||||||
})
|
})
|
||||||
const data = await client.send(command)
|
const data = await client.send(command)
|
||||||
if (data.$metadata.httpStatusCode === 200) {
|
if (data.$metadata.httpStatusCode === 200) {
|
||||||
data.CommonPrefixes && data.CommonPrefixes.forEach((item: CommonPrefix) => {
|
result.fullList = [
|
||||||
result.fullList.push(this.formatFolder(item, slicedPrefix))
|
...(data.CommonPrefixes?.map(item => this.formatFolder(item, slicedPrefix)) || []),
|
||||||
})
|
...(data.Contents?.map(item => this.formatFile(item, slicedPrefix, urlPrefix)) || [])
|
||||||
data.Contents && data.Contents.forEach((item: _Object) => {
|
]
|
||||||
result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix))
|
|
||||||
})
|
|
||||||
result.isTruncated = data.IsTruncated || false
|
result.isTruncated = data.IsTruncated || false
|
||||||
result.nextMarker = data.NextContinuationToken || ''
|
result.nextMarker = data.NextContinuationToken || ''
|
||||||
result.success = true
|
result.success = true
|
||||||
@@ -354,8 +366,7 @@ class S3plistApi {
|
|||||||
const { bucketName, region, oldKey, newKey } = configMap
|
const { bucketName, region, oldKey, newKey } = configMap
|
||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
const options = Object.assign({}, this.baseOptions) as S3ClientConfig
|
const options = Object.assign({}, { ...this.baseOptions, region: region || 'us-east-1' }) as S3ClientConfig
|
||||||
options.region = region || 'us-east-1'
|
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new CopyObjectCommand({
|
const command = new CopyObjectCommand({
|
||||||
Bucket: bucketName,
|
Bucket: bucketName,
|
||||||
|
|||||||
@@ -1,13 +1,34 @@
|
|||||||
|
// 是否为图片的判断函数
|
||||||
import { isImage } from '@/manage/utils/common'
|
import { isImage } from '@/manage/utils/common'
|
||||||
|
|
||||||
|
// Axios 和 Axios 实例类型声明
|
||||||
import axios, { AxiosInstance } from 'axios'
|
import axios, { AxiosInstance } from 'axios'
|
||||||
|
|
||||||
|
// 窗口管理器
|
||||||
import windowManager from 'apis/app/window/windowManager'
|
import windowManager from 'apis/app/window/windowManager'
|
||||||
|
|
||||||
|
// 枚举类型声明
|
||||||
import { IWindowList } from '#/types/enum'
|
import { IWindowList } from '#/types/enum'
|
||||||
|
|
||||||
|
// Electron 相关
|
||||||
import { ipcMain, IpcMainEvent } from 'electron'
|
import { ipcMain, IpcMainEvent } from 'electron'
|
||||||
|
|
||||||
|
// 表单数据库
|
||||||
import FormData from 'form-data'
|
import FormData from 'form-data'
|
||||||
|
|
||||||
|
// 文件系统库
|
||||||
import fs from 'fs-extra'
|
import fs from 'fs-extra'
|
||||||
|
|
||||||
|
// 获取文件 MIME 类型、got 上传函数、新的下载器、并发异步任务池、错误格式化函数
|
||||||
import { getFileMimeType, gotUpload, NewDownloader, ConcurrencyPromisePool, formatError } from '../utils/common'
|
import { getFileMimeType, gotUpload, NewDownloader, ConcurrencyPromisePool, formatError } from '../utils/common'
|
||||||
|
|
||||||
|
// 路径处理库
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
|
||||||
|
// 上传下载任务队列
|
||||||
import UpDownTaskQueue, { commonTaskStatus } from '../datastore/upDownTaskQueue'
|
import UpDownTaskQueue, { commonTaskStatus } from '../datastore/upDownTaskQueue'
|
||||||
|
|
||||||
|
// 日志记录器
|
||||||
import { ManageLogger } from '../utils/logger'
|
import { ManageLogger } from '../utils/logger'
|
||||||
|
|
||||||
class SmmsApi {
|
class SmmsApi {
|
||||||
@@ -99,7 +120,7 @@ class SmmsApi {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
marker++
|
marker++
|
||||||
} while (!cancelTask[0] && res && res.status === 200 && res.data && res.data.success && res.data.CurrentPage < res.data.TotalPages)
|
} while (!cancelTask[0] && res?.status === 200 && res?.data?.success && res.data.CurrentPage < res.data.TotalPages)
|
||||||
result.success = !cancelTask[0]
|
result.success = !cancelTask[0]
|
||||||
result.finished = true
|
result.finished = true
|
||||||
window.webContents.send('refreshFileTransferList', result)
|
window.webContents.send('refreshFileTransferList', result)
|
||||||
@@ -121,16 +142,14 @@ class SmmsApi {
|
|||||||
* customUrl: string
|
* customUrl: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async getBucketFileList (configMap: IStringKeyMap): Promise<any> {
|
async getBucketFileList ({ currentPage }: IStringKeyMap): Promise<any> {
|
||||||
const { currentPage } = configMap
|
|
||||||
let res = {} as any
|
|
||||||
const result = {
|
const result = {
|
||||||
fullList: <any>[],
|
fullList: <any>[],
|
||||||
isTruncated: false,
|
isTruncated: false,
|
||||||
nextMarker: '',
|
nextMarker: '',
|
||||||
success: false
|
success: false
|
||||||
}
|
}
|
||||||
res = await this.axiosInstance(
|
const res = await this.axiosInstance(
|
||||||
'/upload_history',
|
'/upload_history',
|
||||||
{
|
{
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
@@ -142,21 +161,17 @@ class SmmsApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (res && res.status === 200 && res.data && res.data.success) {
|
if (res?.status !== 200 || !res?.data?.success) return result
|
||||||
if (res.data.Count === 0) {
|
|
||||||
result.success = true
|
if (res.data.Count === 0) return { ...result, success: true }
|
||||||
return result
|
|
||||||
}
|
res.data.data.forEach((item: any) => {
|
||||||
res.data.data.forEach((item: any) => {
|
result.fullList.push(this.formatFile(item))
|
||||||
result.fullList.push(this.formatFile(item))
|
})
|
||||||
})
|
result.isTruncated = res.data.CurrentPage < res.data.TotalPages
|
||||||
result.isTruncated = res.data.CurrentPage < res.data.TotalPages
|
result.nextMarker = res.data.CurrentPage + 1
|
||||||
result.nextMarker = res.data.CurrentPage + 1
|
result.success = true
|
||||||
result.success = true
|
return result
|
||||||
return result
|
|
||||||
} else {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -169,20 +184,18 @@ class SmmsApi {
|
|||||||
* DeleteHash: string
|
* DeleteHash: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async deleteBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFile ({ DeleteHash }: IStringKeyMap): Promise<boolean> {
|
||||||
const { DeleteHash } = configMap
|
|
||||||
const params = {
|
|
||||||
hash: DeleteHash,
|
|
||||||
format: 'json'
|
|
||||||
}
|
|
||||||
const res = await this.axiosInstance(
|
const res = await this.axiosInstance(
|
||||||
`/delete/${DeleteHash}`,
|
`/delete/${DeleteHash}`,
|
||||||
{
|
{
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
params
|
params: {
|
||||||
|
hash: DeleteHash,
|
||||||
|
format: 'json'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return res && res.status === 200 && res.data && res.data.success
|
return res?.status === 200 && res?.data?.success
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user