mirror of
https://github.com/Kuingsmile/PicList.git
synced 2025-03-13 00:18:13 -04:00
🐛 Fix: add local path picbed into delete api of http server
This commit is contained in:
parent
517348886c
commit
f585bb4d7d
@ -19,6 +19,11 @@ import picgo from '@core/picgo'
|
|||||||
import GuiApi from '../../gui'
|
import GuiApi from '../../gui'
|
||||||
import uploader from '.'
|
import uploader from '.'
|
||||||
import { IWindowList } from '#/types/enum'
|
import { IWindowList } from '#/types/enum'
|
||||||
|
import { picBedsCanbeDeleted } from '#/utils/static'
|
||||||
|
import path from 'path'
|
||||||
|
import SSHClient from '~/main/utils/sshClient'
|
||||||
|
import { ISftpPlistConfig } from 'piclist'
|
||||||
|
import { getRawData } from '~/renderer/utils/common'
|
||||||
|
|
||||||
const handleClipboardUploading = async (): Promise<false | ImgInfo[]> => {
|
const handleClipboardUploading = async (): Promise<false | ImgInfo[]> => {
|
||||||
const useBuiltinClipboard = db.get('settings.useBuiltinClipboard') === undefined ? true : !!db.get('settings.useBuiltinClipboard')
|
const useBuiltinClipboard = db.get('settings.useBuiltinClipboard') === undefined ? true : !!db.get('settings.useBuiltinClipboard')
|
||||||
@ -125,9 +130,23 @@ export const uploadChoosedFiles = async (webContents: WebContents, files: IFileW
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function deleteWebdavFile (config: ISftpPlistConfig, fileName: string) {
|
||||||
|
try {
|
||||||
|
const client = SSHClient.instance
|
||||||
|
await client.connect(config)
|
||||||
|
const uploadPath = `/${(config.uploadPath || '')}/`.replace(/\/+/g, '/')
|
||||||
|
const remote = path.join(uploadPath, fileName)
|
||||||
|
const deleteResult = await client.deleteFile(remote)
|
||||||
|
client.close()
|
||||||
|
return deleteResult
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const deleteChoosedFiles = async (list: ImgInfo[]): Promise<boolean[]> => {
|
export const deleteChoosedFiles = async (list: ImgInfo[]): Promise<boolean[]> => {
|
||||||
const result = []
|
const result = []
|
||||||
const picBedsCanbeDeleted = ['smms', 'github', 'imgur', 'tcyun', 'aliyun', 'qiniu', 'upyun', 'aws-s3', 'webdavplist']
|
|
||||||
for (const item of list) {
|
for (const item of list) {
|
||||||
if (item.id) {
|
if (item.id) {
|
||||||
try {
|
try {
|
||||||
@ -135,23 +154,44 @@ export const deleteChoosedFiles = async (list: ImgInfo[]): Promise<boolean[]> =>
|
|||||||
const file = await dbStore.removeById(item.id)
|
const file = await dbStore.removeById(item.id)
|
||||||
if (await picgo.getConfig('settings.deleteCloudFile')) {
|
if (await picgo.getConfig('settings.deleteCloudFile')) {
|
||||||
if (item.type !== undefined && picBedsCanbeDeleted.includes(item.type)) {
|
if (item.type !== undefined && picBedsCanbeDeleted.includes(item.type)) {
|
||||||
setTimeout(() => {
|
if (item.type === 'webdavplist') {
|
||||||
ALLApi.delete(item).then((value: boolean) => {
|
const { fileName, config } = item
|
||||||
if (value) {
|
setTimeout(() => {
|
||||||
const notification = new Notification({
|
deleteWebdavFile(getRawData(config), fileName || '').then((value: boolean) => {
|
||||||
title: T('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'),
|
if (value) {
|
||||||
body: T('GALLERY_SYNC_DELETE_NOTICE_SUCCEED')
|
const notification = new Notification({
|
||||||
})
|
title: T('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'),
|
||||||
notification.show()
|
body: T('GALLERY_SYNC_DELETE_NOTICE_SUCCEED')
|
||||||
} else {
|
})
|
||||||
const notification = new Notification({
|
notification.show()
|
||||||
title: T('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'),
|
} else {
|
||||||
body: T('GALLERY_SYNC_DELETE_NOTICE_FAILED')
|
const notification = new Notification({
|
||||||
})
|
title: T('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'),
|
||||||
notification.show()
|
body: T('GALLERY_SYNC_DELETE_NOTICE_FAILED')
|
||||||
}
|
})
|
||||||
})
|
notification.show()
|
||||||
}, 0)
|
}
|
||||||
|
})
|
||||||
|
}, 0)
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
ALLApi.delete(item).then((value: boolean) => {
|
||||||
|
if (value) {
|
||||||
|
const notification = new Notification({
|
||||||
|
title: T('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'),
|
||||||
|
body: T('GALLERY_SYNC_DELETE_NOTICE_SUCCEED')
|
||||||
|
})
|
||||||
|
notification.show()
|
||||||
|
} else {
|
||||||
|
const notification = new Notification({
|
||||||
|
title: T('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'),
|
||||||
|
body: T('GALLERY_SYNC_DELETE_NOTICE_FAILED')
|
||||||
|
})
|
||||||
|
notification.show()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -88,15 +88,7 @@ import SSHClient from '../utils/sshClient'
|
|||||||
// Sftp 配置类型声明
|
// Sftp 配置类型声明
|
||||||
import { ISftpPlistConfig } from 'piclist'
|
import { ISftpPlistConfig } from 'piclist'
|
||||||
|
|
||||||
// AWS S3 相关模块
|
import { removeFileFromS3InMain } from '~/main/utils/deleteFunc'
|
||||||
import { S3Client, DeleteObjectCommand, S3ClientConfig } from '@aws-sdk/client-s3'
|
|
||||||
import { NodeHttpHandler } from '@smithy/node-http-handler'
|
|
||||||
import http, { AgentOptions } from 'http'
|
|
||||||
import https from 'https'
|
|
||||||
|
|
||||||
// 工具函数
|
|
||||||
import { getAgent } from '../manage/utils/common'
|
|
||||||
import logger from '@core/picgo/logger'
|
|
||||||
|
|
||||||
const STORE_PATH = app.getPath('userData')
|
const STORE_PATH = app.getPath('userData')
|
||||||
|
|
||||||
@ -192,62 +184,8 @@ export default {
|
|||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('delete-aws-s3-file', async (_evt: IpcMainInvokeEvent, configMap: IStringKeyMap) => {
|
ipcMain.handle('delete-aws-s3-file', async (_evt: IpcMainInvokeEvent, configMap: IStringKeyMap) => {
|
||||||
try {
|
const result = await removeFileFromS3InMain(configMap)
|
||||||
const { imgUrl, config: { accessKeyID, secretAccessKey, bucketName, region, endpoint, pathStyleAccess, rejectUnauthorized, proxy } } = configMap
|
return result
|
||||||
const url = new URL(!/^https?:\/\//.test(imgUrl) ? `http://${imgUrl}` : imgUrl)
|
|
||||||
const fileKey = url.pathname.replace(/^\/+/, '')
|
|
||||||
const endpointUrl: string | undefined = endpoint
|
|
||||||
? /^https?:\/\//.test(endpoint)
|
|
||||||
? endpoint
|
|
||||||
: `http://${endpoint}`
|
|
||||||
: undefined
|
|
||||||
const sslEnabled = endpointUrl ? endpointUrl.startsWith('https') : true
|
|
||||||
const agent = getAgent(proxy, sslEnabled)
|
|
||||||
const commonOptions: AgentOptions = {
|
|
||||||
keepAlive: true,
|
|
||||||
keepAliveMsecs: 1000,
|
|
||||||
scheduling: 'lifo' as 'lifo' | 'fifo' | undefined
|
|
||||||
}
|
|
||||||
const extraOptions = sslEnabled ? { rejectUnauthorized: !!rejectUnauthorized } : {}
|
|
||||||
const handler = sslEnabled
|
|
||||||
? new NodeHttpHandler({
|
|
||||||
httpsAgent: agent.https
|
|
||||||
? agent.https
|
|
||||||
: new https.Agent({
|
|
||||||
...commonOptions,
|
|
||||||
...extraOptions
|
|
||||||
})
|
|
||||||
})
|
|
||||||
: new NodeHttpHandler({
|
|
||||||
httpAgent: agent.http
|
|
||||||
? agent.http
|
|
||||||
: new http.Agent({
|
|
||||||
...commonOptions,
|
|
||||||
...extraOptions
|
|
||||||
})
|
|
||||||
})
|
|
||||||
const s3Options: S3ClientConfig = {
|
|
||||||
credentials: {
|
|
||||||
accessKeyId: accessKeyID,
|
|
||||||
secretAccessKey
|
|
||||||
},
|
|
||||||
endpoint: endpointUrl,
|
|
||||||
tls: sslEnabled,
|
|
||||||
forcePathStyle: pathStyleAccess,
|
|
||||||
region,
|
|
||||||
requestHandler: handler
|
|
||||||
}
|
|
||||||
const client = new S3Client(s3Options)
|
|
||||||
const command = new DeleteObjectCommand({
|
|
||||||
Bucket: bucketName,
|
|
||||||
Key: fileKey
|
|
||||||
})
|
|
||||||
const result = await client.send(command)
|
|
||||||
return result.$metadata.httpStatusCode === 204
|
|
||||||
} catch (err: any) {
|
|
||||||
logger.error(err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// migrate from PicGo
|
// migrate from PicGo
|
||||||
|
@ -15,10 +15,6 @@ import ipcList from '~/main/events/ipcList'
|
|||||||
import busEventList from '~/main/events/busEventList'
|
import busEventList from '~/main/events/busEventList'
|
||||||
import { IRemoteNoticeTriggerHook, IWindowList } from '#/types/enum'
|
import { IRemoteNoticeTriggerHook, IWindowList } from '#/types/enum'
|
||||||
import windowManager from 'apis/app/window/windowManager'
|
import windowManager from 'apis/app/window/windowManager'
|
||||||
import {
|
|
||||||
updateShortKeyFromVersion212,
|
|
||||||
migrateGalleryFromVersion230
|
|
||||||
} from '~/main/migrate'
|
|
||||||
import {
|
import {
|
||||||
uploadChoosedFiles,
|
uploadChoosedFiles,
|
||||||
uploadClipboardFiles
|
uploadClipboardFiles
|
||||||
@ -29,7 +25,7 @@ import {
|
|||||||
import server from '~/main/server/index'
|
import server from '~/main/server/index'
|
||||||
import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler'
|
import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler'
|
||||||
import { getUploadFiles } from '~/main/utils/handleArgv'
|
import { getUploadFiles } from '~/main/utils/handleArgv'
|
||||||
import db, { GalleryDB } from '~/main/apis/core/datastore'
|
import db from '~/main/apis/core/datastore'
|
||||||
import bus from '@core/bus'
|
import bus from '@core/bus'
|
||||||
import logger from 'apis/core/picgo/logger'
|
import logger from 'apis/core/picgo/logger'
|
||||||
import picgo from 'apis/core/picgo'
|
import picgo from 'apis/core/picgo'
|
||||||
@ -135,8 +131,6 @@ class LifeCycle {
|
|||||||
UpDownTaskQueue.getInstance()
|
UpDownTaskQueue.getInstance()
|
||||||
manageIpcList.listen()
|
manageIpcList.listen()
|
||||||
busEventList.listen()
|
busEventList.listen()
|
||||||
updateShortKeyFromVersion212(db, db.get('settings.shortKey'))
|
|
||||||
await migrateGalleryFromVersion230(db, GalleryDB.getInstance(), picgo)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private onReady () {
|
private onReady () {
|
||||||
|
@ -122,7 +122,7 @@ class AliyunApi {
|
|||||||
marker,
|
marker,
|
||||||
'max-keys': 1000
|
'max-keys': 1000
|
||||||
}) as IStringKeyMap
|
}) as IStringKeyMap
|
||||||
if (res.res.statusCode !== 200 || !res.buckets) return { result: [], isTruncated: false }
|
if (res?.res?.statusCode !== 200 || !res?.buckets) return { result: [], isTruncated: false }
|
||||||
const formattedBuckets = res.buckets.map((item: OSS.Bucket) => ({
|
const formattedBuckets = res.buckets.map((item: OSS.Bucket) => ({
|
||||||
Name: item.name,
|
Name: item.name,
|
||||||
Location: item.region,
|
Location: item.region,
|
||||||
@ -161,7 +161,7 @@ class AliyunApi {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
@ -207,7 +207,7 @@ class AliyunApi {
|
|||||||
dataRedundancyType: 'LRS',
|
dataRedundancyType: 'LRS',
|
||||||
timeout: this.timeOut
|
timeout: this.timeOut
|
||||||
})
|
})
|
||||||
return res && res.res.status === 200
|
return res?.res?.status === 200
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListRecursively (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListRecursively (configMap: IStringKeyMap): Promise<any> {
|
||||||
@ -238,8 +238,8 @@ class AliyunApi {
|
|||||||
}, {
|
}, {
|
||||||
timeout: this.timeOut
|
timeout: this.timeOut
|
||||||
})
|
})
|
||||||
if (res && res.res.statusCode === 200) {
|
if (res?.res?.statusCode === 200) {
|
||||||
res.objects && res.objects.forEach((item: OSS.ObjectMeta) => {
|
res?.objects?.forEach((item: OSS.ObjectMeta) => {
|
||||||
item.size !== 0 && result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix))
|
item.size !== 0 && result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix))
|
||||||
})
|
})
|
||||||
window.webContents.send(refreshDownloadFileTransferList, result)
|
window.webContents.send(refreshDownloadFileTransferList, result)
|
||||||
@ -286,11 +286,11 @@ class AliyunApi {
|
|||||||
}, {
|
}, {
|
||||||
timeout: this.timeOut
|
timeout: this.timeOut
|
||||||
})
|
})
|
||||||
if (res && res.res.statusCode === 200) {
|
if (res?.res?.statusCode === 200) {
|
||||||
res.prefixes && res.prefixes.forEach((item: string) => {
|
res?.prefixes?.forEach((item: string) => {
|
||||||
result.fullList.push(this.formatFolder(item, slicedPrefix))
|
result.fullList.push(this.formatFolder(item, slicedPrefix))
|
||||||
})
|
})
|
||||||
res.objects && res.objects.forEach((item: OSS.ObjectMeta) => {
|
res?.objects?.forEach((item: OSS.ObjectMeta) => {
|
||||||
item.size !== 0 && result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix))
|
item.size !== 0 && result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix))
|
||||||
})
|
})
|
||||||
window.webContents.send('refreshFileTransferList', result)
|
window.webContents.send('refreshFileTransferList', result)
|
||||||
@ -521,7 +521,7 @@ class AliyunApi {
|
|||||||
}
|
}
|
||||||
).then((res: any) => {
|
).then((res: any) => {
|
||||||
const id = `${bucketName}-${region}-${key}-${filePath}`
|
const id = `${bucketName}-${region}-${key}-${filePath}`
|
||||||
if (res && res.res.statusCode === 200) {
|
if (res?.res?.statusCode === 200) {
|
||||||
instance.updateUploadTask({
|
instance.updateUploadTask({
|
||||||
id,
|
id,
|
||||||
progress: 100,
|
progress: 100,
|
||||||
@ -561,7 +561,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.put(key, Buffer.from('')) as any
|
const res = await client.put(key, Buffer.from('')) as any
|
||||||
return res && res.res.statusCode === 200
|
return res?.res?.statusCode === 200
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -104,9 +104,8 @@ export class ManageApi extends EventEmitter implements ManageApiType {
|
|||||||
getConfig<T> (name?: string): T {
|
getConfig<T> (name?: string): T {
|
||||||
if (!name) {
|
if (!name) {
|
||||||
return this._config as unknown as T
|
return this._config as unknown as T
|
||||||
} else {
|
|
||||||
return get(this._config, name)
|
|
||||||
}
|
}
|
||||||
|
return get(this._config, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
saveConfig (config: IStringKeyMap): void {
|
saveConfig (config: IStringKeyMap): void {
|
||||||
|
@ -1,32 +1,33 @@
|
|||||||
const AliyunAreaCodeName : IStringKeyMap = {
|
const AliyunAreaCodeName : IStringKeyMap = {
|
||||||
'oss-cn-hangzhou': '华东1(杭州)',
|
'oss-cn-hangzhou': '华东1(杭州)',
|
||||||
'oss-cn-shanghai': '华东2(上海)',
|
'oss-cn-shanghai': '华东2(上海)',
|
||||||
'oss-cn-nanjing': '华东5(南京本地地域)',
|
'oss-cn-nanjing': '华东5(南京)',
|
||||||
'oss-cn-fuzhou': '华东6(福州本地地域)',
|
'oss-cn-fuzhou': '华东6(福州)',
|
||||||
'oss-cn-qingdao': '华北1(青岛)',
|
'oss-cn-qingdao': '华北1(青岛)',
|
||||||
'oss-cn-beijing': '华北2(北京)',
|
'oss-cn-beijing': '华北2(北京)',
|
||||||
'oss-cn-zhangjiakou': '华北3(张家口)',
|
'oss-cn-zhangjiakou': '华北3(张家口)',
|
||||||
'oss-cn-huhehaote': '华北5(呼和浩特)',
|
'oss-cn-huhehaote': '华北5(呼和浩特)',
|
||||||
'oss-cn-wulanchabu': '华北6(乌兰察布)',
|
'oss-cn-wulanchabu': '华北6(乌兰察布)',
|
||||||
'oss-cn-shenzhen': '华南1(深圳)',
|
'oss-cn-shenzhen': '华南1(深圳)',
|
||||||
'oss-cn-heyuan': '华南2(河源)',
|
'oss-cn-heyuan': '华南2(河源)',
|
||||||
'oss-cn-guangzhou': '华南3(广州)',
|
'oss-cn-guangzhou': '华南3(广州)',
|
||||||
'oss-cn-chengdu': '西南1(成都)',
|
'oss-cn-chengdu': '西南1(成都)',
|
||||||
'oss-cn-hongkong': '中国(香港)',
|
'oss-cn-hongkong': '中国香港',
|
||||||
'oss-us-west-1': '美国(硅谷)',
|
'oss-us-west-1': '美国(硅谷)',
|
||||||
'oss-us-east-1': '美国(弗吉尼亚)',
|
'oss-us-east-1': '美国(弗吉尼亚)',
|
||||||
'oss-ap-northeast-1': '日本(东京)',
|
'oss-ap-northeast-1': '日本(东京)',
|
||||||
'oss-ap-northeast-2': '韩国(首尔)',
|
'oss-ap-northeast-2': '韩国(首尔)',
|
||||||
'oss-ap-southeast-1': '新加坡',
|
'oss-ap-southeast-1': '新加坡',
|
||||||
'oss-ap-southeast-2': '澳大利亚(悉尼)',
|
'oss-ap-southeast-2': '澳大利亚(悉尼)',
|
||||||
'oss-ap-southeast-3': '马来西亚(吉隆坡)',
|
'oss-ap-southeast-3': '马来西亚(吉隆坡)',
|
||||||
'oss-ap-southeast-5': '印度尼西亚(雅加达)',
|
'oss-ap-southeast-5': '印度尼西亚(雅加达)',
|
||||||
'oss-ap-southeast-6': '菲律宾(马尼拉)',
|
'oss-ap-southeast-6': '菲律宾(马尼拉)',
|
||||||
'oss-ap-southeast-7': '泰国(曼谷)',
|
'oss-ap-southeast-7': '泰国(曼谷)',
|
||||||
'oss-ap-south-1': '印度(孟买)',
|
'oss-ap-south-1': '印度(孟买)',
|
||||||
'oss-eu-central-1': '德国(法兰克福)',
|
'oss-eu-central-1': '德国(法兰克福)',
|
||||||
'oss-eu-west-1': '英国(伦敦)',
|
'oss-eu-west-1': '英国(伦敦)',
|
||||||
'oss-me-east-1': '阿联酋(迪拜)'
|
'oss-me-east-1': '阿联酋(迪拜)',
|
||||||
|
'oss-rg-china-mainland': '无地域属性'
|
||||||
}
|
}
|
||||||
|
|
||||||
const QiniuAreaCodeName : IStringKeyMap = {
|
const QiniuAreaCodeName : IStringKeyMap = {
|
||||||
@ -61,8 +62,7 @@ const TencentAreaCodeName : IStringKeyMap = {
|
|||||||
'na-ashburn': '弗吉尼亚(美东)',
|
'na-ashburn': '弗吉尼亚(美东)',
|
||||||
'na-toronto': '多伦多',
|
'na-toronto': '多伦多',
|
||||||
'sa-saopaulo': '圣保罗',
|
'sa-saopaulo': '圣保罗',
|
||||||
'eu-frankfurt': '法兰克福',
|
'eu-frankfurt': '法兰克福'
|
||||||
'eu-moscow': '莫斯科'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { AliyunAreaCodeName, QiniuAreaCodeName, TencentAreaCodeName }
|
export { AliyunAreaCodeName, QiniuAreaCodeName, TencentAreaCodeName }
|
||||||
|
@ -92,30 +92,9 @@ export class ManageLogger implements ILogger {
|
|||||||
): void {
|
): void {
|
||||||
try {
|
try {
|
||||||
if (this.checkLogLevel(type, this.logLevel)) {
|
if (this.checkLogLevel(type, this.logLevel)) {
|
||||||
let log = `${dayjs().format(
|
let log = `${dayjs().format('YYYY-MM-DD HH:mm:ss')} [PicList ${type.toUpperCase()}] `
|
||||||
'YYYY-MM-DD HH:mm:ss'
|
|
||||||
)} [PicList ${type.toUpperCase()}] `
|
|
||||||
msg.forEach((item: ILogArgvTypeWithError) => {
|
msg.forEach((item: ILogArgvTypeWithError) => {
|
||||||
if (item instanceof Error && type === 'error') {
|
log += this.formatLogItem(item, type)
|
||||||
log += `\n------Error Stack Begin------\n${util.format(
|
|
||||||
item?.stack
|
|
||||||
)}\n-------Error Stack End------- `
|
|
||||||
} else {
|
|
||||||
if (typeof item === 'object') {
|
|
||||||
if (item?.stack) {
|
|
||||||
log = log + `\n------Error Stack Begin------\n${util.format(
|
|
||||||
item.stack
|
|
||||||
)}\n-------Error Stack End------- `
|
|
||||||
}
|
|
||||||
item = JSON.stringify(item, (key, value) => {
|
|
||||||
if (key === 'stack') {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}, 2)
|
|
||||||
}
|
|
||||||
log += `${item as string} `
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
log += '\n'
|
log += '\n'
|
||||||
fs.appendFileSync(logPath, log)
|
fs.appendFileSync(logPath, log)
|
||||||
@ -125,6 +104,22 @@ export class ManageLogger implements ILogger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private formatLogItem (item: ILogArgvTypeWithError, type: string): string {
|
||||||
|
let result = ''
|
||||||
|
if (item instanceof Error && type === 'error') {
|
||||||
|
result += `\n------Error Stack Begin------\n${util.format(item?.stack)}\n-------Error Stack End------- `
|
||||||
|
} else {
|
||||||
|
if (typeof item === 'object') {
|
||||||
|
if (item?.stack) {
|
||||||
|
result += `\n------Error Stack Begin------\n${util.format(item.stack)}\n-------Error Stack End------- `
|
||||||
|
}
|
||||||
|
item = JSON.stringify(item, (key, value) => (key === 'stack' ? undefined : value), 2)
|
||||||
|
}
|
||||||
|
result += `${item as string} `
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
private checkLogLevel (
|
private checkLogLevel (
|
||||||
type: string,
|
type: string,
|
||||||
level: undefined | string | string[]
|
level: undefined | string | string[]
|
||||||
@ -134,9 +129,8 @@ export class ManageLogger implements ILogger {
|
|||||||
}
|
}
|
||||||
if (Array.isArray(level)) {
|
if (Array.isArray(level)) {
|
||||||
return level.some((item: string) => item === type || item === 'all')
|
return level.some((item: string) => item === type || item === 'all')
|
||||||
} else {
|
|
||||||
return type === level
|
|
||||||
}
|
}
|
||||||
|
return type === level
|
||||||
}
|
}
|
||||||
|
|
||||||
success (...msq: ILogArgvType[]): void {
|
success (...msq: ILogArgvType[]): void {
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
import { DBStore } from '@picgo/store'
|
|
||||||
import ConfigStore from '~/main/apis/core/datastore'
|
|
||||||
import path from 'path'
|
|
||||||
import fse from 'fs-extra'
|
|
||||||
import { PicGo as PicGoCore } from 'piclist'
|
|
||||||
import { T } from '~/main/i18n'
|
|
||||||
// from v2.1.2
|
|
||||||
const updateShortKeyFromVersion212 = (db: typeof ConfigStore, shortKeyConfig: IShortKeyConfigs | IOldShortKeyConfigs) => {
|
|
||||||
// #557 极端情况可能会出现配置不存在,需要重新写入
|
|
||||||
if (shortKeyConfig === undefined) {
|
|
||||||
const defaultShortKeyConfig = {
|
|
||||||
enable: true,
|
|
||||||
key: 'CommandOrControl+Shift+P',
|
|
||||||
name: 'upload',
|
|
||||||
label: T('QUICK_UPLOAD')
|
|
||||||
}
|
|
||||||
db.set('settings.shortKey[picgo:upload]', defaultShortKeyConfig)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (shortKeyConfig.upload) {
|
|
||||||
// @ts-ignore
|
|
||||||
shortKeyConfig['picgo:upload'] = {
|
|
||||||
enable: true,
|
|
||||||
key: shortKeyConfig.upload,
|
|
||||||
name: 'upload',
|
|
||||||
label: T('QUICK_UPLOAD')
|
|
||||||
}
|
|
||||||
// @ts-ignore
|
|
||||||
delete shortKeyConfig.upload
|
|
||||||
db.set('settings.shortKey', shortKeyConfig)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const migrateGalleryFromVersion230 = async (configDB: typeof ConfigStore, galleryDB: DBStore, picgo: PicGoCore) => {
|
|
||||||
const originGallery: ImgInfo[] = picgo.getConfig('uploaded')
|
|
||||||
// if hasMigrate, we don't need to migrate
|
|
||||||
const hasMigrate: boolean = configDB.get('__migrateUploaded')
|
|
||||||
if (hasMigrate) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const configPath = configDB.getConfigPath()
|
|
||||||
const configBakPath = path.join(path.dirname(configPath), 'config.bak.json')
|
|
||||||
// migrate gallery from config to gallery db
|
|
||||||
if (originGallery && Array.isArray(originGallery) && originGallery?.length > 0) {
|
|
||||||
if (fse.existsSync(configBakPath)) {
|
|
||||||
fse.copyFileSync(configPath, configBakPath)
|
|
||||||
}
|
|
||||||
await galleryDB.insertMany(originGallery)
|
|
||||||
picgo.saveConfig({
|
|
||||||
uploaded: [],
|
|
||||||
__migrateUploaded: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
updateShortKeyFromVersion212,
|
|
||||||
migrateGalleryFromVersion230
|
|
||||||
}
|
|
@ -11,6 +11,7 @@ import axios from 'axios'
|
|||||||
class Server {
|
class Server {
|
||||||
private httpServer: http.Server
|
private httpServer: http.Server
|
||||||
private config: IServerConfig
|
private config: IServerConfig
|
||||||
|
|
||||||
constructor () {
|
constructor () {
|
||||||
let config = picgo.getConfig<IServerConfig>('settings.server')
|
let config = picgo.getConfig<IServerConfig>('settings.server')
|
||||||
const result = this.checkIfConfigIsValid(config)
|
const result = this.checkIfConfigIsValid(config)
|
||||||
@ -31,11 +32,7 @@ class Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private checkIfConfigIsValid (config: IObj | undefined) {
|
private checkIfConfigIsValid (config: IObj | undefined) {
|
||||||
if (config && config.port && config.host && (config.enable !== undefined)) {
|
return config && config.port && config.host && (config.enable !== undefined)
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleRequest = (request: http.IncomingMessage, response: http.ServerResponse) => {
|
private handleRequest = (request: http.IncomingMessage, response: http.ServerResponse) => {
|
||||||
|
@ -7,9 +7,9 @@ import windowManager from 'apis/app/window/windowManager'
|
|||||||
import { uploadChoosedFiles, uploadClipboardFiles, deleteChoosedFiles } from 'apis/app/uploader/apis'
|
import { uploadChoosedFiles, uploadClipboardFiles, deleteChoosedFiles } from 'apis/app/uploader/apis'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { dbPathDir } from 'apis/core/datastore/dbChecker'
|
import { dbPathDir } from 'apis/core/datastore/dbChecker'
|
||||||
|
|
||||||
const STORE_PATH = dbPathDir()
|
const STORE_PATH = dbPathDir()
|
||||||
const LOG_PATH = path.join(STORE_PATH, 'piclist.log')
|
const LOG_PATH = path.join(STORE_PATH, 'piclist.log')
|
||||||
// import AllAPI from '../../renderer/apis/allApi'
|
|
||||||
|
|
||||||
const errorMessage = `upload error. see ${LOG_PATH} for more detail.`
|
const errorMessage = `upload error. see ${LOG_PATH} for more detail.`
|
||||||
const deleteErrorMessage = `delete error. see ${LOG_PATH} for more detail.`
|
const deleteErrorMessage = `delete error. see ${LOG_PATH} for more detail.`
|
||||||
|
64
src/main/utils/deleteFunc.ts
Normal file
64
src/main/utils/deleteFunc.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import { S3Client, DeleteObjectCommand, S3ClientConfig } from '@aws-sdk/client-s3'
|
||||||
|
import { NodeHttpHandler } from '@smithy/node-http-handler'
|
||||||
|
import http, { AgentOptions } from 'http'
|
||||||
|
import https from 'https'
|
||||||
|
import { getAgent } from '../manage/utils/common'
|
||||||
|
|
||||||
|
export async function removeFileFromS3InMain (configMap: IStringKeyMap) {
|
||||||
|
try {
|
||||||
|
const { imgUrl, config: { accessKeyID, secretAccessKey, bucketName, region, endpoint, pathStyleAccess, rejectUnauthorized, proxy } } = configMap
|
||||||
|
const url = new URL(!/^https?:\/\//.test(imgUrl) ? `http://${imgUrl}` : imgUrl)
|
||||||
|
const fileKey = url.pathname.replace(/^\/+/, '')
|
||||||
|
const endpointUrl: string | undefined = endpoint
|
||||||
|
? /^https?:\/\//.test(endpoint)
|
||||||
|
? endpoint
|
||||||
|
: `http://${endpoint}`
|
||||||
|
: undefined
|
||||||
|
const sslEnabled = endpointUrl ? endpointUrl.startsWith('https') : true
|
||||||
|
const agent = getAgent(proxy, sslEnabled)
|
||||||
|
const commonOptions: AgentOptions = {
|
||||||
|
keepAlive: true,
|
||||||
|
keepAliveMsecs: 1000,
|
||||||
|
scheduling: 'lifo' as 'lifo' | 'fifo' | undefined
|
||||||
|
}
|
||||||
|
const extraOptions = sslEnabled ? { rejectUnauthorized: !!rejectUnauthorized } : {}
|
||||||
|
const handler = sslEnabled
|
||||||
|
? new NodeHttpHandler({
|
||||||
|
httpsAgent: agent.https
|
||||||
|
? agent.https
|
||||||
|
: new https.Agent({
|
||||||
|
...commonOptions,
|
||||||
|
...extraOptions
|
||||||
|
})
|
||||||
|
})
|
||||||
|
: new NodeHttpHandler({
|
||||||
|
httpAgent: agent.http
|
||||||
|
? agent.http
|
||||||
|
: new http.Agent({
|
||||||
|
...commonOptions,
|
||||||
|
...extraOptions
|
||||||
|
})
|
||||||
|
})
|
||||||
|
const s3Options: S3ClientConfig = {
|
||||||
|
credentials: {
|
||||||
|
accessKeyId: accessKeyID,
|
||||||
|
secretAccessKey
|
||||||
|
},
|
||||||
|
endpoint: endpointUrl,
|
||||||
|
tls: sslEnabled,
|
||||||
|
forcePathStyle: pathStyleAccess,
|
||||||
|
region,
|
||||||
|
requestHandler: handler
|
||||||
|
}
|
||||||
|
const client = new S3Client(s3Options)
|
||||||
|
const command = new DeleteObjectCommand({
|
||||||
|
Bucket: bucketName,
|
||||||
|
Key: fileKey
|
||||||
|
})
|
||||||
|
const result = await client.send(command)
|
||||||
|
return result.$metadata.httpStatusCode === 204
|
||||||
|
} catch (err: any) {
|
||||||
|
console.log(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
@ -1,35 +1,32 @@
|
|||||||
|
import AliyunApi from './aliyun'
|
||||||
|
import AwsS3Api from './awss3'
|
||||||
|
import GithubApi from './github'
|
||||||
|
import ImgurApi from './imgur'
|
||||||
|
import LocalApi from './local'
|
||||||
|
import QiniuApi from './qiniu'
|
||||||
|
import SftpPlistApi from './sftpplist'
|
||||||
import SmmsApi from './smms'
|
import SmmsApi from './smms'
|
||||||
import TcyunApi from './tcyun'
|
import TcyunApi from './tcyun'
|
||||||
import AliyunApi from './aliyun'
|
|
||||||
import QiniuApi from './qiniu'
|
|
||||||
import ImgurApi from './imgur'
|
|
||||||
import GithubApi from './github'
|
|
||||||
import UpyunApi from './upyun'
|
import UpyunApi from './upyun'
|
||||||
import AwsS3Api from './awss3'
|
|
||||||
import WebdavApi from './webdav'
|
import WebdavApi from './webdav'
|
||||||
import LocalApi from './local'
|
|
||||||
import SftpPlistApi from './sftpplist'
|
|
||||||
|
|
||||||
const apiMap: IStringKeyMap = {
|
const apiMap: IStringKeyMap = {
|
||||||
|
aliyun: AliyunApi,
|
||||||
|
'aws-s3': AwsS3Api,
|
||||||
|
github: GithubApi,
|
||||||
|
imgur: ImgurApi,
|
||||||
|
local: LocalApi,
|
||||||
|
qiniu: QiniuApi,
|
||||||
|
sftpplist: SftpPlistApi,
|
||||||
smms: SmmsApi,
|
smms: SmmsApi,
|
||||||
tcyun: TcyunApi,
|
tcyun: TcyunApi,
|
||||||
aliyun: AliyunApi,
|
|
||||||
qiniu: QiniuApi,
|
|
||||||
imgur: ImgurApi,
|
|
||||||
github: GithubApi,
|
|
||||||
upyun: UpyunApi,
|
upyun: UpyunApi,
|
||||||
'aws-s3': AwsS3Api,
|
webdavplist: WebdavApi
|
||||||
webdavplist: WebdavApi,
|
|
||||||
local: LocalApi,
|
|
||||||
sftpplist: SftpPlistApi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ALLApi {
|
export default class ALLApi {
|
||||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const api = apiMap[configMap.type]
|
const api = apiMap[configMap.type]
|
||||||
if (api) {
|
return api ? await api.delete(configMap) : false
|
||||||
return await api.delete(configMap)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
import { ipcRenderer } from 'electron'
|
import { ipcRenderer } from 'electron'
|
||||||
import { getRawData } from '~/renderer/utils/common'
|
import { getRawData } from '~/renderer/utils/common'
|
||||||
|
import { removeFileFromS3InMain } from '~/main/utils/deleteFunc'
|
||||||
|
|
||||||
export default class AwsS3Api {
|
export default class AwsS3Api {
|
||||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const deleteResult = await ipcRenderer.invoke('delete-aws-s3-file',
|
return ipcRenderer
|
||||||
getRawData(configMap)
|
? await ipcRenderer.invoke('delete-aws-s3-file',
|
||||||
)
|
getRawData(configMap)
|
||||||
return deleteResult
|
)
|
||||||
|
: await removeFileFromS3InMain(getRawData(configMap))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
return false
|
return false
|
||||||
|
@ -17,6 +17,8 @@ interface IConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class ImgurApi {
|
export default class ImgurApi {
|
||||||
|
static baseUrl: 'https://api.imgur.com/3'
|
||||||
|
|
||||||
private static async makeRequest (
|
private static async makeRequest (
|
||||||
method: 'delete',
|
method: 'delete',
|
||||||
url: string,
|
url: string,
|
||||||
@ -35,25 +37,23 @@ export default class ImgurApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
static async delete (configMap: IConfigMap): Promise<boolean> {
|
||||||
const { config = {}, hash = '' } = configMap || {}
|
const {
|
||||||
const { clientId = '', username = '', accessToken = '' } = config
|
config: { clientId = '', username = '', accessToken = '' } = {},
|
||||||
const baseUrl = 'https://api.imgur.com/3'
|
hash = ''
|
||||||
let Authorization: string
|
} = configMap
|
||||||
let apiUrl: string
|
let Authorization: string, apiUrl: string
|
||||||
|
|
||||||
if (username && accessToken) {
|
if (username && accessToken) {
|
||||||
Authorization = `Bearer ${accessToken}`
|
Authorization = `Bearer ${accessToken}`
|
||||||
apiUrl = `${baseUrl}/account/${username}/image/${hash}`
|
apiUrl = `${ImgurApi.baseUrl}/account/${username}/image/${hash}`
|
||||||
} else if (clientId) {
|
} else if (clientId) {
|
||||||
Authorization = `Client-ID ${clientId}`
|
Authorization = `Client-ID ${clientId}`
|
||||||
apiUrl = `${baseUrl}/image/${hash}`
|
apiUrl = `${ImgurApi.baseUrl}/image/${hash}`
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const headers = {
|
|
||||||
Authorization
|
|
||||||
}
|
|
||||||
const requestConfig: IConfig = {
|
const requestConfig: IConfig = {
|
||||||
headers,
|
headers: { Authorization },
|
||||||
timeout: 30000
|
timeout: 30000
|
||||||
}
|
}
|
||||||
return ImgurApi.makeRequest('delete', apiUrl, requestConfig)
|
return ImgurApi.makeRequest('delete', apiUrl, requestConfig)
|
||||||
|
@ -8,7 +8,7 @@ export default class LocalApi {
|
|||||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
static async delete (configMap: IConfigMap): Promise<boolean> {
|
||||||
const { hash } = configMap
|
const { hash } = configMap
|
||||||
if (!hash) {
|
if (!hash) {
|
||||||
console.error('SmmsApi.delete: invalid params')
|
console.error('Local.delete: invalid params')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ export default class QiniuApi {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}) as any
|
}) as any
|
||||||
return res && res.respInfo.statusCode === 200
|
return res?.respInfo?.statusCode === 200
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
return false
|
return false
|
||||||
|
@ -322,7 +322,7 @@ const choosedPicBedForQRCode: Ref<string[]> = ref([])
|
|||||||
const isAlwaysOnTop = ref(false)
|
const isAlwaysOnTop = ref(false)
|
||||||
const keepAlivePages = $router.getRoutes().filter(item => item.meta.keepAlive).map(item => item.name as string)
|
const keepAlivePages = $router.getRoutes().filter(item => item.meta.keepAlive).map(item => item.name as string)
|
||||||
|
|
||||||
const progressShow = ref(true)
|
const progressShow = ref(false)
|
||||||
const progressPercentage = ref(0)
|
const progressPercentage = ref(0)
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
|
@ -461,6 +461,7 @@ import ALLApi from '@/apis/allApi'
|
|||||||
|
|
||||||
// 工具函数
|
// 工具函数
|
||||||
import { customRenameFormatTable, customStrMatch, customStrReplace } from '../manage/utils/common'
|
import { customRenameFormatTable, customStrMatch, customStrReplace } from '../manage/utils/common'
|
||||||
|
import { picBedsCanbeDeleted } from '#/utils/static'
|
||||||
|
|
||||||
const images = ref<ImgInfo[]>([])
|
const images = ref<ImgInfo[]>([])
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
@ -688,7 +689,6 @@ function remove (item: ImgInfo) {
|
|||||||
type: 'warning'
|
type: 'warning'
|
||||||
}).then(async () => {
|
}).then(async () => {
|
||||||
const file = await $$db.getById(item.id!)
|
const file = await $$db.getById(item.id!)
|
||||||
const picBedsCanbeDeleted = ['smms', 'github', 'imgur', 'tcyun', 'aliyun', 'qiniu', 'upyun', 'aws-s3', 'webdavplist', 'local', 'sftpplist']
|
|
||||||
if (await getConfig('settings.deleteCloudFile')) {
|
if (await getConfig('settings.deleteCloudFile')) {
|
||||||
if (item.type !== undefined && picBedsCanbeDeleted.includes(item.type)) {
|
if (item.type !== undefined && picBedsCanbeDeleted.includes(item.type)) {
|
||||||
const result = await ALLApi.delete(item)
|
const result = await ALLApi.delete(item)
|
||||||
@ -798,7 +798,6 @@ function multiRemove () {
|
|||||||
const files: IResult<ImgInfo>[] = []
|
const files: IResult<ImgInfo>[] = []
|
||||||
const imageIDList = Object.keys(choosedList)
|
const imageIDList = Object.keys(choosedList)
|
||||||
const isDeleteCloudFile = await getConfig('settings.deleteCloudFile')
|
const isDeleteCloudFile = await getConfig('settings.deleteCloudFile')
|
||||||
const picBedsCanbeDeleted = ['smms', 'github', 'imgur', 'tcyun', 'aliyun', 'qiniu', 'upyun', 'aws-s3', 'webdavplist', 'local', 'sftpplist']
|
|
||||||
if (isDeleteCloudFile) {
|
if (isDeleteCloudFile) {
|
||||||
for (let i = 0; i < imageIDList.length; i++) {
|
for (let i = 0; i < imageIDList.length; i++) {
|
||||||
const key = imageIDList[i]
|
const key = imageIDList[i]
|
||||||
@ -1161,3 +1160,4 @@ export default {
|
|||||||
color #ddd
|
color #ddd
|
||||||
margin-bottom 10px
|
margin-bottom 10px
|
||||||
</style>
|
</style>
|
||||||
|
@/apis
|
||||||
|
@ -5,3 +5,5 @@ export const RELEASE_URL = 'https://api.github.com/repos/Kuingsmile/PicList/rele
|
|||||||
export const RELEASE_URL_BACKUP = 'https://release.piclist.cn'
|
export const RELEASE_URL_BACKUP = 'https://release.piclist.cn'
|
||||||
export const STABLE_RELEASE_URL = 'https://github.com/Kuingsmile/PicList/releases/latest'
|
export const STABLE_RELEASE_URL = 'https://github.com/Kuingsmile/PicList/releases/latest'
|
||||||
export const C1 = Buffer.from(C1N, 'base64').toString()
|
export const C1 = Buffer.from(C1N, 'base64').toString()
|
||||||
|
|
||||||
|
export const picBedsCanbeDeleted = ['aliyun', 'aws-s3', 'github', 'imgur', 'local', 'sftpplist', 'smms', 'qiniu', 'tcyun', 'upyun', 'webdavplist']
|
||||||
|
Loading…
Reference in New Issue
Block a user