Skip to content

Commit

Permalink
✨ Feature: add dist upload to cos & update checkupdate logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Molunerfinn committed Aug 14, 2022
1 parent dc85123 commit c926414
Show file tree
Hide file tree
Showing 15 changed files with 252 additions and 50 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Expand Up @@ -51,5 +51,8 @@ jobs:
- name: Build & release app
run: |
yarn release
yarn upload-dist
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
PICGO_ENV_COS_SECRET_ID: ${{ secrets.PICGO_ENV_COS_SECRET_ID }}
PICGO_ENV_COS_SECRET_KEY: ${{ secrets.PICGO_ENV_COS_SECRET_KEY }}
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -18,3 +18,4 @@ docs/dist/
dist_electron/
test.js
.env
scripts/*.yml
1 change: 1 addition & 0 deletions appveyor.yml
Expand Up @@ -27,5 +27,6 @@ install:
build_script:
#- yarn test
- yarn release
- yarn upload-dist

test: false
7 changes: 6 additions & 1 deletion package.json
Expand Up @@ -13,7 +13,8 @@
"postuninstall": "electron-builder install-app-deps",
"cz": "git-cz",
"bump": "bump-version",
"release": "vue-cli-service electron:build --publish always"
"release": "vue-cli-service electron:build --publish always",
"upload-dist": "node ./scripts/upload-dist-to-cos.js"
},
"main": "background.js",
"husky": {
Expand All @@ -38,9 +39,11 @@
"@picgo/i18n": "^1.0.0",
"@picgo/store": "2.0.1",
"axios": "^0.19.0",
"compare-versions": "^4.1.3",
"core-js": "^3.3.2",
"element-ui": "^2.13.0",
"fs-extra": "^10.0.0",
"js-yaml": "^4.1.0",
"keycode": "^2.2.0",
"lodash-id": "^0.14.0",
"lowdb": "^1.0.0",
Expand All @@ -59,6 +62,7 @@
"@picgo/bump-version": "^1.1.2",
"@types/fs-extra": "^9.0.13",
"@types/inquirer": "^6.5.0",
"@types/js-yaml": "^4.0.5",
"@types/lowdb": "^1.0.9",
"@types/node": "^16.10.2",
"@types/request-promise-native": "^1.0.17",
Expand All @@ -75,6 +79,7 @@
"@vue/eslint-config-typescript": "^7.0.0",
"conventional-changelog": "^3.1.18",
"cz-customizable": "^6.2.0",
"dotenv": "^16.0.1",
"electron": "^16.0.6",
"electron-devtools-installer": "^3.2.0",
"eslint": "^7.32.0",
Expand Down
50 changes: 50 additions & 0 deletions scripts/config.js
@@ -0,0 +1,50 @@
// different platform has different format

// macos
const darwin = [{
appNameWithPrefix: 'PicGo-',
ext: '.dmg',
arch: '-arm64',
'version-file': 'latest-mac.yml'
}, {
appNameWithPrefix: 'PicGo-',
ext: '.dmg',
arch: '-x64',
'version-file': 'latest-mac.yml'
}]

const linux = [{
appNameWithPrefix: 'PicGo-',
ext: '.AppImage',
arch: '',
'version-file': 'latest-linux.yml'
}, {
appNameWithPrefix: 'picgo_',
ext: '.snap',
arch: '_amd64',
'version-file': 'latest-linux.yml'
}]

// windows
const win32 = [{
appNameWithPrefix: 'PicGo-Setup-',
ext: '.exe',
arch: '-ia32',
'version-file': 'latest.yml'
}, {
appNameWithPrefix: 'PicGo-Setup-',
ext: '.exe',
arch: '-x64',
'version-file': 'latest.yml'
}, {
appNameWithPrefix: 'PicGo-Setup-',
ext: '.exe',
arch: '', // 32 & 64
'version-file': 'latest.yml'
}]

module.exports = {
darwin,
linux,
win32
}
103 changes: 103 additions & 0 deletions scripts/upload-dist-to-cos.js
@@ -0,0 +1,103 @@
// upload dist bundled-app to cos
require('dotenv').config()
const crypto = require('crypto')
const fs = require('fs')
const mime = require('mime-types')
const pkg = require('../package.json')
const configList = require('./config')
const axios = require('axios').default
const path = require('path')
const distPath = path.join(__dirname, '../dist_electron')

const BUCKET = 'picgo-1251750343'
const AREA = 'ap-chengdu'
const VERSION = pkg.version
const FILE_PATH = `${VERSION}/`
const SECRET_ID = process.env.PICGO_ENV_COS_SECRET_ID
const SECRET_KEY = process.env.PICGO_ENV_COS_SECRET_KEY

// https://cloud.tencent.com/document/product/436/7778#signature
/**
* @param {string} fileName
* @returns
*/
const generateSignature = (fileName, folder = FILE_PATH) => {
const secretKey = SECRET_KEY
const area = AREA
const bucket = BUCKET
const path = folder
const today = Math.floor(new Date().getTime() / 1000)
const tomorrow = today + 86400
const signTime = `${today};${tomorrow}`
const signKey = crypto.createHmac('sha1', secretKey).update(signTime).digest('hex')
const httpString = `put\n/${path}${fileName}\n\nhost=${bucket}.cos.${area}.myqcloud.com\n`
const sha1edHttpString = crypto.createHash('sha1').update(httpString).digest('hex')
const stringToSign = `sha1\n${signTime}\n${sha1edHttpString}\n`
const signature = crypto.createHmac('sha1', signKey).update(stringToSign).digest('hex')
return {
signature,
signTime
}
}

/**
*
* @param {string} fileName
* @param {Buffer} fileBuffer
* @param {{ signature: string, signTime: string }} signature
* @returns
*/
const getReqOptions = (fileName, fileBuffer, signature, folder = FILE_PATH) => {
return {
method: 'PUT',
url: `http://${BUCKET}.cos.${AREA}.myqcloud.com/${encodeURI(folder)}${encodeURI(fileName)}`,
headers: {
Host: `${BUCKET}.cos.${AREA}.myqcloud.com`,
Authorization: `q-sign-algorithm=sha1&q-ak=${SECRET_ID}&q-sign-time=${signature.signTime}&q-key-time=${signature.signTime}&q-header-list=host&q-url-param-list=&q-signature=${signature.signature}`,
contentType: mime.lookup(fileName),
useAgent: `PicGo;${pkg.version};null;null`
},
maxContentLength: Infinity,
maxBodyLength: Infinity,
data: fileBuffer,
resolveWithFullResponse: true
}
}

const uploadFile = async () => {
try {
const platform = process.platform
if (configList[platform]) {
let versionFileHasUploaded = false
for (const [index, config] of configList[platform].entries()) {
const fileName = `${config.appNameWithPrefix}${VERSION}${config.arch}${config.ext}`
const filePath = path.join(distPath, fileName)
const versionFilePath = path.join(distPath, config['version-file'])
let versionFileName = config['version-file']
if (VERSION.toLocaleLowerCase().includes('beta')) {
versionFileName = versionFileName.replace('.yml', '.beta.yml')
}
// upload dist file
const signature = generateSignature(fileName)
const reqOptions = getReqOptions(fileName, fs.readFileSync(filePath), signature)
console.log('[PicGo Dist] Uploading...', fileName, `${index + 1}/${configList[platform].length}`)
await axios.request(reqOptions)

// upload version file
if (!versionFileHasUploaded) {
const signature = generateSignature(versionFileName, '')
const reqOptions = getReqOptions(versionFileName, fs.readFileSync(versionFilePath), signature, '')
console.log('[PicGo Version File] Uploading...', versionFileName)
await axios.request(reqOptions)
versionFileHasUploaded = true
}
}
} else {
console.warn('platform not supported!', platform)
}
} catch (e) {
console.error(e)
}
}

uploadFile()
10 changes: 9 additions & 1 deletion src/main/events/picgoCoreIPC.ts
Expand Up @@ -26,7 +26,8 @@ import {
PICGO_REMOVE_BY_ID_DB,
PICGO_OPEN_FILE,
PASTE_TEXT,
OPEN_WINDOW
OPEN_WINDOW,
DEFAULT_LOGO
} from '#/events/constants'

import { GalleryDB } from 'apis/core/datastore'
Expand Down Expand Up @@ -366,6 +367,12 @@ const handleOpenWindow = () => {
})
}

const handleDefaultLogo = () => {
ipcMain.on(DEFAULT_LOGO, (event: IpcMainEvent) => {
event.sender.send(DEFAULT_LOGO, path.join(__static, 'roundLogo.png'))
})
}

export default {
listen () {
handleGetPluginList()
Expand All @@ -379,6 +386,7 @@ export default {
handleImportLocalPlugin()
handleOpenFile()
handleOpenWindow()
handleDefaultLogo()
},
// TODO: separate to single file
handlePluginUninstall,
Expand Down
21 changes: 7 additions & 14 deletions src/main/utils/updateChecker.ts
@@ -1,12 +1,12 @@
import { dialog, shell } from 'electron'
import db from '~/main/apis/core/datastore'
import axios from 'axios'
import pkg from 'root/package.json'
import { lt } from 'semver'
import { T } from '~/universal/i18n'
import { getLatestVersion } from '#/utils/getLatestVersion'
const version = pkg.version
const releaseUrl = 'https://api.github.com/repos/Molunerfinn/PicGo/releases/latest'
const releaseUrlBackup = 'https://cdn.jsdelivr.net/gh/Molunerfinn/PicGo@latest/package.json'
// const releaseUrl = 'https://api.github.com/repos/Molunerfinn/PicGo/releases'
// const releaseUrlBackup = 'https://picgo-1251750343.cos.ap-chengdu.myqcloud.com'
const downloadUrl = 'https://github.com/Molunerfinn/PicGo/releases/latest'

const checkVersion = async () => {
Expand All @@ -16,17 +16,10 @@ const checkVersion = async () => {
showTip = true
}
if (showTip) {
let res: any
try {
res = await axios.get(releaseUrl).catch(async () => {
const result = await axios.get(releaseUrlBackup)
return result
})
} catch (err) {
console.log(err)
}
if (res.status === 200) {
const latest = res.data.version || res.data.name
const isCheckBetaUpdate = db.get('settings.checkBetaUpdate') !== false
const res: string = await getLatestVersion(isCheckBetaUpdate)
if (res !== '') {
const latest = res
const result = compareVersion2Update(version, latest)
if (result) {
dialog.showMessageBox({
Expand Down
43 changes: 13 additions & 30 deletions src/renderer/pages/PicGoSetting.vue
Expand Up @@ -393,10 +393,9 @@ import {
import { Component, Vue } from 'vue-property-decorator'
import { T, languageList } from '~/universal/i18n'
import { enforceNumber } from '~/universal/utils/common'
// import db from '#/datastore'
const releaseUrl = 'https://api.github.com/repos/Molunerfinn/PicGo/releases/latest'
const releaseUrlBackup = 'https://cdn.jsdelivr.net/gh/Molunerfinn/PicGo@latest/package.json'
const downloadUrl = 'https://github.com/Molunerfinn/PicGo/releases/latest'
import { getLatestVersion } from '#/utils/getLatestVersion'
import { compare } from 'compare-versions'
import { STABLE_RELEASE_URL, BETA_RELEASE_URL } from '#/utils/static'
const customLinkRule = (rule: string, value: string, callback: (arg0?: Error) => void) => {
if (!/\$url/.test(value)) {
return callback(new Error(T('TIPS_MUST_CONTAINS_URL')))
Expand Down Expand Up @@ -635,39 +634,23 @@ export default class extends Vue {
})
}
compareVersion2Update (current: string, latest: string) {
const currentVersion = current.split('.').map(item => parseInt(item))
const latestVersion = latest.split('.').map(item => parseInt(item))
for (let i = 0; i < 3; i++) {
if (currentVersion[i] < latestVersion[i]) {
return true
}
if (currentVersion[i] > latestVersion[i]) {
return false
}
}
return false
compareVersion2Update (current: string, latest: string): boolean {
return compare(current, latest, '<')
}
checkUpdate () {
async checkUpdate () {
this.checkUpdateVisible = true
this.$http.get(releaseUrl)
.then(res => {
this.latestVersion = res.data.name
}).catch(async () => {
this.$http.get(releaseUrlBackup)
.then(res => {
this.latestVersion = res.data.version
}).catch(() => {
this.latestVersion = this.$T('TIPS_NETWORK_ERROR')
})
})
const version = await getLatestVersion(this.form.checkBetaUpdate)
if (version) {
this.latestVersion = version
} else {
this.latestVersion = this.$T('TIPS_NETWORK_ERROR')
}
}
confirmCheckVersion () {
if (this.needUpdate) {
ipcRenderer.send(OPEN_URL, downloadUrl)
ipcRenderer.send(OPEN_URL, this.form.checkBetaUpdate ? BETA_RELEASE_URL : STABLE_RELEASE_URL)
}
this.checkUpdateVisible = false
}
Expand Down
14 changes: 12 additions & 2 deletions src/renderer/pages/Plugin.vue
Expand Up @@ -120,7 +120,8 @@ import {
PICGO_CONFIG_PLUGIN,
PICGO_HANDLE_PLUGIN_ING,
PICGO_TOGGLE_PLUGIN,
SHOW_PLUGIN_PAGE_MENU
SHOW_PLUGIN_PAGE_MENU,
DEFAULT_LOGO
} from '#/events/constants'
@Component({
Expand All @@ -144,7 +145,7 @@ export default class extends Vue {
importLocalPluginToolTip = this.$T('PLUGIN_IMPORT_LOCAL')
id = ''
os = ''
defaultLogo: string = 'this.src="https://cdn.jsdelivr.net/gh/Molunerfinn/PicGo@dev/public/roundLogo.png"'
defaultLogo: string = ''
get npmSearchText () {
return this.searchText.match('picgo-plugin-')
? this.searchText
Expand Down Expand Up @@ -247,11 +248,19 @@ export default class extends Vue {
this.needReload = true
}
})
ipcRenderer.on(DEFAULT_LOGO, (evt: IpcRendererEvent, logoPath) => {
this.defaultLogo = `this.src="${logoPath.replace(/\\/g, '/')}"`
})
this.getPluginList()
this.getSearchResult = debounce(this.getSearchResult, 50)
this.getDefaultLogo()
this.needReload = await this.getConfig<boolean>('needReload') || false
}
getDefaultLogo () {
ipcRenderer.send(DEFAULT_LOGO)
}
async buildContextMenu (plugin: IPicGoPlugin) {
ipcRenderer.send(SHOW_PLUGIN_PAGE_MENU, plugin)
}
Expand Down Expand Up @@ -439,6 +448,7 @@ export default class extends Vue {
ipcRenderer.removeAllListeners('uninstallSuccess')
ipcRenderer.removeAllListeners('updateSuccess')
ipcRenderer.removeAllListeners('hideLoading')
ipcRenderer.removeAllListeners(DEFAULT_LOGO)
}
}
</script>
Expand Down
1 change: 1 addition & 0 deletions src/universal/events/constants.ts
Expand Up @@ -34,3 +34,4 @@ export const SHOW_MAIN_PAGE_DONATION = 'SHOW_MAIN_PAGE_DONATION'
export const FORCE_UPDATE = 'FORCE_UPDATE'
export const CHANGE_LANGUAGE = 'CHANGE_LANGUAGE'
export const OPEN_WINDOW = 'OPEN_WINDOW'
export const DEFAULT_LOGO = 'DEFAULT_LOGO'

0 comments on commit c926414

Please sign in to comment.