diff --git a/.eslintignore b/.eslintignore index b908d4d3..15b32ab5 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,5 +1,8 @@ -test/unit/coverage/** -test/unit/*.js -test/e2e/*.js -dist/ -src/**/*.js \ No newline at end of file +test/unit/coverage/** +test/unit/*.js +test/e2e/*.js +dist/ +src/**/*.js +node_modules +dist +vue.config.js diff --git a/.eslintrc.js b/.eslintrc.js index 1e529a69..d37a3983 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -10,7 +10,8 @@ module.exports = { extends: [ 'plugin:vue/vue3-recommended', '@vue/standard', - '@vue/typescript' + '@vue/typescript/recommended', + '@vue/eslint-config-prettier' ], plugins: ['@typescript-eslint'], rules: { @@ -20,8 +21,24 @@ module.exports = { 'no-async-promise-executor': 'off', 'no-unused-vars': 'off', '@typescript-eslint/no-unused-vars': 'error', - '@typescript-eslint/indent': ['error', 2], - 'vue/no-v-html': 'off' + '@typescript-eslint/indent': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/ban-ts-comment': [ + 'error', + { + 'ts-expect-error': 'allow-with-description', + 'ts-nocheck': 'allow-with-description' + } + ], + 'vue/no-v-html': 'off', + 'prettier/prettier': [ + 'error', + {}, + { + usePrettierrc: true + } + ] }, parserOptions: { parser: '@typescript-eslint/parser' diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..feac0f72 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,18 @@ +{ + "arrowParens": "avoid", + "bracketSpacing": true, + "htmlWhitespaceSensitivity": "css", + "insertPragma": false, + "jsxBracketSameLine": false, + "jsxSingleQuote": true, + "printWidth": 120, + "proseWrap": "always", + "quoteProps": "as-needed", + "requirePragma": false, + "semi": false, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "none", + "useTabs": false, + "endOfLine": "lf" +} diff --git a/babel.config.js b/babel.config.js index 296f0e02..ee3bce59 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,6 +1,4 @@ module.exports = { - presets: [ - '@vue/cli-plugin-babel/preset' - ], - plugins: ['@babel/plugin-proposal-optional-chaining'] -} + presets: ["@vue/cli-plugin-babel/preset"], + plugins: ["@babel/plugin-proposal-optional-chaining"], +}; diff --git a/package.json b/package.json index 9e424c6a..92453589 100644 --- a/package.json +++ b/package.json @@ -1,159 +1,155 @@ -{ - "name": "piclist", - "version": "2.9.0", - "author": { - "name": "Kuingsmile", - "email": "pkukuing@gmail.com" - }, - "description": "A powerful cloude storage manage tool.", - "homepage": "https://piclist.cn", - "bugs": { - "url": "https://github.com/Kuingsmile/PicList/issues", - "email": "pkukuing@gmail.com" - }, - "license": "MIT", - "private": true, - "scripts": { - "build": "vue-cli-service electron:build", - "lint": "vue-cli-service lint", - "bump": "bump-version", - "cz": "git-cz", - "dev": "vue-cli-service electron:serve", - "electron:build": "vue-cli-service electron:build", - "electron:serve": "vue-cli-service electron:serve", - "i18n": "node ./scripts/gen-i18n-types.js", - "lint:fix": "eslint --fix --ext .js,.jsx,.ts,.tsx,.vue src/", - "postinstall": "electron-builder install-app-deps", - "postuninstall": "electron-builder install-app-deps", - "release": "vue-cli-service electron:build --publish always", - "upload-dist": "node ./scripts/upload-dist-to-r2.js", - "upload-beta": "node ./scripts/upload-beta.js", - "link": "node ./scripts/link.js", - "sha256": "node ./scripts/gen-sha256.js", - "ncu": "node ./scripts/check-dep.js", - "lint:dpdm": "dpdm -T --tsconfig ./tsconfig.json --no-tree --no-warning --exit-code circular:1 src/background.ts" - }, - "dependencies": { - "@aws-sdk/client-s3": "^3.421.0", - "@aws-sdk/lib-storage": "^3.421.0", - "@aws-sdk/s3-request-presigner": "^3.421.0", - "@element-plus/icons-vue": "^2.3.1", - "@highlightjs/vue-plugin": "^2.1.2", - "@nodelib/fs.walk": "^2.0.0", - "@octokit/rest": "^19.0.7", - "@picgo/i18n": "^1.0.0", - "@picgo/store": "^2.1.0", - "@smithy/node-http-handler": "^2.1.6", - "@videojs-player/vue": "^1.0.0", - "ali-oss": "^6.18.1", - "axios": "^1.6.8", - "compare-versions": "^4.1.3", - "core-js": "^3.37.1", - "cos-nodejs-sdk-v5": "^2.12.5", - "dexie": "^3.2.4", - "electron-updater": "^6.1.4", - "element-plus": "2.7.4", - "epipebomb": "^1.0.0", - "fast-xml-parser": "^4.3.2", - "form-data": "^4.0.0", - "fs-extra": "^11.2.0", - "got": "^12.6.0", - "highlight.js": "^11.9.0", - "hpagent": "^1.2.0", - "lowdb": "^1.0.0", - "marked": "^9.1.5", - "mime-types": "^2.1.35", - "mitt": "^3.0.1", - "multer": "^1.4.5-lts.1", - "node-ssh-no-cpu-features": "^2.0.0", - "nodejs-file-downloader": "^4.12.1", - "piclist": "^1.8.10", - "pinia": "^2.1.7", - "pinia-plugin-persistedstate": "^3.2.1", - "proxy-agent": "^5.0.0", - "qiniu": "7.9.0", - "qrcode.vue": "^3.4.1", - "querystring": "^0.2.1", - "shell-path": "2.1.0", - "ssh2-no-cpu-features": "^2.0.0", - "upyun": "^3.4.6", - "uuid": "^9.0.1", - "video.js": "^8.6.1", - "vue": "^3.4.27", - "vue-router": "^4.3.2", - "vue3-lazyload": "^0.3.8", - "vue3-photo-preview": "^0.3.0", - "webdav": "^5.3.1", - "write-file-atomic": "^4.0.1" - }, - "devDependencies": { - "@types/video.js": "^7.3.58", - "@babel/plugin-proposal-optional-chaining": "^7.21.0", - "@electron/notarize": "^2.1.0", - "@types/ali-oss": "^6.16.11", - "@types/electron-devtools-installer": "^2.2.5", - "@types/fs-extra": "^11.0.4", - "@types/inquirer": "^6.5.0", - "@types/js-yaml": "^4.0.9", - "@types/lowdb": "^1.0.15", - "@types/mime-types": "^2.1.4", - "@types/multer": "^1.4.11", - "@types/node": "^16.10.2", - "@types/semver": "^7.5.6", - "@types/tunnel": "^0.0.7", - "@types/upyun": "^3.4.3", - "@types/uuid": "^9.0.8", - "@types/write-file-atomic": "^4.0.3", - "@typescript-eslint/eslint-plugin": "^6.12.0", - "@typescript-eslint/parser": "^6.12.0", - "@vue/cli-plugin-babel": "^5.0.8", - "@vue/cli-plugin-eslint": "^5.0.8", - "@vue/cli-plugin-router": "^5.0.8", - "@vue/cli-plugin-typescript": "^5.0.8", - "@vue/cli-service": "^5.0.8", - "@vue/eslint-config-standard": "^8.0.1", - "@vue/eslint-config-typescript": "^12.0.0", - "@vue/runtime-dom": "^3.4.27", - "conventional-changelog": "^5.1.0", - "cz-customizable": "^7.0.0", - "dotenv": "^16.3.1", - "dpdm": "^3.14.0", - "electron": "^22.3.27", - "eslint": "^8.54.0", - "eslint-config-standard": "^17.1.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-n": "^16.6.2", - "eslint-plugin-promise": "^6.2.0", - "eslint-plugin-vue": "^9.26.0", - "husky": "^3.1.0", - "node-bump-version": "^1.0.2", - "node-loader": "^2.0.0", - "npm-check-updates": "^16.14.20", - "stylus": "^0.59.0", - "stylus-loader": "^7.1.3", - "typescript": "^4.9.5", - "vue-cli-plugin-electron-builder": "^3.0.0-alpha.4" - }, - "commitlint": { - "extends": [ - "./node_modules/node-bump-version/commitlint-node" - ] - }, - "config": { - "commitizen": { - "path": "./node_modules/cz-customizable" - }, - "cz-customizable": { - "config": "./node_modules/node-bump-version/.cz-config.js" - } - }, - "husky": { - "hooks": { - "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" - } - }, - "resolutions": { - "@types/node": "^16.10.2", - "vue-cli-plugin-electron-builder/**/electron-builder": "23.3.3" - } -} +{ + "name": "piclist", + "version": "2.9.0", + "author": { + "name": "Kuingsmile", + "email": "pkukuing@gmail.com" + }, + "description": "A powerful cloude storage manage tool.", + "homepage": "https://piclist.cn", + "bugs": { + "url": "https://github.com/Kuingsmile/PicList/issues", + "email": "pkukuing@gmail.com" + }, + "license": "MIT", + "private": true, + "scripts": { + "build": "vue-cli-service electron:build", + "lint": "vue-cli-service lint", + "bump": "bump-version", + "cz": "git-cz", + "dev": "vue-cli-service electron:serve", + "electron:build": "vue-cli-service electron:build", + "electron:serve": "vue-cli-service electron:serve", + "i18n": "node ./scripts/gen-i18n-types.js", + "lint:fix": "eslint --fix --ext .js,.jsx,.ts,.tsx,.vue src/", + "postinstall": "electron-builder install-app-deps", + "postuninstall": "electron-builder install-app-deps", + "release": "vue-cli-service electron:build --publish always", + "upload-dist": "node ./scripts/upload-dist-to-r2.js", + "upload-beta": "node ./scripts/upload-beta.js", + "link": "node ./scripts/link.js", + "sha256": "node ./scripts/gen-sha256.js", + "ncu": "node ./scripts/check-dep.js", + "lint:dpdm": "dpdm -T --tsconfig ./tsconfig.json --no-tree --no-warning --exit-code circular:1 src/background.ts" + }, + "dependencies": { + "@aws-sdk/client-s3": "^3.421.0", + "@aws-sdk/lib-storage": "^3.421.0", + "@aws-sdk/s3-request-presigner": "^3.421.0", + "@element-plus/icons-vue": "^2.3.1", + "@highlightjs/vue-plugin": "^2.1.2", + "@nodelib/fs.walk": "^2.0.0", + "@octokit/rest": "^19.0.7", + "@picgo/i18n": "^1.0.0", + "@picgo/store": "^2.1.0", + "@smithy/node-http-handler": "^2.1.6", + "@videojs-player/vue": "^1.0.0", + "ali-oss": "^6.18.1", + "axios": "^1.6.8", + "compare-versions": "^4.1.3", + "core-js": "^3.37.1", + "cos-nodejs-sdk-v5": "^2.12.5", + "dexie": "^3.2.4", + "electron-updater": "^6.1.4", + "element-plus": "2.7.4", + "epipebomb": "^1.0.0", + "fast-xml-parser": "^4.3.2", + "form-data": "^4.0.0", + "fs-extra": "^11.2.0", + "got": "^12.6.0", + "highlight.js": "^11.9.0", + "hpagent": "^1.2.0", + "lowdb": "^1.0.0", + "marked": "^9.1.5", + "mime-types": "^2.1.35", + "mitt": "^3.0.1", + "multer": "^1.4.5-lts.1", + "node-ssh-no-cpu-features": "^2.0.0", + "nodejs-file-downloader": "^4.12.1", + "piclist": "^1.8.10", + "pinia": "^2.1.7", + "pinia-plugin-persistedstate": "^3.2.1", + "proxy-agent": "^5.0.0", + "qiniu": "7.9.0", + "qrcode.vue": "^3.4.1", + "querystring": "^0.2.1", + "shell-path": "2.1.0", + "ssh2-no-cpu-features": "^2.0.0", + "upyun": "^3.4.6", + "uuid": "^9.0.1", + "video.js": "^8.6.1", + "vue": "^3.4.27", + "vue-router": "^4.3.2", + "vue3-lazyload": "^0.3.8", + "vue3-photo-preview": "^0.3.0", + "webdav": "^5.3.1", + "write-file-atomic": "^4.0.1" + }, + "devDependencies": { + "@babel/plugin-proposal-optional-chaining": "^7.21.0", + "@electron/notarize": "^2.1.0", + "@types/ali-oss": "^6.16.11", + "@types/electron-devtools-installer": "^2.2.5", + "@types/fs-extra": "^11.0.4", + "@types/inquirer": "^6.5.0", + "@types/js-yaml": "^4.0.9", + "@types/lowdb": "^1.0.15", + "@types/mime-types": "^2.1.4", + "@types/multer": "^1.4.11", + "@types/node": "^16.10.2", + "@types/semver": "^7.5.6", + "@types/tunnel": "^0.0.7", + "@types/upyun": "^3.4.3", + "@types/uuid": "^9.0.8", + "@types/video.js": "^7.3.58", + "@types/write-file-atomic": "^4.0.3", + "@vue/cli-plugin-babel": "^5.0.8", + "@vue/cli-plugin-eslint": "^5.0.8", + "@vue/cli-plugin-router": "^5.0.8", + "@vue/cli-plugin-typescript": "^5.0.8", + "@vue/cli-service": "^5.0.8", + "@vue/eslint-config-prettier": "^9.0.0", + "@vue/eslint-config-standard": "^8.0.1", + "@vue/eslint-config-typescript": "^12.0.0", + "@vue/runtime-dom": "^3.4.27", + "conventional-changelog": "^5.1.0", + "cz-customizable": "^7.0.0", + "dotenv": "^16.3.1", + "dpdm": "^3.14.0", + "electron": "^22.3.27", + "eslint": "^8.57.0", + "eslint-plugin-vue": "^9.26.0", + "husky": "^3.1.0", + "node-bump-version": "^1.0.2", + "node-loader": "^2.0.0", + "npm-check-updates": "^16.14.20", + "prettier": "^3.3.2", + "stylus": "^0.59.0", + "stylus-loader": "^7.1.3", + "typescript": "^4.9.5", + "vue-cli-plugin-electron-builder": "^3.0.0-alpha.4" + }, + "commitlint": { + "extends": [ + "./node_modules/node-bump-version/commitlint-node" + ] + }, + "config": { + "commitizen": { + "path": "./node_modules/cz-customizable" + }, + "cz-customizable": { + "config": "./node_modules/node-bump-version/.cz-config.js" + } + }, + "husky": { + "hooks": { + "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" + } + }, + "resolutions": { + "@types/node": "^16.10.2", + "vue-cli-plugin-electron-builder/**/electron-builder": "23.3.3" + } +} diff --git a/postcss.config.js b/postcss.config.js index 961986e2..a47ef4f9 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,5 +1,5 @@ module.exports = { plugins: { - autoprefixer: {} - } -} + autoprefixer: {}, + }, +}; diff --git a/src/main/apis/app/remoteNotice/index.ts b/src/main/apis/app/remoteNotice/index.ts index ab6ba2f6..1076f1ea 100644 --- a/src/main/apis/app/remoteNotice/index.ts +++ b/src/main/apis/app/remoteNotice/index.ts @@ -1,21 +1,12 @@ import axios from 'axios' -import { - app, - clipboard, - dialog, - shell -} from 'electron' +import { app, clipboard, dialog, shell } from 'electron' import fs from 'fs-extra' import path from 'path' import { gte, lte } from 'semver' import windowManager from 'apis/app/window/windowManager' import { showNotification } from '~/utils/common' -import { - IRemoteNoticeActionType, - IRemoteNoticeTriggerCount, - IRemoteNoticeTriggerHook -} from '#/types/enum' +import { IRemoteNoticeActionType, IRemoteNoticeTriggerCount, IRemoteNoticeTriggerHook } from '#/types/enum' // for test const REMOTE_NOTICE_URL = 'https://release.piclist.cn/remote-notice.json' @@ -30,38 +21,41 @@ class RemoteNoticeHandler { private remoteNotice: IRemoteNotice | null = null private remoteNoticeLocalCountStorage: IRemoteNoticeLocalCountStorage | null = null - async init () { + async init() { this.remoteNotice = await this.getRemoteNoticeInfo() this.initLocalCountStorage() } - private initLocalCountStorage () { + private initLocalCountStorage() { const localCountStorage = {} if (!fs.existsSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH)) { fs.writeFileSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH, JSON.stringify({})) } try { - 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 } catch (e) { this.remoteNoticeLocalCountStorage = localCountStorage } } - private saveLocalCountStorage (newData?: IRemoteNoticeLocalCountStorage) { + private saveLocalCountStorage(newData?: IRemoteNoticeLocalCountStorage) { if (newData) { this.remoteNoticeLocalCountStorage = newData } fs.writeFileSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH, JSON.stringify(this.remoteNoticeLocalCountStorage)) } - private async getRemoteNoticeInfo (): Promise { + private async getRemoteNoticeInfo(): Promise { try { - const noticeInfo = await axios({ + const noticeInfo = (await axios({ method: 'get', url: REMOTE_NOTICE_URL, responseType: 'json' - }).then(res => res.data) as IRemoteNotice + }).then(res => res.data)) as IRemoteNotice return noticeInfo } catch { return null @@ -72,7 +66,7 @@ class RemoteNoticeHandler { * if the notice is not shown or is always shown, then show the notice * @param action */ - private checkActionCount (action: IRemoteNoticeAction) { + private checkActionCount(action: IRemoteNoticeAction) { try { if (!this.remoteNoticeLocalCountStorage) { return true @@ -106,7 +100,7 @@ class RemoteNoticeHandler { } } - private async doActions (actions: IRemoteNoticeAction[]) { + private async doActions(actions: IRemoteNoticeAction[]) { for (const action of actions) { if (this.checkActionCount(action)) { switch (action.type) { @@ -121,7 +115,7 @@ class RemoteNoticeHandler { body: action.data?.content || '', clickToCopy: !!action.data?.copyToClipboard, copyContent: action.data?.copyToClipboard || '', - clickFn () { + clickFn() { if (action.data?.url) { shell.openExternal(action.data.url) } @@ -129,11 +123,11 @@ class RemoteNoticeHandler { }) break case IRemoteNoticeActionType.OPEN_URL: - // OPEN URL + // OPEN URL shell.openExternal(action.data?.url || '') break case IRemoteNoticeActionType.COMMON: - // DO COMMON CASE + // DO COMMON CASE if (action.data?.copyToClipboard) { clipboard.writeText(action.data.copyToClipboard) } @@ -143,21 +137,23 @@ class RemoteNoticeHandler { break case IRemoteNoticeActionType.SHOW_MESSAGE_BOX: { const currentWindow = windowManager.getAvailableWindow() - dialog.showMessageBox(currentWindow, { - title: action.data?.title || '', - message: action.data?.content || '', - type: 'info', - buttons: action.data?.buttons?.map(item => item.label) || ['Yes'] - }).then(res => { - const button = action.data?.buttons?.[res.response] - if (button?.type === 'cancel') { - // do nothing - } else { - if (button?.action) { - this.doActions([button?.action]) + dialog + .showMessageBox(currentWindow, { + title: action.data?.title || '', + message: action.data?.content || '', + type: 'info', + buttons: action.data?.buttons?.map(item => item.label) || ['Yes'] + }) + .then(res => { + const button = action.data?.buttons?.[res.response] + if (button?.type === 'cancel') { + // do nothing + } else { + if (button?.action) { + this.doActions([button?.action]) + } } - } - }) + }) break } } @@ -165,7 +161,7 @@ class RemoteNoticeHandler { } } - triggerHook (hook: IRemoteNoticeTriggerHook) { + triggerHook(hook: IRemoteNoticeTriggerHook) { if (!this.remoteNotice || !this.remoteNotice.list) { return } @@ -198,6 +194,4 @@ class RemoteNoticeHandler { const remoteNoticeHandler = new RemoteNoticeHandler() -export { - remoteNoticeHandler -} +export { remoteNoticeHandler } diff --git a/src/main/apis/app/shortKey/shortKeyHandler.ts b/src/main/apis/app/shortKey/shortKeyHandler.ts index 25c983e6..d8b01bdf 100644 --- a/src/main/apis/app/shortKey/shortKeyHandler.ts +++ b/src/main/apis/app/shortKey/shortKeyHandler.ts @@ -1,7 +1,4 @@ - -import { - globalShortcut -} from 'electron' +import { globalShortcut } from 'electron' import shortKeyService from 'apis/app/shortKey/shortKeyService' import GuiApi from 'apis/gui' @@ -16,18 +13,18 @@ import { configPaths } from '#/utils/configPaths' class ShortKeyHandler { private isInModifiedMode: boolean = false - constructor () { + constructor() { bus.on(TOGGLE_SHORTKEY_MODIFIED_MODE, flag => { this.isInModifiedMode = flag }) } - init () { + init() { this.initBuiltInShortKey() this.initPluginsShortKey() } - private initBuiltInShortKey () { + private initBuiltInShortKey() { const commands = db.get(configPaths.settings.shortKey._path) as IShortKeyConfigs Object.keys(commands) .filter(item => item.includes('picgo:')) @@ -42,7 +39,7 @@ class ShortKeyHandler { }) } - private initPluginsShortKey () { + private initPluginsShortKey() { // get enabled plugin const pluginList = picgo.pluginLoader.getList() for (const item of pluginList) { @@ -72,7 +69,12 @@ class ShortKeyHandler { } } - private registerShortKey (config: IShortKeyConfig | IPluginShortKeyConfig, command: string, handler: IShortKeyHandler, writeFlag: boolean) { + private registerShortKey( + config: IShortKeyConfig | IPluginShortKeyConfig, + command: string, + handler: IShortKeyHandler, + writeFlag: boolean + ) { shortKeyService.registerCommand(command, handler) if (config.key) { globalShortcut.register(config.key, () => { @@ -96,7 +98,7 @@ class ShortKeyHandler { } // enable or disable shortKey - bindOrUnbindShortKey (item: IShortKeyConfig, from: string): boolean { + bindOrUnbindShortKey(item: IShortKeyConfig, from: string): boolean { const command = `${from}:${item.name}` if (item.enable === false) { globalShortcut.unregister(item.key) @@ -120,7 +122,7 @@ class ShortKeyHandler { } // update shortKey bindings - updateShortKey (item: IShortKeyConfig, oldKey: string, from: string): boolean { + updateShortKey(item: IShortKeyConfig, oldKey: string, from: string): boolean { const command = `${from}:${item.name}` if (globalShortcut.isRegistered(item.key)) return false globalShortcut.unregister(oldKey) @@ -133,7 +135,7 @@ class ShortKeyHandler { return true } - private async handler (command: string) { + private async handler(command: string) { if (this.isInModifiedMode) { return } @@ -149,7 +151,7 @@ class ShortKeyHandler { } } - registerPluginShortKey (pluginName: string) { + registerPluginShortKey(pluginName: string) { const plugin = picgo.pluginLoader.getPlugin(pluginName) if (plugin && plugin.commands) { if (typeof plugin.commands !== 'function') { @@ -169,7 +171,7 @@ class ShortKeyHandler { } } - unregisterPluginShortKey (pluginName: string) { + unregisterPluginShortKey(pluginName: string) { const commands = db.get(configPaths.settings.shortKey._path) as IShortKeyConfigs const keyList = Object.keys(commands) .filter(command => command.includes(pluginName)) diff --git a/src/main/apis/app/shortKey/shortKeyService.ts b/src/main/apis/app/shortKey/shortKeyService.ts index c1e2b6cb..0edfe8b6 100644 --- a/src/main/apis/app/shortKey/shortKeyService.ts +++ b/src/main/apis/app/shortKey/shortKeyService.ts @@ -2,22 +2,22 @@ import logger from '@core/picgo/logger' class ShortKeyService { private commandList: Map = new Map() - registerCommand (command: string, handler: IShortKeyHandler) { + registerCommand(command: string, handler: IShortKeyHandler) { this.commandList.set(command, handler) } - unregisterCommand (command: string) { + unregisterCommand(command: string) { this.commandList.delete(command) } - getShortKeyHandler (command: string): IShortKeyHandler | null { + getShortKeyHandler(command: string): IShortKeyHandler | null { const handler = this.commandList.get(command) if (handler) return handler logger.warn(`cannot find command: ${command}`) return null } - getCommandList () { + getCommandList() { return [...this.commandList.keys()] } } diff --git a/src/main/apis/app/system/index.ts b/src/main/apis/app/system/index.ts index f315bac6..5454f718 100644 --- a/src/main/apis/app/system/index.ts +++ b/src/main/apis/app/system/index.ts @@ -34,7 +34,7 @@ import { hideMiniWindow, openMainWindow, openMiniWindow } from '~/utils/windowHe let contextMenu: Menu | null -export function setDockMenu () { +export function setDockMenu() { const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false const dockMenu = Menu.buildFromTemplate([ { @@ -43,7 +43,7 @@ export function setDockMenu () { }, { label: T('START_WATCH_CLIPBOARD'), - click () { + click() { db.set(configPaths.settings.isListeningClipboard, true) clipboardPoll.startListening() clipboardPoll.on('change', () => { @@ -56,7 +56,7 @@ export function setDockMenu () { }, { label: T('STOP_WATCH_CLIPBOARD'), - click () { + click() { db.set(configPaths.settings.isListeningClipboard, false) clipboardPoll.stopListening() clipboardPoll.removeAllListeners() @@ -68,14 +68,20 @@ export function setDockMenu () { app.dock.setMenu(dockMenu) } -export function createMenu () { +export function createMenu() { const submenu = buildPicBedListMenu() const appMenu = Menu.buildFromTemplate([ { label: 'PicList', submenu: [ { label: T('OPEN_MAIN_WINDOW'), click: openMainWindow }, - { label: T('RELOAD_APP'), click () { app.relaunch(); app.exit(0) } } + { + label: T('RELOAD_APP'), + click() { + app.relaunch() + app.exit(0) + } + } ] }, { label: T('CHOOSE_DEFAULT_PICBED'), type: 'submenu', submenu }, @@ -93,18 +99,17 @@ export function createMenu () { }, { label: T('QUIT'), - submenu: [ - { label: T('QUIT'), role: 'quit' } - ] + submenu: [{ label: T('QUIT'), role: 'quit' }] } ]) Menu.setApplicationMenu(appMenu) } -export function createContextMenu () { +export function createContextMenu() { const ClipboardWatcher = clipboardPoll const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false - const isMiniWindowVisible = windowManager.has(IWindowList.MINI_WINDOW) && windowManager.get(IWindowList.MINI_WINDOW)!.isVisible() + const isMiniWindowVisible = + windowManager.has(IWindowList.MINI_WINDOW) && windowManager.get(IWindowList.MINI_WINDOW)!.isVisible() const startWatchClipboard = () => { db.set(configPaths.settings.isListeningClipboard, true) @@ -125,18 +130,44 @@ export function createContextMenu () { if (process.platform === 'darwin' || process.platform === 'win32') { const submenu = buildPicBedListMenu() - const template: Array<(MenuItemConstructorOptions) | (MenuItem)> = [ + const template: Array = [ { label: T('OPEN_MAIN_WINDOW'), click: openMainWindow }, { label: T('CHOOSE_DEFAULT_PICBED'), type: 'submenu', submenu }, - { label: T('START_WATCH_CLIPBOARD'), click: startWatchClipboard, visible: !isListeningClipboard }, - { label: T('STOP_WATCH_CLIPBOARD'), click: stopWatchClipboard, visible: isListeningClipboard }, - { label: T('RELOAD_APP'), click () { app.relaunch(); app.exit(0) } }, + { + label: T('START_WATCH_CLIPBOARD'), + click: startWatchClipboard, + visible: !isListeningClipboard + }, + { + label: T('STOP_WATCH_CLIPBOARD'), + click: stopWatchClipboard, + visible: isListeningClipboard + }, + { + label: T('RELOAD_APP'), + click() { + app.relaunch() + app.exit(0) + } + }, { label: T('QUIT'), role: 'quit' } ] if (process.platform === 'win32') { - template.splice(2, 0, - { label: T('OPEN_MINI_WINDOW'), click () { openMiniWindow(false) }, visible: !isMiniWindowVisible }, - { label: T('HIDE_MINI_WINDOW'), click: hideMiniWindow, visible: isMiniWindowVisible } + template.splice( + 2, + 0, + { + label: T('OPEN_MINI_WINDOW'), + click() { + openMiniWindow(false) + }, + visible: !isMiniWindowVisible + }, + { + label: T('HIDE_MINI_WINDOW'), + click: hideMiniWindow, + visible: isMiniWindowVisible + } ) } contextMenu = Menu.buildFromTemplate(template) @@ -150,13 +181,31 @@ export function createContextMenu () { contextMenu = Menu.buildFromTemplate([ { label: T('OPEN_MAIN_WINDOW'), click: openMainWindow }, - { label: T('OPEN_MINI_WINDOW'), click () { openMiniWindow(false) }, visible: !isMiniWindowVisible }, - { label: T('HIDE_MINI_WINDOW'), click: hideMiniWindow, visible: isMiniWindowVisible }, - { label: T('START_WATCH_CLIPBOARD'), click: startWatchClipboard, visible: !isListeningClipboard }, - { label: T('STOP_WATCH_CLIPBOARD'), click: stopWatchClipboard, visible: isListeningClipboard }, + { + label: T('OPEN_MINI_WINDOW'), + click() { + openMiniWindow(false) + }, + visible: !isMiniWindowVisible + }, + { + label: T('HIDE_MINI_WINDOW'), + click: hideMiniWindow, + visible: isMiniWindowVisible + }, + { + label: T('START_WATCH_CLIPBOARD'), + click: startWatchClipboard, + visible: !isListeningClipboard + }, + { + label: T('STOP_WATCH_CLIPBOARD'), + click: stopWatchClipboard, + visible: isListeningClipboard + }, { label: T('ABOUT'), - click () { + click() { dialog.showMessageBox({ title: 'PicList', message: 'PicList', @@ -179,7 +228,7 @@ const getTrayIcon = () => { } } -export function createTray (tooltip: string) { +export function createTray(tooltip: string) { const menubarPic = getTrayIcon() setTray(new Tray(menubarPic)) tray.setToolTip(tooltip) @@ -260,9 +309,7 @@ export function createTray (tooltip: string) { const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN const rawInput = cloneDeep(files) const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)! - const imgs = await uploader - .setWebContents(trayWindow.webContents) - .upload(files) + const imgs = await uploader.setWebContents(trayWindow.webContents).upload(files) const deleteLocalFile = db.get(configPaths.settings.deleteLocalFile) || false if (imgs !== false) { const pasteText: string[] = [] @@ -270,8 +317,11 @@ export function createTray (tooltip: string) { if (deleteLocalFile) { await fs.remove(rawInput[i]) } - pasteText.push(await (pasteTemplate(pasteStyle, imgs[i], db.get(configPaths.settings.customLink)))) - const isShowResultNotification = db.get(configPaths.settings.uploadResultNotification) === undefined ? true : !!db.get(configPaths.settings.uploadResultNotification) + pasteText.push(await pasteTemplate(pasteStyle, imgs[i], db.get(configPaths.settings.customLink))) + const isShowResultNotification = + db.get(configPaths.settings.uploadResultNotification) === undefined + ? true + : !!db.get(configPaths.settings.uploadResultNotification) if (isShowResultNotification) { const notification = new Notification({ title: T('UPLOAD_SUCCEED'), @@ -290,8 +340,8 @@ export function createTray (tooltip: string) { }) // toggleWindow() } else if (process.platform === 'linux') { - // click事件在Ubuntu上无法触发,Unity不支持(在Mac和Windows上可以触发) - // 需要使用 setContextMenu 设置菜单 + // click事件在Ubuntu上无法触发,Unity不支持(在Mac和Windows上可以触发) + // 需要使用 setContextMenu 设置菜单 createContextMenu() tray!.setContextMenu(contextMenu) } diff --git a/src/main/apis/app/uploader/apis.ts b/src/main/apis/app/uploader/apis.ts index d24f3cbc..a8a4ac8b 100644 --- a/src/main/apis/app/uploader/apis.ts +++ b/src/main/apis/app/uploader/apis.ts @@ -1,7 +1,4 @@ -import { - Notification, - WebContents -} from 'electron' +import { Notification, WebContents } from 'electron' import fs from 'fs-extra' import { cloneDeep } from 'lodash' @@ -19,7 +16,10 @@ import { IPasteStyle, IWindowList } from '#/types/enum' import { configPaths } from '#/utils/configPaths' const handleClipboardUploading = async (): Promise => { - const useBuiltinClipboard = db.get(configPaths.settings.useBuiltinClipboard) === undefined ? true : !!db.get(configPaths.settings.useBuiltinClipboard) + const useBuiltinClipboard = + db.get(configPaths.settings.useBuiltinClipboard) === undefined + ? true + : !!db.get(configPaths.settings.useBuiltinClipboard) const win = windowManager.getAvailableWindow() if (useBuiltinClipboard) { return await uploader.setWebContents(win!.webContents).uploadWithBuildInClipboard() @@ -33,8 +33,11 @@ export const uploadClipboardFiles = async (): Promise => { if (img.length > 0) { const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW) const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN - handleCopyUrl(await (pasteTemplate(pasteStyle, img[0], db.get(configPaths.settings.customLink)))) - const isShowResultNotification = db.get(configPaths.settings.uploadResultNotification) === undefined ? true : !!db.get(configPaths.settings.uploadResultNotification) + handleCopyUrl(await pasteTemplate(pasteStyle, img[0], db.get(configPaths.settings.customLink))) + const isShowResultNotification = + db.get(configPaths.settings.uploadResultNotification) === undefined + ? true + : !!db.get(configPaths.settings.uploadResultNotification) if (isShowResultNotification) { const notification = new Notification({ title: T('UPLOAD_SUCCEED'), @@ -75,7 +78,10 @@ export const uploadClipboardFiles = async (): Promise => { } } -export const uploadChoosedFiles = async (webContents: WebContents, files: IFileWithPath[]): Promise => { +export const uploadChoosedFiles = async ( + webContents: WebContents, + files: IFileWithPath[] +): Promise => { const input = files.map(item => item.path) const rawInput = cloneDeep(input) const imgs = await uploader.setWebContents(webContents).upload(input) @@ -86,14 +92,19 @@ export const uploadChoosedFiles = async (webContents: WebContents, files: IFileW const pasteText: string[] = [] for (let i = 0; i < imgs.length; i++) { if (deleteLocalFile) { - fs.remove(rawInput[i]).then(() => { - picgo.log.info(`delete local file: ${rawInput[i]}`) - }).catch((err: Error) => { - picgo.log.error(err) - }) + fs.remove(rawInput[i]) + .then(() => { + picgo.log.info(`delete local file: ${rawInput[i]}`) + }) + .catch((err: Error) => { + picgo.log.error(err) + }) } - pasteText.push(await (pasteTemplate(pasteStyle, imgs[i], db.get(configPaths.settings.customLink)))) - const isShowResultNotification = db.get(configPaths.settings.uploadResultNotification) === undefined ? true : !!db.get(configPaths.settings.uploadResultNotification) + pasteText.push(await pasteTemplate(pasteStyle, imgs[i], db.get(configPaths.settings.customLink))) + const isShowResultNotification = + db.get(configPaths.settings.uploadResultNotification) === undefined + ? true + : !!db.get(configPaths.settings.uploadResultNotification) if (isShowResultNotification) { const notification = new Notification({ title: T('UPLOAD_SUCCEED'), diff --git a/src/main/apis/app/uploader/index.ts b/src/main/apis/app/uploader/index.ts index 845c8448..103ff1fb 100644 --- a/src/main/apis/app/uploader/index.ts +++ b/src/main/apis/app/uploader/index.ts @@ -1,11 +1,5 @@ import dayjs from 'dayjs' -import { - BrowserWindow, - clipboard, - ipcMain, - Notification, - WebContents -} from 'electron' +import { BrowserWindow, clipboard, ipcMain, Notification, WebContents } from 'electron' import fs from 'fs-extra' import util from 'util' import path from 'path' @@ -21,17 +15,13 @@ import logger from '@core/picgo/logger' import { T } from '~/i18n' import { showNotification, getClipboardFilePath, calcDurationRange } from '~/utils/common' -import { - GET_RENAME_FILE_NAME, - RENAME_FILE_NAME, - TALKING_DATA_EVENT -} from '#/events/constants' +import { GET_RENAME_FILE_NAME, RENAME_FILE_NAME, TALKING_DATA_EVENT } from '#/events/constants' import { ICOREBuildInEvent, IWindowList } from '#/types/enum' import { configPaths } from '#/utils/configPaths' import { CLIPBOARD_IMAGE_FOLDER } from '#/utils/static' -const waitForRename = (window: BrowserWindow, id: number): Promise => { - return new Promise((resolve) => { +const waitForRename = (window: BrowserWindow, id: number): Promise => { + return new Promise(resolve => { const windowId = window.id ipcMain.once(`${RENAME_FILE_NAME}${id}`, (_: Event, newName: string) => { resolve(newName) @@ -62,11 +52,11 @@ const handleTalkingData = (webContents: WebContents, options: IAnalyticsData) => class Uploader { private webContents: WebContents | null = null - constructor () { + constructor() { this.init() } - init () { + init() { picgo.on(ICOREBuildInEvent.NOTIFICATION, (message: Electron.NotificationConstructorOptions | undefined) => { const notification = new Notification(message) notification.show() @@ -91,37 +81,39 @@ class Uploader { const rename = db.get(configPaths.settings.rename) const autoRename = db.get(configPaths.settings.autoRename) if (autoRename || rename) { - await Promise.all(ctx.output.map(async (item, index) => { - let name: undefined | string | null - let fileName: string | undefined - if (autoRename) { - fileName = dayjs().add(index, 'ms').format('YYYYMMDDHHmmSSS') + item.extname - } else { - fileName = item.fileName - } - if (rename) { - const window = windowManager.create(IWindowList.RENAME_WINDOW)! - logger.info('create rename window') - ipcMain.on(GET_RENAME_FILE_NAME, (evt) => { - try { - if (evt.sender.id === window.webContents.id) { - logger.info('rename window ready, wait for rename...') - window.webContents.send(RENAME_FILE_NAME, fileName, item.fileName, window.webContents.id) + await Promise.all( + ctx.output.map(async (item, index) => { + let name: undefined | string | null + let fileName: string | undefined + if (autoRename) { + fileName = dayjs().add(index, 'ms').format('YYYYMMDDHHmmSSS') + item.extname + } else { + fileName = item.fileName + } + if (rename) { + const window = windowManager.create(IWindowList.RENAME_WINDOW)! + logger.info('create rename window') + ipcMain.on(GET_RENAME_FILE_NAME, evt => { + try { + if (evt.sender.id === window.webContents.id) { + logger.info('rename window ready, wait for rename...') + window.webContents.send(RENAME_FILE_NAME, fileName, item.fileName, window.webContents.id) + } + } catch (e: any) { + logger.error(e) } - } catch (e: any) { - logger.error(e) - } - }) - name = await waitForRename(window, window.webContents.id) - } - item.fileName = name || fileName - })) + }) + name = await waitForRename(window, window.webContents.id) + } + item.fileName = name || fileName + }) + ) } } }) } - setWebContents (webContents: WebContents) { + setWebContents(webContents: WebContents) { this.webContents = webContents return this } @@ -129,7 +121,7 @@ class Uploader { /** * use electron's clipboard image to upload */ - async uploadWithBuildInClipboard (): Promise { + async uploadWithBuildInClipboard(): Promise { let filePath = '' try { const imgPath = getClipboardFilePath() @@ -157,7 +149,7 @@ class Uploader { } } - async upload (img?: IUploadOption): Promise { + async upload(img?: IUploadOption): Promise { try { const startTime = Date.now() const output = await picgo.upload(img) diff --git a/src/main/apis/app/window/constants.ts b/src/main/apis/app/window/constants.ts index 913d3fe3..a9f3acab 100644 --- a/src/main/apis/app/window/constants.ts +++ b/src/main/apis/app/window/constants.ts @@ -1,25 +1,26 @@ const isDevelopment = process.env.NODE_ENV !== 'production' -export const MANUAL_WINDOW_URL = process.env.NODE_ENV === 'development' - ? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#documents` - : 'picgo://./index.html#documents' +export const MANUAL_WINDOW_URL = + process.env.NODE_ENV === 'development' + ? `${process.env.WEBPACK_DEV_SERVER_URL as string}#documents` + : 'picgo://./index.html#documents' export const MINI_WINDOW_URL = isDevelopment - ? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#mini-page` + ? `${process.env.WEBPACK_DEV_SERVER_URL as string}#mini-page` : 'picgo://./index.html#mini-page' -export const RENAME_WINDOW_URL = process.env.NODE_ENV === 'development' - ? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#rename-page` - : 'picgo://./index.html#rename-page' +export const RENAME_WINDOW_URL = + process.env.NODE_ENV === 'development' + ? `${process.env.WEBPACK_DEV_SERVER_URL as string}#rename-page` + : 'picgo://./index.html#rename-page' export const SETTING_WINDOW_URL = isDevelopment - ? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#main-page/upload` + ? `${process.env.WEBPACK_DEV_SERVER_URL as string}#main-page/upload` : 'picgo://./index.html#main-page/upload' -export const TRAY_WINDOW_URL = isDevelopment - ? (process.env.WEBPACK_DEV_SERVER_URL as string) - : 'picgo://./index.html' +export const TRAY_WINDOW_URL = isDevelopment ? (process.env.WEBPACK_DEV_SERVER_URL as string) : 'picgo://./index.html' -export const TOOLBOX_WINDOW_URL = process.env.NODE_ENV === 'development' - ? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#toolbox-page` - : 'picgo://./index.html#toolbox-page' +export const TOOLBOX_WINDOW_URL = + process.env.NODE_ENV === 'development' + ? `${process.env.WEBPACK_DEV_SERVER_URL as string}#toolbox-page` + : 'picgo://./index.html#toolbox-page' diff --git a/src/main/apis/app/window/windowList.ts b/src/main/apis/app/window/windowList.ts index 20a15b86..0072c8f9 100644 --- a/src/main/apis/app/window/windowList.ts +++ b/src/main/apis/app/window/windowList.ts @@ -23,8 +23,11 @@ const windowList = new Map() const handleWindowParams = (windowURL: string) => windowURL -const getDefaultWindowSizes = (): { width: number, height: number } => { - const [mainWindowWidth, mainWindowHeight] = db.get([configPaths.settings.mainWindowWidth, configPaths.settings.mainWindowHeight]) +const getDefaultWindowSizes = (): { width: number; height: number } => { + const [mainWindowWidth, mainWindowHeight] = db.get([ + configPaths.settings.mainWindowWidth, + configPaths.settings.mainWindowHeight + ]) return { width: mainWindowWidth || 1200, height: mainWindowHeight || 800 @@ -176,7 +179,7 @@ windowList.set(IWindowList.TRAY_WINDOW, { isValid: process.platform !== 'linux', multiple: false, options: () => trayWindowOptions, - callback (window) { + callback(window) { window.loadURL(handleWindowParams(TRAY_WINDOW_URL)) window.on('blur', () => { window.hide() @@ -188,7 +191,7 @@ windowList.set(IWindowList.MANUAL_WINDOW, { isValid: true, multiple: false, options: () => manualWindowOptions, - callback (window) { + callback(window) { window.loadURL(handleWindowParams(MANUAL_WINDOW_URL)) window.focus() } @@ -198,7 +201,7 @@ windowList.set(IWindowList.SETTING_WINDOW, { isValid: true, multiple: false, options: () => settingWindowOptions, - callback (window, windowManager) { + callback(window, windowManager) { window.loadURL(handleWindowParams(SETTING_WINDOW_URL)) window.on('closed', () => { bus.emit(TOGGLE_SHORTKEY_MODIFIED_MODE, false) @@ -217,7 +220,7 @@ windowList.set(IWindowList.MINI_WINDOW, { isValid: process.platform !== 'darwin', multiple: false, options: () => miniWindowOptions, - callback (window) { + callback(window) { window.loadURL(handleWindowParams(MINI_WINDOW_URL)) } }) @@ -226,18 +229,19 @@ windowList.set(IWindowList.RENAME_WINDOW, { isValid: true, multiple: true, options: () => renameWindowOptions, - async callback (window, windowManager) { + async callback(window, windowManager) { window.loadURL(handleWindowParams(RENAME_WINDOW_URL)) const currentWindow = windowManager.getAvailableWindow(true) if (currentWindow && currentWindow.isVisible()) { - // bounds: { x: 821, y: 75, width: 800, height: 450 } + // bounds: { x: 821, y: 75, width: 800, height: 450 } const bounds = currentWindow.getBounds() const positionX = bounds.x + bounds.width / 2 - 150 let positionY // if is the settingWindow if (bounds.height > 400) { positionY = bounds.y + bounds.height / 2 - 88 - } else { // if is the miniWindow + } else { + // if is the miniWindow positionY = bounds.y + bounds.height / 2 } window.setPosition(positionX, positionY, false) @@ -249,7 +253,7 @@ windowList.set(IWindowList.TOOLBOX_WINDOW, { isValid: true, multiple: false, options: () => toolboxWindowOptions, - async callback (window, windowManager) { + async callback(window, windowManager) { window.loadURL(TOOLBOX_WINDOW_URL) const currentWindow = windowManager.getAvailableWindow(true) if (currentWindow && currentWindow.isVisible()) { diff --git a/src/main/apis/app/window/windowManager.ts b/src/main/apis/app/window/windowManager.ts index 496ee50d..0ec2cc0f 100644 --- a/src/main/apis/app/window/windowManager.ts +++ b/src/main/apis/app/window/windowManager.ts @@ -7,7 +7,7 @@ class WindowManager implements IWindowManager { #windowMap: Map = new Map() #windowIdMap: Map = new Map() - create (name: IWindowList) { + create(name: IWindowList) { const windowConfig: IWindowListItem = windowList.get(name)! if (windowConfig.isValid) { if (!windowConfig.multiple) { @@ -32,7 +32,7 @@ class WindowManager implements IWindowManager { } } - get (name: IWindowList) { + get(name: IWindowList) { if (this.has(name)) { return this.#windowMap.get(name)! } else { @@ -41,7 +41,7 @@ class WindowManager implements IWindowManager { } } - has (name: IWindowList) { + has(name: IWindowList) { return this.#windowMap.has(name) } @@ -53,7 +53,7 @@ class WindowManager implements IWindowManager { } } - getAvailableWindow (isSkipMiniWindow = false) { + getAvailableWindow(isSkipMiniWindow = false) { const miniWindow = this.#windowMap.get(IWindowList.MINI_WINDOW) if (miniWindow && miniWindow.isVisible() && !isSkipMiniWindow) { return miniWindow diff --git a/src/main/apis/core/bus/apis.ts b/src/main/apis/core/bus/apis.ts index 76e7501b..f92c3940 100644 --- a/src/main/apis/core/bus/apis.ts +++ b/src/main/apis/core/bus/apis.ts @@ -11,10 +11,10 @@ import { } from '@core/bus/constants' export const uploadWithClipboardFiles = (): Promise<{ - success: boolean, + success: boolean result?: string[] }> => { - return new Promise((resolve) => { + return new Promise(resolve => { bus.once(UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE, (result: string) => { if (result) { return resolve({ @@ -31,11 +31,13 @@ export const uploadWithClipboardFiles = (): Promise<{ }) } -export const uploadWithFiles = (pathList: IFileWithPath[]): Promise<{ - success: boolean, +export const uploadWithFiles = ( + pathList: IFileWithPath[] +): Promise<{ + success: boolean result?: string[] }> => { - return new Promise((resolve) => { + return new Promise(resolve => { bus.once(UPLOAD_WITH_FILES_RESPONSE, (result: string[]) => { if (result.length) { return resolve({ @@ -55,7 +57,7 @@ export const uploadWithFiles = (pathList: IFileWithPath[]): Promise<{ // get available window id: // miniWindow or settingWindow or trayWindow export const getWindowId = (): Promise => { - return new Promise((resolve) => { + return new Promise(resolve => { bus.once(GET_WINDOW_ID_REPONSE, (id: number) => { resolve(id) }) @@ -65,7 +67,7 @@ export const getWindowId = (): Promise => { // get settingWindow id: export const getSettingWindowId = (): Promise => { - return new Promise((resolve) => { + return new Promise(resolve => { bus.once(GET_SETTING_WINDOW_ID_RESPONSE, (id: number) => { resolve(id) }) diff --git a/src/main/apis/core/datastore/dbChecker.ts b/src/main/apis/core/datastore/dbChecker.ts index c7732e85..960bf367 100644 --- a/src/main/apis/core/datastore/dbChecker.ts +++ b/src/main/apis/core/datastore/dbChecker.ts @@ -25,7 +25,7 @@ const errorMsg = { /** ensure notification list */ if (!global.notificationList) global.notificationList = [] -function dbChecker () { +function dbChecker() { if (process.type !== 'renderer') { // db save bak try { @@ -54,7 +54,9 @@ function dbChecker () { fs.unlinkSync(configFilePath) if (fs.existsSync(configFileBackupPath)) { try { - configFile = fs.readFileSync(configFileBackupPath, { encoding: 'utf-8' }) + configFile = fs.readFileSync(configFileBackupPath, { + encoding: 'utf-8' + }) JSON.parse(configFile) writeFile.sync(configFilePath, configFile, { encoding: 'utf-8' }) const stats = fs.statSync(configFileBackupPath) @@ -80,7 +82,7 @@ function dbChecker () { /** * Get config path */ -function dbPathChecker (): string { +function dbPathChecker(): string { if (_configFilePath) { return _configFilePath } @@ -91,7 +93,9 @@ function dbPathChecker (): string { return _configFilePath } try { - const configString = fs.readFileSync(defaultConfigPath, { encoding: 'utf-8' }) + const configString = fs.readFileSync(defaultConfigPath, { + encoding: 'utf-8' + }) const config = JSON.parse(configString) const userConfigPath: string = config.configPath || '' if (userConfigPath) { @@ -118,11 +122,11 @@ function dbPathChecker (): string { } } -function dbPathDir () { +function dbPathDir() { return path.dirname(dbPathChecker()) } -function getGalleryDBPath (): { +function getGalleryDBPath(): { dbPath: string dbBackupPath: string } { @@ -135,9 +139,4 @@ function getGalleryDBPath (): { } } -export { - dbChecker, - dbPathChecker, - dbPathDir, - getGalleryDBPath -} +export { dbChecker, dbPathChecker, dbPathDir, getGalleryDBPath } diff --git a/src/main/apis/core/datastore/index.ts b/src/main/apis/core/datastore/index.ts index 78888dfe..bcd7a974 100644 --- a/src/main/apis/core/datastore/index.ts +++ b/src/main/apis/core/datastore/index.ts @@ -19,7 +19,7 @@ export const DB_PATH: string = getGalleryDBPath().dbPath class ConfigStore { #db: JSONStore - constructor () { + constructor() { this.#db = new JSONStore(CONFIG_PATH) if (!this.#db.has('picBed')) { @@ -43,11 +43,11 @@ class ConfigStore { this.read() } - read (flush?: boolean): IJSON { + read(flush?: boolean): IJSON { return this.#db.read(flush) } - getSingle (key = ''): any { + getSingle(key = ''): any { if (key === '') { return this.#db.read(true) } @@ -55,43 +55,43 @@ class ConfigStore { return this.#db.get(key) } - get (key: string): any - get (key: string[]): any[] - get (key: string | string[] = ''): any { + get(key: string): any + get(key: string[]): any[] + get(key: string | string[] = ''): any { if (Array.isArray(key)) { return key.map(k => this.getSingle(k)) } return this.getSingle(key) } - set (key: string, value: any): void { + set(key: string, value: any): void { this.read(true) return this.#db.set(key, value) } - has (key: string) { + has(key: string) { this.read(true) return this.#db.has(key) } - unset (key: string, value: any): boolean { + unset(key: string, value: any): boolean { this.read(true) return this.#db.unset(key, value) } - saveConfig (config: Partial): void { + saveConfig(config: Partial): void { Object.keys(config).forEach((name: string) => { this.set(name, config[name]) }) } - removeConfig (config: IConfig): void { + removeConfig(config: IConfig): void { Object.keys(config).forEach((name: string) => { this.unset(name, config[name]) }) } - getConfigPath () { + getConfigPath() { return CONFIG_PATH } } @@ -103,11 +103,11 @@ export default db // v2.3.0 add gallery db class GalleryDB { static #instance: DBStore - private constructor () { + private constructor() { console.log('init gallery db') } - static getInstance (): DBStore { + static getInstance(): DBStore { if (!GalleryDB.#instance) { GalleryDB.#instance = new DBStore(DB_PATH, 'gallery') } @@ -115,6 +115,4 @@ class GalleryDB { } } -export { - GalleryDB -} +export { GalleryDB } diff --git a/src/main/apis/core/picgo/index.ts b/src/main/apis/core/picgo/index.ts index 92d61f5c..f386cade 100644 --- a/src/main/apis/core/picgo/index.ts +++ b/src/main/apis/core/picgo/index.ts @@ -21,7 +21,7 @@ picgo.GUI_VERSION = global.PICGO_GUI_VERSION const originPicGoSaveConfig = picgo.saveConfig.bind(picgo) -function flushDB () { +function flushDB() { db.read(true) } diff --git a/src/main/apis/core/utils/localLogger.ts b/src/main/apis/core/utils/localLogger.ts index 35730f3f..2a95e085 100644 --- a/src/main/apis/core/utils/localLogger.ts +++ b/src/main/apis/core/utils/localLogger.ts @@ -94,6 +94,4 @@ const getLogger = (logPath: string, logType: string) => { } } -export { - getLogger -} +export { getLogger } diff --git a/src/main/apis/gui/index.ts b/src/main/apis/gui/index.ts index 4e995f0e..50991c12 100644 --- a/src/main/apis/gui/index.ts +++ b/src/main/apis/gui/index.ts @@ -1,9 +1,4 @@ -import { - BrowserWindow, - dialog, - ipcMain, - Notification -} from 'electron' +import { BrowserWindow, dialog, ipcMain, Notification } from 'electron' import fs from 'fs-extra' import { cloneDeep } from 'lodash' import { DBStore } from '@picgo/store' @@ -29,55 +24,57 @@ class GuiApi implements IGuiApi { private static instance: GuiApi private windowId: number = -1 private settingWindowId: number = -1 - private constructor () { + private constructor() { console.log('init guiapi') } - static getInstance (): GuiApi { + static getInstance(): GuiApi { if (!GuiApi.instance) { GuiApi.instance = new GuiApi() } return GuiApi.instance } - private async showSettingWindow () { + private async showSettingWindow() { this.settingWindowId = await getSettingWindowId() const settingWindow = BrowserWindow.fromId(this.settingWindowId) if (settingWindow?.isVisible()) { return true } settingWindow?.show() - return new Promise((resolve) => { + return new Promise(resolve => { setTimeout(() => { resolve() }, 1000) // TODO: a better way to wait page loaded. }) } - private getWebcontentsByWindowId (id: number) { + private getWebcontentsByWindowId(id: number) { return BrowserWindow.fromId(id)?.webContents } - async showInputBox (options: IShowInputBoxOption = { - title: '', - placeholder: '' - }) { + async showInputBox( + options: IShowInputBoxOption = { + title: '', + placeholder: '' + } + ) { await this.showSettingWindow() this.getWebcontentsByWindowId(this.settingWindowId)?.send(SHOW_INPUT_BOX, options) - return new Promise((resolve) => { + return new Promise(resolve => { ipcMain.once(SHOW_INPUT_BOX, (_: Event, value: string) => { resolve(value) }) }) } - async showFileExplorer (options: IShowFileExplorerOption = {}) { + async showFileExplorer(options: IShowFileExplorerOption = {}) { this.windowId = await getWindowId() const res = await dialog.showOpenDialog(BrowserWindow.fromId(this.windowId)!, options) return res.filePaths || [] } - async upload (input: IUploadOption) { + async upload(input: IUploadOption) { this.windowId = await getWindowId() const webContents = this.getWebcontentsByWindowId(this.windowId) const rawInput = cloneDeep(input) @@ -90,8 +87,11 @@ class GuiApi implements IGuiApi { if (deleteLocalFile) { await fs.remove(rawInput[i]) } - pasteText.push(await (pasteTemplate(pasteStyle, imgs[i], db.get(configPaths.settings.customLink)))) - const isShowResultNotification = db.get(configPaths.settings.uploadResultNotification) === undefined ? true : !!db.get(configPaths.settings.uploadResultNotification) + pasteText.push(await pasteTemplate(pasteStyle, imgs[i], db.get(configPaths.settings.customLink))) + const isShowResultNotification = + db.get(configPaths.settings.uploadResultNotification) === undefined + ? true + : !!db.get(configPaths.settings.uploadResultNotification) if (isShowResultNotification) { const notification = new Notification({ title: T('UPLOAD_SUCCEED'), @@ -112,10 +112,12 @@ class GuiApi implements IGuiApi { return [] } - showNotification (options: IShowNotificationOption = { - title: '', - body: '' - }) { + showNotification( + options: IShowNotificationOption = { + title: '', + body: '' + } + ) { const notification = new Notification({ title: options.title, body: options.body @@ -123,18 +125,17 @@ class GuiApi implements IGuiApi { notification.show() } - showMessageBox (options: IShowMessageBoxOption = { - title: '', - message: '', - type: 'info', - buttons: ['Yes', 'No'] - }) { - return new Promise(async (resolve) => { + showMessageBox( + options: IShowMessageBoxOption = { + title: '', + message: '', + type: 'info', + buttons: ['Yes', 'No'] + } + ) { + return new Promise(async resolve => { this.windowId = await getWindowId() - dialog.showMessageBox( - BrowserWindow.fromId(this.windowId)!, - options - ).then((res) => { + dialog.showMessageBox(BrowserWindow.fromId(this.windowId)!, options).then(res => { resolve({ result: res.response, checkboxChecked: res.checkboxChecked @@ -146,7 +147,7 @@ class GuiApi implements IGuiApi { /** * get picgo config/data path */ - async getConfigPath () { + async getConfigPath() { const currentConfigPath = dbPathChecker() const galleryDBPath = getGalleryDBPath().dbPath return { @@ -156,47 +157,51 @@ class GuiApi implements IGuiApi { } } - get galleryDB (): DBStore { + get galleryDB(): DBStore { return new Proxy(GalleryDB.getInstance(), { - get (target, prop: keyof DBStore) { + get(target, prop: keyof DBStore) { if (prop === 'overwrite') { return new Proxy(GalleryDB.getInstance().overwrite, { - apply (target, ctx, args) { - return new Promise((resolve) => { + apply(target, ctx, args) { + return new Promise(resolve => { const guiApi = GuiApi.getInstance() - guiApi.showMessageBox({ - title: T('TIPS_WARNING'), - message: T('TIPS_PLUGIN_REMOVE_GALLERY_ITEM'), - type: 'info', - buttons: ['Yes', 'No'] - }).then(res => { - if (res.result === 0) { - resolve(Reflect.apply(target, ctx, args)) - } else { - resolve(undefined) - } - }) + guiApi + .showMessageBox({ + title: T('TIPS_WARNING'), + message: T('TIPS_PLUGIN_REMOVE_GALLERY_ITEM'), + type: 'info', + buttons: ['Yes', 'No'] + }) + .then(res => { + if (res.result === 0) { + resolve(Reflect.apply(target, ctx, args)) + } else { + resolve(undefined) + } + }) }) } }) } if (prop === 'removeById') { return new Proxy(GalleryDB.getInstance().removeById, { - apply (target, ctx, args) { - return new Promise((resolve) => { + apply(target, ctx, args) { + return new Promise(resolve => { const guiApi = GuiApi.getInstance() - guiApi.showMessageBox({ - title: T('TIPS_WARNING'), - message: T('TIPS_PLUGIN_REMOVE_GALLERY_ITEM'), - type: 'info', - buttons: ['Yes', 'No'] - }).then(res => { - if (res.result === 0) { - resolve(Reflect.apply(target, ctx, args)) - } else { - resolve(undefined) - } - }) + guiApi + .showMessageBox({ + title: T('TIPS_WARNING'), + message: T('TIPS_PLUGIN_REMOVE_GALLERY_ITEM'), + type: 'info', + buttons: ['Yes', 'No'] + }) + .then(res => { + if (res.result === 0) { + resolve(Reflect.apply(target, ctx, args)) + } else { + resolve(undefined) + } + }) }) } }) diff --git a/src/main/events/busEventList.ts b/src/main/events/busEventList.ts index 2fd78a60..d10dcfb5 100644 --- a/src/main/events/busEventList.ts +++ b/src/main/events/busEventList.ts @@ -11,18 +11,13 @@ import { UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE } from '@core/bus/constants' -import { - createMenu -} from 'apis/app/system' -import { - uploadChoosedFiles, - uploadClipboardFiles -} from 'apis/app/uploader/apis' +import { createMenu } from 'apis/app/system' +import { uploadChoosedFiles, uploadClipboardFiles } from 'apis/app/uploader/apis' import windowManager from 'apis/app/window/windowManager' import { IWindowList } from '#/types/enum' -function initEventCenter () { +function initEventCenter() { const eventList: any = { 'picgo:upload': uploadClipboardFiles, [UPLOAD_WITH_CLIPBOARD_FILES]: busCallUploadClipboardFiles, @@ -36,31 +31,31 @@ function initEventCenter () { } } -async function busCallUploadClipboardFiles () { +async function busCallUploadClipboardFiles() { const result = await uploadClipboardFiles() const imgUrl = result.url bus.emit(UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE, imgUrl) } -async function busCallUploadFiles (pathList: IFileWithPath[]) { +async function busCallUploadFiles(pathList: IFileWithPath[]) { const win = windowManager.getAvailableWindow() const result = await uploadChoosedFiles(win.webContents, pathList) const urls = result.map((item: any) => item.url) bus.emit(UPLOAD_WITH_FILES_RESPONSE, urls) } -function busCallGetWindowId () { +function busCallGetWindowId() { const win = windowManager.getAvailableWindow() bus.emit(GET_WINDOW_ID_REPONSE, win.id) } -function busCallGetSettingWindowId () { +function busCallGetSettingWindowId() { const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)! bus.emit(GET_SETTING_WINDOW_ID_RESPONSE, settingWindow.id) } export default { - listen () { + listen() { initEventCenter() } } diff --git a/src/main/events/remotes/menu.ts b/src/main/events/remotes/menu.ts index 96669a54..a2558c80 100644 --- a/src/main/events/remotes/menu.ts +++ b/src/main/events/remotes/menu.ts @@ -1,20 +1,10 @@ -import { - app, - dialog, - BrowserWindow, - Menu, - shell, - MenuItemConstructorOptions, - MenuItem -} from 'electron' +import { app, dialog, BrowserWindow, Menu, shell, MenuItemConstructorOptions, MenuItem } from 'electron' import { PicGo as PicGoCore } from 'piclist' import db from '@core/datastore' import picgo from '@core/picgo' -import { - uploadClipboardFiles -} from 'apis/app/uploader/apis' +import { uploadClipboardFiles } from 'apis/app/uploader/apis' import windowManager from 'apis/app/window/windowManager' import GuiApi from 'apis/gui' @@ -47,7 +37,7 @@ const buildMiniPageMenu = () => { const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false const ClipboardWatcher = clipboardPoll const submenu = buildPicBedListMenu() - const template: Array<(MenuItemConstructorOptions) | (MenuItem)> = [ + const template: Array = [ { label: T('OPEN_MAIN_WINDOW'), click: openMainWindow @@ -59,19 +49,19 @@ const buildMiniPageMenu = () => { }, { label: T('UPLOAD_BY_CLIPBOARD'), - click () { + click() { uploadClipboardFiles() } }, { label: T('HIDE_MINI_WINDOW'), - click () { + click() { BrowserWindow.getFocusedWindow()!.hide() } }, { label: T('START_WATCH_CLIPBOARD'), - click () { + click() { db.set(configPaths.settings.isListeningClipboard, true) ClipboardWatcher.startListening() ClipboardWatcher.on('change', () => { @@ -84,7 +74,7 @@ const buildMiniPageMenu = () => { }, { label: T('STOP_WATCH_CLIPBOARD'), - click () { + click() { db.set(configPaths.settings.isListeningClipboard, false) ClipboardWatcher.stopListening() ClipboardWatcher.removeAllListeners() @@ -94,7 +84,7 @@ const buildMiniPageMenu = () => { }, { label: T('RELOAD_APP'), - click () { + click() { app.relaunch() app.exit(0) } @@ -111,7 +101,7 @@ const buildMainPageMenu = (win: BrowserWindow) => { const template = [ { label: T('ABOUT'), - click () { + click() { dialog.showMessageBox({ title: 'PicList', message: 'PicList', @@ -121,32 +111,31 @@ const buildMainPageMenu = (win: BrowserWindow) => { }, { label: T('SHOW_PICBED_QRCODE'), - click () { + click() { win?.webContents?.send(SHOW_MAIN_PAGE_QRCODE) } }, { label: T('OPEN_TOOLBOX'), - click () { + click() { const window = windowManager.create(IWindowList.TOOLBOX_WINDOW) window?.show() } }, { label: T('SHOW_DEVTOOLS'), - click () { + click() { win?.webContents?.openDevTools({ mode: 'detach' }) } }, { label: T('FEEDBACK'), - click () { + click() { const url = 'https://github.com/Kuingsmile/PicList/issues' shell.openExternal(url) } } - ] - // @ts-ignore + ] as Array return Menu.buildFromTemplate(template) } @@ -155,55 +144,60 @@ const buildPicBedListMenu = () => { const currentPicBed = picgo.getConfig(configPaths.picBed.uploader) const currentPicBedName = picBeds.find(item => item.type === currentPicBed)?.name const picBedConfigList = picgo.getConfig('uploader') - const currentPicBedMenuItem = [{ - label: `${T('CURRENT_PICBED')} - ${currentPicBedName}`, - enabled: false - }, { - type: 'separator' - }] - let submenu = picBeds.filter(item => item.visible).map(item => { - const configList = picBedConfigList?.[item.type]?.configList - const defaultId = picBedConfigList?.[item.type]?.defaultId - const hasSubmenu = !!configList - return { - label: item.name, - type: !hasSubmenu ? 'checkbox' : undefined, - checked: !hasSubmenu ? (currentPicBed === item.type) : undefined, - submenu: hasSubmenu - ? configList.map((config) => { - return { - label: config._configName || 'Default', - // if only one config, use checkbox, or radio will checked as default - // see: https://github.com/electron/electron/issues/21292 - type: 'checkbox', - checked: config._id === defaultId && (item.type === currentPicBed), - click: function () { - changeCurrentUploader(item.type, config, config._id) + const currentPicBedMenuItem = [ + { + label: `${T('CURRENT_PICBED')} - ${currentPicBedName}`, + enabled: false + }, + { + type: 'separator' + } + ] + let submenu = picBeds + .filter(item => item.visible) + .map(item => { + const configList = picBedConfigList?.[item.type]?.configList + const defaultId = picBedConfigList?.[item.type]?.defaultId + const hasSubmenu = !!configList + return { + label: item.name, + type: !hasSubmenu ? 'checkbox' : undefined, + checked: !hasSubmenu ? currentPicBed === item.type : undefined, + submenu: hasSubmenu + ? configList.map(config => { + return { + label: config._configName || 'Default', + // if only one config, use checkbox, or radio will checked as default + // see: https://github.com/electron/electron/issues/21292 + type: 'checkbox', + checked: config._id === defaultId && item.type === currentPicBed, + click: function () { + changeCurrentUploader(item.type, config, config._id) + if (windowManager.has(IWindowList.SETTING_WINDOW)) { + windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed') + } + setTrayToolTip(`${item.type} ${config._configName || 'Default'}`) + } + } + }) + : undefined, + click: !hasSubmenu + ? function () { + picgo.saveConfig({ + [configPaths.picBed.current]: item.type, + [configPaths.picBed.uploader]: item.type + }) if (windowManager.has(IWindowList.SETTING_WINDOW)) { windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed') } - setTrayToolTip(`${item.type} ${config._configName || 'Default'}`) + setTrayToolTip(item.type) } - } - }) - : undefined, - click: !hasSubmenu - ? function () { - picgo.saveConfig({ - [configPaths.picBed.current]: item.type, - [configPaths.picBed.uploader]: item.type - }) - if (windowManager.has(IWindowList.SETTING_WINDOW)) { - windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed') - } - setTrayToolTip(item.type) - } - : undefined - } - }) - // @ts-ignore + : undefined + } + }) + // @ts-expect-error submenu type submenu = currentPicBedMenuItem.concat(submenu) - // @ts-ignore + // @ts-expect-error submenu type return Menu.buildFromTemplate(submenu) } @@ -230,56 +224,61 @@ const handleRestoreState = (item: string, name: string): void => { } const buildPluginPageMenu = (plugin: IPicGoPlugin) => { - const menu = [{ - label: T('ENABLE_PLUGIN'), - enabled: !plugin.enabled, - click () { - picgo.saveConfig({ - [`picgoPlugins.${plugin.fullName}`]: true - }) - const window = windowManager.get(IWindowList.SETTING_WINDOW)! - window.webContents.send(PICGO_TOGGLE_PLUGIN, plugin.fullName, true) - } - }, { - label: T('DISABLE_PLUGIN'), - enabled: plugin.enabled, - click () { - picgo.saveConfig({ - [`picgoPlugins.${plugin.fullName}`]: false - }) - const window = windowManager.get(IWindowList.SETTING_WINDOW)! - window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName) - window.webContents.send(PICGO_TOGGLE_PLUGIN, plugin.fullName, false) - window.webContents.send(PICGO_HANDLE_PLUGIN_DONE, plugin.fullName) - if (plugin.config.transformer.name) { - handleRestoreState('transformer', plugin.config.transformer.name) + const menu = [ + { + label: T('ENABLE_PLUGIN'), + enabled: !plugin.enabled, + click() { + picgo.saveConfig({ + [`picgoPlugins.${plugin.fullName}`]: true + }) + const window = windowManager.get(IWindowList.SETTING_WINDOW)! + window.webContents.send(PICGO_TOGGLE_PLUGIN, plugin.fullName, true) } - if (plugin.config.uploader.name) { - handleRestoreState('uploader', plugin.config.uploader.name) + }, + { + label: T('DISABLE_PLUGIN'), + enabled: plugin.enabled, + click() { + picgo.saveConfig({ + [`picgoPlugins.${plugin.fullName}`]: false + }) + const window = windowManager.get(IWindowList.SETTING_WINDOW)! + window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName) + window.webContents.send(PICGO_TOGGLE_PLUGIN, plugin.fullName, false) + window.webContents.send(PICGO_HANDLE_PLUGIN_DONE, plugin.fullName) + if (plugin.config.transformer.name) { + handleRestoreState('transformer', plugin.config.transformer.name) + } + if (plugin.config.uploader.name) { + handleRestoreState('uploader', plugin.config.uploader.name) + } + } + }, + { + label: T('UNINSTALL_PLUGIN'), + click() { + const window = windowManager.get(IWindowList.SETTING_WINDOW)! + window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName) + handlePluginUninstall(plugin.fullName) + } + }, + { + label: T('UPDATE_PLUGIN'), + click() { + const window = windowManager.get(IWindowList.SETTING_WINDOW)! + window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName) + handlePluginUpdate(plugin.fullName) } } - }, { - label: T('UNINSTALL_PLUGIN'), - click () { - const window = windowManager.get(IWindowList.SETTING_WINDOW)! - window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName) - handlePluginUninstall(plugin.fullName) - } - }, { - label: T('UPDATE_PLUGIN'), - click () { - const window = windowManager.get(IWindowList.SETTING_WINDOW)! - window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName) - handlePluginUpdate(plugin.fullName) - } - }] + ] as Array for (const i in plugin.config) { if (plugin.config[i].config.length > 0) { const obj = { label: T('CONFIG_THING', { c: `${i} - ${plugin.config[i].fullName || plugin.config[i].name}` }), - click () { + click() { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const currentType = i const configName = plugin.config[i].fullName || plugin.config[i].name @@ -297,7 +296,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { const pluginTransformer = plugin.config.transformer.name const obj = { label: `${currentTransformer === pluginTransformer ? T('DISABLE') : T('ENABLE')}transformer - ${plugin.config.transformer.name}`, - click () { + click() { const transformer = plugin.config.transformer.name const currentTransformer = picgo.getConfig(configPaths.picBed.transformer) || 'path' if (currentTransformer === transformer) { @@ -317,13 +316,12 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { // plugin custom menus if (plugin.guiMenu) { menu.push({ - // @ts-ignore type: 'separator' }) for (const i of plugin.guiMenu) { menu.push({ label: i.label, - click () { + click() { const picgPlugin = picgo.pluginLoader.getPlugin(plugin.fullName) if (picgPlugin?.guiMenu?.(picgo)?.length) { const menu: GuiMenuItem[] = picgPlugin.guiMenu(picgo) @@ -338,13 +336,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { } } - // @ts-ignore return Menu.buildFromTemplate(menu) } -export { - buildMiniPageMenu, - buildMainPageMenu, - buildPicBedListMenu, - buildPluginPageMenu -} +export { buildMiniPageMenu, buildMainPageMenu, buildPicBedListMenu, buildPluginPageMenu } diff --git a/src/main/events/rpc/index.ts b/src/main/events/rpc/index.ts index 8b6a8892..8f270d92 100644 --- a/src/main/events/rpc/index.ts +++ b/src/main/events/rpc/index.ts @@ -45,12 +45,12 @@ class RPCServer implements IRPCServer { } } - start () { + start() { ipcMain.on(RPC_ACTIONS, this.rpcEventHandler) ipcMain.handle(RPC_ACTIONS_INVOKE, this.rpcEventHandlerWithResponse) } - use (routes: IRPCRoutes) { + use(routes: IRPCRoutes) { for (const [action, route] of routes) { if (route.type === IRPCType.SEND) { this.routes.set(action, route) @@ -60,7 +60,7 @@ class RPCServer implements IRPCServer { } } - stop () { + stop() { ipcMain.off(RPC_ACTIONS, this.rpcEventHandler) } } @@ -82,6 +82,4 @@ for (const route of routes) { rpcServer.use(route) } -export { - rpcServer -} +export { rpcServer } diff --git a/src/main/events/rpc/router.ts b/src/main/events/rpc/router.ts index 8117e21b..5c07b96f 100644 --- a/src/main/events/rpc/router.ts +++ b/src/main/events/rpc/router.ts @@ -20,7 +20,7 @@ export class RPCRouter implements IRPCRouter { return this } - routes () { + routes() { return this.routeMap } } diff --git a/src/main/events/rpc/routes/gallery/index.ts b/src/main/events/rpc/routes/gallery/index.ts index 5ae1e388..fc049b80 100644 --- a/src/main/events/rpc/routes/gallery/index.ts +++ b/src/main/events/rpc/routes/gallery/index.ts @@ -1,4 +1,3 @@ - import { clipboard } from 'electron' import { GalleryDB } from '@core/datastore' @@ -8,7 +7,12 @@ import { IFilter, IObject } from '@picgo/store/dist/types' import GuiApi from 'apis/gui' import { RPCRouter } from '~/events/rpc/router' -import { removeFileFromDogeInMain, removeFileFromHuaweiInMain, removeFileFromS3InMain, removeFileFromSFTPInMain } from '~/utils/deleteFunc' +import { + removeFileFromDogeInMain, + removeFileFromHuaweiInMain, + removeFileFromS3InMain, + removeFileFromSFTPInMain +} from '~/utils/deleteFunc' import pasteTemplate from '~/utils/pasteTemplate' import { ICOREBuildInEvent, IPasteStyle, IRPCActionType, IRPCType } from '#/types/enum' @@ -19,7 +23,7 @@ const galleryRouter = new RPCRouter() const galleryRoutes = [ { action: IRPCActionType.GALLERY_PASTE_TEXT, - handler: async (_: IIPCEvent, args: [ item: ImgInfo, copy?: boolean]) => { + handler: async (_: IIPCEvent, args: [item: ImgInfo, copy?: boolean]) => { const [item, copy = true] = args const pasteStyle = picgo.getConfig(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN const customLink = picgo.getConfig(configPaths.settings.customLink) @@ -128,6 +132,4 @@ const galleryRoutes = [ galleryRouter.addBatch(galleryRoutes) -export { - galleryRouter -} +export { galleryRouter } diff --git a/src/main/events/rpc/routes/picbed/index.ts b/src/main/events/rpc/routes/picbed/index.ts index 5936a863..5db2e1be 100644 --- a/src/main/events/rpc/routes/picbed/index.ts +++ b/src/main/events/rpc/routes/picbed/index.ts @@ -94,6 +94,4 @@ const picbedRoutes = [ picbedRouter.addBatch(picbedRoutes) -export { - picbedRouter -} +export { picbedRouter } diff --git a/src/main/events/rpc/routes/plugin/index.ts b/src/main/events/rpc/routes/plugin/index.ts index ea91bc78..55739f98 100644 --- a/src/main/events/rpc/routes/plugin/index.ts +++ b/src/main/events/rpc/routes/plugin/index.ts @@ -1,4 +1,3 @@ - import { RPCRouter } from '~/events/rpc/router' import { pluginImportLocalFunc, @@ -32,6 +31,4 @@ const pluginRoutes = [ pluginRouter.addBatch(pluginRoutes) -export { - pluginRouter -} +export { pluginRouter } diff --git a/src/main/events/rpc/routes/plugin/utils.ts b/src/main/events/rpc/routes/plugin/utils.ts index 37711074..415a33cc 100644 --- a/src/main/events/rpc/routes/plugin/utils.ts +++ b/src/main/events/rpc/routes/plugin/utils.ts @@ -17,7 +17,7 @@ import { ICOREBuildInEvent, IPicGoHelperType, IWindowList } from '#/types/enum' const STORE_PATH = dbPathDir() // eslint-disable-next-line -const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require +const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require // get uploader or transformer config const getConfig = (name: string, type: IPicGoHelperType, ctx: PicGoCore) => { @@ -104,15 +104,17 @@ const getPluginList = (): IPicGoPlugin[] => { const handleNPMError = (): IDispose => { const handler = (msg: string) => { if (msg === 'NPM is not installed') { - dialog.showMessageBox({ - title: T('TIPS_ERROR'), - message: T('TIPS_INSTALL_NODE_AND_RELOAD_PICGO'), - buttons: ['Yes'] - }).then((res) => { - if (res.response === 0) { - shell.openExternal('https://nodejs.org/') - } - }) + dialog + .showMessageBox({ + title: T('TIPS_ERROR'), + message: T('TIPS_INSTALL_NODE_AND_RELOAD_PICGO'), + buttons: ['Yes'] + }) + .then(res => { + if (res.response === 0) { + shell.openExternal('https://nodejs.org/') + } + }) } } picgo.once(ICOREBuildInEvent.FAILED, handler) diff --git a/src/main/events/rpc/routes/setting/advanced.ts b/src/main/events/rpc/routes/setting/advanced.ts index 9edef769..75619c7e 100644 --- a/src/main/events/rpc/routes/setting/advanced.ts +++ b/src/main/events/rpc/routes/setting/advanced.ts @@ -1,4 +1,3 @@ - import { IRPCActionType } from '#/types/enum' import server from '~/server' import webServer from '~/server/webServer' diff --git a/src/main/events/rpc/routes/setting/configure.ts b/src/main/events/rpc/routes/setting/configure.ts index 0987cad6..7293962e 100644 --- a/src/main/events/rpc/routes/setting/configure.ts +++ b/src/main/events/rpc/routes/setting/configure.ts @@ -16,19 +16,15 @@ export default [ action: IRPCActionType.CONFIGURE_MIGRATE_FROM_PICGO, handler: async () => { const picGoConfigPath = STORE_PATH.replace('piclist', 'picgo') - const files = [ - 'data.json', - 'data.bak.json', - 'picgo.db', - 'picgo.bak.db' - ] + const files = ['data.json', 'data.bak.json', 'picgo.db', 'picgo.bak.db'] try { - await Promise.all(files.map(async file => { - const sourcePath = path.join(picGoConfigPath, file) - const targetPath = path.join(STORE_PATH, file.replace('picgo', 'piclist')) - await fs.copy(sourcePath, targetPath, { overwrite: true }) - } - )) + await Promise.all( + files.map(async file => { + const sourcePath = path.join(picGoConfigPath, file) + const targetPath = path.join(STORE_PATH, file.replace('picgo', 'piclist')) + await fs.copy(sourcePath, targetPath, { overwrite: true }) + }) + ) return true } catch (err: any) { logger.error(err) diff --git a/src/main/events/rpc/routes/setting/index.ts b/src/main/events/rpc/routes/setting/index.ts index 20ecdbe9..febac630 100644 --- a/src/main/events/rpc/routes/setting/index.ts +++ b/src/main/events/rpc/routes/setting/index.ts @@ -7,15 +7,8 @@ import shortKeyRoutes from '~/events/rpc/routes/setting/shortKey' const settingRouter = new RPCRouter() -const settingRoutes = [ - ...advancedRoutes, - ...configureRoutes, - ...mainAppRoutes, - ...shortKeyRoutes -] +const settingRoutes = [...advancedRoutes, ...configureRoutes, ...mainAppRoutes, ...shortKeyRoutes] settingRouter.addBatch(settingRoutes) -export { - settingRouter -} +export { settingRouter } diff --git a/src/main/events/rpc/routes/setting/shortKey.ts b/src/main/events/rpc/routes/setting/shortKey.ts index 9cf4443c..e91169e8 100644 --- a/src/main/events/rpc/routes/setting/shortKey.ts +++ b/src/main/events/rpc/routes/setting/shortKey.ts @@ -1,6 +1,4 @@ -import { - Notification -} from 'electron' +import { Notification } from 'electron' import bus from '@core/bus' import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler' diff --git a/src/main/events/rpc/routes/system/index.ts b/src/main/events/rpc/routes/system/index.ts index 9b5a6df4..13ab2d3f 100644 --- a/src/main/events/rpc/routes/system/index.ts +++ b/src/main/events/rpc/routes/system/index.ts @@ -4,13 +4,8 @@ import windowRoutes from '~/events/rpc/routes/system/window' const systemRouter = new RPCRouter() -const systemRoutes = [ - ...appRoutes, - ...windowRoutes -] +const systemRoutes = [...appRoutes, ...windowRoutes] systemRouter.addBatch(systemRoutes) -export { - systemRouter -} +export { systemRouter } diff --git a/src/main/events/rpc/routes/system/window.ts b/src/main/events/rpc/routes/system/window.ts index e2a70cd1..fe5f88a9 100644 --- a/src/main/events/rpc/routes/system/window.ts +++ b/src/main/events/rpc/routes/system/window.ts @@ -2,12 +2,7 @@ import { app, BrowserWindow } from 'electron' import windowManager from 'apis/app/window/windowManager' -import { - buildMainPageMenu, - buildMiniPageMenu, - buildPicBedListMenu, - buildPluginPageMenu -} from '~/events/remotes/menu' +import { buildMainPageMenu, buildMiniPageMenu, buildPicBedListMenu, buildPluginPageMenu } from '~/events/remotes/menu' import { openMiniWindow } from '~/utils/windowHelper' import { IRPCActionType, IWindowList } from '#/types/enum' diff --git a/src/main/events/rpc/routes/toolbox/checkClipboardUpload.ts b/src/main/events/rpc/routes/toolbox/checkClipboardUpload.ts index 77fefa7c..98cad3c3 100644 --- a/src/main/events/rpc/routes/toolbox/checkClipboardUpload.ts +++ b/src/main/events/rpc/routes/toolbox/checkClipboardUpload.ts @@ -14,10 +14,8 @@ const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.HAS_PROBLEM_WITH_ const defaultClipboardImagePath = path.join(defaultConfigPath, CLIPBOARD_IMAGE_FOLDER) -export const checkClipboardUploadMap: IToolboxCheckerMap< -IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD -> = { - [IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD]: async (event) => { +export const checkClipboardUploadMap: IToolboxCheckerMap = { + [IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD]: async event => { sendToolboxRes(event, { status: IToolboxItemCheckStatus.LOADING }) @@ -54,9 +52,7 @@ IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD } } -export const fixClipboardUploadMap: IToolboxFixMap< -IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD -> = { +export const fixClipboardUploadMap: IToolboxFixMap = { [IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD]: async () => { const configFilePath = dbPathChecker() const dirPath = path.dirname(configFilePath) diff --git a/src/main/events/rpc/routes/toolbox/checkFile.ts b/src/main/events/rpc/routes/toolbox/checkFile.ts index f5a00cbc..317a4c93 100644 --- a/src/main/events/rpc/routes/toolbox/checkFile.ts +++ b/src/main/events/rpc/routes/toolbox/checkFile.ts @@ -11,7 +11,7 @@ import { T } from '~/i18n' import { IToolboxItemCheckStatus, IToolboxItemType } from '#/types/enum' export const checkFileMap: IToolboxCheckerMap< -IToolboxItemType.IS_CONFIG_FILE_BROKEN | IToolboxItemType.IS_GALLERY_FILE_BROKEN + IToolboxItemType.IS_CONFIG_FILE_BROKEN | IToolboxItemType.IS_GALLERY_FILE_BROKEN > = { [IToolboxItemType.IS_CONFIG_FILE_BROKEN]: async (event: IpcMainEvent) => { const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.IS_CONFIG_FILE_BROKEN) @@ -38,7 +38,7 @@ IToolboxItemType.IS_CONFIG_FILE_BROKEN | IToolboxItemType.IS_GALLERY_FILE_BROKEN }) } }, - [IToolboxItemType.IS_GALLERY_FILE_BROKEN]: async (event) => { + [IToolboxItemType.IS_GALLERY_FILE_BROKEN]: async event => { const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.IS_GALLERY_FILE_BROKEN) sendToolboxRes(event, { status: IToolboxItemCheckStatus.LOADING @@ -63,7 +63,7 @@ IToolboxItemType.IS_CONFIG_FILE_BROKEN | IToolboxItemType.IS_GALLERY_FILE_BROKEN } export const fixFileMap: IToolboxFixMap< -IToolboxItemType.IS_CONFIG_FILE_BROKEN | IToolboxItemType.IS_GALLERY_FILE_BROKEN + IToolboxItemType.IS_CONFIG_FILE_BROKEN | IToolboxItemType.IS_GALLERY_FILE_BROKEN > = { [IToolboxItemType.IS_CONFIG_FILE_BROKEN]: async () => { try { diff --git a/src/main/events/rpc/routes/toolbox/checkProxy.ts b/src/main/events/rpc/routes/toolbox/checkProxy.ts index 5e7b680d..f1707dd8 100644 --- a/src/main/events/rpc/routes/toolbox/checkProxy.ts +++ b/src/main/events/rpc/routes/toolbox/checkProxy.ts @@ -1,4 +1,3 @@ - import axios, { AxiosRequestConfig } from 'axios' import fs from 'fs-extra' import { IConfig } from 'piclist' @@ -11,7 +10,7 @@ import { T } from '~/i18n' import { IToolboxItemCheckStatus, IToolboxItemType } from '#/types/enum' -function getProxy (proxyStr: string): AxiosRequestConfig['proxy'] | null { +function getProxy(proxyStr: string): AxiosRequestConfig['proxy'] | null { if (proxyStr) { try { const proxyOptions = new URL(proxyStr) @@ -27,10 +26,8 @@ function getProxy (proxyStr: string): AxiosRequestConfig['proxy'] | null { const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.HAS_PROBLEM_WITH_PROXY) -export const checkProxyMap: IToolboxCheckerMap< -IToolboxItemType.HAS_PROBLEM_WITH_PROXY -> = { - [IToolboxItemType.HAS_PROBLEM_WITH_PROXY]: async (event) => { +export const checkProxyMap: IToolboxCheckerMap = { + [IToolboxItemType.HAS_PROBLEM_WITH_PROXY]: async event => { sendToolboxRes(event, { status: IToolboxItemCheckStatus.LOADING }) @@ -38,9 +35,8 @@ IToolboxItemType.HAS_PROBLEM_WITH_PROXY if (fs.existsSync(configFilePath)) { let config: IConfig | undefined try { - config = await fs.readJSON(configFilePath) as IConfig - } catch (e) { - } + config = (await fs.readJSON(configFilePath)) as IConfig + } catch (e) {} if (!config) { return sendToolboxRes(event, { status: IToolboxItemCheckStatus.SUCCESS, diff --git a/src/main/events/rpc/routes/toolbox/index.ts b/src/main/events/rpc/routes/toolbox/index.ts index dfc7db1d..00a3b4a0 100644 --- a/src/main/events/rpc/routes/toolbox/index.ts +++ b/src/main/events/rpc/routes/toolbox/index.ts @@ -30,7 +30,7 @@ toolboxRouter handler(event as IpcMainEvent) } } else { - // do check all + // do check all for (const key in toolboxCheckMap) { const handler = toolboxCheckMap[key as IToolboxItemType] if (handler) { @@ -42,7 +42,8 @@ toolboxRouter IRPCType.SEND ) .add( - IRPCActionType.TOOLBOX_CHECK_FIX, async (event, args) => { + IRPCActionType.TOOLBOX_CHECK_FIX, + async (event, args) => { const [type] = args as IToolboxCheckArgs const handler = toolboxFixMap[type] if (handler) { @@ -52,6 +53,4 @@ toolboxRouter IRPCType.INVOKE ) -export { - toolboxRouter -} +export { toolboxRouter } diff --git a/src/main/events/rpc/routes/toolbox/utils.ts b/src/main/events/rpc/routes/toolbox/utils.ts index 4cb34285..08a48b52 100644 --- a/src/main/events/rpc/routes/toolbox/utils.ts +++ b/src/main/events/rpc/routes/toolbox/utils.ts @@ -1,7 +1,7 @@ import { IpcMainEvent } from 'electron' import { IRPCActionType, IToolboxItemType } from '#/types/enum' -export function sendToolboxResWithType (type: IToolboxItemType) { +export function sendToolboxResWithType(type: IToolboxItemType) { return (event: IpcMainEvent, res?: Omit) => { return event.sender.send(IRPCActionType.TOOLBOX_CHECK_RES, { ...res, diff --git a/src/main/events/rpc/routes/tray/index.ts b/src/main/events/rpc/routes/tray/index.ts index 40906dc9..a48cc2e0 100644 --- a/src/main/events/rpc/routes/tray/index.ts +++ b/src/main/events/rpc/routes/tray/index.ts @@ -1,6 +1,4 @@ -import { - Notification -} from 'electron' +import { Notification } from 'electron' import { RPCRouter } from '~/events/rpc/router' import { generateShortUrl, setTrayToolTip, handleCopyUrl } from '~/utils/common' @@ -42,8 +40,11 @@ const trayRoutes = [ const img = await uploader.setWebContents(trayWindow.webContents).uploadWithBuildInClipboard() if (img !== false) { const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN - handleCopyUrl(await (pasteTemplate(pasteStyle, img[0], db.get(configPaths.settings.customLink)))) - const isShowResultNotification = db.get(configPaths.settings.uploadResultNotification) === undefined ? true : !!db.get(configPaths.settings.uploadResultNotification) + handleCopyUrl(await pasteTemplate(pasteStyle, img[0], db.get(configPaths.settings.customLink))) + const isShowResultNotification = + db.get(configPaths.settings.uploadResultNotification) === undefined + ? true + : !!db.get(configPaths.settings.uploadResultNotification) if (isShowResultNotification) { const notification = new Notification({ title: T('UPLOAD_SUCCEED'), @@ -66,6 +67,4 @@ const trayRoutes = [ trayRouter.addBatch(trayRoutes) -export { - trayRouter -} +export { trayRouter } diff --git a/src/main/events/rpc/routes/upload/index.ts b/src/main/events/rpc/routes/upload/index.ts index 740f7cb3..723ed5b4 100644 --- a/src/main/events/rpc/routes/upload/index.ts +++ b/src/main/events/rpc/routes/upload/index.ts @@ -30,6 +30,4 @@ const uploadRoutes = [ uploadRouter.addBatch(uploadRoutes) -export { - uploadRouter -} +export { uploadRouter } diff --git a/src/main/fileServer/index.ts b/src/main/fileServer/index.ts index 06ec7ca1..1f7cb600 100644 --- a/src/main/fileServer/index.ts +++ b/src/main/fileServer/index.ts @@ -12,7 +12,7 @@ const serverPort = 36699 let server: http.Server -export function startFileServer () { +export function startFileServer() { server = http.createServer((req, res) => { const requestPath = req.url?.split('?')[0] const filePath = path.join(imgFilePath, decodeURIComponent(requestPath as string)) @@ -27,14 +27,16 @@ export function startFileServer () { }) }) - server.listen(serverPort, () => { - logger.info(`File server is running, http://localhost:${serverPort}`) - }).on('error', (err) => { - logger.error(err) - }) + server + .listen(serverPort, () => { + logger.info(`File server is running, http://localhost:${serverPort}`) + }) + .on('error', err => { + logger.error(err) + }) } -export function stopFileServer () { +export function stopFileServer() { server.close(() => { logger.info('File server is stopped') }) diff --git a/src/main/i18n/index.ts b/src/main/i18n/index.ts index bf1245fc..1f874c4c 100644 --- a/src/main/i18n/index.ts +++ b/src/main/i18n/index.ts @@ -15,18 +15,18 @@ class I18nManager { readonly defaultLanguage: string = 'zh-CN' private i18nFileList: II18nItem[] = builtinI18nList - setOutterI18nFolder (folder: string) { + setOutterI18nFolder(folder: string) { this.outterI18nFolder = folder } - addI18nFile (file: string, label: string) { + addI18nFile(file: string, label: string) { this.i18nFileList.push({ label, value: file }) } - private getLocales (lang: string): ILocales { + private getLocales(lang: string): ILocales { if (this.localesMap.has(lang)) { return this.localesMap.get(lang)! } @@ -53,13 +53,13 @@ class I18nManager { } } - setCurrentLanguage (lang: string) { + setCurrentLanguage(lang: string) { const locales = this.getLocales(lang) this.currentLanguage = lang this.initI18n(lang, locales) } - private initI18n (lang: string = this.defaultLanguage, locales: ILocales) { + private initI18n(lang: string = this.defaultLanguage, locales: ILocales) { const objectAdapter = new ObjectAdapter({ [lang]: locales }) @@ -69,15 +69,15 @@ class I18nManager { }) } - T (key: ILocalesKey, args: IStringKeyMap = {}): string { + T(key: ILocalesKey, args: IStringKeyMap = {}): string { return this.i18n?.translate(key, args) || key } - get languageList () { + get languageList() { return this.i18nFileList } - getCurrentLocales () { + getCurrentLocales() { return { lang: this.currentLanguage, locales: this.getLocales(this.currentLanguage) diff --git a/src/main/lifeCycle/errorHandler.ts b/src/main/lifeCycle/errorHandler.ts index ed6bf3ff..6533669a 100644 --- a/src/main/lifeCycle/errorHandler.ts +++ b/src/main/lifeCycle/errorHandler.ts @@ -24,9 +24,9 @@ process.on('unhandledRejection', (error: any) => { }) // acconrding to https://github.com/Molunerfinn/PicGo/commit/7363be798cfef11e980934e542817ff1d6c04389#diff-896d0db4fbd446798fbffec14d456b4cd98d4c72c46856c770a585fa7ab0926f -function bootstrapEPIPESuppression () { +function bootstrapEPIPESuppression() { let suppressing = false - function logEPIPEErrorOnce () { + function logEPIPEErrorOnce() { if (suppressing) { return } diff --git a/src/main/lifeCycle/fixPath.ts b/src/main/lifeCycle/fixPath.ts index c01ab22d..41522d89 100644 --- a/src/main/lifeCycle/fixPath.ts +++ b/src/main/lifeCycle/fixPath.ts @@ -1,20 +1,16 @@ // TODO: so how to import pure esm module in electron main process????? help wanted // just copy the fix-path because I can't import pure ESM module in electron main process -// @ts-nocheck +// @ts-nocheck since the module is not pure ESM // shell-path 3.0.0 not work const shellPath = require('shell-path') -export default function fixPath () { +export default function fixPath() { if (process.platform === 'win32') { return } - process.env.PATH = shellPath.sync() || [ - './node_modules/.bin', - '/.nodebrew/current/bin', - '/usr/local/bin', - process.env.PATH - ].join(':') + process.env.PATH = + shellPath.sync() || ['./node_modules/.bin', '/.nodebrew/current/bin', '/usr/local/bin', process.env.PATH].join(':') } diff --git a/src/main/lifeCycle/index.ts b/src/main/lifeCycle/index.ts index ccba9f7d..ec3839dc 100644 --- a/src/main/lifeCycle/index.ts +++ b/src/main/lifeCycle/index.ts @@ -1,19 +1,9 @@ import axios from 'axios' import fs from 'fs-extra' -import { - app, - globalShortcut, - protocol, - Notification, - dialog, - screen, - shell -} from 'electron' +import { app, globalShortcut, protocol, Notification, dialog, screen, shell } from 'electron' import { UpdateInfo, autoUpdater } from 'electron-updater' import path from 'path' -import { - createProtocol -} from 'vue-cli-plugin-electron-builder/lib' +import { createProtocol } from 'vue-cli-plugin-electron-builder/lib' import bus from '@core/bus' import db from '@core/datastore' @@ -22,13 +12,8 @@ import logger from '@core/picgo/logger' import { remoteNoticeHandler } from 'apis/app/remoteNotice' import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler' -import { - createTray, setDockMenu -} from 'apis/app/system' -import { - uploadChoosedFiles, - uploadClipboardFiles -} from 'apis/app/uploader/apis' +import { createTray, setDockMenu } from 'apis/app/system' +import { uploadChoosedFiles, uploadClipboardFiles } from 'apis/app/uploader/apis' import windowManager from 'apis/app/window/windowManager' import busEventList from '~/events/busEventList' @@ -57,7 +42,8 @@ const isDevelopment = process.env.NODE_ENV !== 'production' const handleStartUpFiles = (argv: string[], cwd: string) => { const files = getUploadFiles(argv, cwd, logger) - if (files === null || files.length > 0) { // 如果有文件列表作为参数,说明是命令行启动 + if (files === null || files.length > 0) { + // 如果有文件列表作为参数,说明是命令行启动 if (files === null) { logger.info('cli -> uploading file from clipboard') uploadClipboardFiles() @@ -83,34 +69,43 @@ autoUpdater.on('update-available', async (info: UpdateInfo) => { const lang = db.get(configPaths.settings.language) || II18nLanguage.ZH_CN let updateLog = '' try { - const url = lang === II18nLanguage.ZH_CN ? 'https://release.piclist.cn/currentVersion.md' : 'https://release.piclist.cn/currentVersion_en.md' + const url = + lang === II18nLanguage.ZH_CN + ? 'https://release.piclist.cn/currentVersion.md' + : 'https://release.piclist.cn/currentVersion_en.md' const res = await axios.get(url) updateLog = res.data } catch (e: any) { logger.error(e) } - dialog.showMessageBox({ - type: 'info', - title: T('FIND_NEW_VERSION'), - buttons: ['Yes', 'Go to download page'], - message: T('TIPS_FIND_NEW_VERSION', { - v: info.version - }) + '\n\n' + updateLog, - checkboxLabel: T('NO_MORE_NOTICE'), - checkboxChecked: false - }).then((result) => { - if (result.response === 0) { - autoUpdater.downloadUpdate() - } else { - shell.openExternal('https://github.com/Kuingsmile/PicList/releases/latest') - } - db.set(configPaths.settings.showUpdateTip, !result.checkboxChecked) - }).catch((err) => { - logger.error(err) - }) + dialog + .showMessageBox({ + type: 'info', + title: T('FIND_NEW_VERSION'), + buttons: ['Yes', 'Go to download page'], + message: + T('TIPS_FIND_NEW_VERSION', { + v: info.version + }) + + '\n\n' + + updateLog, + checkboxLabel: T('NO_MORE_NOTICE'), + checkboxChecked: false + }) + .then(result => { + if (result.response === 0) { + autoUpdater.downloadUpdate() + } else { + shell.openExternal('https://github.com/Kuingsmile/PicList/releases/latest') + } + db.set(configPaths.settings.showUpdateTip, !result.checkboxChecked) + }) + .catch(err => { + logger.error(err) + }) }) -autoUpdater.on('download-progress', (progressObj) => { +autoUpdater.on('download-progress', progressObj => { const percent = { progress: progressObj.percent } @@ -119,28 +114,31 @@ autoUpdater.on('download-progress', (progressObj) => { }) autoUpdater.on('update-downloaded', () => { - dialog.showMessageBox({ - type: 'info', - title: T('UPDATE_DOWNLOADED'), - buttons: ['Yes', 'No'], - message: T('TIPS_UPDATE_DOWNLOADED') - }).then((result) => { - const window = windowManager.get(IWindowList.SETTING_WINDOW)! - window.webContents.send('updateProgress', { progress: 100 }) - if (result.response === 0) { - autoUpdater.quitAndInstall() - } - }).catch((err) => { - logger.error(err) - }) + dialog + .showMessageBox({ + type: 'info', + title: T('UPDATE_DOWNLOADED'), + buttons: ['Yes', 'No'], + message: T('TIPS_UPDATE_DOWNLOADED') + }) + .then(result => { + const window = windowManager.get(IWindowList.SETTING_WINDOW)! + window.webContents.send('updateProgress', { progress: 100 }) + if (result.response === 0) { + autoUpdater.quitAndInstall() + } + }) + .catch(err => { + logger.error(err) + }) }) -autoUpdater.on('error', (err) => { +autoUpdater.on('error', err => { console.log(err) }) class LifeCycle { - async #beforeReady () { + async #beforeReady() { protocol.registerSchemesAsPrivileged([{ scheme: 'picgo', privileges: { secure: true, standard: true } }]) // fix the $PATH in macOS & linux fixPath() @@ -153,7 +151,7 @@ class LifeCycle { busEventList.listen() } - #onReady () { + #onReady() { const readyFunction = async () => { createProtocol('picgo') windowManager.create(IWindowList.TRAY_WINDOW) @@ -173,7 +171,6 @@ class LifeCycle { const isHideDock = db.get(configPaths.settings.isHideDock) || false const startMode = db.get(configPaths.settings.startMode) || ISartMode.QUIET const currentPicBed = db.get(configPaths.picBed.uploader) || db.get(configPaths.picBed.current) || 'smms' - // @ts-ignore const currentPicBedConfig = db.get(`picBed.${currentPicBed}`)?._configName || 'Default' const tooltip = `${currentPicBed} ${currentPicBedConfig}` if (process.platform === 'darwin') { @@ -237,7 +234,7 @@ class LifeCycle { app.whenReady().then(readyFunction) } - #onRunning () { + #onRunning() { app.on('second-instance', (_, commandLine, workingDirectory) => { logger.info('detect second instance') const result = handleStartUpFiles(commandLine, workingDirectory) @@ -272,7 +269,7 @@ class LifeCycle { } } - #onQuit () { + #onQuit() { app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit() @@ -304,7 +301,7 @@ class LifeCycle { } } - async launchApp () { + async launchApp() { const gotTheLock = app.requestSingleInstanceLock() if (!gotTheLock) { app.quit() @@ -319,6 +316,4 @@ class LifeCycle { const bootstrap = new LifeCycle() -export { - bootstrap -} +export { bootstrap } diff --git a/src/main/manage/apis/aliyun.ts b/src/main/manage/apis/aliyun.ts index caac6698..9beed19f 100644 --- a/src/main/manage/apis/aliyun.ts +++ b/src/main/manage/apis/aliyun.ts @@ -8,7 +8,13 @@ import windowManager from 'apis/app/window/windowManager' import UpDownTaskQueue from '~/manage/datastore/upDownTaskQueue' import { ManageLogger } from '~/manage/utils/logger' -import { hmacSha1Base64, getFileMimeType, formatError, NewDownloader, ConcurrencyPromisePool } from '~/manage/utils/common' +import { + hmacSha1Base64, + getFileMimeType, + formatError, + NewDownloader, + ConcurrencyPromisePool +} from '~/manage/utils/common' import { commonTaskStatus, IWindowList, uploadTaskSpecialStatus } from '#/types/enum' import { isImage } from '#/utils/common' @@ -22,7 +28,7 @@ class AliyunApi { timeOut = 30000 logger: ManageLogger - constructor (accessKeyId: string, accessKeySecret: string, logger: ManageLogger) { + constructor(accessKeyId: string, accessKeySecret: string, logger: ManageLogger) { this.ctx = new OSS({ accessKeyId, accessKeySecret, @@ -33,7 +39,7 @@ class AliyunApi { this.logger = logger } - formatFolder (item: string, slicedPrefix: string, urlPrefix: string): any { + formatFolder(item: string, slicedPrefix: string, urlPrefix: string): any { return { key: item, url: `${urlPrefix}/${item}`, @@ -48,7 +54,7 @@ class AliyunApi { } } - formatFile (item: OSS.ObjectMeta, slicedPrefix: string, urlPrefix: string): any { + formatFile(item: OSS.ObjectMeta, slicedPrefix: string, urlPrefix: string): any { const fileName = item.name.replace(slicedPrefix, '') return { ...item, @@ -65,26 +71,32 @@ class AliyunApi { } } - getCanonicalizedOSSHeaders (headers: IStringKeyMap) { + getCanonicalizedOSSHeaders(headers: IStringKeyMap) { const lowerCaseHeaders = Object.keys(headers).reduce((acc, key) => { acc[key.toLowerCase()] = headers[key] return acc }, {} as IStringKeyMap) let canonicalizedOSSHeaders = '' const headerKeys = Object.keys(lowerCaseHeaders).sort() - headerKeys.forEach((key) => { + headerKeys.forEach(key => { key.startsWith('x-oss-') && (canonicalizedOSSHeaders += `${key}:${lowerCaseHeaders[key]}\n`) }) return canonicalizedOSSHeaders } - authorization (method: string, canonicalizedResource: string, headers: IStringKeyMap, contentMd5: string, contentType: string) { + authorization( + method: string, + canonicalizedResource: string, + headers: IStringKeyMap, + contentMd5: string, + contentType: string + ) { const date = new Date().toUTCString() const stringToSign = `${method.toUpperCase()}\n${contentMd5}\n${contentType}\n${date}\n${this.getCanonicalizedOSSHeaders(headers)}${canonicalizedResource}` return `OSS ${this.accessKeyId}:${hmacSha1Base64(this.accessKeySecret, stringToSign)}` } - getNewCtx (region: string, bucket: string) { + getNewCtx(region: string, bucket: string) { return new OSS({ accessKeyId: this.accessKeyId, accessKeySecret: this.accessKeySecret, @@ -95,21 +107,25 @@ class AliyunApi { } /** - * 获取存储桶列表 - */ - async getBucketList (): Promise { + * 获取存储桶列表 + */ + async getBucketList(): Promise { const getBuckets = async (marker?: string) => { - const res = await this.ctx.listBuckets({ + const res = (await this.ctx.listBuckets({ marker, 'max-keys': 1000 - }) as IStringKeyMap + })) as IStringKeyMap if (res?.res?.statusCode !== 200 || !res?.buckets) return { result: [], isTruncated: false } const formattedBuckets = res.buckets.map((item: OSS.Bucket) => ({ Name: item.name, Location: item.region, CreationDate: item.creationDate })) - return { result: formattedBuckets, isTruncated: res.isTruncated, nextMarker: res.nextMarker } + return { + result: formattedBuckets, + isTruncated: res.isTruncated, + nextMarker: res.nextMarker + } } const result: IStringKeyMap[] = [] let NextMarker: string | undefined @@ -127,7 +143,7 @@ class AliyunApi { /** * 获取自定义域名 */ - async getBucketDomain (param: IStringKeyMap): Promise { + async getBucketDomain(param: IStringKeyMap): Promise { const headers = { Date: new Date().toUTCString() } @@ -160,17 +176,17 @@ class AliyunApi { } /** - * 创建存储桶 - * @param {Object} configMap - * configMap = { - * BucketName: string, - * region: string, - * acl: string - * } - * @description - * acl: private | publicRead | publicReadWrite - */ - async createBucket (configMap: IStringKeyMap): Promise { + * 创建存储桶 + * @param {Object} configMap + * configMap = { + * BucketName: string, + * region: string, + * acl: string + * } + * @description + * acl: private | publicRead | publicReadWrite + */ + async createBucket(configMap: IStringKeyMap): Promise { const client = new OSS({ accessKeyId: this.accessKeyId, accessKeySecret: this.accessKeySecret, @@ -191,9 +207,14 @@ class AliyunApi { return res?.res?.status === 200 } - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! - const { bucketName: bucket, bucketConfig: { Location: region }, prefix, cancelToken } = configMap + const { + bucketName: bucket, + bucketConfig: { Location: region }, + prefix, + cancelToken + } = configMap const slicedPrefix = prefix.slice(1) const urlPrefix = configMap.customUrl || `https://${bucket}.${region}.aliyuncs.com` let marker @@ -212,13 +233,16 @@ class AliyunApi { } const client = this.getNewCtx(region, bucket) do { - res = await client.listV2({ - prefix: slicedPrefix === '' ? undefined : slicedPrefix, - 'max-keys': '1000', - 'continuation-token': marker - }, { - timeout: this.timeOut - }) + res = await client.listV2( + { + prefix: slicedPrefix === '' ? undefined : slicedPrefix, + 'max-keys': '1000', + 'continuation-token': marker + }, + { + timeout: this.timeOut + } + ) if (res?.res?.statusCode === 200) { res?.objects?.forEach((item: OSS.ObjectMeta) => { item.size !== 0 && result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix)) @@ -238,9 +262,14 @@ class AliyunApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! - const { bucketName: bucket, bucketConfig: { Location: region }, prefix, cancelToken } = configMap + const { + bucketName: bucket, + bucketConfig: { Location: region }, + prefix, + cancelToken + } = configMap const slicedPrefix = prefix.slice(1) const urlPrefix = configMap.customUrl || `https://${bucket}.${region}.aliyuncs.com` let marker @@ -259,14 +288,17 @@ class AliyunApi { } const client = this.getNewCtx(region, bucket) do { - res = await client.listV2({ - prefix: slicedPrefix === '' ? undefined : slicedPrefix, - delimiter: '/', - 'max-keys': '1000', - 'continuation-token': marker - }, { - timeout: this.timeOut - }) + res = await client.listV2( + { + prefix: slicedPrefix === '' ? undefined : slicedPrefix, + delimiter: '/', + 'max-keys': '1000', + 'continuation-token': marker + }, + { + timeout: this.timeOut + } + ) if (res?.res?.statusCode === 200) { res?.prefixes?.forEach((item: string) => { result.fullList.push(this.formatFolder(item, slicedPrefix, urlPrefix)) @@ -303,21 +335,30 @@ class AliyunApi { * itemsPerPage: number, * customUrl: string * } - */ - async getBucketFileList (configMap: IStringKeyMap): Promise { - const { bucketName: bucket, bucketConfig: { Location: region }, prefix, marker, itemsPerPage } = configMap + */ + async getBucketFileList(configMap: IStringKeyMap): Promise { + const { + bucketName: bucket, + bucketConfig: { Location: region }, + prefix, + marker, + itemsPerPage + } = configMap const slicedPrefix = prefix.slice(1) const urlPrefix = configMap.customUrl || `https://${bucket}.${region}.aliyuncs.com` const client = this.getNewCtx(region, bucket) - const res = await client.listV2({ - prefix: slicedPrefix || undefined, - delimiter: '/', - 'max-keys': itemsPerPage.toString(), - 'continuation-token': marker - }, { - timeout: this.timeOut - }) as any + const res = (await client.listV2( + { + prefix: slicedPrefix || undefined, + delimiter: '/', + 'max-keys': itemsPerPage.toString(), + 'continuation-token': marker + }, + { + timeout: this.timeOut + } + )) as any // prefixes can be null // objects will be [] when no file if (res?.res.statusCode !== 200) { @@ -330,7 +371,9 @@ class AliyunApi { } const fullList = [ ...(res.prefixes?.map((item: string) => this.formatFolder(item, slicedPrefix, urlPrefix)) || []), - ...(res.objects?.filter((item: OSS.ObjectMeta) => item.size !== 0).map((item: OSS.ObjectMeta) => this.formatFile(item, slicedPrefix, urlPrefix)) || []) + ...(res.objects + ?.filter((item: OSS.ObjectMeta) => item.size !== 0) + .map((item: OSS.ObjectMeta) => this.formatFile(item, slicedPrefix, urlPrefix)) || []) ] return { fullList, @@ -341,50 +384,47 @@ class AliyunApi { } /** - * 重命名文件 - * @param configMap - * configMap = { - * bucketName: string, - * region: string, - * oldKey: string, - * newKey: string - * } - */ - async renameBucketFile (configMap: IStringKeyMap): Promise { + * 重命名文件 + * @param configMap + * configMap = { + * bucketName: string, + * region: string, + * oldKey: string, + * newKey: string + * } + */ + async renameBucketFile(configMap: IStringKeyMap): Promise { const { bucketName, region, oldKey, newKey } = configMap const client = this.getNewCtx(region, bucketName) - const copyRes = await client.copy( - newKey, - oldKey - ) as any + const copyRes = (await client.copy(newKey, oldKey)) as any if (copyRes?.res.statusCode === 200) { - const deleteRes = await client.delete(oldKey) as any + const deleteRes = (await client.delete(oldKey)) as any return deleteRes?.res.statusCode === 204 } return false } /** - * 删除文件 - * @param configMap - * configMap = { - * bucketName: string, - * region: string, - * key: string - * } - */ - async deleteBucketFile (configMap: IStringKeyMap): Promise { + * 删除文件 + * @param configMap + * configMap = { + * bucketName: string, + * region: string, + * key: string + * } + */ + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap 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.statusCode === 204 } /** - * 删除文件夹 - * @param configMap - */ - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + * 删除文件夹 + * @param configMap + */ + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap const client = this.getNewCtx(region, bucketName) let marker @@ -394,14 +434,17 @@ class AliyunApi { Contents: [] as any[] } do { - const res = await client.listV2({ - prefix: key, - delimiter: '/', - 'max-keys': '1000', - 'continuation-token': marker - }, { - timeout: this.timeOut - }) as any + const res = (await client.listV2( + { + prefix: key, + delimiter: '/', + 'max-keys': '1000', + 'continuation-token': marker + }, + { + timeout: this.timeOut + } + )) as any if (res?.res.statusCode !== 200) return false res.prefixes !== null && allFileList.CommonPrefixes.push(...res.prefixes) @@ -423,8 +466,9 @@ class AliyunApi { if (allFileList.Contents.length > 0) { const cycle = Math.ceil(allFileList.Contents.length / 1000) for (let i = 0; i < cycle; i++) { - const deleteRes = await client.deleteMulti( - allFileList.Contents.slice(i * 1000, (i + 1) * 1000).map((item: any) => item.name)) as any + const deleteRes = (await client.deleteMulti( + allFileList.Contents.slice(i * 1000, (i + 1) * 1000).map((item: any) => item.name) + )) as any if (deleteRes?.res.statusCode !== 200) return false } } @@ -432,17 +476,17 @@ class AliyunApi { } /** - * 获取预签名url - * @param configMap - * configMap = { - * bucketName: string, - * region: string, - * key: string, - * expires: number, - * customUrl: string - * } - */ - async getPreSignedUrl (configMap: IStringKeyMap): Promise { + * 获取预签名url + * @param configMap + * configMap = { + * bucketName: string, + * region: string, + * key: string, + * expires: number, + * customUrl: string + * } + */ + async getPreSignedUrl(configMap: IStringKeyMap): Promise { const { bucketName, region, key, expires, customUrl } = configMap const client = this.getNewCtx(region, bucketName) const res = client.signatureUrl(key, { @@ -455,7 +499,7 @@ class AliyunApi { * 上传文件 * @param configMap */ - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap // fileArray = [{ // bucketName: string, @@ -485,10 +529,8 @@ class AliyunApi { targetFileBucket: bucketName, targetFileRegion: region }) - client.multipartUpload( - key, - filePath, - { + client + .multipartUpload(key, filePath, { partSize: 1 * 1024 * 1024, mime: getFileMimeType(fileName), progress: (p: number) => { @@ -499,37 +541,43 @@ class AliyunApi { status: uploadTaskSpecialStatus.uploading }) } - } - ).then((res: any) => { - const id = `${bucketName}-${region}-${key}-${filePath}` - if (res?.res?.statusCode === 200) { - instance.updateUploadTask({ - id, - progress: 100, - status: uploadTaskSpecialStatus.uploaded, - response: JSON.stringify(res), - finishTime: new Date().toLocaleString() - }) - } else { + }) + .then((res: any) => { + const id = `${bucketName}-${region}-${key}-${filePath}` + if (res?.res?.statusCode === 200) { + instance.updateUploadTask({ + id, + progress: 100, + status: uploadTaskSpecialStatus.uploaded, + response: JSON.stringify(res), + finishTime: new Date().toLocaleString() + }) + } else { + instance.updateUploadTask({ + id, + progress: 0, + status: commonTaskStatus.failed, + response: JSON.stringify(res), + finishTime: new Date().toLocaleString() + }) + } + }) + .catch((err: any) => { + this.logger.error( + formatError(err, { + class: 'AliyunApi', + method: 'uploadBucketFile' + }) + ) + const id = `${bucketName}-${region}-${key}-${filePath}` instance.updateUploadTask({ id, progress: 0, status: commonTaskStatus.failed, - response: JSON.stringify(res), + response: JSON.stringify(err), finishTime: new Date().toLocaleString() }) - } - }).catch((err: any) => { - this.logger.error(formatError(err, { class: 'AliyunApi', method: 'uploadBucketFile' })) - const id = `${bucketName}-${region}-${key}-${filePath}` - instance.updateUploadTask({ - id, - progress: 0, - status: commonTaskStatus.failed, - response: JSON.stringify(err), - finishTime: new Date().toLocaleString() }) - }) } return true } @@ -538,10 +586,10 @@ class AliyunApi { * 新建文件夹 * @param configMap */ - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap 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?.statusCode === 200 } @@ -549,7 +597,7 @@ class AliyunApi { * 下载文件 * @param configMap */ - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray, maxDownloadFileCount } = configMap const instance = UpDownTaskQueue.getInstance() const promises = [] as any @@ -571,20 +619,27 @@ class AliyunApi { const preSignedUrl = client.signatureUrl(key, { expires: 60 * 60 * 48 }) - promises.push(() => new Promise((resolve, reject) => { - NewDownloader(instance, preSignedUrl, id, savedFilePath, this.logger) - .then((res: boolean) => { - if (res) { - resolve(res) - } else { - reject(res) - } + promises.push( + () => + new Promise((resolve, reject) => { + NewDownloader(instance, preSignedUrl, id, savedFilePath, this.logger).then((res: boolean) => { + if (res) { + resolve(res) + } else { + reject(res) + } + }) }) - })) + ) } const pool = new ConcurrencyPromisePool(maxDownloadFileCount) pool.all(promises).catch((error: any) => { - this.logger.error(formatError(error, { class: 'AliyunApi', method: 'downloadBucketFile' })) + this.logger.error( + formatError(error, { + class: 'AliyunApi', + method: 'downloadBucketFile' + }) + ) }) return true } diff --git a/src/main/manage/apis/github.ts b/src/main/manage/apis/github.ts index 54d4140a..b1657d32 100644 --- a/src/main/manage/apis/github.ts +++ b/src/main/manage/apis/github.ts @@ -6,7 +6,14 @@ import path from 'path' import windowManager from 'apis/app/window/windowManager' import UpDownTaskQueue from '~/manage/datastore/upDownTaskQueue' -import { gotUpload, NewDownloader, getAgent, getOptions, ConcurrencyPromisePool, formatError } from '~/manage/utils/common' +import { + gotUpload, + NewDownloader, + getAgent, + getOptions, + ConcurrencyPromisePool, + formatError +} from '~/manage/utils/common' import { ManageLogger } from '~/manage/utils/logger' import { commonTaskStatus, IWindowList } from '#/types/enum' @@ -20,9 +27,9 @@ class GithubApi { proxy: any proxyStr: string | undefined baseUrl = 'https://api.github.com' - commonHeaders : IStringKeyMap + commonHeaders: IStringKeyMap - constructor (token: string, username: string, proxy: string | undefined, logger: ManageLogger) { + constructor(token: string, username: string, proxy: string | undefined, logger: ManageLogger) { this.logger = logger this.token = token.startsWith('Bearer ') ? token : `Bearer ${token}`.trim() this.username = username @@ -34,16 +41,25 @@ class GithubApi { } } - formatFolder (item: any, slicedPrefix: string, branch: string, repo: string, cdnUrl: string | undefined) { + formatFolder(item: any, slicedPrefix: string, branch: string, repo: string, cdnUrl: string | undefined) { const key = `${slicedPrefix ? `${slicedPrefix}/` : ''}${item.path}/` let rawUrl = '' const placeholders = ['{username}', '{repo}', '{branch}', '{path}'] rawUrl = cdnUrl ? placeholders.some(item => cdnUrl.includes(item)) ? placeholders.reduce((url, ph) => { - const value = ph === '{username}' ? this.username : ph === '{repo}' ? repo : ph === '{branch}' ? branch : ph === '{path}' ? key : '' - return url.replaceAll(ph, value) - }, cdnUrl) + const value = + ph === '{username}' + ? this.username + : ph === '{repo}' + ? repo + : ph === '{branch}' + ? branch + : ph === '{path}' + ? key + : '' + return url.replaceAll(ph, value) + }, cdnUrl) : `${cdnUrl}/${key}` : `https://raw.githubusercontent.com/${this.username}/${repo}/${branch}/${key}` rawUrl = rawUrl.replace(/(? cdnUrl.includes(item)) ? placeholders.reduce((url, ph) => { - const value = ph === '{username}' ? this.username : ph === '{repo}' ? repo : ph === '{branch}' ? branch : ph === '{path}' ? `${slicedPrefix}/${item.path}` : '' - return url.replaceAll(ph, value) - }, cdnUrl) + const value = + ph === '{username}' + ? this.username + : ph === '{repo}' + ? repo + : ph === '{branch}' + ? branch + : ph === '{path}' + ? `${slicedPrefix}/${item.path}` + : '' + return url.replaceAll(ph, value) + }, cdnUrl) : `${cdnUrl}/${key}` : `https://raw.githubusercontent.com/${this.username}/${repo}/${branch}/${key}` rawUrl = rawUrl.replace(/(? { + * get repo list + */ + async getBucketList(): Promise { let initPage = 1 let res const result = [] as any[] do { - res = await got( + res = (await got( `${this.baseUrl}/user/repos`, - getOptions('GET', this.commonHeaders, { page: initPage, per_page: 100 }, 'json', undefined, undefined, this.proxy) - ) as any + getOptions( + 'GET', + this.commonHeaders, + { page: initPage, per_page: 100 }, + 'json', + undefined, + undefined, + this.proxy + ) + )) as any if (res.statusCode === 200) { res.body.forEach((item: any) => { result.push({ @@ -123,16 +156,24 @@ class GithubApi { /** * 获取branch列表 */ - async getBucketDomain (param: IStringKeyMap): Promise { + async getBucketDomain(param: IStringKeyMap): Promise { const { bucketName: repo } = param let initPage = 1 let res const result = [] as string[] do { - res = await got( + res = (await got( `${this.baseUrl}/repos/${this.username}/${repo}/branches`, - getOptions('GET', this.commonHeaders, { page: initPage, per_page: 100 }, 'json', undefined, undefined, this.proxy) - ) as any + getOptions( + 'GET', + this.commonHeaders, + { page: initPage, per_page: 100 }, + 'json', + undefined, + undefined, + this.proxy + ) + )) as any if (res.statusCode === 200) { res.body.forEach((item: any) => result.push(item.name)) } else { @@ -143,7 +184,7 @@ class GithubApi { return result } - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: repo, customUrl: branch, prefix, cancelToken, cdnUrl } = configMap const slicedPrefix = prefix.replace(/(^\/+|\/+$)/g, '') @@ -167,10 +208,10 @@ class GithubApi { return result } const currentPrefix = treeQueue[0] - res = await got( + res = (await got( `${this.baseUrl}/repos/${this.username}/${repo}/git/trees/${branch}:${treeQueue.shift()}`, getOptions('GET', this.commonHeaders, {}, 'json', undefined, undefined, this.proxy) - ) as any + )) as any if (res && res.statusCode === 200) { const { tree } = res.body tree.forEach((item: any) => { @@ -194,7 +235,7 @@ class GithubApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: repo, customUrl: branch, prefix, cancelToken, cdnUrl } = configMap const slicedPrefix = prefix.replace(/(^\/+|\/+$)/g, '') @@ -236,15 +277,15 @@ class GithubApi { } /** - * 删除文件 - * @param configMap - * configMap = { - * bucketName: string, - * region: string, - * key: string - * } - */ - async deleteBucketFile (configMap: IStringKeyMap): Promise { + * 删除文件 + * @param configMap + * configMap = { + * bucketName: string, + * region: string, + * key: string + * } + */ + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { bucketName: repo, githubBranch: branch, key, DeleteHash: sha } = configMap const body = { message: 'deleted by PicList', @@ -259,94 +300,135 @@ class GithubApi { } /** - * create a new tree to delete a folder - * @param configMap - */ - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + * create a new tree to delete a folder + * @param configMap + */ + async deleteBucketFolder(configMap: IStringKeyMap): Promise { 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}`, getOptions('GET', this.commonHeaders, undefined, 'json', undefined, undefined, this.proxy) - ) as any + )) as any if (refRes.statusCode !== 200) return false 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}`, getOptions('GET', undefined, undefined, 'json', undefined, undefined, this.proxy) - ) as any + )) as any if (rootRes.statusCode !== 200) return false const rootSha = rootRes.body.commit.commit.tree.sha // TODO: if there are more than 10000 files in the folder, it will be truncated // 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, '')}`, - getOptions('GET', this.commonHeaders, { - recursive: true - }, 'json', undefined, undefined, this.proxy) - ) as any + getOptions( + 'GET', + this.commonHeaders, + { + recursive: true + }, + 'json', + undefined, + undefined, + this.proxy + ) + )) as any if (treeRes.statusCode !== 200) return false const oldTree = treeRes.body.tree // create a new tree - const newTree = oldTree.filter((item: any) => item.type === 'blob') - .map((item:any) => ({ + const newTree = oldTree + .filter((item: any) => item.type === 'blob') + .map((item: any) => ({ path: `${key.replace(/(^\/+|\/+$)/g, '')}/${item.path}`, mode: item.mode, type: item.type, sha: null })) - const newTreeShaRes = await got( + const newTreeShaRes = (await got( `${this.baseUrl}/repos/${this.username}/${repo}/git/trees`, - getOptions('POST', this.commonHeaders, undefined, 'json', JSON.stringify({ - base_tree: rootSha, - tree: newTree - }), undefined, this.proxy) - ) as any + getOptions( + 'POST', + this.commonHeaders, + undefined, + 'json', + JSON.stringify({ + base_tree: rootSha, + tree: newTree + }), + undefined, + this.proxy + ) + )) as any if (newTreeShaRes.statusCode !== 201) return false 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`, - getOptions('POST', this.commonHeaders, undefined, 'json', JSON.stringify({ - message: 'deleted by PicList', - tree: newTreeSha, - parents: [refSha] - }), undefined, this.proxy) - ) as any + getOptions( + 'POST', + this.commonHeaders, + undefined, + 'json', + JSON.stringify({ + message: 'deleted by PicList', + tree: newTreeSha, + parents: [refSha] + }), + undefined, + this.proxy + ) + )) as any if (commitRes.statusCode !== 201) return false 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}`, - getOptions('PATCH', this.commonHeaders, undefined, 'json', JSON.stringify({ - sha: commitSha - }), undefined, this.proxy) - ) as any + getOptions( + 'PATCH', + this.commonHeaders, + undefined, + 'json', + JSON.stringify({ + sha: commitSha + }), + undefined, + this.proxy + ) + )) as any return updateRefRes.statusCode === 200 } /** - * 获取预签名url - * @param configMap - * configMap = { - * bucketName: string, - * region: string, - * key: string, - * expires: number, - * customUrl: string - * } - */ - async getPreSignedUrl (configMap: IStringKeyMap): Promise { + * 获取预签名url + * @param configMap + * configMap = { + * bucketName: string, + * region: string, + * key: string, + * expires: number, + * customUrl: string + * } + */ + async getPreSignedUrl(configMap: IStringKeyMap): Promise { const { bucketName: repo, customUrl: branch, key, rawUrl, githubPrivate: isPrivate } = configMap if (!isPrivate) return rawUrl - const res = await got( + const res = (await got( `${this.baseUrl}/repos/${this.username}/${repo}/contents/${key}`, - getOptions('GET', this.commonHeaders, { - ref: branch - }, 'json', undefined, undefined, this.proxy) - ) as any + getOptions( + 'GET', + this.commonHeaders, + { + ref: branch + }, + 'json', + undefined, + undefined, + this.proxy + ) + )) as any return res.statusCode === 200 ? res.body.download_url : '' } @@ -354,7 +436,7 @@ class GithubApi { * 新建文件夹 * @param configMap */ - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName: repo, githubBranch: branch, key } = configMap const newFileKey = `${trimPath(key)}/.gitkeep` const base64Content = Buffer.from('created by PicList').toString('base64') @@ -374,7 +456,7 @@ class GithubApi { * 上传文件 * @param configMap */ - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap const instance = UpDownTaskQueue.getInstance() fileArray.forEach((item: any) => { @@ -423,7 +505,7 @@ class GithubApi { * 下载文件 * @param configMap */ - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray, maxDownloadFileCount } = configMap const instance = UpDownTaskQueue.getInstance() const promises = [] as any @@ -454,27 +536,27 @@ class GithubApi { } else { downloadUrl = githubUrl } - promises.push(() => new Promise((resolve, reject) => { - NewDownloader( - instance, - downloadUrl, - id, - savedFilePath, - this.logger, - this.proxyStr - ) - .then((res: boolean) => { - if (res) { - resolve(res) - } else { - reject(res) - } + promises.push( + () => + new Promise((resolve, reject) => { + NewDownloader(instance, downloadUrl, id, savedFilePath, this.logger, this.proxyStr).then((res: boolean) => { + if (res) { + resolve(res) + } else { + reject(res) + } + }) }) - })) + ) } const pool = new ConcurrencyPromisePool(maxDownloadFileCount) - pool.all(promises).catch((error) => { - this.logger.error(formatError(error, { class: 'GithubApi', method: 'downloadBucketFile' })) + pool.all(promises).catch(error => { + this.logger.error( + formatError(error, { + class: 'GithubApi', + method: 'downloadBucketFile' + }) + ) }) return true } diff --git a/src/main/manage/apis/imgur.ts b/src/main/manage/apis/imgur.ts index 377254e7..d5ccf4f1 100644 --- a/src/main/manage/apis/imgur.ts +++ b/src/main/manage/apis/imgur.ts @@ -31,7 +31,7 @@ class ImgurApi { idHeaders: any baseUrl = 'https://api.imgur.com/3' - constructor (userName: string, accessToken: string, proxy: any, logger: ManageLogger) { + constructor(userName: string, accessToken: string, proxy: any, logger: ManageLogger) { this.userName = userName this.accessToken = accessToken.startsWith('Bearer ') ? accessToken : `Bearer ${accessToken}` this.proxy = proxy @@ -42,7 +42,7 @@ class ImgurApi { } } - formatFile (item: any) { + formatFile(item: any) { const fileName = path.basename(item.link) const isImg = isImage(fileName) return { @@ -62,17 +62,17 @@ class ImgurApi { } /** - * get repo list - */ - async getBucketList (): Promise { + * get repo list + */ + async getBucketList(): Promise { let initPage = 0 let res const result = [] as any[] do { - res = await got( + res = (await got( `${this.baseUrl}/account/${this.userName}/albums/${initPage}`, getOptions('GET', this.tokenHeaders, undefined, 'json', undefined, undefined, this.proxy) - ) as any + )) as any if (!(res.statusCode === 200 && res.body.success)) { return [] } @@ -93,9 +93,12 @@ class ImgurApi { return finalResult } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! - const { bucketConfig: { Location: albumHash }, cancelToken } = configMap + const { + bucketConfig: { Location: albumHash }, + cancelToken + } = configMap const cancelTask = [false] ipcMain.on('cancelLoadingFileList', (_: IpcMainEvent, token: string) => { if (token === cancelToken) { @@ -110,10 +113,10 @@ class ImgurApi { finished: false } if (albumHash !== 'unclassified') { - res = await got( + res = (await got( `${this.baseUrl}/account/${this.userName}/album/${albumHash}`, getOptions('GET', this.tokenHeaders, undefined, 'json', undefined, undefined, this.proxy) - ) as any + )) as any if (res.statusCode === 200 && res.body.success) { res.body.data.images.forEach((item: any) => { result.fullList.push(this.formatFile(item)) @@ -127,10 +130,10 @@ class ImgurApi { } else { let initPage = 0 do { - res = await got( + res = (await got( `${this.baseUrl}/account/${this.userName}/images/${initPage}`, getOptions('GET', this.tokenHeaders, undefined, 'json', undefined, undefined, this.proxy) - ) as any + )) as any if (res.statusCode === 200 && res.body.success) { res.body.data.forEach((item: any) => { result.fullList.push(this.formatFile(item)) @@ -150,12 +153,12 @@ class ImgurApi { ipcMain.removeAllListeners('cancelLoadingFileList') } - async deleteBucketFile (configMap: IStringKeyMap): Promise { + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { DeleteHash: deleteHash } = configMap - const res = await got( + const res = (await got( `${this.baseUrl}/account/${this.userName}/image/${deleteHash}`, getOptions('DELETE', this.tokenHeaders, undefined, 'json', undefined, undefined, this.proxy) - ) as any + )) as any return res.statusCode === 200 && res.body.success } @@ -163,7 +166,7 @@ class ImgurApi { * 上传文件 * @param configMap */ - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap const instance = UpDownTaskQueue.getInstance() fileArray.forEach((item: any) => { @@ -223,7 +226,7 @@ class ImgurApi { * 下载文件 * @param configMap */ - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray, maxDownloadFileCount } = configMap const instance = UpDownTaskQueue.getInstance() const promises = [] as any @@ -241,26 +244,21 @@ class ImgurApi { sourceFileName: fileName, targetFilePath: savedFilePath }) - promises.push(() => new Promise((resolve, reject) => { - NewDownloader( - instance, - url, - id, - savedFilePath, - this.logger, - this.proxyStr - ) - .then((res: boolean) => { - if (res) { - resolve(res) - } else { - reject(res) - } + promises.push( + () => + new Promise((resolve, reject) => { + NewDownloader(instance, url, id, savedFilePath, this.logger, this.proxyStr).then((res: boolean) => { + if (res) { + resolve(res) + } else { + reject(res) + } + }) }) - })) + ) } const pool = new ConcurrencyPromisePool(maxDownloadFileCount) - pool.all(promises).catch((error) => { + pool.all(promises).catch(error => { this.logger.error(formatError(error, { class: 'ImgurApi', method: 'downloadBucketFile' })) }) return true diff --git a/src/main/manage/apis/local.ts b/src/main/manage/apis/local.ts index 37d22d59..4c725568 100644 --- a/src/main/manage/apis/local.ts +++ b/src/main/manage/apis/local.ts @@ -16,28 +16,30 @@ class LocalApi { logger: ManageLogger isWindows: boolean - constructor (logger: ManageLogger) { + constructor(logger: ManageLogger) { this.logger = logger this.isWindows = process.platform === 'win32' } - logParam = (error:any, method: string) => - this.logger.error(formatError(error, { class: 'LocalApi', method })) + logParam = (error: any, method: string) => this.logger.error(formatError(error, { class: 'LocalApi', method })) // windows 系统下将路径转换为 unix 风格 - transPathToUnix (filePath: string | undefined) { + transPathToUnix(filePath: string | undefined) { if (!filePath) return '' return this.isWindows ? filePath.split(path.sep).join(path.posix.sep) : filePath.replace(/^\/+/, '') } - transBack (filePath: string | undefined) { + transBack(filePath: string | undefined) { if (!filePath) return '' return this.isWindows - ? filePath.split(path.posix.sep).join(path.sep).replace(/^\\+|\\+$/g, '') + ? filePath + .split(path.posix.sep) + .join(path.sep) + .replace(/^\\+|\\+$/g, '') : `/${filePath.replace(/^\/+|\/+$/g, '')}` } - formatFolder (item: fs.Stats, urlPrefix: string, fileName: string, filePath: string) { + formatFolder(item: fs.Stats, urlPrefix: string, fileName: string, filePath: string) { const key = `${this.transPathToUnix(filePath)}/`.replace(/\/+$/, '/') return { ...item, @@ -54,7 +56,7 @@ class LocalApi { } } - formatFile (item: fs.Stats, urlPrefix: string, fileName: string, filePath: string, isDownload = false) { + formatFile(item: fs.Stats, urlPrefix: string, fileName: string, filePath: string, isDownload = false) { const key = isDownload ? filePath : this.transPathToUnix(filePath) return { ...item, @@ -71,7 +73,7 @@ class LocalApi { } } - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { prefix, customUrl = '', cancelToken } = configMap const urlPrefix = customUrl.replace(/\/+$/, '') @@ -111,7 +113,7 @@ class LocalApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { customUrl = '', cancelToken, baseDir } = configMap let prefix = configMap.prefix @@ -167,7 +169,7 @@ class LocalApi { ipcMain.removeAllListeners('cancelLoadingFileList') } - async renameBucketFile (configMap: IStringKeyMap): Promise { + async renameBucketFile(configMap: IStringKeyMap): Promise { const { oldKey, newKey } = configMap let result = false try { @@ -179,7 +181,7 @@ class LocalApi { return result } - async deleteBucketFile (configMap: IStringKeyMap): Promise { + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -191,7 +193,7 @@ class LocalApi { return result } - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -205,7 +207,7 @@ class LocalApi { return result } - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap const instance = UpDownTaskQueue.getInstance() for (const item of fileArray) { @@ -247,7 +249,7 @@ class LocalApi { return true } - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -261,7 +263,7 @@ class LocalApi { return result } - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray } = configMap const instance = UpDownTaskQueue.getInstance() for (const item of fileArray) { diff --git a/src/main/manage/apis/qiniu.ts b/src/main/manage/apis/qiniu.ts index eaaea405..70caafe0 100644 --- a/src/main/manage/apis/qiniu.ts +++ b/src/main/manage/apis/qiniu.ts @@ -1,4 +1,3 @@ - import axios from 'axios' import { ipcMain, IpcMainEvent } from 'electron' import path from 'path' @@ -7,7 +6,13 @@ import qiniu from 'qiniu/index' import windowManager from 'apis/app/window/windowManager' import UpDownTaskQueue from '~/manage/datastore/upDownTaskQueue' -import { hmacSha1Base64, getFileMimeType, NewDownloader, formatError, ConcurrencyPromisePool } from '~/manage/utils/common' +import { + hmacSha1Base64, + getFileMimeType, + NewDownloader, + formatError, + ConcurrencyPromisePool +} from '~/manage/utils/common' import { ManageLogger } from '~/manage/utils/logger' import { commonTaskStatus, IWindowList, uploadTaskSpecialStatus } from '#/types/enum' @@ -28,14 +33,14 @@ class QiniuApi { getBucketDomain: 'https://uc.qiniuapi.com/v2/domains' } - constructor (accessKey: string, secretKey: string, logger: ManageLogger) { + constructor(accessKey: string, secretKey: string, logger: ManageLogger) { this.mac = new qiniu.auth.digest.Mac(accessKey, secretKey) this.accessKey = accessKey this.secretKey = secretKey this.logger = logger } - formatFolder (item: string, slicedPrefix: string, urlPrefix: string) { + formatFolder(item: string, slicedPrefix: string, urlPrefix: string) { return { Key: item, key: item, @@ -49,7 +54,7 @@ class QiniuApi { } } - formatFile (item: any, slicedPrefix: string, urlPrefix: string) { + formatFile(item: any, slicedPrefix: string, urlPrefix: string) { const fileName = item.key.replace(slicedPrefix, '') return { ...item, @@ -64,7 +69,7 @@ class QiniuApi { } } - authorization ( + authorization( method: string, urlPath: string, host: string, @@ -79,7 +84,7 @@ class QiniuApi { if (xQiniuHeaders) { const xQiniuHeaderStr = Object.keys(xQiniuHeaders) .sort() - .map((key) => `\n${key}:${xQiniuHeaders[key]}`) + .map(key => `\n${key}:${xQiniuHeaders[key]}`) .join('') signStr += xQiniuHeaderStr } @@ -92,8 +97,8 @@ class QiniuApi { /** * 获取存储桶列表 - */ - async getBucketList (): Promise { + */ + async getBucketList(): Promise { const host = this.hostList.getBucketList const authorization = qiniu.util.generateAccessToken(this.mac, host, undefined) const res = await axios.get(host, { @@ -122,8 +127,8 @@ class QiniuApi { /** * 获取存储桶详细信息 - */ - async getBucketInfo (param: IStringKeyMap): Promise { + */ + async getBucketInfo(param: IStringKeyMap): Promise { const { bucketName } = param const urlPath = `/v2/bucketInfo?bucket=${bucketName}&fs=true` const authorization = this.authorization('POST', urlPath, this.host, '', '', 'application/json') @@ -143,19 +148,19 @@ class QiniuApi { }) return res?.status === 200 ? { - success: true, - private: res.data.private, - zone: res.data.zone - } + success: true, + private: res.data.private, + zone: res.data.zone + } : { - success: false - } + success: false + } } /** * 获取自定义域名 */ - async getBucketDomain (param: IStringKeyMap): Promise { + async getBucketDomain(param: IStringKeyMap): Promise { const { bucketName } = param const host = this.hostList.getBucketDomain const authorization = qiniu.util.generateAccessToken(this.mac, `${host}?tbl=${bucketName}`, undefined) @@ -175,7 +180,7 @@ class QiniuApi { /** * 修改存储桶权限 */ - async setBucketAclPolicy (param: IStringKeyMap): Promise { + async setBucketAclPolicy(param: IStringKeyMap): Promise { // 0: 公开访问 1: 私有访问 const { bucketName } = param let { isPrivate } = param @@ -207,8 +212,8 @@ class QiniuApi { * region: string, * acl: boolean // 是否公开访问 * } - */ - async createBucket (configMap: IStringKeyMap): Promise { + */ + async createBucket(configMap: IStringKeyMap): Promise { const { BucketName, region, acl } = configMap const urlPath = `/mkbucketv3/${BucketName}/region/${region}` const authorization = this.authorization('POST', urlPath, this.host, '', '', 'application/json') @@ -224,13 +229,13 @@ class QiniuApi { }) return res?.status === 200 ? await this.setBucketAclPolicy({ - bucketName: BucketName, - isPrivate: !acl - }) + bucketName: BucketName, + isPrivate: !acl + }) : false } - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: bucket, prefix, cancelToken, customUrl: urlPrefix } = configMap let marker = undefined as any @@ -252,25 +257,31 @@ class QiniuApi { const bucketManager = new qiniu.rs.BucketManager(this.mac, config) do { res = await new Promise((resolve, reject) => { - bucketManager.listPrefix(bucket, { - prefix: slicedPrefix === '' ? undefined : slicedPrefix, - marker, - limit: 1000 - }, (err: any, respBody: any, respInfo: any) => { - if (err) { - reject(err) - } else { - resolve({ - respBody, - respInfo - }) + bucketManager.listPrefix( + bucket, + { + prefix: slicedPrefix === '' ? undefined : slicedPrefix, + marker, + limit: 1000 + }, + (err: any, respBody: any, respInfo: any) => { + if (err) { + reject(err) + } else { + resolve({ + respBody, + respInfo + }) + } } - }) + ) }) if (res && res.respInfo.statusCode === 200) { - res.respBody && res.respBody.items && res.respBody.items.forEach((item: any) => { - item.fsize !== 0 && result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix)) - }) + res.respBody && + res.respBody.items && + res.respBody.items.forEach((item: any) => { + item.fsize !== 0 && result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix)) + }) window.webContents.send(refreshDownloadFileTransferList, result) } else { result.finished = true @@ -286,7 +297,7 @@ class QiniuApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: bucket, prefix, cancelToken, customUrl: urlPrefix } = configMap let marker = undefined as any @@ -308,29 +319,37 @@ class QiniuApi { const bucketManager = new qiniu.rs.BucketManager(this.mac, config) do { res = await new Promise((resolve, reject) => { - bucketManager.listPrefix(bucket, { - prefix: slicedPrefix === '' ? undefined : slicedPrefix, - delimiter: '/', - marker, - limit: 1000 - }, (err: any, respBody: any, respInfo: any) => { - if (err) { - reject(err) - } else { - resolve({ - respBody, - respInfo - }) + bucketManager.listPrefix( + bucket, + { + prefix: slicedPrefix === '' ? undefined : slicedPrefix, + delimiter: '/', + marker, + limit: 1000 + }, + (err: any, respBody: any, respInfo: any) => { + if (err) { + reject(err) + } else { + resolve({ + respBody, + respInfo + }) + } } - }) + ) }) if (res && res.respInfo.statusCode === 200) { - res.respBody && res.respBody.commonPrefixes && res.respBody.commonPrefixes.forEach((item: any) => { - result.fullList.push(this.formatFolder(item, slicedPrefix, urlPrefix)) - }) - res.respBody && res.respBody.items && res.respBody.items.forEach((item: any) => { - item.fsize !== 0 && result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix)) - }) + res.respBody && + res.respBody.commonPrefixes && + res.respBody.commonPrefixes.forEach((item: any) => { + result.fullList.push(this.formatFolder(item, slicedPrefix, urlPrefix)) + }) + res.respBody && + res.respBody.items && + res.respBody.items.forEach((item: any) => { + item.fsize !== 0 && result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix)) + }) window.webContents.send('refreshFileTransferList', result) } else { result.finished = true @@ -360,8 +379,8 @@ class QiniuApi { * itemsPerPage: number, * customUrl: string * } - */ - async getBucketFileList (configMap: IStringKeyMap): Promise { + */ + async getBucketFileList(configMap: IStringKeyMap): Promise { const { bucketName: bucket, prefix, marker, itemsPerPage, customUrl: urlPrefix } = configMap const slicedPrefix = prefix.slice(1) const config = new qiniu.conf.Config() @@ -374,21 +393,25 @@ class QiniuApi { success: false } res = await new Promise((resolve, reject) => { - bucketManager.listPrefix(bucket, { - limit: itemsPerPage, - prefix: slicedPrefix === '' ? undefined : slicedPrefix, - marker, - delimiter: '/' - }, (err, respBody, respInfo) => { - if (err) { - reject(err) - } else { - resolve({ - respBody, - respInfo - }) + bucketManager.listPrefix( + bucket, + { + limit: itemsPerPage, + prefix: slicedPrefix === '' ? undefined : slicedPrefix, + marker, + delimiter: '/' + }, + (err, respBody, respInfo) => { + if (err) { + reject(err) + } else { + resolve({ + respBody, + respInfo + }) + } } - }) + ) }) if (res?.respInfo?.statusCode === 200) { if (res.respBody?.commonPrefixes) { @@ -401,7 +424,7 @@ class QiniuApi { item.fsize !== 0 && result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix)) }) } - result.isTruncated = !!(res.respBody?.marker) + result.isTruncated = !!res.respBody?.marker result.nextMarker = res.respBody?.marker ? res.respBody.marker : '' result.success = true } @@ -409,19 +432,19 @@ class QiniuApi { } /** - * 删除文件 - * @param configMap - * configMap = { - * bucketName: string, - * region: string, - * key: string - * } - */ - async deleteBucketFile (configMap: IStringKeyMap): Promise { + * 删除文件 + * @param configMap + * configMap = { + * bucketName: string, + * region: string, + * key: string + * } + */ + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { bucketName, key } = configMap const config = new qiniu.conf.Config() const bucketManager = new qiniu.rs.BucketManager(this.mac, config) - const res = await new Promise((resolve, reject) => { + const res = (await new Promise((resolve, reject) => { bucketManager.delete(bucketName, key, (err, respBody, respInfo) => { if (err) { reject(err) @@ -432,7 +455,7 @@ class QiniuApi { }) } }) - }) as any + })) as any return res?.respInfo?.statusCode === 200 } @@ -440,7 +463,7 @@ class QiniuApi { * 删除文件夹 * @param configMap */ - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, key } = configMap const config = new qiniu.conf.Config() const bucketManager = new qiniu.rs.BucketManager(this.mac, config) @@ -450,27 +473,31 @@ class QiniuApi { Contents: [] as any[] } do { - const res = await new Promise((resolve, reject) => { - bucketManager.listPrefix(bucketName, { - prefix: key, - marker, - limit: 1000 - }, (err, respBody, respInfo) => { - if (err) { - reject(err) - } else { - resolve({ - respBody, - respInfo - }) + const res = (await new Promise((resolve, reject) => { + bucketManager.listPrefix( + bucketName, + { + prefix: key, + marker, + limit: 1000 + }, + (err, respBody, respInfo) => { + if (err) { + reject(err) + } else { + resolve({ + respBody, + respInfo + }) + } } - }) - }) as any + ) + })) as any if (res?.respInfo?.statusCode === 200) { if (res.respBody?.items) { allFileList.Contents = allFileList.Contents.concat(res.respBody.items) } - isTruncated = !!(res.respBody?.marker) + isTruncated = !!res.respBody?.marker marker = res.respBody?.marker ? res.respBody.marker : '' } else { return false @@ -481,7 +508,7 @@ class QiniuApi { const deleteOps = allFileList.Contents.slice(i * 1000, (i + 1) * 1000).map((item: any) => { return qiniu.rs.deleteOp(bucketName, item.key) }) - const res = await new Promise((resolve, reject) => { + const res = (await new Promise((resolve, reject) => { bucketManager.batch(deleteOps, (err, respBody, respInfo) => { if (err) { reject(err) @@ -492,40 +519,47 @@ class QiniuApi { }) } }) - }) as any + })) as any if (res?.respInfo?.statusCode !== 200) return false } return true } /** - * 重命名文件 - * @param configMap - * configMap = { - * bucketName: string, - * region: string, - * oldKey: string, - * newKey: string - * } - */ - async renameBucketFile (configMap: IStringKeyMap): Promise { + * 重命名文件 + * @param configMap + * configMap = { + * bucketName: string, + * region: string, + * oldKey: string, + * newKey: string + * } + */ + async renameBucketFile(configMap: IStringKeyMap): Promise { const { bucketName, oldKey, newKey } = configMap const config = new qiniu.conf.Config() const bucketManager = new qiniu.rs.BucketManager(this.mac, config) - const res = await new Promise((resolve, reject) => { - bucketManager.move(bucketName, oldKey, bucketName, newKey, { - force: true - }, (err, respBody, respInfo) => { - if (err) { - reject(err) - } else { - resolve({ - respBody, - respInfo - }) + const res = (await new Promise((resolve, reject) => { + bucketManager.move( + bucketName, + oldKey, + bucketName, + newKey, + { + force: true + }, + (err, respBody, respInfo) => { + if (err) { + reject(err) + } else { + resolve({ + respBody, + respInfo + }) + } } - }) - }) as any + ) + })) as any return res?.respInfo?.statusCode === 200 } @@ -540,7 +574,7 @@ class QiniuApi { * customUrl: string * } */ - async getPreSignedUrl (configMap: IStringKeyMap): Promise { + async getPreSignedUrl(configMap: IStringKeyMap): Promise { const { key, expires, customUrl } = configMap const config = new qiniu.conf.Config() const bucketManager = new qiniu.rs.BucketManager(this.mac, config) @@ -554,7 +588,7 @@ class QiniuApi { * 上传文件 * @param configMap */ - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap const instance = UpDownTaskQueue.getInstance() fileArray.forEach((item: any) => { @@ -585,7 +619,7 @@ class QiniuApi { putExtra.version = 'v2' putExtra.partSize = 4 * 1024 * 1024 putExtra.progressCallback = (uploadBytes, totalBytes) => { - const progress = Math.floor(uploadBytes / totalBytes * 100) + const progress = Math.floor((uploadBytes / totalBytes) * 100) instance.updateUploadTask({ id: `${bucketName}-${region}-${key}-${filePath}`, progress, @@ -594,7 +628,12 @@ class QiniuApi { } resumeUploader.putFile(uploadToken, key, filePath, putExtra, (respErr, respBody, respInfo) => { if (respErr) { - this.logger.error(formatError(respErr, { class: 'Qiniu', method: 'uploadBucketFile' })) + this.logger.error( + formatError(respErr, { + class: 'Qiniu', + method: 'uploadBucketFile' + }) + ) instance.updateUploadTask({ id: `${bucketName}-${region}-${key}-${filePath}`, progress: 0, @@ -628,7 +667,7 @@ class QiniuApi { * 新建文件夹 * @param configMap */ - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, key } = configMap const putPolicy = new qiniu.rs.PutPolicy({ scope: `${bucketName}:${key}` @@ -636,7 +675,7 @@ class QiniuApi { const uploadToken = putPolicy.uploadToken(this.mac) const FormUploader = new qiniu.form_up.FormUploader() const putExtra = new qiniu.form_up.PutExtra() - const res = await new Promise((resolve, reject) => { + const res = (await new Promise((resolve, reject) => { FormUploader.put(uploadToken, key, '', putExtra, (err, respBody, respInfo) => { if (err) { reject(err) @@ -647,7 +686,7 @@ class QiniuApi { }) } }) - }) as any + })) as any return res?.respInfo?.statusCode === 200 } @@ -655,7 +694,7 @@ class QiniuApi { * 下载文件 * @param configMap */ - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray, maxDownloadFileCount } = configMap const instance = UpDownTaskQueue.getInstance() const promises = [] as any @@ -673,20 +712,26 @@ class QiniuApi { sourceFileName: fileName, targetFilePath: savedFilePath }) - const preSignedUrl = await this.getPreSignedUrl({ key, expires: 36000, customUrl }) - promises.push(() => new Promise((resolve, reject) => { - NewDownloader(instance, preSignedUrl, id, savedFilePath, this.logger) - .then((res: boolean) => { - if (res) { - resolve(res) - } else { - reject(res) - } + const preSignedUrl = await this.getPreSignedUrl({ + key, + expires: 36000, + customUrl + }) + promises.push( + () => + new Promise((resolve, reject) => { + NewDownloader(instance, preSignedUrl, id, savedFilePath, this.logger).then((res: boolean) => { + if (res) { + resolve(res) + } else { + reject(res) + } + }) }) - })) + ) } const pool = new ConcurrencyPromisePool(maxDownloadFileCount) - pool.all(promises).catch((error) => { + pool.all(promises).catch(error => { this.logger.error(formatError(error, { class: 'QiniuApi', method: 'downloadBucketFile' })) }) return true diff --git a/src/main/manage/apis/s3plist.ts b/src/main/manage/apis/s3plist.ts index ca69f41a..057c62ee 100644 --- a/src/main/manage/apis/s3plist.ts +++ b/src/main/manage/apis/s3plist.ts @@ -46,7 +46,7 @@ class S3plistApi { secretAccessKey: string bucketName: string - constructor ( + constructor( accessKeyId: string, secretAccessKey: string, endpoint: string | undefined, @@ -75,9 +75,9 @@ class S3plistApi { this.proxy = formatHttpProxy(proxy, 'string') as string | undefined } - async getDogeCloudToken () { + async getDogeCloudToken() { if (!this.dogeCloudSupport) return - const token = await getTempToken(this.accessKeyId, this.secretAccessKey) as DogecloudToken + const token = (await getTempToken(this.accessKeyId, this.secretAccessKey)) as DogecloudToken if (Object.keys(token).length === 0) { throw new Error('manage.setting.dogeCloudTokenError') } @@ -88,7 +88,7 @@ class S3plistApi { } } - setAgent (proxy: string | undefined, sslEnabled: boolean) : NodeHttpHandler { + setAgent(proxy: string | undefined, sslEnabled: boolean): NodeHttpHandler { const agent = getAgent(proxy, sslEnabled) const commonOptions: AgentOptions = { keepAlive: true, @@ -98,27 +98,26 @@ class S3plistApi { const extraOptions = sslEnabled ? { rejectUnauthorized: false } : {} return sslEnabled ? new NodeHttpHandler({ - httpsAgent: agent.https - ? agent.https - : new https.Agent({ - ...commonOptions, - ...extraOptions - }) - }) + httpsAgent: agent.https + ? agent.https + : new https.Agent({ + ...commonOptions, + ...extraOptions + }) + }) : new NodeHttpHandler({ - httpAgent: agent.http - ? agent.http - : new http.Agent({ - ...commonOptions, - ...extraOptions - }) - }) + httpAgent: agent.http + ? agent.http + : new http.Agent({ + ...commonOptions, + ...extraOptions + }) + }) } - logParam = (error:any, method: string) => - this.logger.error(formatError(error, { class: 'S3plistApi', method })) + logParam = (error: any, method: string) => this.logger.error(formatError(error, { class: 'S3plistApi', method })) - formatFolder (item: CommonPrefix, slicedPrefix: string, urlPrefix: string): any { + formatFolder(item: CommonPrefix, slicedPrefix: string, urlPrefix: string): any { return { Key: item.Prefix, url: `${urlPrefix}/${item.Prefix}`, @@ -133,7 +132,7 @@ 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 { ...item, @@ -149,7 +148,7 @@ class S3plistApi { } } - async putPublicAccess (bucketName: string, client: S3Client) { + async putPublicAccess(bucketName: string, client: S3Client) { const input = { Bucket: bucketName, PublicAccessBlockConfiguration: { @@ -170,13 +169,13 @@ class S3plistApi { /** * 新建存储桶 * @param {Object} configMap - * configMap = { - * BucketName: string, - * region: string, - * acl: string - * } + * configMap = { + * BucketName: string, + * region: string, + * acl: string + * } */ - async createBucket (configMap: IStringKeyMap): Promise { + async createBucket(configMap: IStringKeyMap): Promise { const { BucketName, region, acl, endpoint } = configMap try { await this.getDogeCloudToken() @@ -186,7 +185,7 @@ class S3plistApi { const command = new ListBucketsCommand({}) const data = await client.send(command) if (data.$metadata.httpStatusCode === 200) { - const bucketList = data.Buckets?.map((item) => item.Name) + const bucketList = data.Buckets?.map(item => item.Name) if (bucketList?.includes(BucketName)) { return true } @@ -233,9 +232,9 @@ class S3plistApi { } /** - * 获取存储桶列表 - */ - async getBucketList (): Promise { + * 获取存储桶列表 + */ + async getBucketList(): Promise { if (this.dogeCloudSupport) { try { const res = await dogecloudApi('/oss/bucket/list.json', {}, false, this.accessKeyId, this.secretAccessKey) @@ -258,7 +257,7 @@ class S3plistApi { } const options = Object.assign({}, this.baseOptions) as S3ClientConfig const result: IStringKeyMap[] = [] - const endpoint = options.endpoint as string || '' + const endpoint = (options.endpoint as string) || '' options.region = endpoint.includes('cloudflarestorage') ? 'auto' : 'us-east-1' try { const client = new S3Client(options) @@ -271,23 +270,28 @@ class S3plistApi { if (data.Buckets) { if (endpoint.includes('cloudflarestorage')) { - result.push(...data.Buckets.map(bucket => ({ - Name: bucket.Name, - CreationDate: bucket.CreationDate, - 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 - })) + 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' + Location: + bucketConfig.$metadata.httpStatusCode === 200 + ? bucketConfig.LocationConstraint?.toLowerCase() || 'us-east-1' + : 'us-east-1' }) if (bucketConfig.$metadata.httpStatusCode !== 200) { this.logParam(bucketConfig, 'getBucketList') @@ -301,9 +305,14 @@ class S3plistApi { return result } - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! - const { bucketName: bucket, bucketConfig: { Location: region }, prefix, cancelToken } = configMap + const { + bucketName: bucket, + bucketConfig: { Location: region }, + prefix, + cancelToken + } = configMap const slicedPrefix = prefix.slice(1) const urlPrefix = configMap.customUrl || `https://${bucket}.s3.amazonaws.com` let marker @@ -333,9 +342,10 @@ class S3plistApi { }) res = await client.send(command) if (res.$metadata.httpStatusCode === 200) { - res.Contents && res.Contents.forEach((item: _Object) => { - result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix)) - }) + res.Contents && + res.Contents.forEach((item: _Object) => { + result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix)) + }) window.webContents.send(refreshDownloadFileTransferList, result) } else { this.logParam(res, 'getBucketListRecursively') @@ -359,9 +369,14 @@ class S3plistApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! - const { bucketName: bucket, bucketConfig: { Location: region }, prefix, cancelToken } = configMap + const { + bucketName: bucket, + bucketConfig: { Location: region }, + prefix, + cancelToken + } = configMap const slicedPrefix = prefix.slice(1) const urlPrefix = configMap.customUrl || `https://${bucket}.s3.amazonaws.com` let marker @@ -393,12 +408,14 @@ class S3plistApi { }) res = await client.send(command) if (res.$metadata.httpStatusCode === 200) { - res.CommonPrefixes && res.CommonPrefixes.forEach((item: CommonPrefix) => { - result.fullList.push(this.formatFolder(item, slicedPrefix, urlPrefix)) - }) - res.Contents && res.Contents.forEach((item: _Object) => { - result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix)) - }) + res.CommonPrefixes && + res.CommonPrefixes.forEach((item: CommonPrefix) => { + result.fullList.push(this.formatFolder(item, slicedPrefix, urlPrefix)) + }) + res.Contents && + res.Contents.forEach((item: _Object) => { + result.fullList.push(this.formatFile(item, slicedPrefix, urlPrefix)) + }) window.webContents.send('refreshFileTransferList', result) } else { this.logParam(res, 'getBucketListBackstage') @@ -422,8 +439,14 @@ class S3plistApi { ipcMain.removeAllListeners('cancelLoadingFileList') } - async getBucketFileList (configMap: IStringKeyMap): Promise { - const { bucketName: bucket, bucketConfig: { Location: region }, prefix, marker, itemsPerPage } = configMap + async getBucketFileList(configMap: IStringKeyMap): Promise { + const { + bucketName: bucket, + bucketConfig: { Location: region }, + prefix, + marker, + itemsPerPage + } = configMap const slicedPrefix = prefix.slice(1) const urlPrefix = configMap.customUrl || `https://${bucket}.s3.amazonaws.com` const result = { @@ -434,7 +457,10 @@ class S3plistApi { } try { await this.getDogeCloudToken() - const options = Object.assign({}, { ...this.baseOptions, region: String(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, @@ -460,21 +486,24 @@ class S3plistApi { } /** - * 重命名文件 - * @param configMap - * configMap = { - * bucketName: string, - * region: string, - * oldKey: string, - * newKey: string - * } - */ - async renameBucketFile (configMap: IStringKeyMap): Promise { + * 重命名文件 + * @param configMap + * configMap = { + * bucketName: string, + * region: string, + * oldKey: string, + * newKey: string + * } + */ + async renameBucketFile(configMap: IStringKeyMap): Promise { const { bucketName, region, oldKey, newKey } = configMap let result = false try { await this.getDogeCloudToken() - const options = Object.assign({}, { ...this.baseOptions, region: String(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, @@ -503,15 +532,15 @@ class S3plistApi { } /** - * 删除文件 - * @param configMap - * configMap = { - * bucketName: string, - * region: string, - * key: string - * } - */ - async deleteBucketFile (configMap: IStringKeyMap): Promise { + * 删除文件 + * @param configMap + * configMap = { + * bucketName: string, + * region: string, + * key: string + * } + */ + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap let result = false try { @@ -536,10 +565,10 @@ class S3plistApi { } /** - * 删除文件夹 - * @param configMap - */ - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + * 删除文件夹 + * @param configMap + */ + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap let marker let result = false @@ -562,7 +591,7 @@ class S3plistApi { Delimiter: '/', MaxKeys: 1000 }) - res = await client.send(command) as ListObjectsV2CommandOutput + res = (await client.send(command)) as ListObjectsV2CommandOutput if (res.$metadata.httpStatusCode === 200) { res.CommonPrefixes && allFileList.CommonPrefixes.push(...res.CommonPrefixes) res.Contents && allFileList.Contents.push(...res.Contents) @@ -595,7 +624,7 @@ class S3plistApi { const deleteCommand = new DeleteObjectsCommand({ Bucket: bucketName, Delete: { - Objects: deleteList.map((item) => { + Objects: deleteList.map(item => { return { Key: item.Key } @@ -618,29 +647,33 @@ class S3plistApi { } /** - * 获取预签名url - * @param configMap - * configMap = { - * bucketName: string, - * region: string, - * key: string, - * expires: number, - * customUrl: string - * } - */ - async getPreSignedUrl (configMap: IStringKeyMap): Promise { + * 获取预签名url + * @param configMap + * configMap = { + * bucketName: string, + * region: string, + * key: string, + * expires: number, + * customUrl: string + * } + */ + async getPreSignedUrl(configMap: IStringKeyMap): Promise { const { bucketName, region, key, expires } = configMap try { await this.getDogeCloudToken() const options = Object.assign({}, this.baseOptions) as S3ClientConfig options.region = String(region) || 'us-east-1' const client = new S3Client(options) - const signedUrl = await getSignedUrl(client, new GetObjectCommand({ - Bucket: bucketName, - Key: key - }), { - expiresIn: expires || 3600 - }) + const signedUrl = await getSignedUrl( + client, + new GetObjectCommand({ + Bucket: bucketName, + Key: key + }), + { + expiresIn: expires || 3600 + } + ) return signedUrl } catch (error) { this.logParam(error, 'getPreSignedUrl') @@ -652,7 +685,7 @@ class S3plistApi { * 新建文件夹 * @param configMap */ - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap let result = false try { @@ -680,7 +713,7 @@ class S3plistApi { * upload file * @param configMap */ - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap // fileArray = [{ // bucketName: string, @@ -693,7 +726,15 @@ class S3plistApi { fileArray.forEach((item: any) => { item.key.startsWith('/') && (item.key = item.key.slice(1)) }) - const allowedAcl = ['private', 'public-read', 'public-read-write', 'aws-exec-read', 'authenticated-read', 'bucket-owner-read', 'bucket-owner-full-control'] + 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 const id = `${bucketName}-${String(region)}-${key}-${filePath}` @@ -743,36 +784,39 @@ class S3plistApi { parallelUploads3.on('httpUploadProgress', (progress: Progress) => { instance.updateUploadTask({ id, - progress: progress.loaded && progress.total ? Math.floor(progress.loaded / progress.total * 100) : 0, + progress: progress.loaded && progress.total ? Math.floor((progress.loaded / progress.total) * 100) : 0, status: uploadTaskSpecialStatus.uploading }) }) - parallelUploads3.done().then((data) => { - if (data.$metadata.httpStatusCode === 200) { - instance.updateUploadTask({ - id, - progress: 100, - status: uploadTaskSpecialStatus.uploaded, - finishTime: new Date().toLocaleString() - }) - } else { + parallelUploads3 + .done() + .then(data => { + if (data.$metadata.httpStatusCode === 200) { + instance.updateUploadTask({ + id, + progress: 100, + status: uploadTaskSpecialStatus.uploaded, + finishTime: new Date().toLocaleString() + }) + } else { + instance.updateUploadTask({ + id, + progress: 0, + status: commonTaskStatus.failed, + finishTime: new Date().toLocaleString() + }) + } + }) + .catch(error => { + this.logParam(error, 'uploadBucketFile') instance.updateUploadTask({ id, progress: 0, status: commonTaskStatus.failed, + response: JSON.stringify(error), finishTime: new Date().toLocaleString() }) - } - }).catch((error) => { - this.logParam(error, 'uploadBucketFile') - instance.updateUploadTask({ - id, - progress: 0, - status: commonTaskStatus.failed, - response: JSON.stringify(error), - finishTime: new Date().toLocaleString() }) - }) } return true } @@ -781,7 +825,7 @@ class S3plistApi { * 下载文件 * @param configMap */ - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray, maxDownloadFileCount } = configMap const instance = UpDownTaskQueue.getInstance() const promises = [] as any @@ -806,19 +850,21 @@ class S3plistApi { expires: 36000, customUrl }) - promises.push(() => new Promise((resolve, reject) => { - NewDownloader(instance, preSignedUrl, id, savedFilePath, this.logger, this.proxy) - .then((res: boolean) => { - if (res) { - resolve(res) - } else { - reject(res) - } + promises.push( + () => + new Promise((resolve, reject) => { + NewDownloader(instance, preSignedUrl, id, savedFilePath, this.logger, this.proxy).then((res: boolean) => { + if (res) { + resolve(res) + } else { + reject(res) + } + }) }) - })) + ) } const pool = new ConcurrencyPromisePool(maxDownloadFileCount) - pool.all(promises).catch((error) => { + pool.all(promises).catch(error => { this.logParam(error, 'downloadBucketFile') }) return true diff --git a/src/main/manage/apis/sftp.ts b/src/main/manage/apis/sftp.ts index 2f2177d0..3e015375 100644 --- a/src/main/manage/apis/sftp.ts +++ b/src/main/manage/apis/sftp.ts @@ -45,7 +45,7 @@ class SftpApi { passphrase: string } - constructor ( + constructor( host: string, port: Undefinable, username: Undefinable, @@ -76,8 +76,7 @@ class SftpApi { } } - logParam = (error:any, method: string) => - this.logger.error(formatError(error, { class: 'SftpApi', method })) + logParam = (error: any, method: string) => this.logger.error(formatError(error, { class: 'SftpApi', method })) transFormPermission = (permissionsStr: string) => { const permissions = permissionsStr.length === 10 ? permissionsStr.slice(1) : permissionsStr @@ -96,7 +95,7 @@ class SftpApi { return `0${result}` } - formatFolder (item: listDirResult, urlPrefix: string, isWebPath = false) { + formatFolder(item: listDirResult, urlPrefix: string, isWebPath = false) { const key = item.key let url: string if (isWebPath) { @@ -123,7 +122,7 @@ class SftpApi { } } - formatFile (item: listDirResult, urlPrefix: string, isWebPath = false) { + formatFile(item: listDirResult, urlPrefix: string, isWebPath = false) { const key = item.key return { ...item, @@ -153,7 +152,7 @@ class SftpApi { } } - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { prefix, customUrl, cancelToken } = configMap const urlPrefix = customUrl || `${this.host}:${this.port}` @@ -193,7 +192,7 @@ class SftpApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - formatLSResult (res: string, cwd: string): listDirResult[] { + formatLSResult(res: string, cwd: string): listDirResult[] { const result = [] as listDirResult[] const resArray = res.trim().split('\n') resArray.slice(resArray[0].startsWith('total') ? 1 : 0).forEach((item: string) => { @@ -219,7 +218,7 @@ class SftpApi { return result } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { prefix, customUrl, cancelToken, baseDir } = configMap let urlPrefix = customUrl || `${this.host}:${this.port}` @@ -250,7 +249,8 @@ class SftpApi { if (formatedLSRes.length) { formatedLSRes.forEach((item: listDirResult) => { const relativePath = path.relative(baseDir, item.key.startsWith('/') ? item.key : `/${item.key}`) - const relative = webPath && urlPrefix + `/${path.join(webPath, relativePath)}`.replace(/\\/g, '/').replace(/\/+/g, '/') + const relative = + webPath && urlPrefix + `/${path.join(webPath, relativePath)}`.replace(/\\/g, '/').replace(/\/+/g, '/') if (item.isDir) { result.fullList.push(this.formatFolder(item, webPath ? relative : urlPrefix, !!webPath)) } else { @@ -277,7 +277,7 @@ class SftpApi { ipcMain.removeAllListeners('cancelLoadingFileList') } - async renameBucketFile (configMap: IStringKeyMap): Promise { + async renameBucketFile(configMap: IStringKeyMap): Promise { const { oldKey, newKey } = configMap let result = false try { @@ -291,7 +291,7 @@ class SftpApi { return result } - async deleteBucketFile (configMap: IStringKeyMap): Promise { + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -305,7 +305,7 @@ class SftpApi { return result } - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -322,7 +322,7 @@ class SftpApi { return result } - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap const instance = UpDownTaskQueue.getInstance() for (const item of fileArray) { @@ -377,7 +377,7 @@ class SftpApi { return true } - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -391,7 +391,7 @@ class SftpApi { return result } - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray } = configMap const instance = UpDownTaskQueue.getInstance() for (const item of fileArray) { diff --git a/src/main/manage/apis/smms.ts b/src/main/manage/apis/smms.ts index 06b533bb..1c666b97 100644 --- a/src/main/manage/apis/smms.ts +++ b/src/main/manage/apis/smms.ts @@ -20,7 +20,7 @@ class SmmsApi { logger: ManageLogger timeout = 30000 - constructor (token: string, logger: ManageLogger) { + constructor(token: string, logger: ManageLogger) { this.token = token this.axiosInstance = axios.create({ baseURL: this.baseUrl, @@ -36,7 +36,7 @@ class SmmsApi { this.logger = logger } - formatFile (item: any) { + formatFile(item: any) { return { ...item, Key: item.path, @@ -53,7 +53,7 @@ class SmmsApi { } } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { cancelToken } = configMap let marker = 1 @@ -71,17 +71,15 @@ class SmmsApi { finished: false } do { - res = await this.axiosInstance( - '/upload_history', - { - method: 'GET', - headers: { - 'Content-Type': 'multipart/form-data' - }, - params: { - page: marker - } - }) + res = await this.axiosInstance('/upload_history', { + method: 'GET', + headers: { + 'Content-Type': 'multipart/form-data' + }, + params: { + page: marker + } + }) if (res && res.status === 200 && res.data && res.data.success) { if (res.data.Count === 0) { result.success = true @@ -123,26 +121,23 @@ class SmmsApi { * itemsPerPage: number, * customUrl: string * } - */ - async getBucketFileList ({ currentPage }: IStringKeyMap): Promise { + */ + async getBucketFileList({ currentPage }: IStringKeyMap): Promise { const result = { fullList: [], isTruncated: false, nextMarker: '', success: false } - const res = await this.axiosInstance( - '/upload_history', - { - method: 'GET', - headers: { - 'Content-Type': 'multipart/form-data' - }, - params: { - page: currentPage - } + const res = await this.axiosInstance('/upload_history', { + method: 'GET', + headers: { + 'Content-Type': 'multipart/form-data' + }, + params: { + page: currentPage } - ) + }) if (res?.status !== 200 || !res?.data?.success) return result if (res.data.Count === 0) return { ...result, success: true } @@ -157,26 +152,23 @@ class SmmsApi { } /** - * 删除文件 - * @param configMap - * configMap = { - * bucketName: string, - * region: string, - * key: string, - * DeleteHash: string - * } - */ - async deleteBucketFile ({ DeleteHash }: IStringKeyMap): Promise { - const res = await this.axiosInstance( - `/delete/${DeleteHash}`, - { - method: 'GET', - params: { - hash: DeleteHash, - format: 'json' - } + * 删除文件 + * @param configMap + * configMap = { + * bucketName: string, + * region: string, + * key: string, + * DeleteHash: string + * } + */ + async deleteBucketFile({ DeleteHash }: IStringKeyMap): Promise { + const res = await this.axiosInstance(`/delete/${DeleteHash}`, { + method: 'GET', + params: { + hash: DeleteHash, + format: 'json' } - ) + }) return res?.status === 200 && res?.data?.success } @@ -184,7 +176,7 @@ class SmmsApi { * 上传文件 * @param configMap */ - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap const instance = UpDownTaskQueue.getInstance() for (const item of fileArray) { @@ -221,7 +213,7 @@ class SmmsApi { * 下载文件 * @param configMap */ - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray, maxDownloadFileCount } = configMap const instance = UpDownTaskQueue.getInstance() const promises = [] as any @@ -239,19 +231,21 @@ class SmmsApi { sourceFileName: fileName, targetFilePath: savedFilePath }) - promises.push(() => new Promise((resolve, reject) => { - NewDownloader(instance, preSignedUrl, id, savedFilePath, this.logger) - .then((res: boolean) => { - if (res) { - resolve(res) - } else { - reject(res) - } + promises.push( + () => + new Promise((resolve, reject) => { + NewDownloader(instance, preSignedUrl, id, savedFilePath, this.logger).then((res: boolean) => { + if (res) { + resolve(res) + } else { + reject(res) + } + }) }) - })) + ) } const pool = new ConcurrencyPromisePool(maxDownloadFileCount) - pool.all(promises).catch((error) => { + pool.all(promises).catch(error => { this.logger.error(formatError(error, { class: 'SmmsApi', method: 'downloadBucketFile' })) }) return true diff --git a/src/main/manage/apis/tcyun.ts b/src/main/manage/apis/tcyun.ts index 08509b1c..b5de643c 100644 --- a/src/main/manage/apis/tcyun.ts +++ b/src/main/manage/apis/tcyun.ts @@ -1,4 +1,3 @@ - import COS from 'cos-nodejs-sdk-v5' import { ipcMain, IpcMainEvent } from 'electron' import fs from 'fs-extra' @@ -18,7 +17,7 @@ class TcyunApi { ctx: COS logger: ManageLogger - constructor (secretId: string, secretKey: string, logger: ManageLogger) { + constructor(secretId: string, secretKey: string, logger: ManageLogger) { this.ctx = new COS({ SecretId: secretId, SecretKey: secretKey @@ -26,7 +25,7 @@ class TcyunApi { this.logger = logger } - formatFolder (item: {Prefix: string}, slicedPrefix: string, urlPrefix: string) { + formatFolder(item: { Prefix: string }, slicedPrefix: string, urlPrefix: string) { return { ...item, key: item.Prefix, @@ -41,7 +40,7 @@ class TcyunApi { } } - formatFile (item: COS.CosObject, slicedPrefix: string, urlPrefix: string): any { + formatFile(item: COS.CosObject, slicedPrefix: string, urlPrefix: string): any { return { ...item, key: item.Key, @@ -58,8 +57,8 @@ class TcyunApi { /** * 获取存储桶列表 - */ - async getBucketList (): Promise { + */ + async getBucketList(): Promise { const res = await this.ctx.getService({}) return res?.Buckets || [] } @@ -67,7 +66,7 @@ class TcyunApi { /** * 获取自定义域名 */ - async getBucketDomain (param: IStringKeyMap): Promise { + async getBucketDomain(param: IStringKeyMap): Promise { const { bucketName, region } = param const res = await this.ctx.getBucketDomain({ Bucket: bucketName, @@ -87,8 +86,8 @@ class TcyunApi { * } * @description * acl: private | publicRead | publicReadWrite - */ - async createBucket (configMap: IStringKeyMap): Promise < boolean > { + */ + async createBucket(configMap: IStringKeyMap): Promise { const res = await this.ctx.putBucket({ ACL: configMap.acl, Bucket: configMap.BucketName, @@ -97,9 +96,15 @@ class TcyunApi { return res?.statusCode === 200 } - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! - const { bucketName: bucket, bucketConfig: { Location: region }, prefix, customUrl, cancelToken } = configMap + const { + bucketName: bucket, + bucketConfig: { Location: region }, + prefix, + customUrl, + cancelToken + } = configMap const slicedPrefix = prefix.slice(1, prefix.length) const urlPrefix = customUrl || `https://${bucket}.cos.${region}.myqcloud.com` const cancelTask = [false] @@ -125,8 +130,11 @@ class TcyunApi { Marker: marker }) if (res?.statusCode === 200) { - result.fullList.push(...res.Contents.filter(item => parseInt(item.Size) !== 0) - .map(item => this.formatFile(item, slicedPrefix, urlPrefix))) + result.fullList.push( + ...res.Contents.filter(item => parseInt(item.Size) !== 0).map(item => + this.formatFile(item, slicedPrefix, urlPrefix) + ) + ) window.webContents.send(refreshDownloadFileTransferList, result) } else { result.finished = true @@ -142,9 +150,15 @@ class TcyunApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - async getBucketListBackstage (configMap: IStringKeyMap): Promise < any > { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! - const { bucketName: bucket, bucketConfig: { Location: region }, prefix, customUrl, cancelToken } = configMap + const { + bucketName: bucket, + bucketConfig: { Location: region }, + prefix, + customUrl, + cancelToken + } = configMap const slicedPrefix = prefix.slice(1, prefix.length) const urlPrefix = customUrl || `https://${bucket}.cos.${region}.myqcloud.com` const cancelTask = [false] @@ -173,8 +187,9 @@ class TcyunApi { if (res?.statusCode === 200) { result.fullList.push( ...res.CommonPrefixes.map(item => this.formatFolder(item, slicedPrefix, urlPrefix)), - ...res.Contents.filter(item => parseInt(item.Size) !== 0) - .map(item => this.formatFile(item, slicedPrefix, urlPrefix)) + ...res.Contents.filter(item => parseInt(item.Size) !== 0).map(item => + this.formatFile(item, slicedPrefix, urlPrefix) + ) ) window.webContents.send('refreshFileTransferList', result) } else { @@ -205,19 +220,26 @@ class TcyunApi { * itemsPerPage: number, * customUrl: string * } - */ - async getBucketFileList (configMap: IStringKeyMap): Promise { - const { bucketName: bucket, bucketConfig: { Location: region }, prefix, customUrl, marker, itemsPerPage } = configMap + */ + async getBucketFileList(configMap: IStringKeyMap): Promise { + const { + bucketName: bucket, + bucketConfig: { Location: region }, + prefix, + customUrl, + marker, + itemsPerPage + } = configMap const slicedPrefix = prefix.slice(1) const urlPrefix = customUrl || `https://${bucket}.cos.${region}.myqcloud.com` - const res = await this.ctx.getBucket({ + const res = (await this.ctx.getBucket({ Bucket: bucket, Region: region, Prefix: slicedPrefix === '' ? undefined : slicedPrefix, Delimiter: '/', Marker: marker, MaxKeys: itemsPerPage - }) as COS.GetBucketResult + })) as COS.GetBucketResult if (res?.statusCode !== 200) { return { fullList: [], @@ -229,8 +251,9 @@ class TcyunApi { const result = { fullList: [ ...res.CommonPrefixes.map(item => this.formatFolder(item, slicedPrefix, urlPrefix)), - ...res.Contents.filter(item => parseInt(item.Size) !== 0) - .map(item => this.formatFile(item, slicedPrefix, urlPrefix)) + ...res.Contents.filter(item => parseInt(item.Size) !== 0).map(item => + this.formatFile(item, slicedPrefix, urlPrefix) + ) ], isTruncated: res.IsTruncated === 'true', nextMarker: res.NextMarker || '', @@ -248,8 +271,8 @@ class TcyunApi { * oldKey: string, * newKey: string * } - */ - async renameBucketFile (configMap: IStringKeyMap): Promise { + */ + async renameBucketFile(configMap: IStringKeyMap): Promise { const { bucketName, region, oldKey, newKey } = configMap const copyRes = await this.ctx.putObjectCopy({ Bucket: bucketName, @@ -277,8 +300,8 @@ class TcyunApi { * region: string, * key: string * } - */ - async deleteBucketFile (configMap: IStringKeyMap): Promise { + */ + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap const res = await this.ctx.deleteObject({ Bucket: bucketName, @@ -292,7 +315,7 @@ class TcyunApi { * 删除文件夹 * @param configMap */ - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap let marker let res: any @@ -317,7 +340,14 @@ class TcyunApi { marker = res.NextMarker } while (res.IsTruncated === 'true') for (const item of allFileList.CommonPrefixes) { - if (!(await this.deleteBucketFolder({ bucketName, region, key: item.Prefix }))) return false + if ( + !(await this.deleteBucketFolder({ + bucketName, + region, + key: item.Prefix + })) + ) + return false } const cycles = Math.ceil(allFileList.Contents.length / 1000) for (let i = 0; i < cycles; i++) { @@ -342,16 +372,18 @@ class TcyunApi { * customUrl: string * } */ - async getPreSignedUrl (configMap: IStringKeyMap): Promise { + async getPreSignedUrl(configMap: IStringKeyMap): Promise { const { bucketName, region, key, expires, customUrl } = configMap - const res = this.ctx.getObjectUrl({ - Bucket: bucketName, - Region: region, - Key: key, - Expires: expires, - Sign: true - }, () => { - }) + const res = this.ctx.getObjectUrl( + { + Bucket: bucketName, + Region: region, + Key: key, + Expires: expires, + Sign: true + }, + () => {} + ) return customUrl ? `${customUrl.replace(/\/+$/, '')}/${key}${res.slice(res.indexOf('?'))}` : res } @@ -359,7 +391,7 @@ class TcyunApi { * 高级上传文件 * @param configMap */ - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap // fileArray = [{ // bucketName: string, @@ -412,7 +444,12 @@ class TcyunApi { finishTime: new Date().toLocaleString() }) } else { - this.logger.error(formatError(err, { method: 'uploadBucketFile', class: 'TcyunApi' })) + this.logger.error( + formatError(err, { + method: 'uploadBucketFile', + class: 'TcyunApi' + }) + ) instance.updateUploadTask({ id, progress: 0, @@ -434,7 +471,7 @@ class TcyunApi { * 新建文件夹 * @param configMap */ - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap const res = await this.ctx.putObject({ Bucket: bucketName, @@ -449,7 +486,7 @@ class TcyunApi { * 下载文件 * @param configMap */ - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray } = configMap // fileArray = [{ // bucketName: string, @@ -472,38 +509,46 @@ class TcyunApi { targetFilePath: path.join(downloadPath, fileName) }) fs.ensureDirSync(path.dirname(path.join(downloadPath, fileName))) - this.ctx.downloadFile({ - Bucket: bucketName, - Region: region, - Key: key, - RetryTimes: 3, - ChunkSize: 1024 * 1024 * 1, - FilePath: path.join(downloadPath, fileName), - onProgress: (progress: any) => { + this.ctx + .downloadFile({ + Bucket: bucketName, + Region: region, + Key: key, + RetryTimes: 3, + ChunkSize: 1024 * 1024 * 1, + FilePath: path.join(downloadPath, fileName), + onProgress: (progress: any) => { + instance.updateDownloadTask({ + id, + progress: Math.floor(progress.percent * 100), + status: downloadTaskSpecialStatus.downloading + }) + } + }) + .then((res: any) => { instance.updateDownloadTask({ id, - progress: Math.floor(progress.percent * 100), - status: downloadTaskSpecialStatus.downloading + progress: res && res.statusCode === 200 ? 100 : 0, + status: res && res.statusCode === 200 ? downloadTaskSpecialStatus.downloaded : commonTaskStatus.failed, + response: typeof res === 'object' ? JSON.stringify(res) : String(res), + finishTime: new Date().toLocaleString() }) - } - }).then((res: any) => { - instance.updateDownloadTask({ - id, - progress: res && res.statusCode === 200 ? 100 : 0, - status: res && res.statusCode === 200 ? downloadTaskSpecialStatus.downloaded : commonTaskStatus.failed, - response: typeof res === 'object' ? JSON.stringify(res) : String(res), - finishTime: new Date().toLocaleString() }) - }).catch((err: any) => { - this.logger.error(formatError(err, { method: 'downloadBucketFile', class: 'TcyunApi' })) - instance.updateDownloadTask({ - id, - progress: 0, - status: commonTaskStatus.failed, - response: typeof err === 'object' ? JSON.stringify(err) : String(err), - finishTime: new Date().toLocaleString() + .catch((err: any) => { + this.logger.error( + formatError(err, { + method: 'downloadBucketFile', + class: 'TcyunApi' + }) + ) + instance.updateDownloadTask({ + id, + progress: 0, + status: commonTaskStatus.failed, + response: typeof err === 'object' ? JSON.stringify(err) : String(err), + finishTime: new Date().toLocaleString() + }) }) - }) } return true } diff --git a/src/main/manage/apis/upyun.ts b/src/main/manage/apis/upyun.ts index 1b09fcf5..f5d39b2e 100644 --- a/src/main/manage/apis/upyun.ts +++ b/src/main/manage/apis/upyun.ts @@ -7,7 +7,15 @@ import Upyun from 'upyun' import windowManager from 'apis/app/window/windowManager' -import { md5, hmacSha1Base64, getFileMimeType, NewDownloader, gotUpload, ConcurrencyPromisePool, formatError } from '~/manage/utils/common' +import { + md5, + hmacSha1Base64, + getFileMimeType, + NewDownloader, + gotUpload, + ConcurrencyPromisePool, + formatError +} from '~/manage/utils/common' import { ManageLogger } from '~/manage/utils/logger' import UpDownTaskQueue from '~/manage/datastore/upDownTaskQueue' @@ -26,7 +34,14 @@ class UpyunApi { stopMarker = 'g2gCZAAEbmV4dGQAA2VvZg' logger: ManageLogger - constructor (bucket: string, operator: string, password: string, logger: ManageLogger, antiLeechToken?: string, expireTime?: number) { + constructor( + bucket: string, + operator: string, + password: string, + logger: ManageLogger, + antiLeechToken?: string, + expireTime?: number + ) { this.ser = new Upyun.Service(bucket, operator, password) this.cli = new Upyun.Client(this.ser) this.bucket = bucket @@ -37,7 +52,7 @@ class UpyunApi { this.expireTime = expireTime || 24 * 60 * 60 } - getAntiLeechParam (key: string): string { + getAntiLeechParam(key: string): string { const uri = `/${key}`.replace(/%2F/g, '/').replace(/^\/+/g, '/') const now = Math.round(new Date().getTime() / 1000) const expire = this.expireTime ? now + parseInt(this.expireTime.toString(), 10) : now + 1800 @@ -46,7 +61,7 @@ class UpyunApi { return `_upt=${upt}` } - formatFolder (item: any, slicedPrefix: string, urlPrefix: string) { + formatFolder(item: any, slicedPrefix: string, urlPrefix: string) { const key = `${slicedPrefix}${item.name}/` let url = `${urlPrefix}/${key}` if (this.antiLeechToken) { @@ -67,7 +82,7 @@ class UpyunApi { } } - formatFile (item: any, slicedPrefix: string, urlPrefix: string) { + formatFile(item: any, slicedPrefix: string, urlPrefix: string) { const key = `${slicedPrefix}${item.name}` let url = `${urlPrefix}/${key}` if (this.antiLeechToken) { @@ -87,13 +102,7 @@ class UpyunApi { } } - authorization ( - method: string, - uri: string, - contentMd5: string, - operator: string, - password: string - ) { + authorization(method: string, uri: string, contentMd5: string, operator: string, password: string) { return `UPYUN ${operator}:${hmacSha1Base64( md5(password, 'hex'), `${method.toUpperCase()}&${encodeURI(uri)}&${new Date().toUTCString()}${contentMd5 ? `&${contentMd5}` : ''}` @@ -103,11 +112,11 @@ class UpyunApi { /** * 获取空间列表 */ - async getBucketList (): Promise { + async getBucketList(): Promise { return this.bucket } - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: bucket, prefix, cancelToken } = configMap const slicedPrefix = prefix.slice(1) @@ -159,7 +168,7 @@ class UpyunApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: bucket, prefix, cancelToken } = configMap const slicedPrefix = prefix.slice(1) @@ -217,8 +226,8 @@ class UpyunApi { * itemsPerPage: number, * customUrl: string * } - */ - async getBucketFileList (configMap: IStringKeyMap): Promise { + */ + async getBucketFileList(configMap: IStringKeyMap): Promise { const { bucketName: bucket, prefix, marker, itemsPerPage } = configMap const slicedPrefix = prefix.slice(1) const urlPrefix = configMap.customUrl || `http://${bucket}.test.upcdn.net` @@ -246,16 +255,16 @@ class UpyunApi { } /** - * 重命名文件 - * @param configMap - * configMap = { - * bucketName: string, - * region: string, - * oldKey: string, - * newKey: string - * } - */ - async renameBucketFile (configMap: IStringKeyMap): Promise { + * 重命名文件 + * @param configMap + * configMap = { + * bucketName: string, + * region: string, + * oldKey: string, + * newKey: string + * } + */ + async renameBucketFile(configMap: IStringKeyMap): Promise { const oldKey = configMap.oldKey let newKey = configMap.newKey const method = 'PUT' @@ -280,25 +289,25 @@ class UpyunApi { } /** - * 删除文件 - * @param configMap - * configMap = { - * bucketName: string, - * region: string, - * key: string - * } - */ - async deleteBucketFile (configMap: IStringKeyMap): Promise { + * 删除文件 + * @param configMap + * configMap = { + * bucketName: string, + * region: string, + * key: string + * } + */ + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { key } = configMap const res = await this.cli.deleteFile(key) return res } /** - * delete bucket folder - * @param configMap - */ - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + * delete bucket folder + * @param configMap + */ + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { key } = configMap let marker = '' let isTruncated @@ -313,14 +322,16 @@ class UpyunApi { }) if (res) { res.files.forEach((item: any) => { - item.type === 'N' && allFileList.Contents.push({ - ...item, - key: `${key}${item.name}` - }) - item.type === 'F' && allFileList.CommonPrefixes.push({ - ...item, - key: `${key}${item.name}/` - }) + item.type === 'N' && + allFileList.Contents.push({ + ...item, + key: `${key}${item.name}` + }) + item.type === 'F' && + allFileList.CommonPrefixes.push({ + ...item, + key: `${key}${item.name}/` + }) }) marker = res.next isTruncated = res.next !== this.stopMarker @@ -360,7 +371,7 @@ class UpyunApi { * axiso:onUploadProgress not work in nodejs , use got instead * @param configMap */ - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap const instance = UpDownTaskQueue.getInstance() fileArray.forEach((item: any) => { @@ -416,7 +427,7 @@ class UpyunApi { * 新建文件夹 * @param configMap */ - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { key } = configMap const res = await this.cli.makeDir(`/${key}`) return res @@ -426,7 +437,7 @@ class UpyunApi { * 下载文件 * @param configMap */ - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray, maxDownloadFileCount } = configMap const instance = UpDownTaskQueue.getInstance() const promises = [] as any @@ -445,19 +456,21 @@ class UpyunApi { targetFilePath: savedFilePath }) const preSignedUrl = `${customUrl}/${key}` - promises.push(() => new Promise((resolve, reject) => { - NewDownloader(instance, preSignedUrl, id, savedFilePath, this.logger) - .then((res: boolean) => { - if (res) { - resolve(res) - } else { - reject(res) - } + promises.push( + () => + new Promise((resolve, reject) => { + NewDownloader(instance, preSignedUrl, id, savedFilePath, this.logger).then((res: boolean) => { + if (res) { + resolve(res) + } else { + reject(res) + } + }) }) - })) + ) } const pool = new ConcurrencyPromisePool(maxDownloadFileCount) - pool.all(promises).catch((error) => { + pool.all(promises).catch(error => { this.logger.error(formatError(error, { class: 'UpyunApi', method: 'downloadBucketFile' })) }) return true diff --git a/src/main/manage/apis/webdavplist.ts b/src/main/manage/apis/webdavplist.ts index 9959e71d..7be4d3f0 100644 --- a/src/main/manage/apis/webdavplist.ts +++ b/src/main/manage/apis/webdavplist.ts @@ -29,7 +29,15 @@ class WebdavplistApi { agent: https.Agent | http.Agent ctx: WebDAVClient - constructor (endpoint: string, username: string, password: string, sslEnabled: boolean, proxy: string | undefined, authType: 'basic' | 'digest' | undefined, logger: ManageLogger) { + constructor( + endpoint: string, + username: string, + password: string, + sslEnabled: boolean, + proxy: string | undefined, + authType: 'basic' | 'digest' | undefined, + logger: ManageLogger + ) { this.endpoint = formatEndpoint(endpoint, sslEnabled) this.username = username this.password = password @@ -50,16 +58,12 @@ class WebdavplistApi { if (this.authType === 'digest') { options.authType = AuthType.Digest } - this.ctx = createClient( - this.endpoint, - options - ) + this.ctx = createClient(this.endpoint, options) } - logParam = (error:any, method: string) => - this.logger.error(formatError(error, { class: 'WebdavplistApi', method })) + logParam = (error: any, method: string) => this.logger.error(formatError(error, { class: 'WebdavplistApi', method })) - formatFolder (item: FileStat, urlPrefix: string, isWebPath = false) { + formatFolder(item: FileStat, urlPrefix: string, isWebPath = false) { const key = item.filename.replace(/^\/+/, '') return { ...item, @@ -76,7 +80,7 @@ class WebdavplistApi { } } - formatFile (item: FileStat, urlPrefix: string, isWebPath = false) { + formatFile(item: FileStat, urlPrefix: string, isWebPath = false) { const key = item.filename.replace(/^\/+/, '') return { ...item, @@ -95,7 +99,7 @@ class WebdavplistApi { isRequestSuccess = (code: number) => code >= 200 && code < 300 - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { prefix, customUrl, cancelToken } = configMap const urlPrefix = customUrl || this.endpoint @@ -135,7 +139,7 @@ class WebdavplistApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { prefix, customUrl, cancelToken, baseDir } = configMap let urlPrefix = customUrl || this.endpoint @@ -166,7 +170,8 @@ class WebdavplistApi { if (res.data?.length) { res.data.forEach((item: FileStat) => { const relativePath = path.relative(baseDir, item.filename) - const relative = webPath && urlPrefix + `/${path.join(webPath, relativePath)}`.replace(/\\/g, '/').replace(/\/+/g, '/') + const relative = + webPath && urlPrefix + `/${path.join(webPath, relativePath)}`.replace(/\\/g, '/').replace(/\/+/g, '/') if (item.type === 'directory') { result.fullList.push(this.formatFolder(item, webPath ? relative : urlPrefix, !!webPath)) } else { @@ -193,7 +198,7 @@ class WebdavplistApi { ipcMain.removeAllListeners('cancelLoadingFileList') } - async renameBucketFile (configMap: IStringKeyMap): Promise { + async renameBucketFile(configMap: IStringKeyMap): Promise { const { oldKey, newKey } = configMap let result = false try { @@ -205,7 +210,7 @@ class WebdavplistApi { return result } - async deleteBucketFile (configMap: IStringKeyMap): Promise { + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -217,7 +222,7 @@ class WebdavplistApi { return result } - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -229,7 +234,7 @@ class WebdavplistApi { return result } - async getPreSignedUrl (configMap: IStringKeyMap): Promise { + async getPreSignedUrl(configMap: IStringKeyMap): Promise { const { key } = configMap let result = '' try { @@ -241,7 +246,7 @@ class WebdavplistApi { return result } - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap const instance = UpDownTaskQueue.getInstance() for (const item of fileArray) { @@ -261,10 +266,8 @@ class WebdavplistApi { targetFileRegion: region, noProgress: true }) - this.ctx.putFileContents( - key, - this.authType === 'digest' ? fs.readFileSync(filePath) : fs.createReadStream(filePath), - { + this.ctx + .putFileContents(key, this.authType === 'digest' ? fs.readFileSync(filePath) : fs.createReadStream(filePath), { overwrite: true, onUploadProgress: (progressEvent: ProgressEvent) => { instance.updateUploadTask({ @@ -273,37 +276,38 @@ class WebdavplistApi { status: uploadTaskSpecialStatus.uploading }) } - } - ).then((res: boolean) => { - if (res) { - instance.updateUploadTask({ - id, - progress: 100, - status: uploadTaskSpecialStatus.uploaded, - finishTime: new Date().toLocaleString() - }) - } else { + }) + .then((res: boolean) => { + if (res) { + instance.updateUploadTask({ + id, + progress: 100, + status: uploadTaskSpecialStatus.uploaded, + finishTime: new Date().toLocaleString() + }) + } else { + instance.updateUploadTask({ + id, + progress: 0, + status: commonTaskStatus.failed, + finishTime: new Date().toLocaleString() + }) + } + }) + .catch((error: any) => { + this.logParam(error, 'uploadBucketFile') instance.updateUploadTask({ id, progress: 0, status: commonTaskStatus.failed, finishTime: new Date().toLocaleString() }) - } - }).catch((error: any) => { - this.logParam(error, 'uploadBucketFile') - instance.updateUploadTask({ - id, - progress: 0, - status: commonTaskStatus.failed, - finishTime: new Date().toLocaleString() }) - }) } return true } - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -317,7 +321,7 @@ class WebdavplistApi { return result } - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray, maxDownloadFileCount } = configMap const instance = UpDownTaskQueue.getInstance() const promises = [] as any @@ -345,25 +349,35 @@ class WebdavplistApi { Authorization: `Basic ${base64Str}` } } else if (this.authType === 'digest') { - const authHeader = await getAuthHeader('GET', this.endpoint, `/${key.replace(/^\/+/, '')}`, this.username, this.password) + const authHeader = await getAuthHeader( + 'GET', + this.endpoint, + `/${key.replace(/^\/+/, '')}`, + this.username, + this.password + ) headers = { Authorization: authHeader } preSignedUrl = `${this.endpoint}/${key.replace(/^\/+/, '')}` } - promises.push(() => new Promise((resolve, reject) => { - NewDownloader(instance, preSignedUrl, id, savedFilePath, this.logger, this.proxyStr, headers) - .then((res: boolean) => { - if (res) { - resolve(res) - } else { - reject(res) - } + promises.push( + () => + new Promise((resolve, reject) => { + NewDownloader(instance, preSignedUrl, id, savedFilePath, this.logger, this.proxyStr, headers).then( + (res: boolean) => { + if (res) { + resolve(res) + } else { + reject(res) + } + } + ) }) - })) + ) } const pool = new ConcurrencyPromisePool(maxDownloadFileCount) - pool.all(promises).catch((error) => { + pool.all(promises).catch(error => { this.logParam(error, 'downloadBucketFile') }) return true diff --git a/src/main/manage/datastore/db.ts b/src/main/manage/datastore/db.ts index 7c65eef7..0a2b1f4e 100644 --- a/src/main/manage/datastore/db.ts +++ b/src/main/manage/datastore/db.ts @@ -6,7 +6,7 @@ import { IManageApiType, IManageConfigType } from '#/types/manage' class ManageDB { readonly #ctx: IManageApiType readonly #db: JSONStore - constructor (ctx: IManageApiType) { + constructor(ctx: IManageApiType) { this.#ctx = ctx this.#db = new JSONStore(this.#ctx.configPath) const initParams: IStringKeyMap = { @@ -25,37 +25,37 @@ class ManageDB { } } - read (flush?: boolean): IJSON { + read(flush?: boolean): IJSON { return this.#db.read(flush) } - get (key: string = ''): any { + get(key: string = ''): any { this.read(true) return this.#db.get(key) } - set (key: string, value: any): void { + set(key: string, value: any): void { this.read(true) return this.#db.set(key, value) } - has (key: string): boolean { + has(key: string): boolean { this.read(true) return this.#db.has(key) } - unset (key: string, value: any): boolean { + unset(key: string, value: any): boolean { this.read(true) return this.#db.unset(key, value) } - saveConfig (config: Partial): void { + saveConfig(config: Partial): void { Object.keys(config).forEach((name: string) => { this.set(name, config[name]) }) } - removeConfig (config: IManageConfigType): void { + removeConfig(config: IManageConfigType): void { Object.keys(config).forEach((name: string) => { this.unset(name, config[name]) }) diff --git a/src/main/manage/datastore/dbChecker.ts b/src/main/manage/datastore/dbChecker.ts index 789b8db6..fa7c71bd 100644 --- a/src/main/manage/datastore/dbChecker.ts +++ b/src/main/manage/datastore/dbChecker.ts @@ -23,7 +23,7 @@ const errorMsg = { /** ensure notification list */ if (!global.notificationList) global.notificationList = [] -function manageDbChecker () { +function manageDbChecker() { if (process.type !== 'renderer') { const manageConfigFilePath = managePathChecker() if (!fs.existsSync(manageConfigFilePath)) { @@ -42,9 +42,13 @@ function manageDbChecker () { fs.unlinkSync(manageConfigFilePath) if (fs.existsSync(manageConfigFileBackupPath)) { try { - configFile = fs.readFileSync(manageConfigFileBackupPath, { encoding: 'utf-8' }) + configFile = fs.readFileSync(manageConfigFileBackupPath, { + encoding: 'utf-8' + }) JSON.parse(configFile) - writeFile.sync(manageConfigFilePath, configFile, { encoding: 'utf-8' }) + writeFile.sync(manageConfigFilePath, configFile, { + encoding: 'utf-8' + }) const stats = fs.statSync(manageConfigFileBackupPath) optionsTpl.body = `${errorMsg.brokenButBackup}\n${T('TIPS_PICGO_BACKUP_FILE_VERSION', { v: dayjs(stats.mtime).format('YYYY-MM-DD HH:mm:ss') @@ -61,14 +65,16 @@ function manageDbChecker () { global.notificationList.push(optionsTpl) return } - writeFile.sync(manageConfigFileBackupPath, configFile, { encoding: 'utf-8' }) + writeFile.sync(manageConfigFileBackupPath, configFile, { + encoding: 'utf-8' + }) } } /** * Get manage config path */ -function managePathChecker (): string { +function managePathChecker(): string { if (_configFilePath) { return _configFilePath } @@ -80,7 +86,9 @@ function managePathChecker (): string { return _configFilePath } try { - const configString = fs.readFileSync(defaultManageConfigPath, { encoding: 'utf-8' }) + const configString = fs.readFileSync(defaultManageConfigPath, { + encoding: 'utf-8' + }) const config = JSON.parse(configString) const userConfigPath: string = config.configPath || '' if (userConfigPath) { @@ -107,12 +115,8 @@ function managePathChecker (): string { } } -function managePathDir () { +function managePathDir() { return path.dirname(managePathChecker()) } -export { - managePathChecker, - managePathDir, - manageDbChecker -} +export { managePathChecker, managePathDir, manageDbChecker } diff --git a/src/main/manage/datastore/upDownTaskQueue.ts b/src/main/manage/datastore/upDownTaskQueue.ts index d00e5522..372531c8 100644 --- a/src/main/manage/datastore/upDownTaskQueue.ts +++ b/src/main/manage/datastore/upDownTaskQueue.ts @@ -9,8 +9,8 @@ import { commonTaskStatus, downloadTaskSpecialStatus, uploadTaskSpecialStatus } import { IDownloadTask, IUploadTask } from '#/types/manage' class UpDownTaskQueue { - /* eslint-disable */ - private static instance: UpDownTaskQueue + /* eslint-disable */ + private static instance: UpDownTaskQueue /* eslint-enable */ private uploadTaskQueue = [] @@ -18,38 +18,38 @@ class UpDownTaskQueue { private persistPath = path.join(app.getPath('userData'), 'UpDownTaskQueue.json') - private constructor () { + private constructor() { this.restore() } - static getInstance () { + static getInstance() { if (!UpDownTaskQueue.instance) { UpDownTaskQueue.instance = new UpDownTaskQueue() } return UpDownTaskQueue.instance } - getUploadTaskQueue () { + getUploadTaskQueue() { return UpDownTaskQueue.getInstance().uploadTaskQueue } - getDownloadTaskQueue () { + getDownloadTaskQueue() { return UpDownTaskQueue.getInstance().downloadTaskQueue } - getUploadTask (taskId: string) { + getUploadTask(taskId: string) { return UpDownTaskQueue.getInstance().uploadTaskQueue.find(item => item.id === taskId) } - getAllUploadTask () { + getAllUploadTask() { return UpDownTaskQueue.getInstance().uploadTaskQueue } - addUploadTask (task: IUploadTask) { + addUploadTask(task: IUploadTask) { UpDownTaskQueue.getInstance().uploadTaskQueue.push(task) } - updateUploadTask (task: Partial) { + updateUploadTask(task: Partial) { const taskIndex = UpDownTaskQueue.getInstance().uploadTaskQueue.findIndex(item => item.id === task.id) if (taskIndex !== -1) { const taskKeys = Object.keys(task) @@ -61,33 +61,33 @@ class UpDownTaskQueue { } } - removeUploadTask (taskId: string) { + removeUploadTask(taskId: string) { const taskIndex = UpDownTaskQueue.getInstance().uploadTaskQueue.findIndex(item => item.id === taskId) if (taskIndex !== -1) { UpDownTaskQueue.getInstance().uploadTaskQueue.splice(taskIndex, 1) } } - removeDownloadTask (taskId: string) { + removeDownloadTask(taskId: string) { const taskIndex = UpDownTaskQueue.getInstance().downloadTaskQueue.findIndex(item => item.id === taskId) if (taskIndex !== -1) { UpDownTaskQueue.getInstance().downloadTaskQueue.splice(taskIndex, 1) } } - getDownloadTask (taskId: string) { + getDownloadTask(taskId: string) { return UpDownTaskQueue.getInstance().downloadTaskQueue.find(item => item.id === taskId) } - getAllDownloadTask () { + getAllDownloadTask() { return UpDownTaskQueue.getInstance().downloadTaskQueue } - addDownloadTask (task: IDownloadTask) { + addDownloadTask(task: IDownloadTask) { UpDownTaskQueue.getInstance().downloadTaskQueue.push(task) } - updateDownloadTask (task: Partial) { + updateDownloadTask(task: Partial) { const taskIndex = UpDownTaskQueue.getInstance().downloadTaskQueue.findIndex(item => item.id === task.id) if (taskIndex !== -1) { const taskKeys = Object.keys(task) @@ -99,40 +99,53 @@ class UpDownTaskQueue { } } - clearUploadTaskQueue () { + clearUploadTaskQueue() { UpDownTaskQueue.getInstance().uploadTaskQueue = [] } - removeUploadedTask () { - UpDownTaskQueue.getInstance().uploadTaskQueue = UpDownTaskQueue.getInstance().uploadTaskQueue.filter(item => item.status !== uploadTaskSpecialStatus.uploaded && item.status !== commonTaskStatus.canceled && item.status !== commonTaskStatus.failed) + removeUploadedTask() { + UpDownTaskQueue.getInstance().uploadTaskQueue = UpDownTaskQueue.getInstance().uploadTaskQueue.filter( + item => + item.status !== uploadTaskSpecialStatus.uploaded && + item.status !== commonTaskStatus.canceled && + item.status !== commonTaskStatus.failed + ) } - removeDownloadedTask () { - UpDownTaskQueue.getInstance().downloadTaskQueue = UpDownTaskQueue.getInstance().downloadTaskQueue.filter(item => item.status !== downloadTaskSpecialStatus.downloaded && item.status !== commonTaskStatus.canceled && item.status !== commonTaskStatus.failed) + removeDownloadedTask() { + UpDownTaskQueue.getInstance().downloadTaskQueue = UpDownTaskQueue.getInstance().downloadTaskQueue.filter( + item => + item.status !== downloadTaskSpecialStatus.downloaded && + item.status !== commonTaskStatus.canceled && + item.status !== commonTaskStatus.failed + ) } - clearDownloadTaskQueue () { + clearDownloadTaskQueue() { UpDownTaskQueue.getInstance().downloadTaskQueue = [] } - clearAllTaskQueue () { + clearAllTaskQueue() { this.clearUploadTaskQueue() this.clearDownloadTaskQueue() } - persist () { + persist() { try { this.checkPersistPath() - fs.writeFileSync(this.persistPath, JSON.stringify({ - uploadTaskQueue: this.uploadTaskQueue, - downloadTaskQueue: this.downloadTaskQueue - })) + fs.writeFileSync( + this.persistPath, + JSON.stringify({ + uploadTaskQueue: this.uploadTaskQueue, + downloadTaskQueue: this.downloadTaskQueue + }) + ) } catch (e) { console.log(e) } } - private restore () { + private restore() { try { this.checkPersistPath() const persistData = JSON.parse(fs.readFileSync(this.persistPath, { encoding: 'utf-8' })) @@ -144,20 +157,26 @@ class UpDownTaskQueue { } } - private checkPersistPath () { + private checkPersistPath() { if (!fs.existsSync(this.persistPath)) { - fs.writeFileSync(this.persistPath, JSON.stringify({ - uploadTaskQueue: this.uploadTaskQueue, - downloadTaskQueue: this.downloadTaskQueue - })) + fs.writeFileSync( + this.persistPath, + JSON.stringify({ + uploadTaskQueue: this.uploadTaskQueue, + downloadTaskQueue: this.downloadTaskQueue + }) + ) } try { JSON.parse(fs.readFileSync(this.persistPath, { encoding: 'utf-8' })) } catch (e) { - fs.writeFileSync(this.persistPath, JSON.stringify({ - uploadTaskQueue: this.uploadTaskQueue, - downloadTaskQueue: this.downloadTaskQueue - })) + fs.writeFileSync( + this.persistPath, + JSON.stringify({ + uploadTaskQueue: this.uploadTaskQueue, + downloadTaskQueue: this.downloadTaskQueue + }) + ) } } } diff --git a/src/main/manage/events/ipcList.ts b/src/main/manage/events/ipcList.ts index dfadd013..744d8e6c 100644 --- a/src/main/manage/events/ipcList.ts +++ b/src/main/manage/events/ipcList.ts @@ -10,7 +10,7 @@ import { downloadFileFromUrl } from '~/manage/utils/common' import { selectDownloadFolder } from '#/utils/static' export const manageIpcList = { - listen () { + listen() { manageCoreIPC.listen() ipcMain.handle('getBucketList', async (_: IpcMainInvokeEvent, currentPicBed: string) => { @@ -59,10 +59,13 @@ export const manageIpcList = { return manage.getBucketListBackstage(param) }) - ipcMain.on('getBucketListRecursively', async (_: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => { - const manage = new ManageApi(currentPicBed) - return manage.getBucketListRecursively(param) - }) + ipcMain.on( + 'getBucketListRecursively', + async (_: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => { + const manage = new ManageApi(currentPicBed) + return manage.getBucketListRecursively(param) + } + ) ipcMain.handle('convertPathToBase64', async (_: IpcMainInvokeEvent, filePath: string) => { const res = fs.readFileSync(filePath, 'base64') diff --git a/src/main/manage/events/manageCoreIPC.ts b/src/main/manage/events/manageCoreIPC.ts index 04b48f56..2e5fb952 100644 --- a/src/main/manage/events/manageCoreIPC.ts +++ b/src/main/manage/events/manageCoreIPC.ts @@ -1,11 +1,11 @@ -import { - IpcMainEvent, - IpcMainInvokeEvent, - ipcMain -} from 'electron' +import { IpcMainEvent, IpcMainInvokeEvent, ipcMain } from 'electron' import getManageApi from '~/manage/Main' -import { PICLIST_MANAGE_GET_CONFIG, PICLIST_MANAGE_SAVE_CONFIG, PICLIST_MANAGE_REMOVE_CONFIG } from '~/manage/events/constants' +import { + PICLIST_MANAGE_GET_CONFIG, + PICLIST_MANAGE_SAVE_CONFIG, + PICLIST_MANAGE_REMOVE_CONFIG +} from '~/manage/events/constants' const manageApi = getManageApi() @@ -28,7 +28,7 @@ const handleManageRemoveConfig = () => { } export default { - listen () { + listen() { handleManageGetConfig() handleManageSaveConfig() handleManageRemoveConfig() diff --git a/src/main/manage/manageApi.ts b/src/main/manage/manageApi.ts index e614b9e6..b5427798 100644 --- a/src/main/manage/manageApi.ts +++ b/src/main/manage/manageApi.ts @@ -1,4 +1,3 @@ - import { ipcMain } from 'electron' import { EventEmitter } from 'events' import fs from 'fs-extra' @@ -15,12 +14,7 @@ import { isInputConfigValid, formatError } from '~/manage/utils/common' import { ManageLogger } from '~/manage/utils/logger' import { IWindowList } from '#/types/enum' -import { - IManageApiType, - IManageConfigType, - IManageError, - IPicBedMangeConfig -} from '#/types/manage' +import { IManageApiType, IManageConfigType, IManageError, IPicBedMangeConfig } from '#/types/manage' import { cancelDownloadLoadingFileList, refreshDownloadFileTransferList } from '#/utils/static' export class ManageApi extends EventEmitter implements IManageApiType { @@ -32,7 +26,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { logger: ManageLogger currentPicBedConfig: IPicBedMangeConfig - constructor (currentPicBed: string = '') { + constructor(currentPicBed: string = '') { super() this.currentPicBed = currentPicBed || 'placeholder' this.configPath = managePathChecker() @@ -42,7 +36,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.currentPicBedConfig = this.getPicBedConfig(this.currentPicBed) } - getMsgParam (method: string) { + getMsgParam(method: string) { return { class: 'ManageApi', method, @@ -50,19 +44,33 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - errorMsg (err: any, param: IStringKeyMap) { + errorMsg(err: any, param: IStringKeyMap) { this.logger.error(formatError(err, param)) } - createClient () { + createClient() { const name = this.currentPicBedConfig.picBedName switch (name) { case 'aliyun': - return new API.AliyunApi(this.currentPicBedConfig.accessKeyId, this.currentPicBedConfig.accessKeySecret, this.logger) + return new API.AliyunApi( + this.currentPicBedConfig.accessKeyId, + this.currentPicBedConfig.accessKeySecret, + this.logger + ) case 'github': - return new API.GithubApi(this.currentPicBedConfig.token, this.currentPicBedConfig.githubUsername, this.currentPicBedConfig.proxy, this.logger) + return new API.GithubApi( + this.currentPicBedConfig.token, + this.currentPicBedConfig.githubUsername, + this.currentPicBedConfig.proxy, + this.logger + ) case 'imgur': - return new API.ImgurApi(this.currentPicBedConfig.imgurUserName, this.currentPicBedConfig.accessToken, this.currentPicBedConfig.proxy, this.logger) + return new API.ImgurApi( + this.currentPicBedConfig.imgurUserName, + this.currentPicBedConfig.accessToken, + this.currentPicBedConfig.proxy, + this.logger + ) case 'local': return new API.LocalApi(this.logger) case 'qiniu': @@ -70,25 +78,60 @@ export class ManageApi extends EventEmitter implements IManageApiType { 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, this.currentPicBedConfig.dogeCloudSupport || false, this.currentPicBedConfig.bucketName || '') + 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) + return new API.SftpApi( + this.currentPicBedConfig.host, + this.currentPicBedConfig.port, + this.currentPicBedConfig.username, + this.currentPicBedConfig.password, + this.currentPicBedConfig.privateKey, + this.currentPicBedConfig.passphrase, + this.currentPicBedConfig.fileMode, + this.currentPicBedConfig.dirMode, + this.logger + ) case 'tcyun': return new API.TcyunApi(this.currentPicBedConfig.secretId, this.currentPicBedConfig.secretKey, this.logger) case 'upyun': - return new API.UpyunApi(this.currentPicBedConfig.bucketName, this.currentPicBedConfig.operator, this.currentPicBedConfig.password, this.logger, this.currentPicBedConfig.antiLeechToken, this.currentPicBedConfig.expireTime) + return new API.UpyunApi( + this.currentPicBedConfig.bucketName, + this.currentPicBedConfig.operator, + this.currentPicBedConfig.password, + this.logger, + this.currentPicBedConfig.antiLeechToken, + this.currentPicBedConfig.expireTime + ) case 'webdavplist': - return new API.WebdavplistApi(this.currentPicBedConfig.endpoint, this.currentPicBedConfig.username, this.currentPicBedConfig.password, this.currentPicBedConfig.sslEnabled, this.currentPicBedConfig.proxy, this.currentPicBedConfig.authType, this.logger) + return new API.WebdavplistApi( + this.currentPicBedConfig.endpoint, + this.currentPicBedConfig.username, + this.currentPicBedConfig.password, + this.currentPicBedConfig.sslEnabled, + this.currentPicBedConfig.proxy, + this.currentPicBedConfig.authType, + this.logger + ) default: return {} as any } } - private getPicBedConfig (picBedName: string): IPicBedMangeConfig { + private getPicBedConfig(picBedName: string): IPicBedMangeConfig { return this.getConfig(`picBed.${picBedName}`) } - private initConfigPath (): void { + private initConfigPath(): void { if (this.configPath === '') { this.configPath = `${homedir()}/.piclist/manage.json` } @@ -103,30 +146,28 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - private initconfig (): void { + private initconfig(): void { this.db = new ManageDB(this) this._config = this.db.read(true) as IManageConfigType } - getConfig (name?: string): T { + getConfig(name?: string): T { if (!name) { return this._config as unknown as T } return get(this._config, name) } - saveConfig (config: IStringKeyMap): void { + saveConfig(config: IStringKeyMap): void { if (!isInputConfigValid(config)) { - this.logger.warn( - 'the format of config is invalid, please provide object' - ) + this.logger.warn('the format of config is invalid, please provide object') return } this.setConfig(config) this.db.saveConfig(config) } - removeConfig (key: string, propName: string): void { + removeConfig(key: string, propName: string): void { if (!key || !propName) { return } @@ -134,11 +175,9 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.db.unset(key, propName) } - setConfig (config: IStringKeyMap): void { + setConfig(config: IStringKeyMap): void { if (!isInputConfigValid(config)) { - this.logger.warn( - 'the format of config is invalid, please provide object' - ) + this.logger.warn('the format of config is invalid, please provide object') return } Object.keys(config).forEach((name: string) => { @@ -146,14 +185,12 @@ export class ManageApi extends EventEmitter implements IManageApiType { }) } - unsetConfig (key: string, propName: string): void { + unsetConfig(key: string, propName: string): void { if (!key || !propName) return unset(this.getConfig(key), propName) } - async getBucketList ( - param?: IStringKeyMap | undefined - ): Promise { + async getBucketList(param?: IStringKeyMap | undefined): Promise { let client const name = this.currentPicBedConfig.picBedName.replace('plist', '') switch (this.currentPicBedConfig.picBedName) { @@ -171,36 +208,36 @@ export class ManageApi extends EventEmitter implements IManageApiType { return [] } case 'upyun': - return [{ - Name: this.currentPicBedConfig.bucketName, - Location: 'upyun', - CreationDate: new Date().toISOString() - }] + return [ + { + Name: this.currentPicBedConfig.bucketName, + Location: 'upyun', + CreationDate: new Date().toISOString() + } + ] case 'smms': case 'webdavplist': case 'local': case 'sftp': - return [{ - Name: name, - Location: name, - CreationDate: new Date().toISOString() - }] + return [ + { + Name: name, + Location: name, + CreationDate: new Date().toISOString() + } + ] default: console.log(param) return [] } } - async getBucketInfo ( - param?: IStringKeyMap | undefined - ): Promise { + async getBucketInfo(param?: IStringKeyMap | undefined): Promise { console.log(param) return {} } - async getBucketDomain ( - param: IStringKeyMap - ): Promise { + async getBucketDomain(param: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': @@ -225,9 +262,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async createBucket ( - param?: IStringKeyMap - ): Promise { + async createBucket(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': @@ -246,44 +281,32 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async deleteBucket ( - param?: IStringKeyMap - ): Promise { + async deleteBucket(param?: IStringKeyMap): Promise { console.log(param) return false } - async getOperatorList ( - param?: IStringKeyMap - ): Promise { + async getOperatorList(param?: IStringKeyMap): Promise { console.log(param) return [] } - async addOperator ( - param?: IStringKeyMap - ): Promise { + async addOperator(param?: IStringKeyMap): Promise { console.log(param) return false } - async deleteOperator ( - param?: IStringKeyMap - ): Promise { + async deleteOperator(param?: IStringKeyMap): Promise { console.log(param) return false } - async getBucketAclPolicy ( - param?: IStringKeyMap - ): Promise { + async getBucketAclPolicy(param?: IStringKeyMap): Promise { console.log(param) return {} } - async setBucketAclPolicy ( - param?: IStringKeyMap - ): Promise { + async setBucketAclPolicy(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'qiniu': @@ -299,9 +322,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async getBucketListRecursively ( - param?: IStringKeyMap - ): Promise { + async getBucketListRecursively(param?: IStringKeyMap): Promise { let client let window const defaultResult = { @@ -344,9 +365,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { * @param param * @returns */ - async getBucketListBackstage ( - param?: IStringKeyMap - ): Promise { + async getBucketListBackstage(param?: IStringKeyMap): Promise { let client let window const defaultResult = { @@ -385,17 +404,15 @@ export class ManageApi extends EventEmitter implements IManageApiType { } /** - * 获取文件夹列表 - * 结果统一进行格式化 文件夹提取到最前 - * key: 完整路径 - * fileName: 文件名 - * formatedTime: 格式化时间 - * isDir: 是否是文件夹 - * fileSize: 文件大小 - **/ - async getBucketFileList ( - param?: IStringKeyMap - ): Promise { + * 获取文件夹列表 + * 结果统一进行格式化 文件夹提取到最前 + * key: 完整路径 + * fileName: 文件名 + * formatedTime: 格式化时间 + * isDir: 是否是文件夹 + * fileSize: 文件大小 + **/ + async getBucketFileList(param?: IStringKeyMap): Promise { const defaultResponse = { fullList: [], isTruncated: false, @@ -422,9 +439,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async deleteBucketFile ( - param?: IStringKeyMap - ): Promise { + async deleteBucketFile(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': @@ -451,9 +466,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async deleteBucketFolder ( - param?: IStringKeyMap - ): Promise { + async deleteBucketFolder(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': @@ -477,9 +490,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async renameBucketFile ( - param?: IStringKeyMap - ): Promise { + async renameBucketFile(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': @@ -502,9 +513,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async downloadBucketFile ( - param?: IStringKeyMap - ): Promise { + async downloadBucketFile(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': @@ -531,16 +540,12 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async copyMoveBucketFile ( - param?: IStringKeyMap - ): Promise { + async copyMoveBucketFile(param?: IStringKeyMap): Promise { console.log(param) return false } - async createBucketFolder ( - param?: IStringKeyMap - ): Promise { + async createBucketFolder(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': @@ -564,9 +569,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async uploadBucketFile ( - param?: IStringKeyMap - ): Promise { + async uploadBucketFile(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': @@ -592,9 +595,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async getPreSignedUrl ( - param?: IStringKeyMap - ): Promise { + async getPreSignedUrl(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': diff --git a/src/main/manage/utils/common.ts b/src/main/manage/utils/common.ts index 16182fb0..ace84b21 100644 --- a/src/main/manage/utils/common.ts +++ b/src/main/manage/utils/common.ts @@ -18,17 +18,12 @@ import { ManageLogger } from '~/manage/utils/logger' import { commonTaskStatus, downloadTaskSpecialStatus, uploadTaskSpecialStatus } from '#/types/enum' import { formatHttpProxy } from '#/utils/common' -export const getFSFile = async ( - filePath: string, - stream: boolean = false -): Promise => { +export const getFSFile = async (filePath: string, stream: boolean = false): Promise => { try { return { extension: path.extname(filePath), fileName: path.basename(filePath), - buffer: stream - ? fs.createReadStream(filePath) - : await fs.readFile(filePath), + buffer: stream ? fs.createReadStream(filePath) : await fs.readFile(filePath), success: true } } catch (e) { @@ -38,10 +33,8 @@ export const getFSFile = async ( } } -export function isInputConfigValid (config: any): boolean { - return typeof config === 'object' && - !Array.isArray(config) && - Object.keys(config).length > 0 +export function isInputConfigValid(config: any): boolean { + return typeof config === 'object' && !Array.isArray(config) && Object.keys(config).length > 0 } export const getFileMimeType = (filePath: string): string => mime.lookup(filePath) || 'application/octet-stream' @@ -83,17 +76,18 @@ export const clearTempFolder = () => fs.emptyDirSync(getTempDirPath()) export const md5 = (str: string, code: 'hex' | 'base64'): string => crypto.createHash('md5').update(str).digest(code) -export const hmacSha1Base64 = (secretKey: string, stringToSign: string) : string => crypto.createHmac('sha1', secretKey).update(Buffer.from(stringToSign, 'utf8')).digest('base64') +export const hmacSha1Base64 = (secretKey: string, stringToSign: string): string => + crypto.createHmac('sha1', secretKey).update(Buffer.from(stringToSign, 'utf8')).digest('base64') export const NewDownloader = async ( instance: UpDownTaskQueue, preSignedUrl: string, - id : string, + id: string, savedFilePath: string, logger?: ManageLogger, proxy?: string, headers?: any -) : Promise => { +): Promise => { const options = { url: preSignedUrl, directory: path.dirname(savedFilePath), @@ -150,19 +144,16 @@ export const gotUpload = async ( throwHttpErrors: boolean = false, agent: any = {} ) => { - got( - url, - { - headers, - method, - body, - timeout: { - lookup: timeout - }, - throwHttpErrors, - agent - } - ) + got(url, { + headers, + method, + body, + timeout: { + lookup: timeout + }, + throwHttpErrors, + agent + }) .on('uploadProgress', (progress: any) => { instance.updateUploadTask({ id, @@ -174,7 +165,10 @@ export const gotUpload = async ( instance.updateUploadTask({ id, progress: res?.statusCode === 200 || res?.statusCode === 201 ? 100 : 0, - status: res?.statusCode === 200 || res?.statusCode === 201 ? uploadTaskSpecialStatus.uploaded : commonTaskStatus.failed, + status: + res?.statusCode === 200 || res?.statusCode === 201 + ? uploadTaskSpecialStatus.uploaded + : commonTaskStatus.failed, finishTime: new Date().toLocaleString() }) }) @@ -190,7 +184,7 @@ export const gotUpload = async ( }) } -export const formatError = (err: any, params:IStringKeyMap) => { +export const formatError = (err: any, params: IStringKeyMap) => { if (err instanceof RequestError) { return { ...params, @@ -220,7 +214,10 @@ const commonOptions = { scheduling: 'lifo' as 'lifo' | 'fifo' | undefined } as any -export const getAgent = (proxy:any, https: boolean = true): { +export const getAgent = ( + proxy: any, + https: boolean = true +): { https?: HttpsProxyAgent http?: HttpProxyAgent } => { @@ -253,36 +250,36 @@ export const getInnerAgent = (proxy: any, sslEnabled: boolean = true) => { if (sslEnabled) { return formatProxy ? { - agent: new https.Agent({ + agent: new https.Agent({ + ...commonOptions, + rejectUnauthorized: false, + host: formatProxy.host, + port: formatProxy.port + }) + } + : { + agent: new https.Agent({ + rejectUnauthorized: false, + keepAlive: true + }) + } + } + return formatProxy + ? { + agent: new http.Agent({ ...commonOptions, - rejectUnauthorized: false, host: formatProxy.host, port: formatProxy.port }) } - : { - agent: new https.Agent({ - rejectUnauthorized: false, - keepAlive: true + : { + agent: new http.Agent({ + ...commonOptions }) } - } - return formatProxy - ? { - agent: new http.Agent({ - ...commonOptions, - host: formatProxy.host, - port: formatProxy.port - }) - } - : { - agent: new http.Agent({ - ...commonOptions - }) - } } -export function getOptions ( +export function getOptions( method?: string, headers?: IStringKeyMap, searchParams?: IStringKeyMap, @@ -298,7 +295,9 @@ export function getOptions ( ...(body && { body }), ...(responseType && { responseType }), ...(timeout !== undefined ? { timeout: { request: timeout } } : { timeout: { request: 30000 } }), - ...(proxy && { agent: Object.fromEntries(Object.entries(getAgent(proxy)).filter(([, v]) => v !== undefined)) }), + ...(proxy && { + agent: Object.fromEntries(Object.entries(getAgent(proxy)).filter(([, v]) => v !== undefined)) + }), throwHttpErrors: false } } @@ -309,14 +308,14 @@ export class ConcurrencyPromisePool { runningNum: number results: any[] - constructor (limit: number) { + constructor(limit: number) { this.limit = limit this.queue = [] this.runningNum = 0 this.results = [] } - all (promises: any[] = []) { + all(promises: any[] = []) { return new Promise((resolve, reject) => { for (const promise of promises) { this._run(promise, resolve, reject) @@ -324,7 +323,7 @@ export class ConcurrencyPromisePool { }) } - _run (promise: any, resolve: any, reject: any) { + _run(promise: any, resolve: any, reject: any) { if (this.runningNum >= this.limit) { this.queue.push(promise) return diff --git a/src/main/manage/utils/constants.ts b/src/main/manage/utils/constants.ts index afaaada6..b6948e0e 100644 --- a/src/main/manage/utils/constants.ts +++ b/src/main/manage/utils/constants.ts @@ -1,4 +1,4 @@ -const AliyunAreaCodeName : IStringKeyMap = { +const AliyunAreaCodeName: IStringKeyMap = { 'oss-cn-hangzhou': '华东1(杭州)', 'oss-cn-shanghai': '华东2(上海)', 'oss-cn-nanjing': '华东5(南京)', @@ -31,7 +31,7 @@ const AliyunAreaCodeName : IStringKeyMap = { 'oss-rg-china-mainland': '无地域属性' } -const QiniuAreaCodeName : IStringKeyMap = { +const QiniuAreaCodeName: IStringKeyMap = { z0: '华东-浙江', 'cn-east-2': '华东 浙江2', z1: '华北-河北', @@ -42,7 +42,7 @@ const QiniuAreaCodeName : IStringKeyMap = { 'ap-southeast-2': '亚太-河内' } -const TencentAreaCodeName : IStringKeyMap = { +const TencentAreaCodeName: IStringKeyMap = { 'ap-beijing-1': '北京一区', 'ap-beijing': '北京', 'ap-nanjing': '南京', diff --git a/src/main/manage/utils/dogeAPI.ts b/src/main/manage/utils/dogeAPI.ts index f10dcce0..ea4da44f 100644 --- a/src/main/manage/utils/dogeAPI.ts +++ b/src/main/manage/utils/dogeAPI.ts @@ -10,7 +10,7 @@ export interface DogecloudToken { sessionToken: string } -export async function dogecloudApi ( +export async function dogecloudApi( apiPath: string, data = {}, jsonMode: boolean = false, @@ -18,7 +18,10 @@ export async function dogecloudApi ( secretKey: string ) { const body = jsonMode ? JSON.stringify(data) : querystring.encode(data) - const sign = crypto.createHmac('sha1', secretKey).update(Buffer.from(apiPath + '\n' + body, 'utf8')).digest('hex') + const sign = crypto + .createHmac('sha1', secretKey) + .update(Buffer.from(apiPath + '\n' + body, 'utf8')) + .digest('hex') const authorization = `TOKEN ${accessKey}:${sign}` try { const res = await axios.request({ @@ -40,16 +43,22 @@ export async function dogecloudApi ( } } -export async function getTempToken (accessKey: string, secretKey: string): Promise<{} | DogecloudToken> { - const dogeTempToken = await picgo.getConfig('Credentials.doge-token') || {} as any +export async function getTempToken(accessKey: string, secretKey: string): Promise { + const dogeTempToken = (await picgo.getConfig('Credentials.doge-token')) || ({} as any) if (dogeTempToken.token && dogeTempToken.expires > Date.now() + 7200000) { return dogeTempToken.token } try { - const data = await dogecloudApi('/auth/tmp_token.json', { - channel: 'OSS_FULL', - scopes: ['*'] - }, true, accessKey, secretKey) + const data = await dogecloudApi( + '/auth/tmp_token.json', + { + channel: 'OSS_FULL', + scopes: ['*'] + }, + true, + accessKey, + secretKey + ) const token = data.Credentials picgo.saveConfig({ Credentials: { diff --git a/src/main/manage/utils/logger.ts b/src/main/manage/utils/logger.ts index 98bc2235..c8378e4b 100644 --- a/src/main/manage/utils/logger.ts +++ b/src/main/manage/utils/logger.ts @@ -22,14 +22,12 @@ export class ManageLogger implements ILogger { #logLevel!: string #logPath!: string - constructor (ctx: IManageApiType) { + constructor(ctx: IManageApiType) { this.#ctx = ctx } - #handleLog (type: ILogType, ...msg: ILogArgvTypeWithError[]): void { - const logHeader = chalk[this.#level[type] as ILogColor]( - `[PicList ${type.toUpperCase()}]` - ) + #handleLog(type: ILogType, ...msg: ILogArgvTypeWithError[]): void { + const logHeader = chalk[this.#level[type] as ILogColor](`[PicList ${type.toUpperCase()}]`) console.log(logHeader, ...msg) this.#logLevel = this.#ctx.getConfig(configPaths.settings.logLevel) this.#logPath = @@ -53,7 +51,7 @@ export class ManageLogger implements ILogger { }, 0) } - #checkLogFileIsLarge (logPath: string): { + #checkLogFileIsLarge(logPath: string): { isLarge: boolean logFileSize?: number logFileSizeLimit?: number @@ -61,11 +59,7 @@ export class ManageLogger implements ILogger { if (fs.existsSync(logPath)) { const logFileSize = fs.statSync(logPath).size const logFileSizeLimit = - enforceNumber( - this.#ctx.getConfig>( - configPaths.settings.logFileSizeLimit - ) || 10 - ) * + enforceNumber(this.#ctx.getConfig>(configPaths.settings.logFileSizeLimit) || 10) * 1024 * 1024 return { @@ -80,18 +74,14 @@ export class ManageLogger implements ILogger { } } - #recreateLogFile (logPath: string): void { + #recreateLogFile(logPath: string): void { if (fs.existsSync(logPath)) { fs.unlinkSync(logPath) fs.createFileSync(logPath) } } - #handleWriteLog ( - logPath: string, - type: string, - ...msg: ILogArgvTypeWithError[] - ): void { + #handleWriteLog(logPath: string, type: string, ...msg: ILogArgvTypeWithError[]): void { try { if (this.#checkLogLevel(type, this.#logLevel)) { let log = `${dayjs().format('YYYY-MM-DD HH:mm:ss')} [PicList ${type.toUpperCase()}] ` @@ -106,7 +96,7 @@ export class ManageLogger implements ILogger { } } - #formatLogItem (item: ILogArgvTypeWithError, type: string): string { + #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------- ` @@ -122,10 +112,7 @@ export class ManageLogger implements ILogger { return result } - #checkLogLevel ( - type: string, - level: undefined | string | string[] - ): boolean { + #checkLogLevel(type: string, level: undefined | string | string[]): boolean { if (level === undefined || level === 'all') { return true } @@ -135,23 +122,23 @@ export class ManageLogger implements ILogger { return type === level } - success (...msq: ILogArgvType[]): void { + success(...msq: ILogArgvType[]): void { return this.#handleLog(ILogType.success, ...msq) } - info (...msq: ILogArgvType[]): void { + info(...msq: ILogArgvType[]): void { return this.#handleLog(ILogType.info, ...msq) } - error (...msq: ILogArgvTypeWithError[]): void { + error(...msq: ILogArgvTypeWithError[]): void { return this.#handleLog(ILogType.error, ...msq) } - warn (...msq: ILogArgvType[]): void { + warn(...msq: ILogArgvType[]): void { return this.#handleLog(ILogType.warn, ...msq) } - debug (...msq: ILogArgvType[]): void { + debug(...msq: ILogArgvType[]): void { if (isDev) { this.#handleLog(ILogType.info, ...msq) } diff --git a/src/main/server/index.ts b/src/main/server/index.ts index 5b89e08e..04554d41 100644 --- a/src/main/server/index.ts +++ b/src/main/server/index.ts @@ -9,10 +9,7 @@ import picgo from '@core/picgo' import logger from '@core/picgo/logger' import routers from '~/server/routerManager' -import { - handleResponse, - ensureHTTPLink -} from '~/server/utils' +import { handleResponse, ensureHTTPLink } from '~/server/utils' import { configPaths } from '#/utils/configPaths' @@ -31,9 +28,7 @@ const multerStorage = multer.diskStorage({ filename: function (_req: any, file: { originalname: any }, cb: (arg0: null, arg1: any) => void) { // eslint-disable-next-line no-control-regex if (!/[^\u0000-\u00ff]/.test(file.originalname)) { - file.originalname = Buffer.from(file.originalname, 'latin1').toString( - 'utf8' - ) + file.originalname = Buffer.from(file.originalname, 'latin1').toString('utf8') } cb(null, file.originalname) } @@ -47,12 +42,12 @@ class Server { #httpServer: http.Server #config: IServerConfig - constructor () { + constructor() { this.#config = this.getConfigWithDefaults() this.#httpServer = http.createServer(this.#handleRequest) } - getConfigWithDefaults () { + getConfigWithDefaults() { let config = picgo.getConfig(configPaths.settings.server) if (!this.#isValidConfig(config)) { config = { port: DEFAULT_PORT, host: DEFAULT_HOST, enable: true } @@ -62,8 +57,8 @@ class Server { return config } - #isValidConfig (config: IObj | undefined) { - return config && config.port && config.host && (config.enable !== undefined) + #isValidConfig(config: IObj | undefined) { + return config && config.port && config.host && config.enable !== undefined } #handleRequest = (request: http.IncomingMessage, response: http.ServerResponse) => { @@ -108,7 +103,7 @@ class Server { } } if (request.headers['content-type'] && request.headers['content-type'].startsWith('multipart/form-data')) { - // @ts-ignore + // @ts-expect-error since the multer type is not correct uploadMulter.any()(request, response, (err: any) => { if (err) { logger.info('[PicList Server]', err) @@ -120,7 +115,7 @@ class Server { } }) } - // @ts-ignore + // @ts-expect-error since the multer type is not correct const list = request.files.map(file => file.path) logger.info('[PicList Server] get a formData request') const handler = routers.getHandler(url!, 'POST')?.handler @@ -140,7 +135,7 @@ class Server { }) request.on('end', () => { try { - postObj = (body === '') ? {} : JSON.parse(body) + postObj = body === '' ? {} : JSON.parse(body) } catch (err: any) { logger.error('[PicList Server]', err) return handleResponse({ @@ -205,20 +200,20 @@ class Server { }) } - startup () { + startup() { if (this.#config.enable) { this.#listen(this.#config.port) } } - shutdown (hasStarted?: boolean) { + shutdown(hasStarted?: boolean) { this.#httpServer.close() if (!hasStarted) { logger.info('[PicList Server] shutdown') } } - restart () { + restart() { this.shutdown() this.#config = this.getConfigWithDefaults() this.startup() diff --git a/src/main/server/router.ts b/src/main/server/router.ts index 2211be02..ddc7c03c 100644 --- a/src/main/server/router.ts +++ b/src/main/server/router.ts @@ -1,29 +1,29 @@ type HttpMethod = 'GET' | 'POST' class Router { - #router = new Map>() + #router = new Map>() - #addRoute (method: HttpMethod, url: string, callback: routeHandler, urlparams?: URLSearchParams): void { + #addRoute(method: HttpMethod, url: string, callback: routeHandler, urlparams?: URLSearchParams): void { if (!this.#router.has(url)) { this.#router.set(url, new Map()) } this.#router.get(url)!.set(method, { handler: callback, urlparams }) } - get (url: string, callback: routeHandler, urlparams?: URLSearchParams): void { + get(url: string, callback: routeHandler, urlparams?: URLSearchParams): void { this.#addRoute('GET', url, callback, urlparams) } - post (url: string, callback: routeHandler, urlparams?: URLSearchParams): void { + post(url: string, callback: routeHandler, urlparams?: URLSearchParams): void { this.#addRoute('POST', url, callback, urlparams) } - any (url: string, callback: routeHandler, urlparams?: URLSearchParams): void { + any(url: string, callback: routeHandler, urlparams?: URLSearchParams): void { this.#addRoute('GET', url, callback, urlparams) this.#addRoute('POST', url, callback, urlparams) } - getHandler (url: string, method: HttpMethod) { + getHandler(url: string, method: HttpMethod) { if (this.#router.has(url)) { const methods = this.#router.get(url)! if (methods.has(method)) { diff --git a/src/main/server/routerManager.ts b/src/main/server/routerManager.ts index 34b7495f..6f37b3a1 100644 --- a/src/main/server/routerManager.ts +++ b/src/main/server/routerManager.ts @@ -16,10 +16,7 @@ import windowManager from 'apis/app/window/windowManager' import { markdownContent } from '~/server/apiDoc' import router from '~/server/router' -import { - deleteChoosedFiles, - handleResponse -} from '~/server/utils' +import { deleteChoosedFiles, handleResponse } from '~/server/utils' import { configPaths } from '#/utils/configPaths' @@ -32,7 +29,7 @@ const LOG_PATH = path.join(STORE_PATH, 'piclist.log') const errorMessage = `upload error. see ${LOG_PATH} for more detail.` const deleteErrorMessage = `delete error. see ${LOG_PATH} for more detail.` -async function responseForGet ({ response } : {response: http.ServerResponse}) { +async function responseForGet({ response }: { response: http.ServerResponse }) { response.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }) const htmlContent = marked(markdownContent) response.write(htmlContent) @@ -42,192 +39,188 @@ async function responseForGet ({ response } : {response: http.ServerResponse}) { router.get('/', responseForGet) router.get('/upload', responseForGet) -router.post('/upload', async ({ - response, - list = [], - urlparams -} : { - response: IHttpResponse, - list?: string[], - urlparams?: URLSearchParams -}): Promise => { - try { - const picbed = urlparams?.get('picbed') - const passedKey = urlparams?.get('key') - const serverKey = picgo.getConfig(configPaths.settings.serverKey) || '' - if (serverKey && passedKey !== serverKey) { +router.post( + '/upload', + async ({ + response, + list = [], + urlparams + }: { + response: IHttpResponse + list?: string[] + urlparams?: URLSearchParams + }): Promise => { + try { + const picbed = urlparams?.get('picbed') + const passedKey = urlparams?.get('key') + const serverKey = picgo.getConfig(configPaths.settings.serverKey) || '' + if (serverKey && passedKey !== serverKey) { + handleResponse({ + response, + body: { + success: false, + message: 'server key is uncorrect' + } + }) + return + } + let currentPicBedType = '' + let currentPicBedConfig = {} as IStringKeyMap + let currentPicBedConfigId = '' + let needRestore = false + if (picbed) { + const currentPicBed = picgo.getConfig('picBed') || ({} as IStringKeyMap) + currentPicBedType = currentPicBed.current || '' + currentPicBedConfig = currentPicBed[currentPicBedType] || ({} as IStringKeyMap) + currentPicBedConfigId = currentPicBedConfig._id + const configName = urlparams?.get('configName') || currentPicBed[picbed]?._configName + if (picbed === currentPicBedType && configName === currentPicBedConfig._configName) { + // do nothing + } else { + needRestore = true + const picBeds = picgo.getConfig('uploader') + const currentPicBedList = picBeds?.[picbed]?.configList + if (currentPicBedList) { + const currentConfig = currentPicBedList?.find((item: any) => item._configName === configName) + if (currentConfig) { + changeCurrentUploader(picbed, currentConfig, currentConfig._id) + } + } + } + } + if (list.length === 0) { + // upload with clipboard + logger.info('[PicList Server] upload clipboard file') + const result = await uploadClipboardFiles() + const res = result.url + const fullResult = result.fullResult + logger.info('[PicList Server] upload result:', res) + if (res) { + const treatedFullResult = { + isEncrypted: 1, + EncryptedData: new AESHelper().encrypt(JSON.stringify(fullResult)), + ...fullResult + } + delete treatedFullResult.config + handleResponse({ + response, + body: { + success: true, + result: [res], + fullResult: [treatedFullResult] + } + }) + } else { + handleResponse({ + response, + body: { + success: false, + message: errorMessage + } + }) + } + } else { + logger.info('[PicList Server] upload files in list') + // upload with files + const pathList = list.map(item => { + return { + path: item + } + }) + const win = windowManager.getAvailableWindow() + const result = await uploadChoosedFiles(win.webContents, pathList) + const res = result.map(item => { + return item.url + }) + const fullResult = result.map((item: any) => { + const treatedItem = { + isEncrypted: 1, + EncryptedData: new AESHelper().encrypt(JSON.stringify(item.fullResult)), + ...item.fullResult + } + delete treatedItem.config + return treatedItem + }) + logger.info('[PicList Server] upload result', res.join(' ; ')) + if (res.length) { + handleResponse({ + response, + body: { + success: true, + result: res, + fullResult + } + }) + } else { + handleResponse({ + response, + body: { + success: false, + message: errorMessage + } + }) + } + } + fs.emptyDirSync(serverTempDir) + if (needRestore) { + changeCurrentUploader(currentPicBedType, currentPicBedConfig, currentPicBedConfigId) + } + } catch (err: any) { + logger.error(err) handleResponse({ response, body: { success: false, - message: 'server key is uncorrect' + message: errorMessage + } + }) + } + } +) + +router.post( + '/delete', + async ({ response, list = [] }: { response: IHttpResponse; list?: IStringKeyMap[] }): Promise => { + if (list.length === 0) { + handleResponse({ + response, + body: { + success: false, + message: 'no file to delete' } }) return } - let currentPicBedType = '' - let currentPicBedConfig = {} as IStringKeyMap - let currentPicBedConfigId = '' - let needRestore = false - if (picbed) { - const currentPicBed = picgo.getConfig('picBed') || {} as IStringKeyMap - currentPicBedType = currentPicBed.current || '' - currentPicBedConfig = currentPicBed[currentPicBedType] || {} as IStringKeyMap - currentPicBedConfigId = currentPicBedConfig._id - const configName = urlparams?.get('configName') || currentPicBed[picbed]?._configName - if (picbed === currentPicBedType && configName === currentPicBedConfig._configName) { - // do nothing - } else { - needRestore = true - const picBeds = picgo.getConfig('uploader') - const currentPicBedList = picBeds?.[picbed]?.configList - if (currentPicBedList) { - const currentConfig = currentPicBedList?.find((item: any) => item._configName === configName) - if (currentConfig) { - changeCurrentUploader(picbed, currentConfig, currentConfig._id) - } - } - } - } - if (list.length === 0) { - // upload with clipboard - logger.info('[PicList Server] upload clipboard file') - const result = await uploadClipboardFiles() - const res = result.url - const fullResult = result.fullResult - logger.info('[PicList Server] upload result:', res) - if (res) { - const treatedFullResult = { - isEncrypted: 1, - EncryptedData: new AESHelper().encrypt(JSON.stringify(fullResult)), - ...fullResult - } - delete treatedFullResult.config - handleResponse({ - response, - body: { - success: true, - result: [res], - fullResult: [treatedFullResult] - } - }) - } else { - handleResponse({ - response, - body: { - success: false, - message: errorMessage - } - }) - } - } else { - logger.info('[PicList Server] upload files in list') - // upload with files - const pathList = list.map(item => { - return { - path: item + try { + const aesHelper = new AESHelper() + const treatList = list.map(item => { + if (!item.isEncrypted) return item + return JSON.parse(aesHelper.decrypt(item.EncryptedData)) + }) + const result = await deleteChoosedFiles(treatList) + const successCount = result.filter(item => item).length + const failCount = result.length - successCount + handleResponse({ + response, + body: { + success: !!successCount, + message: successCount ? `delete success: ${successCount}, fail: ${failCount}` : deleteErrorMessage } }) - const win = windowManager.getAvailableWindow() - const result = await uploadChoosedFiles(win.webContents, pathList) - const res = result.map(item => { - return item.url - }) - const fullResult = result.map((item: any) => { - const treatedItem = { - isEncrypted: 1, - EncryptedData: new AESHelper().encrypt(JSON.stringify(item.fullResult)), - ...item.fullResult + } catch (err: any) { + logger.error(err) + handleResponse({ + response, + body: { + success: false, + message: deleteErrorMessage } - delete treatedItem.config - return treatedItem }) - logger.info('[PicList Server] upload result', res.join(' ; ')) - if (res.length) { - handleResponse({ - response, - body: { - success: true, - result: res, - fullResult - } - }) - } else { - handleResponse({ - response, - body: { - success: false, - message: errorMessage - } - }) - } } - fs.emptyDirSync(serverTempDir) - if (needRestore) { - changeCurrentUploader(currentPicBedType, currentPicBedConfig, currentPicBedConfigId) - } - } catch (err: any) { - logger.error(err) - handleResponse({ - response, - body: { - success: false, - message: errorMessage - } - }) } -}) +) -router.post('/delete', async ({ - response, - list = [] -} : { - response: IHttpResponse, - list?: IStringKeyMap[] -}): Promise => { - if (list.length === 0) { - handleResponse({ - response, - body: { - success: false, - message: 'no file to delete' - } - }) - return - } - try { - const aesHelper = new AESHelper() - const treatList = list.map(item => { - if (!item.isEncrypted) return item - return JSON.parse(aesHelper.decrypt(item.EncryptedData)) - }) - const result = await deleteChoosedFiles(treatList) - const successCount = result.filter(item => item).length - const failCount = result.length - successCount - handleResponse({ - response, - body: { - success: !!successCount, - message: successCount ? `delete success: ${successCount}, fail: ${failCount}` : deleteErrorMessage - } - }) - } catch (err: any) { - logger.error(err) - handleResponse({ - response, - body: { - success: false, - message: deleteErrorMessage - } - }) - } -}) - -router.any('/heartbeat', async ({ - response -} : { - response: IHttpResponse, -}) => { +router.any('/heartbeat', async ({ response }: { response: IHttpResponse }) => { handleResponse({ response, body: { diff --git a/src/main/server/utils.ts b/src/main/server/utils.ts index b1f6de89..bc0af109 100644 --- a/src/main/server/utils.ts +++ b/src/main/server/utils.ts @@ -1,6 +1,4 @@ -import { - Notification -} from 'electron' +import { Notification } from 'electron' import picgo from '@core/picgo' import logger from '@core/picgo/logger' @@ -28,10 +26,10 @@ export const handleResponse = ({ body = { success: false } -} : { - response: IHttpResponse, - statusCode?: number, - header?: IObj, +}: { + response: IHttpResponse + statusCode?: number + header?: IObj body?: any }) => { if (body?.success === false) { @@ -43,9 +41,7 @@ export const handleResponse = ({ } export const ensureHTTPLink = (url: string): string => { - return url.startsWith('http') - ? url - : `http://${url}` + return url.startsWith('http') ? url : `http://${url}` } export const deleteChoosedFiles = async (list: ImgInfo[]): Promise => { @@ -61,10 +57,7 @@ export const deleteChoosedFiles = async (list: ImgInfo[]): Promise => const noteFunc = (value: boolean) => { const notification = new Notification({ title: T('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'), - body: T(value - ? 'GALLERY_SYNC_DELETE_NOTICE_SUCCEED' - : 'GALLERY_SYNC_DELETE_NOTICE_FAILED' - ) + body: T(value ? 'GALLERY_SYNC_DELETE_NOTICE_SUCCEED' : 'GALLERY_SYNC_DELETE_NOTICE_FAILED') }) notification.show() } diff --git a/src/main/server/webServer/index.ts b/src/main/server/webServer/index.ts index dd439844..68b79871 100644 --- a/src/main/server/webServer/index.ts +++ b/src/main/server/webServer/index.ts @@ -10,7 +10,7 @@ import { configPaths } from '#/utils/configPaths' const defaultPath = process.platform === 'win32' ? 'C:\\Users' : '/' -function generateDirectoryListingHtml (files: any[], requestPath: any) { +function generateDirectoryListingHtml(files: any[], requestPath: any) { let html = '

Directory Listing

    ' files.forEach((file: string) => { const filePath = path.join(requestPath, file) @@ -20,7 +20,7 @@ function generateDirectoryListingHtml (files: any[], requestPath: any) { return html } -function serveDirectory (res: http.ServerResponse, filePath: fs.PathLike, requestPath: any) { +function serveDirectory(res: http.ServerResponse, filePath: fs.PathLike, requestPath: any) { fs.readdir(filePath, (err, files) => { if (err) { res.writeHead(500) @@ -32,7 +32,7 @@ function serveDirectory (res: http.ServerResponse, filePath: fs.PathLike, reques }) } -function serveFile (res:http.ServerResponse, filePath: fs.PathLike) { +function serveFile(res: http.ServerResponse, filePath: fs.PathLike) { const readStream = fs.createReadStream(filePath) readStream.pipe(res) readStream.on('error', () => { @@ -45,12 +45,12 @@ class WebServer { #server!: http.Server #config!: IStringKeyMap - constructor () { + constructor() { this.loadConfig() this.initServer() } - loadConfig (): void { + loadConfig(): void { this.#config = { enableWebServer: picgo.getConfig(configPaths.settings.enableWebServer) || false, webServerHost: picgo.getConfig(configPaths.settings.webServerHost) || '0.0.0.0', @@ -59,7 +59,7 @@ class WebServer { } } - initServer (): void { + initServer(): void { this.#server = http.createServer((req, res) => { const requestPath = req.url?.split('?')[0] const filePath = path.join(this.#config.webServerPath, decodeURIComponent(requestPath || '')) @@ -78,15 +78,19 @@ class WebServer { }) } - start () { + start() { if (this.#config.enableWebServer) { this.#server .listen( this.#config.webServerPort === 36699 ? 37777 : this.#config.webServerPort, - this.#config.webServerHost, () => { - logger.info(`Web server is running at http://${this.#config.webServerHost}:${this.#config.webServerPort}, root path is ${this.#config.webServerPath}`) - }) - .on('error', (err) => { + this.#config.webServerHost, + () => { + logger.info( + `Web server is running at http://${this.#config.webServerHost}:${this.#config.webServerPort}, root path is ${this.#config.webServerPath}` + ) + } + ) + .on('error', err => { logger.error(err) }) } else { @@ -94,13 +98,13 @@ class WebServer { } } - stop () { + stop() { this.#server.close(() => { logger.info('Web server is stopped') }) } - restart () { + restart() { this.stop() this.loadConfig() this.initServer() diff --git a/src/main/utils/aesHelper.ts b/src/main/utils/aesHelper.ts index 79ba22bc..e8220768 100644 --- a/src/main/utils/aesHelper.ts +++ b/src/main/utils/aesHelper.ts @@ -8,7 +8,7 @@ import { DEFAULT_AES_PASSWORD } from '#/utils/static' export class AESHelper { key: Buffer - constructor () { + constructor() { const userPassword = picgo.getConfig(configPaths.settings.aesPassword) || DEFAULT_AES_PASSWORD const fixedSalt = Buffer.from('a8b3c4d2e4f5098712345678feedc0de', 'hex') const fixedIterations = 100000 @@ -16,7 +16,7 @@ export class AESHelper { this.key = crypto.pbkdf2Sync(userPassword, fixedSalt, fixedIterations, keyLength, 'sha512') } - encrypt (plainText: string) { + encrypt(plainText: string) { const iv = crypto.randomBytes(16) const cipher = crypto.createCipheriv('aes-256-cbc', this.key, iv) let encrypted = cipher.update(plainText, 'utf8', 'hex') @@ -24,7 +24,7 @@ export class AESHelper { return `${iv.toString('hex')}:${encrypted}` } - decrypt (encryptedData: string) { + decrypt(encryptedData: string) { const [ivHex, encryptedText] = encryptedData.split(':') if (!ivHex || !encryptedText) { return '{}' diff --git a/src/main/utils/beforeOpen.ts b/src/main/utils/beforeOpen.ts index da4addf0..da4a68f4 100644 --- a/src/main/utils/beforeOpen.ts +++ b/src/main/utils/beforeOpen.ts @@ -10,7 +10,7 @@ import { i18nManager } from '~/i18n' const configPath = dbPathChecker() const CONFIG_DIR = path.dirname(configPath) -function beforeOpen () { +function beforeOpen() { if (process.platform === 'darwin') { resolveMacWorkFlow() } @@ -18,10 +18,7 @@ function beforeOpen () { resolveOtherI18nFiles() } -function copyFileOutsideOfElectronAsar ( - sourceInAsarArchive: string, - destOutsideAsarArchive: string -) { +function copyFileOutsideOfElectronAsar(sourceInAsarArchive: string, destOutsideAsarArchive: string) { if (fs.existsSync(sourceInAsarArchive)) { // file will be copied if (fs.statSync(sourceInAsarArchive).isFile()) { @@ -45,7 +42,7 @@ function copyFileOutsideOfElectronAsar ( /** * macOS 右键菜单 */ -function resolveMacWorkFlow () { +function resolveMacWorkFlow() { const dest = `${os.homedir()}/Library/Services/Upload pictures with PicList.workflow` if (fs.existsSync(dest)) return true try { @@ -55,7 +52,7 @@ function resolveMacWorkFlow () { } } -function diffFilesAndUpdate (filePath1: string, filePath2: string) { +function diffFilesAndUpdate(filePath1: string, filePath2: string) { try { const file1 = fs.existsSync(filePath1) && fs.readFileSync(filePath1) const file2 = fs.existsSync(filePath1) && fs.readFileSync(filePath2) @@ -72,7 +69,7 @@ function diffFilesAndUpdate (filePath1: string, filePath2: string) { /** * 初始化剪贴板生成图片的脚本 */ -function resolveClipboardImageGenerator () { +function resolveClipboardImageGenerator() { const clipboardFiles = getClipboardFiles() if (!fs.pathExistsSync(path.join(CONFIG_DIR, 'windows10.ps1'))) { clipboardFiles.forEach(item => { @@ -84,14 +81,8 @@ function resolveClipboardImageGenerator () { }) } - function getClipboardFiles () { - const files = [ - '/linux.sh', - '/mac.applescript', - '/windows.ps1', - '/windows10.ps1', - '/wsl.sh' - ] + function getClipboardFiles() { + const files = ['/linux.sh', '/mac.applescript', '/windows.ps1', '/windows10.ps1', '/wsl.sh'] return files.map(item => { return { @@ -105,7 +96,7 @@ function resolveClipboardImageGenerator () { /** * 初始化其他语言文件 */ -function resolveOtherI18nFiles () { +function resolveOtherI18nFiles() { const i18nFolder = path.join(CONFIG_DIR, 'i18n') if (!fs.pathExistsSync(i18nFolder)) { fs.mkdirSync(i18nFolder) diff --git a/src/main/utils/clipboardPoll.ts b/src/main/utils/clipboardPoll.ts index 999dd520..39b9f5ad 100644 --- a/src/main/utils/clipboardPoll.ts +++ b/src/main/utils/clipboardPoll.ts @@ -8,13 +8,13 @@ class ClipboardWatcher extends EventEmitter { timer: NodeJS.Timeout | null lastImageHash: string | null - constructor () { + constructor() { super() this.lastImageHash = null this.timer = null } - startListening (watchDelay = 500) { + startListening(watchDelay = 500) { this.stopListening(false) this.timer = setInterval(() => { @@ -33,7 +33,7 @@ class ClipboardWatcher extends EventEmitter { logger.info('Start to watch clipboard') } - stopListening (isLog = true) { + stopListening(isLog = true) { if (this.timer) { clearInterval(this.timer) this.timer = null @@ -42,7 +42,7 @@ class ClipboardWatcher extends EventEmitter { isLog && logger.info('Stop to watch clipboard') } - getImageHash (image: Electron.NativeImage): string { + getImageHash(image: Electron.NativeImage): string { const buffer = image.toBitmap() return crypto.createHash('md5').update(buffer).digest('hex') } diff --git a/src/main/utils/common.ts b/src/main/utils/common.ts index f115d2c2..bb5b4c37 100644 --- a/src/main/utils/common.ts +++ b/src/main/utils/common.ts @@ -12,11 +12,13 @@ import { configPaths } from '#/utils/configPaths' export let tray: Tray -export const setTray = (t: Tray) => { tray = t } +export const setTray = (t: Tray) => { + tray = t +} export const getTray = () => tray -export function setTrayToolTip (title: string): void { +export function setTrayToolTip(title: string): void { if (tray) { tray.setToolTip(title) } @@ -32,13 +34,15 @@ export const handleCopyUrl = (str: string): void => { * show notification * @param options */ -export const showNotification = (options: IPrivateShowNotificationOption = { - title: '', - body: '', - clickToCopy: false, - copyContent: '', - clickFn: () => {} -}) => { +export const showNotification = ( + options: IPrivateShowNotificationOption = { + title: '', + body: '', + clickToCopy: false, + copyContent: '', + clickFn: () => {} + } +) => { const notification = new Notification({ title: options.title, body: options.body @@ -60,10 +64,8 @@ export const showNotification = (options: IPrivateShowNotificationOption = { } export const showMessageBox = (options: any) => { - return new Promise(async (resolve) => { - dialog.showMessageBox( - options - ).then((res) => { + return new Promise(async resolve => { + dialog.showMessageBox(options).then(res => { resolve({ result: res.response, checkboxChecked: res.checkboxChecked @@ -118,14 +120,18 @@ export const getClipboardFilePath = (): string => { } if (img.isEmpty() && platform === 'win32') { - const imgPath = clipboard.readBuffer('FileNameW')?.toString('ucs2')?.replace(RegExp(String.fromCharCode(0), 'g'), '') + const imgPath = clipboard + .readBuffer('FileNameW') + ?.toString('ucs2') + ?.replace(RegExp(String.fromCharCode(0), 'g'), '') return imgPath || '' } return '' } -export const handleUrlEncodeWithSetting = (url: string) => db.get(configPaths.settings.encodeOutputURL) ? handleUrlEncode(url) : url +export const handleUrlEncodeWithSetting = (url: string) => + db.get(configPaths.settings.encodeOutputURL) ? handleUrlEncode(url) : url const c1nApi = 'https://c1n.cn/link/short' @@ -163,7 +169,12 @@ const generateYOURLSShortUrl = async (url: string) => { if (!/^https?:\/\//.test(domain)) { domain = `http://${domain}` } - const params = new URLSearchParams({ signature, action: 'shorturl', format: 'json', url }) + const params = new URLSearchParams({ + signature, + action: 'shorturl', + format: 'json', + url + }) try { const res = await axios.get(`${domain}/yourls-api.php?${params.toString()}`) if (res.data?.shorturl) { diff --git a/src/main/utils/deleteFunc.ts b/src/main/utils/deleteFunc.ts index 078abe43..fad49fd6 100644 --- a/src/main/utils/deleteFunc.ts +++ b/src/main/utils/deleteFunc.ts @@ -32,7 +32,7 @@ const dogeRegionMap: IStringKeyMap = { 'ap-chengdu': '3' } -async function dogecloudApi ( +async function dogecloudApi( apiPath: string, data = {}, jsonMode: boolean = false, @@ -40,7 +40,10 @@ async function dogecloudApi ( secretKey: string ) { const body = jsonMode ? JSON.stringify(data) : querystring.encode(data) - const sign = crypto.createHmac('sha1', secretKey).update(Buffer.from(apiPath + '\n' + body, 'utf8')).digest('hex') + const sign = crypto + .createHmac('sha1', secretKey) + .update(Buffer.from(apiPath + '\n' + body, 'utf8')) + .digest('hex') const authorization = `TOKEN ${accessKey}:${sign}` try { const res = await axios.request({ @@ -62,12 +65,18 @@ async function dogecloudApi ( } } -async function getDogeToken (accessKey: string, secretKey: string): Promise<{} | DogecloudTokenFull> { +async function getDogeToken(accessKey: string, secretKey: string): Promise { try { - const data = await dogecloudApi('/auth/tmp_token.json', { - channel: 'OSS_FULL', - scopes: ['*'] - }, true, accessKey, secretKey) + const data = await dogecloudApi( + '/auth/tmp_token.json', + { + channel: 'OSS_FULL', + scopes: ['*'] + }, + true, + accessKey, + secretKey + ) return data } catch (err: any) { console.log(err) @@ -75,10 +84,17 @@ async function getDogeToken (accessKey: string, secretKey: string): Promise<{} | } } -export async function removeFileFromS3InMain (configMap: IStringKeyMap, dogeMode: boolean = false) { +export async function removeFileFromS3InMain(configMap: IStringKeyMap, dogeMode: boolean = false) { try { - const { url: rawUrl, type, config: { accessKeyID, secretAccessKey, bucketName, endpoint, pathStyleAccess, rejectUnauthorized, proxy } } = configMap - let { imgUrl, config: { region } } = configMap + const { + url: rawUrl, + type, + config: { accessKeyID, secretAccessKey, bucketName, endpoint, pathStyleAccess, rejectUnauthorized, proxy } + } = configMap + let { + imgUrl, + config: { region } + } = configMap if (type === 'aws-s3' || type === 'aws-s3-plist') { imgUrl = rawUrl || imgUrl || '' } @@ -105,21 +121,21 @@ export async function removeFileFromS3InMain (configMap: IStringKeyMap, dogeMode const extraOptions = sslEnabled ? { rejectUnauthorized: !!rejectUnauthorized } : {} const handler = sslEnabled ? new NodeHttpHandler({ - httpsAgent: agent.https - ? agent.https - : new https.Agent({ - ...commonOptions, - ...extraOptions - }) - }) + httpsAgent: agent.https + ? agent.https + : new https.Agent({ + ...commonOptions, + ...extraOptions + }) + }) : new NodeHttpHandler({ - httpAgent: agent.http - ? agent.http - : new http.Agent({ - ...commonOptions, - ...extraOptions - }) - }) + httpAgent: agent.http + ? agent.http + : new http.Agent({ + ...commonOptions, + ...extraOptions + }) + }) const s3Options: S3ClientConfig = { credentials: { accessKeyId: accessKeyID, @@ -162,10 +178,12 @@ export async function removeFileFromS3InMain (configMap: IStringKeyMap, dogeMode } } -export async function removeFileFromDogeInMain (configMap: IStringKeyMap) { +export async function removeFileFromDogeInMain(configMap: IStringKeyMap) { try { - const { config: { bucketName, AccessKey, SecretKey } } = configMap - const token = await getDogeToken(AccessKey, SecretKey) as DogecloudTokenFull + const { + config: { bucketName, AccessKey, SecretKey } + } = configMap + const token = (await getDogeToken(AccessKey, SecretKey)) as DogecloudTokenFull const bucket = token.Buckets?.find(item => item.name === bucketName || item.s3Bucket === bucketName) const newConfigMap = Object.assign({}, configMap) newConfigMap.config = { @@ -184,7 +202,7 @@ export async function removeFileFromDogeInMain (configMap: IStringKeyMap) { } } -function createHuaweiAuthorization ( +function createHuaweiAuthorization( bucketName: string, path: string, fileName: string, @@ -197,7 +215,7 @@ function createHuaweiAuthorization ( return `OBS ${accessKey}:${singature}` } -export async function removeFileFromHuaweiInMain (configMap: IStringKeyMap) { +export async function removeFileFromHuaweiInMain(configMap: IStringKeyMap) { const { fileName, config } = configMap const { accessKeyId, accessKeySecret, bucketName, endpoint } = config let path = config.path || '/' @@ -223,11 +241,11 @@ export async function removeFileFromHuaweiInMain (configMap: IStringKeyMap) { } } -export async function removeFileFromSFTPInMain (config: ISftpPlistConfig, fileName: string) { +export async function removeFileFromSFTPInMain(config: ISftpPlistConfig, fileName: string) { try { const client = SSHClient.instance await client.connect(config) - const uploadPath = `/${(config.uploadPath || '')}/`.replace(/\/+/g, '/') + const uploadPath = `/${config.uploadPath || ''}/`.replace(/\/+/g, '/') const remote = path.join(uploadPath, fileName) const deleteResult = await client.deleteFileSFTP(config, remote) client.close() diff --git a/src/main/utils/getMacOSVersion.ts b/src/main/utils/getMacOSVersion.ts index bb31634c..69cedaa9 100644 --- a/src/main/utils/getMacOSVersion.ts +++ b/src/main/utils/getMacOSVersion.ts @@ -9,11 +9,8 @@ export const isMacOS = process.platform === 'darwin' let version: string | undefined -const clean = (version: string) => version.split('.').length === 1 - ? `${version}.0.0` - : version.split('.').length === 2 - ? `${version}.0` - : version +const clean = (version: string) => + version.split('.').length === 1 ? `${version}.0.0` : version.split('.').length === 2 ? `${version}.0` : version const parseVersion = (plist: string) => { const matches = /ProductVersion<\/key>\s*([\d.]+)<\/string>/.exec(plist) @@ -24,7 +21,7 @@ const parseVersion = (plist: string) => { return matches[1].replace('10.16', '11') } -export function macOSVersion (): string { +export function macOSVersion(): string { if (!isMacOS) return '' if (!version) { @@ -45,7 +42,7 @@ if (process.env.NODE_ENV === 'test') { macOSVersion._parseVersion = parseVersion } -export function isMacOSVersion (semverRange: string) { +export function isMacOSVersion(semverRange: string) { if (!isMacOS) { return false } @@ -55,7 +52,7 @@ export function isMacOSVersion (semverRange: string) { return semver.satisfies(macOSVersion(), clean(semverRange)) } -export function isMacOSVersionGreaterThanOrEqualTo (version: string) { +export function isMacOSVersionGreaterThanOrEqualTo(version: string) { if (!isMacOS) { return false } @@ -65,7 +62,7 @@ export function isMacOSVersionGreaterThanOrEqualTo (version: string) { return semver.gte(macOSVersion(), clean(version)) } -export function assertMacOSVersion (semverRange: string) { +export function assertMacOSVersion(semverRange: string) { semverRange = semverRange.replace('10.16', '11') if (!isMacOSVersion(semverRange)) { @@ -73,7 +70,7 @@ export function assertMacOSVersion (semverRange: string) { } } -export function assertMacOSVersionGreaterThanOrEqualTo (version: string) { +export function assertMacOSVersionGreaterThanOrEqualTo(version: string) { version = version.replace('10.16', '11') if (!isMacOSVersionGreaterThanOrEqualTo(version)) { @@ -81,7 +78,7 @@ export function assertMacOSVersionGreaterThanOrEqualTo (version: string) { } } -export function assertMacOS () { +export function assertMacOS() { if (!isMacOS) { throw new Error('Requires macOS') } diff --git a/src/main/utils/getPicBeds.ts b/src/main/utils/getPicBeds.ts index 24316644..6582a2ad 100644 --- a/src/main/utils/getPicBeds.ts +++ b/src/main/utils/getPicBeds.ts @@ -4,19 +4,21 @@ import { configPaths } from '#/utils/configPaths' const getPicBeds = () => { const picBedTypes = picgo.helper.uploader.getIdList() const picBedFromDB = picgo.getConfig(configPaths.picBed.list) || [] - const picBeds = picBedTypes.map((item: string) => { - const visible = picBedFromDB.find((i: IPicBedType) => i.type === item) // object or undefined - return { - type: item, - name: picgo.helper.uploader.get(item)!.name || item, - visible: visible ? visible.visible : true - } - }).sort((a) => { - if (a.type === 'tcyun') { - return -1 - } - return 0 - }) as IPicBedType[] + const picBeds = picBedTypes + .map((item: string) => { + const visible = picBedFromDB.find((i: IPicBedType) => i.type === item) // object or undefined + return { + type: item, + name: picgo.helper.uploader.get(item)!.name || item, + visible: visible ? visible.visible : true + } + }) + .sort(a => { + if (a.type === 'tcyun') { + return -1 + } + return 0 + }) as IPicBedType[] return picBeds } diff --git a/src/main/utils/handleArgv.ts b/src/main/utils/handleArgv.ts index a2cacd9d..d4c9a569 100644 --- a/src/main/utils/handleArgv.ts +++ b/src/main/utils/handleArgv.ts @@ -36,34 +36,34 @@ const getUploadFiles = (argv = process.argv, cwd = process.cwd(), logger: Logger if (fileList?.length === 0) { return null // for uploading images in clipboard } else if ((fileList?.length || 0) > 0) { - const result = fileList!.map(item => { - if (isUrl(item)) { - return { - path: item - } - } - if (path.isAbsolute(item)) { - return { - path: item - } - } else { - const tempPath = path.join(cwd, item) - if (fs.existsSync(tempPath)) { + const result = fileList! + .map(item => { + if (isUrl(item)) { return { - path: tempPath + path: item + } + } + if (path.isAbsolute(item)) { + return { + path: item } } else { - logger.warn(`cli -> can't get file: ${tempPath}, invalid path`) - return null + const tempPath = path.join(cwd, item) + if (fs.existsSync(tempPath)) { + return { + path: tempPath + } + } else { + logger.warn(`cli -> can't get file: ${tempPath}, invalid path`) + return null + } } - } - }).filter(item => item !== null) as Result + }) + .filter(item => item !== null) as Result return result } } return [] } -export { - getUploadFiles -} +export { getUploadFiles } diff --git a/src/main/utils/handleUploaderConfig.ts b/src/main/utils/handleUploaderConfig.ts index 506fa20e..07ad164b 100644 --- a/src/main/utils/handleUploaderConfig.ts +++ b/src/main/utils/handleUploaderConfig.ts @@ -13,6 +13,7 @@ export const handleConfigWithFunction = (config: IPicGoPluginOriginConfig[]): IP config[i].default = config[i].default() } if (typeof config[i].choices === 'function') { + // eslint-disable-next-line @typescript-eslint/ban-types config[i].choices = (config[i].choices as Function)() } } @@ -20,13 +21,17 @@ export const handleConfigWithFunction = (config: IPicGoPluginOriginConfig[]): IP } export const completeUploaderMetaConfig = (originData: IStringKeyMap): IUploaderConfigListItem => { - return Object.assign({ - _configName: 'Default' - }, trimValues(originData), { - _id: uuid(), - _createdAt: Date.now(), - _updatedAt: Date.now() - }) + return Object.assign( + { + _configName: 'Default' + }, + trimValues(originData), + { + _id: uuid(), + _createdAt: Date.now(), + _updatedAt: Date.now() + } + ) } /** @@ -130,7 +135,9 @@ export const deleteUploaderConfig = (type: string, id: string): IUploaderConfigI /** * upgrade old uploader config to new format */ -export const upgradeUploaderConfig = (type: string): { +export const upgradeUploaderConfig = ( + type: string +): { configList: IStringKeyMap[] defaultId: string } => { diff --git a/src/main/utils/sshClient.ts b/src/main/utils/sshClient.ts index e6766030..311851ad 100644 --- a/src/main/utils/sshClient.ts +++ b/src/main/utils/sshClient.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import fs from 'fs-extra' import { NodeSSH, Config, SSHExecCommandResponse } from 'node-ssh-no-cpu-features' import path from 'path' @@ -11,22 +10,26 @@ class SSHClient { private static _client: NodeSSH private _isConnected = false - static get instance (): SSHClient { + static get instance(): SSHClient { return this._instance || (this._instance = new this()) } - static get client (): NodeSSH { + static get client(): NodeSSH { return this._client || (this._client = new NodeSSH()) } - private changeWinStylePathToUnix (path: string): string { + private changeWinStylePathToUnix(path: string): string { return path.replace(/\\/g, '/') } - async connect (config: ISftpPlistConfig): Promise { + async connect(config: ISftpPlistConfig): Promise { const { username, password, privateKey, passphrase } = config const loginInfo: Config = privateKey - ? { username, privateKeyPath: privateKey, passphrase: passphrase || undefined } + ? { + username, + privateKeyPath: privateKey, + passphrase: passphrase || undefined + } : { username, password } try { await SSHClient.client.connect({ @@ -41,52 +44,64 @@ class SSHClient { } } - async deleteFileSFTP (config: ISftpPlistConfig, remote: string): Promise { + async deleteFileSFTP(config: ISftpPlistConfig, remote: string): Promise { try { const client = new Client() const { username, password, privateKey, passphrase } = config const loginInfo: Config = privateKey - ? { username, privateKey: fs.readFileSync(privateKey), passphrase: passphrase || undefined } + ? { + username, + privateKey: fs.readFileSync(privateKey), + passphrase: passphrase || undefined + } : { username, password } remote = this.changeWinStylePathToUnix(remote) if (remote === '/' || remote.includes('*')) return false const promise = new Promise((resolve, reject) => { - client.on('ready', () => { - client.sftp((err, sftp) => { - // eslint-disable-next-line prefer-promise-reject-errors - if (err) reject(false) - sftp.unlink(remote, (err) => { - // eslint-disable-next-line prefer-promise-reject-errors - if (err) reject(false) - client.end() - resolve(true) - }) + client + .on('ready', () => { + client.sftp( + ( + err: any, + sftp: { + unlink: (arg0: string, arg1: (err: any) => void) => void + } + ) => { + // eslint-disable-next-line prefer-promise-reject-errors + if (err) reject(false) + sftp.unlink(remote, (err: any) => { + // eslint-disable-next-line prefer-promise-reject-errors + if (err) reject(false) + client.end() + resolve(true) + }) + } + ) }) - }).connect({ - host: config.host, - port: Number(config.port) || 22, - ...loginInfo - }) - } - ) - return await promise + .connect({ + host: config.host, + port: Number(config.port) || 22, + ...loginInfo + }) + }) + return (await promise) as boolean } catch (err: any) { console.log(err) return false } } - private async exec (script: string): Promise { + private async exec(script: string): Promise { const execResult = await SSHClient.client.execCommand(script) return execResult.code === 0 } - async execCommand (script: string): Promise { + async execCommand(script: string): Promise { const execResult = await SSHClient.client.execCommand(script) return execResult || { code: 1, stdout: '', stderr: '' } } - async getFile (local: string, remote: string): Promise { + async getFile(local: string, remote: string): Promise { if (!this._isConnected) { throw new Error('SSH 未连接') } @@ -103,10 +118,14 @@ class SSHClient { } } - async putFile (local: string, remote: string, config: { - fileMode?: string - dirMode?: string - } = {}): Promise { + async putFile( + local: string, + remote: string, + config: { + fileMode?: string + dirMode?: string + } = {} + ): Promise { if (!this._isConnected) { throw new Error('SSH 未连接') } @@ -126,9 +145,12 @@ class SSHClient { } } - async mkdir (dirPath: string, config: { - dirMode?: string - } = {}): Promise { + async mkdir( + dirPath: string, + config: { + dirMode?: string + } = {} + ): Promise { if (!this._isConnected) { throw new Error('SSH 未连接') } @@ -158,11 +180,11 @@ class SSHClient { } } - get isConnected (): boolean { + get isConnected(): boolean { return SSHClient.client.isConnected() } - close (): void { + close(): void { SSHClient.client.dispose() this._isConnected = false } diff --git a/src/main/utils/syncSettings.ts b/src/main/utils/syncSettings.ts index 3edd0bd8..232f2483 100644 --- a/src/main/utils/syncSettings.ts +++ b/src/main/utils/syncSettings.ts @@ -15,32 +15,35 @@ const STORE_PATH = app.getPath('userData') const readFileAsBase64 = (filePath: string) => fs.readFileSync(filePath, { encoding: 'base64' }) const isHttpResSuccess = (res: any) => res.status >= 200 && res.status < 300 -const uploadOrUpdateMsg = (fileName: string, isUpdate: boolean = true) => isUpdate ? `update ${fileName} from PicList` : `upload ${fileName} from PicList` +const uploadOrUpdateMsg = (fileName: string, isUpdate: boolean = true) => + isUpdate ? `update ${fileName} from PicList` : `upload ${fileName} from PicList` const getSyncConfig = () => { - return db.get(configPaths.settings.sync) || { - type: 'github', - username: '', - repo: '', - branch: '', - token: '', - proxy: '' - } + return ( + db.get(configPaths.settings.sync) || { + type: 'github', + username: '', + repo: '', + branch: '', + token: '', + proxy: '' + } + ) } const getProxyagent = (proxy: string | undefined) => { return proxy ? new HttpsProxyAgent({ - keepAlive: true, - keepAliveMsecs: 1000, - rejectUnauthorized: false, - proxy: proxy.replace('127.0.0.1', 'localhost'), - scheduling: 'lifo' - }) + keepAlive: true, + keepAliveMsecs: 1000, + rejectUnauthorized: false, + proxy: proxy.replace('127.0.0.1', 'localhost'), + scheduling: 'lifo' + }) : undefined } -function getOctokit (syncConfig: ISyncConfig) { +function getOctokit(syncConfig: ISyncConfig) { const { token, proxy } = syncConfig return new Octokit({ auth: token, @@ -50,17 +53,11 @@ function getOctokit (syncConfig: ISyncConfig) { }) } -const isSyncConfigValidate = ({ - type, - username, - repo, - branch, - token -}: ISyncConfig) => { +const isSyncConfigValidate = ({ type, username, repo, branch, token }: ISyncConfig) => { return type && username && repo && branch && token } -async function uploadLocalToRemote (syncConfig: ISyncConfig, fileName: string) { +async function uploadLocalToRemote(syncConfig: ISyncConfig, fileName: string) { const localFilePath = path.join(STORE_PATH, fileName) if (!fs.existsSync(localFilePath)) { return false @@ -109,7 +106,7 @@ async function uploadLocalToRemote (syncConfig: ISyncConfig, fileName: string) { } } -async function updateLocalToRemote (syncConfig: ISyncConfig, fileName: string) { +async function updateLocalToRemote(syncConfig: ISyncConfig, fileName: string) { const localFilePath = path.join(STORE_PATH, fileName) if (!fs.existsSync(localFilePath)) { return false @@ -179,12 +176,16 @@ async function updateLocalToRemote (syncConfig: ISyncConfig, fileName: string) { } const data = shaRes.data as any const sha = data.sha - const res = await axios.put(apiUrl, { - ...defaultConfig, - sha - }, { - headers - }) + const res = await axios.put( + apiUrl, + { + ...defaultConfig, + sha + }, + { + headers + } + ) return isHttpResSuccess(res) } default: @@ -192,7 +193,7 @@ async function updateLocalToRemote (syncConfig: ISyncConfig, fileName: string) { } } -async function uploadFile (fileName: string[]): Promise { +async function uploadFile(fileName: string[]): Promise { const syncConfig = getSyncConfig() if (!isSyncConfigValidate(syncConfig)) { logger.error('sync config is invalid') @@ -217,16 +218,19 @@ async function uploadFile (fileName: string[]): Promise { return count } -async function downloadAndWriteFile (url: string, localFilePath:string, config: any, isWriteJson = false) { +async function downloadAndWriteFile(url: string, localFilePath: string, config: any, isWriteJson = false) { const res = await axios.get(url, config) if (isHttpResSuccess(res)) { - await fs.writeFile(localFilePath, isWriteJson ? JSON.stringify(res.data, null, 2) : Buffer.from(res.data.content, 'base64')) + await fs.writeFile( + localFilePath, + isWriteJson ? JSON.stringify(res.data, null, 2) : Buffer.from(res.data.content, 'base64') + ) return true } return false } -async function downloadRemoteToLocal (syncConfig: ISyncConfig, fileName: string) { +async function downloadRemoteToLocal(syncConfig: ISyncConfig, fileName: string) { const localFilePath = path.join(STORE_PATH, fileName) const { username, repo, branch, token, proxy, type } = syncConfig try { @@ -251,9 +255,14 @@ async function downloadRemoteToLocal (syncConfig: ISyncConfig, fileName: string) if (res.status === 200) { const data = res.data as any const downloadUrl = data.download_url - return downloadAndWriteFile(downloadUrl, localFilePath, { - httpsAgent: getProxyagent(proxy) - }, true) + return downloadAndWriteFile( + downloadUrl, + localFilePath, + { + httpsAgent: getProxyagent(proxy) + }, + true + ) } return false } @@ -278,7 +287,7 @@ async function downloadRemoteToLocal (syncConfig: ISyncConfig, fileName: string) } } -async function downloadFile (fileName: string[]): Promise { +async function downloadFile(fileName: string[]): Promise { const syncConfig = getSyncConfig() if (!isSyncConfigValidate(syncConfig)) { logger.error('sync config is invalid') @@ -294,7 +303,4 @@ async function downloadFile (fileName: string[]): Promise { return (await Promise.all(fileName.map(downloadFunc))).reduce((a, b) => a + b, 0) } -export { - uploadFile, - downloadFile -} +export { uploadFile, downloadFile } diff --git a/src/main/utils/windowHelper.ts b/src/main/utils/windowHelper.ts index 37175c47..89b23efc 100644 --- a/src/main/utils/windowHelper.ts +++ b/src/main/utils/windowHelper.ts @@ -7,7 +7,7 @@ import windowManager from 'apis/app/window/windowManager' import { IWindowList } from '#/types/enum' import { configPaths } from '#/utils/configPaths' -export function openMiniWindow (hideSettingWindow:boolean = true) { +export function openMiniWindow(hideSettingWindow: boolean = true) { const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)! miniWindow.removeAllListeners() if (db.get(configPaths.settings.miniWindowOntop)) { diff --git a/src/renderer/App.vue b/src/renderer/App.vue index 7cb4db9d..5b28a2ce 100644 --- a/src/renderer/App.vue +++ b/src/renderer/App.vue @@ -1,8 +1,5 @@ @@ -25,7 +22,6 @@ onBeforeMount(async () => { store?.setDefaultPicBed(config?.picBed?.uploader || config?.picBed?.current || 'smms') } }) - diff --git a/src/renderer/apis/alist.ts b/src/renderer/apis/alist.ts index e70be769..31e94cab 100644 --- a/src/renderer/apis/alist.ts +++ b/src/renderer/apis/alist.ts @@ -14,7 +14,7 @@ interface IConfigMap { } export default class AlistApi { - static async delete (configMap: IConfigMap): Promise { + static async delete(configMap: IConfigMap): Promise { const { fileName, config } = configMap try { const { version, url, uploadPath, token } = config diff --git a/src/renderer/apis/aliyun.ts b/src/renderer/apis/aliyun.ts index c02dcbb5..7a19b9db 100644 --- a/src/renderer/apis/aliyun.ts +++ b/src/renderer/apis/aliyun.ts @@ -8,13 +8,11 @@ interface IConfigMap { } export default class AliyunApi { - static #getKey (fileName: string, path?: string): string { - return path && path !== '/' - ? `${path.replace(/^\/+|\/+$/, '')}/${fileName}` - : fileName + static #getKey(fileName: string, path?: string): string { + return path && path !== '/' ? `${path.replace(/^\/+|\/+$/, '')}/${fileName}` : fileName } - static async delete (configMap: IConfigMap): Promise { + static async delete(configMap: IConfigMap): Promise { const { fileName, config } = configMap try { const client = new OSS({ ...config, region: config.area }) diff --git a/src/renderer/apis/allApi.ts b/src/renderer/apis/allApi.ts index fe70a368..bb3991e6 100644 --- a/src/renderer/apis/allApi.ts +++ b/src/renderer/apis/allApi.ts @@ -36,7 +36,7 @@ const apiMap: IStringKeyMap = { } export default class ALLApi { - static async delete (configMap: IStringKeyMap): Promise { + static async delete(configMap: IStringKeyMap): Promise { const api = apiMap[configMap.type] return api ? await api.delete(configMap) : false } diff --git a/src/renderer/apis/awss3.ts b/src/renderer/apis/awss3.ts index 5b4a3a5f..8e8cb4ff 100644 --- a/src/renderer/apis/awss3.ts +++ b/src/renderer/apis/awss3.ts @@ -6,10 +6,10 @@ import { deleteFailedLog } from '#/utils/deleteLog' import { IRPCActionType } from '#/types/enum' export default class AwsS3Api { - static async delete (configMap: IStringKeyMap): Promise { + static async delete(configMap: IStringKeyMap): Promise { try { return ipcRenderer - ? await triggerRPC(IRPCActionType.GALLERY_DELETE_AWS_S3_FILE, getRawData(configMap)) || false + ? (await triggerRPC(IRPCActionType.GALLERY_DELETE_AWS_S3_FILE, getRawData(configMap))) || false : await removeFileFromS3InMain(getRawData(configMap)) } catch (error: any) { deleteFailedLog(configMap.fileName, 'AWS S3', error) diff --git a/src/renderer/apis/dogecloud.ts b/src/renderer/apis/dogecloud.ts index 2e4796f3..e5c4059a 100644 --- a/src/renderer/apis/dogecloud.ts +++ b/src/renderer/apis/dogecloud.ts @@ -7,10 +7,10 @@ import { deleteFailedLog } from '#/utils/deleteLog' import { IRPCActionType } from '#/types/enum' export default class AwsS3Api { - static async delete (configMap: IStringKeyMap): Promise { + static async delete(configMap: IStringKeyMap): Promise { try { return ipcRenderer - ? await triggerRPC(IRPCActionType.GALLERY_DELETE_DOGE_FILE, getRawData(configMap)) || false + ? (await triggerRPC(IRPCActionType.GALLERY_DELETE_DOGE_FILE, getRawData(configMap))) || false : await removeFileFromDogeInMain(getRawData(configMap)) } catch (error: any) { deleteFailedLog(configMap.fileName, 'DogeCloud', error) diff --git a/src/renderer/apis/github.ts b/src/renderer/apis/github.ts index 70091dc4..ed928d98 100644 --- a/src/renderer/apis/github.ts +++ b/src/renderer/apis/github.ts @@ -9,21 +9,23 @@ interface IConfigMap { } export default class GithubApi { - static #createOctokit (token: string) { + static #createOctokit(token: string) { return new Octokit({ auth: token }) } - static #createKey (path: string | undefined, fileName: string): string { + static #createKey(path: string | undefined, fileName: string): string { const formatedFileName = fileName.replace(/%2F/g, '/') - return path && path !== '/' - ? `${path.replace(/^\/+|\/+$/, '')}/${formatedFileName}` - : formatedFileName + return path && path !== '/' ? `${path.replace(/^\/+|\/+$/, '')}/${formatedFileName}` : formatedFileName } - static async delete (configMap: IConfigMap): Promise { - const { fileName, hash, config: { repo, token, branch, path } } = configMap + static async delete(configMap: IConfigMap): Promise { + const { + fileName, + hash, + config: { repo, token, branch, path } + } = configMap const [owner, repoName] = repo.split('/') const octokit = GithubApi.#createOctokit(token) const key = GithubApi.#createKey(path, fileName) diff --git a/src/renderer/apis/huaweiyun.ts b/src/renderer/apis/huaweiyun.ts index 5499e7a0..f8a4f385 100644 --- a/src/renderer/apis/huaweiyun.ts +++ b/src/renderer/apis/huaweiyun.ts @@ -7,10 +7,10 @@ import { deleteFailedLog } from '#/utils/deleteLog' import { IRPCActionType } from '#/types/enum' export default class HuaweicloudApi { - static async delete (configMap: IStringKeyMap): Promise { + static async delete(configMap: IStringKeyMap): Promise { try { return ipcRenderer - ? await triggerRPC(IRPCActionType.GALLERY_DELETE_HUAWEI_OSS_FILE, getRawData(configMap)) || false + ? (await triggerRPC(IRPCActionType.GALLERY_DELETE_HUAWEI_OSS_FILE, getRawData(configMap))) || false : await removeFileFromHuaweiInMain(getRawData(configMap)) } catch (error: any) { deleteFailedLog(configMap.fileName, 'HuaweiCloud', error) diff --git a/src/renderer/apis/imgur.ts b/src/renderer/apis/imgur.ts index 4c980775..298ecdcc 100644 --- a/src/renderer/apis/imgur.ts +++ b/src/renderer/apis/imgur.ts @@ -10,11 +10,8 @@ interface IConfigMap { export default class ImgurApi { static #baseUrl = 'https://api.imgur.com/3' - static async delete (configMap: IConfigMap): Promise { - const { - config: { clientId = '', username = '', accessToken = '' } = {}, - hash = '' - } = configMap + static async delete(configMap: IConfigMap): Promise { + const { config: { clientId = '', username = '', accessToken = '' } = {}, hash = '' } = configMap let Authorization: string, apiUrl: string if (username && accessToken) { diff --git a/src/renderer/apis/local.ts b/src/renderer/apis/local.ts index 1f08a5c3..e622dade 100644 --- a/src/renderer/apis/local.ts +++ b/src/renderer/apis/local.ts @@ -7,7 +7,7 @@ interface IConfigMap { } export default class LocalApi { - static async delete (configMap: IConfigMap): Promise { + static async delete(configMap: IConfigMap): Promise { const { hash } = configMap if (!hash) { deleteLog(hash, 'Local', false, 'Local.delete: invalid params') diff --git a/src/renderer/apis/lskyplist.ts b/src/renderer/apis/lskyplist.ts index e0404e33..181f34c2 100644 --- a/src/renderer/apis/lskyplist.ts +++ b/src/renderer/apis/lskyplist.ts @@ -4,7 +4,7 @@ import https from 'https' import { deleteFailedLog, deleteLog } from '#/utils/deleteLog' export default class LskyplistApi { - static async delete (configMap: IStringKeyMap): Promise { + static async delete(configMap: IStringKeyMap): Promise { const { hash, config } = configMap if (!hash || !config || !config.token) { deleteLog(hash, 'Lskyplist', false, 'LskyplistApi.delete: invalid params') @@ -26,12 +26,11 @@ export default class LskyplistApi { rejectUnauthorized: false }) try { - const response: AxiosResponse = await axios.delete( - `${host}/api/v1/images/${hash}`, { - headers: v2Headers, - timeout: 30000, - httpsAgent: requestAgent - }) + const response: AxiosResponse = await axios.delete(`${host}/api/v1/images/${hash}`, { + headers: v2Headers, + timeout: 30000, + httpsAgent: requestAgent + }) if (response.status === 200 && response.data.status === true) { deleteLog(hash, 'Lskyplist') return true diff --git a/src/renderer/apis/piclist.ts b/src/renderer/apis/piclist.ts index 26a5607c..221fe208 100644 --- a/src/renderer/apis/piclist.ts +++ b/src/renderer/apis/piclist.ts @@ -3,7 +3,7 @@ import axios, { AxiosResponse } from 'axios' import { deleteFailedLog, deleteLog } from '#/utils/deleteLog' export default class PiclistApi { - static async delete (configMap: IStringKeyMap): Promise { + static async delete(configMap: IStringKeyMap): Promise { const { config, fullResult } = configMap const { host, port } = config if (!host) { @@ -14,12 +14,9 @@ export default class PiclistApi { const url = `http://${host || '127.0.0.1'}:${port || 36677}/delete` try { - const response: AxiosResponse = await axios.post( - url, - { - list: [fullResult] - } - ) + const response: AxiosResponse = await axios.post(url, { + list: [fullResult] + }) if (response.status === 200 && response.data?.success) { deleteLog(fullResult, 'Piclist') return true diff --git a/src/renderer/apis/qiniu.ts b/src/renderer/apis/qiniu.ts index 12fa90e1..887cf7f1 100644 --- a/src/renderer/apis/qiniu.ts +++ b/src/renderer/apis/qiniu.ts @@ -8,15 +8,18 @@ interface IConfigMap { } export default class QiniuApi { - static async delete (configMap: IConfigMap): Promise { - const { fileName, config: { accessKey, secretKey, bucket, path } } = configMap + static async delete(configMap: IConfigMap): Promise { + const { + fileName, + config: { accessKey, secretKey, bucket, path } + } = configMap const mac = new Qiniu.auth.digest.Mac(accessKey, secretKey) const qiniuConfig = new Qiniu.conf.Config() try { const bucketManager = new Qiniu.rs.BucketManager(mac, qiniuConfig) const formattedPath = path?.replace(/^\/+|\/+$/, '') || '' const key = path === '/' || !path ? fileName : `${formattedPath}/${fileName}` - const res = await new Promise((resolve, reject) => { + const res = (await new Promise((resolve, reject) => { bucketManager.delete(bucket, key, (err, respBody, respInfo) => { if (err) { reject(err) @@ -27,7 +30,7 @@ export default class QiniuApi { }) } }) - }) as any + })) as any if (res?.respInfo?.statusCode === 200) { deleteLog(fileName, 'Qiniu') return true diff --git a/src/renderer/apis/sftpplist.ts b/src/renderer/apis/sftpplist.ts index 60a17d66..1e169fe3 100644 --- a/src/renderer/apis/sftpplist.ts +++ b/src/renderer/apis/sftpplist.ts @@ -7,12 +7,11 @@ import { deleteFailedLog } from '#/utils/deleteLog' import { IRPCActionType } from '#/types/enum' export default class SftpPlistApi { - static async delete (configMap: IStringKeyMap): Promise { + static async delete(configMap: IStringKeyMap): Promise { const { fileName, config } = configMap try { return ipcRenderer - ? await triggerRPC(IRPCActionType.GALLERY_DELETE_SFTP_FILE, getRawData(config), - fileName) || false + ? (await triggerRPC(IRPCActionType.GALLERY_DELETE_SFTP_FILE, getRawData(config), fileName)) || false : await removeFileFromSFTPInMain(getRawData(config), fileName) } catch (error: any) { deleteFailedLog(fileName, 'SFTP', error) diff --git a/src/renderer/apis/smms.ts b/src/renderer/apis/smms.ts index bd21fb4a..a3ee9475 100644 --- a/src/renderer/apis/smms.ts +++ b/src/renderer/apis/smms.ts @@ -10,7 +10,7 @@ interface IConfigMap { export default class SmmsApi { static readonly #baseUrl = 'https://smms.app/api/v2' - static async delete (configMap: IConfigMap): Promise { + static async delete(configMap: IConfigMap): Promise { const { hash, config } = configMap if (!hash || !config || !config.token) { deleteLog(hash, 'Smms', false, 'SmmsApi.delete: invalid params') @@ -20,17 +20,16 @@ export default class SmmsApi { const { token } = config try { - const response: AxiosResponse = await axios.get( - `${SmmsApi.#baseUrl}/delete/${hash}`, { - headers: { - Authorization: token - }, - params: { - hash, - format: 'json' - }, - timeout: 30000 - }) + const response: AxiosResponse = await axios.get(`${SmmsApi.#baseUrl}/delete/${hash}`, { + headers: { + Authorization: token + }, + params: { + hash, + format: 'json' + }, + timeout: 30000 + }) if (response.status === 200) { deleteLog(hash, 'Smms') return true diff --git a/src/renderer/apis/tcyun.ts b/src/renderer/apis/tcyun.ts index 1026e20e..5393c60f 100644 --- a/src/renderer/apis/tcyun.ts +++ b/src/renderer/apis/tcyun.ts @@ -8,15 +8,18 @@ interface IConfigMap { } export default class TcyunApi { - static #createCOS (SecretId: string, SecretKey: string): COS { + static #createCOS(SecretId: string, SecretKey: string): COS { return new COS({ SecretId, SecretKey }) } - static async delete (configMap: IConfigMap): Promise { - const { fileName, config: { secretId, secretKey, bucket, area, path } } = configMap + static async delete(configMap: IConfigMap): Promise { + const { + fileName, + config: { secretId, secretKey, bucket, area, path } + } = configMap try { const cos = TcyunApi.#createCOS(secretId, secretKey) let key diff --git a/src/renderer/apis/upyun.ts b/src/renderer/apis/upyun.ts index a2283bfc..dcc92ad7 100644 --- a/src/renderer/apis/upyun.ts +++ b/src/renderer/apis/upyun.ts @@ -8,8 +8,11 @@ interface IConfigMap { } export default class UpyunApi { - static async delete (configMap: IConfigMap): Promise { - const { fileName, config: { bucket, operator, password, path } } = configMap + static async delete(configMap: IConfigMap): Promise { + const { + fileName, + config: { bucket, operator, password, path } + } = configMap try { const service = new Upyun.Service(bucket, operator, password) const client = new Upyun.Client(service) diff --git a/src/renderer/apis/webdav.ts b/src/renderer/apis/webdav.ts index c7ef4803..a49937d5 100644 --- a/src/renderer/apis/webdav.ts +++ b/src/renderer/apis/webdav.ts @@ -9,8 +9,11 @@ interface IConfigMap { } export default class WebdavApi { - static async delete (configMap: IConfigMap): Promise { - const { fileName, config: { host, username, password, path, sslEnabled, authType } } = configMap + static async delete(configMap: IConfigMap): Promise { + const { + fileName, + config: { host, username, password, path, sslEnabled, authType } + } = configMap const endpoint = formatEndpoint(host, sslEnabled) const options: WebDAVClientOptions = { username, @@ -19,10 +22,7 @@ export default class WebdavApi { if (authType === 'digest') { options.authType = AuthType.Digest } - const ctx = createClient( - endpoint, - options - ) + const ctx = createClient(endpoint, options) let key if (path === '/' || !path) { key = fileName diff --git a/src/renderer/components/ConfigForm.vue b/src/renderer/components/ConfigForm.vue index 326fc042..c3b1eb84 100644 --- a/src/renderer/components/ConfigForm.vue +++ b/src/renderer/components/ConfigForm.vue @@ -1,25 +1,8 @@