feature: 1)检查更新功能,使用 github api 来获取版本数据;2)自动检查更新功能,可配置化。 (#303)

pull/311/head
王良 2024-04-23 17:10:37 +08:00 committed by GitHub
parent 178ac3c12b
commit 084e3dd886
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 215 additions and 58 deletions

View File

@ -24,6 +24,8 @@ module.exports = {
url: 'https://gitee.com/wangliang181230/dev-sidecar/raw/docmirror/packages/core/src/config/remote_config.json5'
},
theme: 'light', // 主题light=亮色, dark=暗色
autoChecked: true, // 是否自动检查更新
skipPreRelease: true, // 是否忽略预发布版本
dock: {
hideWhenWinClose: false
},

View File

@ -7,6 +7,9 @@ import fs from 'fs'
import AdmZip from 'adm-zip'
import log from '../../utils/util.log'
import appPathUtil from '../../utils/util.apppath'
import pkg from '../../../package.json'
import DevSidecar from '@docmirror/dev-sidecar'
// eslint-disable-next-line no-unused-vars
const isMac = process.platform === 'darwin'
const isLinux = process.platform === 'linux'
@ -72,6 +75,104 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
let partPackagePath = null
// 检查更新
const releasesApiUrl = 'https://api.github.com/repos/docmirror/dev-sidecar/releases'
async function checkForUpdatesFromGitHub () {
request(releasesApiUrl, { headers: { 'User-Agent': 'DS/' + pkg.version } }, (error, response, body) => {
try {
if (error) {
log.error('检查更新失败:', error)
const errorMsg = '检查更新失败:' + error
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: errorMsg })
return
}
if (response && response.statusCode === 200) {
if (body == null || body.length < 2) {
log.warn('检查更新失败github API返回数据为空:', body)
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: '检查更新失败github 返回数据为空' })
return
}
// 尝试解析API响应内容
let data
try {
data = JSON.parse(body)
} catch (e) {
log.error('检查更新失败github API返回数据格式不正确:', body)
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: '检查更新失败github API返回数据格式不正确' })
return
}
if (typeof data !== 'object' || data.length === undefined) {
log.error('检查更新失败github API返回数据不是数组:', body)
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: '检查更新失败github API返回数据不是数组' })
return
}
// log.info('github api返回的release数据', JSON.stringify(data, null, '\t'))
// 检查更新
for (let i = 0; i < data.length; i++) {
const versionData = data[i]
if (!versionData.assets || versionData.assets.length === 0) {
continue // 跳过空版本,即上传过安装包
}
if (DevSidecar.api.config.get().app.skipPreRelease && versionData.name.indexOf('Pre-release') >= 0) {
continue // 跳过预发布版本
}
// log.info('最近正式版本数据:', versionData)
let version = versionData.tag_name
if (version.indexOf('v') === 0) {
version = version.substring(1)
}
if (version !== pkg.version) {
log.info('检查更新-发现新版本:', version)
win.webContents.send('update', {
key: 'available',
value: {
version,
releaseNotes: '发布公告:' + (versionData.html_url || ('https://github.com/docmirror/dev-sidecar/releases/tag/' + versionData.tag_name))
}
})
} else {
log.info('检查更新-没有新版本,最新版本号为:', version)
win.webContents.send('update', { key: 'notAvailable' })
}
return // 只检查最近一个正式版本
}
log.info('检查更新-没有正式版本数据')
win.webContents.send('update', { key: 'notAvailable' })
} else {
log.error('检查更新失败, status:', response.statusCode, ', body:', body)
let bodyObj
try {
bodyObj = JSON.parse(body)
} catch (e) {
bodyObj = null
}
let message
if (response) {
message = '检查更新失败: ' + (bodyObj && bodyObj.message ? bodyObj.message : response.message) + ', code: ' + response.statusCode
} else {
message = '检查更新失败: ' + (bodyObj && bodyObj.message ? bodyObj.message : body)
}
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: message })
}
} catch (e) {
log.error('检查更新失败:', e)
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: '检查更新失败:' + e.message })
}
})
}
// 下载升级包
function downloadPart (app, value) {
const appPath = appPathUtil.getAppRootPath(app)
const fileDir = path.join(appPath, 'update')
@ -171,8 +272,11 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
})
} else if (arg.key === 'checkForUpdate') {
// 执行自动更新检查
log.info('autoUpdater checkForUpdates')
autoUpdater.checkForUpdates()
log.info('autoUpdater checkForUpdates:', arg.fromUser)
// 调用 github API获取release数据来检查更新
// autoUpdater.checkForUpdates()
checkForUpdatesFromGitHub()
} else if (arg.key === 'downloadUpdate') {
// 下载新版本
log.info('autoUpdater downloadUpdate')

View File

@ -1,5 +1,5 @@
function install (app, api) {
const updateParams = app.$global.update = { fromUser: false, autoDownload: false, progress: 0, downloading: false, newVersion: false, isFullUpdate: true }
const updateParams = app.$global.update = { fromUser: false, autoDownload: false, progress: 0, checking: false, downloading: false, newVersion: false, isFullUpdate: true }
api.ipc.on('update', (event, message) => {
console.log('on message', event, message)
handleUpdateMessage(message, app)
@ -10,6 +10,7 @@ function install (app, api) {
if (fromUser != null) {
updateParams.fromUser = fromUser
}
updateParams.checking = true
api.ipc.send('update', { key: 'checkForUpdate', fromUser })
},
downloadUpdate () {
@ -27,8 +28,11 @@ function install (app, api) {
function handleUpdateMessage (message) {
const type = message.key
if (type === 'available') {
updateParams.checking = false
updateParams.newVersionData = message.value
foundNewVersion(message.value)
} else if (type === 'notAvailable') {
updateParams.checking = false
noNewVersion()
} else if (type === 'downloaded') {
// 更新包已下载完成,让用户确认是否更新
@ -38,9 +42,15 @@ function install (app, api) {
} else if (type === 'progress') {
progressUpdate(message.value)
} else if (type === 'error') {
updateParams.checking = false
updateParams.downloading = false
const error = message.error
app.$message.error((error == null ? '未知错误' : (error.stack || error).toString()))
if (message.action === 'checkForUpdate' && updateParams.newVersionData) {
// 如果检查更新报错了,但刚才成功拿到过一次数据,就拿之前的数据
foundNewVersion(updateParams.newVersionData)
} else {
const error = message.error
app.$message.error((error == null ? '未知错误' : (error.stack || error).toString()))
}
}
}
@ -55,55 +65,67 @@ function install (app, api) {
updateParams.progress = value
}
function openGithubUrl () {
api.ipc.openExternal('https://github.com/docmirror/dev-sidecar/releases')
}
function goManualUpdate (value) {
updateParams.newVersion = false
app.$confirm({
title: '暂不支持自动升级',
// title: '暂不支持自动升级',
title: '暂不提供自动升级',
cancelText: '取消',
okText: '确定',
okText: '打开链接',
width: 420,
content: h => {
function openGithubUrl () {
api.ipc.openExternal('https://github.com/docmirror/dev-sidecar/releases')
}
return <div>请前往 <a onClick={openGithubUrl}>github项目release页面</a> </div>
return <div>
<div>请前往 <a onClick={openGithubUrl}>github项目release页面</a> </div>
<div><a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div>
</div>
},
onOk () {
openGithubUrl()
}
})
}
/**
* 是否小版本升级
* @param value
*/
async function isSupportPartUpdate (value) {
const info = await api.info.get()
console.log('升级版本:', value.version)
console.log('增量更新最小版本:', value.partMiniVersion)
console.log('当前版本:', info.version)
if (!value.partPackage) {
return false
}
return !!(value.partMiniVersion && value.partMiniVersion < info.version)
}
// /**
// * 是否小版本升级
// * @param value
// */
// async function isSupportPartUpdate (value) {
// const info = await api.info.get()
// console.log('升级版本:', value.version)
// console.log('增量更新最小版本:', value.partMiniVersion)
// console.log('当前版本:', info.version)
// if (!value.partPackage) {
// return false
// }
// return !!(value.partMiniVersion && value.partMiniVersion < info.version)
// }
async function downloadNewVersion (value) {
const platform = await api.shell.getSystemPlatform()
console.log(`download new version: ${JSON.stringify(value)}, platform: ${platform}`)
if (platform === 'linux') {
goManualUpdate(value)
return
}
const partUpdate = await isSupportPartUpdate(value)
if (partUpdate) {
// 有增量更新
api.update.downloadPart(value)
} else {
if (platform === 'mac') {
goManualUpdate(value)
return
}
updateParams.downloading = true
api.update.downloadUpdate()
}
// 暂时取消自动更新功能
goManualUpdate(value)
// const platform = await api.shell.getSystemPlatform()
// console.log(`download new version: ${JSON.stringify(value)}, platform: ${platform}`)
// if (platform === 'linux') {
// goManualUpdate(value)
// return
// }
// const partUpdate = await isSupportPartUpdate(value)
// if (partUpdate) {
// // 有增量更新
// api.update.downloadPart(value)
// } else {
// if (platform === 'mac') {
// goManualUpdate(value)
// return
// }
// updateParams.downloading = true
// api.update.downloadUpdate()
// }
}
function foundNewVersion (value) {
updateParams.newVersion = true
@ -116,13 +138,14 @@ function install (app, api) {
}
console.log(value)
app.$confirm({
title: '发现新版本:' + value.version,
title: '发现新版本:v' + value.version,
cancelText: '暂不升级',
okText: '升级',
width: 710,
content: h => {
if (value.releaseNotes) {
if (typeof value.releaseNotes === 'string') {
return <div><div>更新内容</div><div>{value.releaseNotes}</div></div>
return <div>{value.releaseNotes}</div>
} else {
const notes = []
for (const note of value.releaseNotes) {
@ -144,24 +167,26 @@ function install (app, api) {
function newUpdateIsReady (value) {
updateParams.downloading = false
console.log(value)
app.$confirm({
title: `新版本(v${value.version})已准备好,是否立即升级?`,
title: `新版本(v${value.version})已准备好是否立即升级?`,
cancelText: '暂不升级',
okText: '立即升级',
content: h => {
console.log(value)
if (value.releaseNotes) {
const notes = []
for (const note of value.releaseNotes) {
notes.push(<li>{note}</li>)
if (typeof value.releaseNotes === 'string') {
return <div>{value.releaseNotes}</div>
} else {
const notes = []
for (const note of value.releaseNotes) {
notes.push(<li>{note}</li>)
}
return <div><div>更新内容</div><ol>{notes}</ol></div>
}
return <div><div>更新内容</div><ol>{notes}</ol></div>
}
},
onOk () {
api.update.doUpdateNow()
},
onCancel () {
}
})
}

View File

@ -7,10 +7,10 @@
<a-badge :count="_rootCaSetuped?0:1" dot>安装根证书</a-badge>
</a-button>
<a-button style="margin-right:10px" @click="doCheckUpdate(true)" :loading="update.downloading"
<a-button style="margin-right:10px" @click="doCheckUpdate(true)" :loading="update.downloading || update.checking"
:title="'当前版本:'+info.version">
<a-badge :count="update.newVersion?1:0" dot>
<span v-if="update.downloading">{{ update.progress }}%</span>{{ update.downloading ? '' : '' }}
<span v-if="update.downloading">{{ update.progress }}%</span>{{ update.downloading ? '' : ('' + (update.checking ? '' : '')) }}
</a-badge>
</a-button>
</span>
@ -161,7 +161,7 @@ export default {
setupCa: {
visible: false
},
update: { downloading: false, progress: 0, newVersion: false }
update: { checking: false, downloading: false, progress: 0, newVersion: false }
}
},
async created () {
@ -170,8 +170,8 @@ export default {
this.$set(this, 'status', this.$status)
this.switchBtns = this.createSwitchBtns()
this.$set(this, 'update', this.$global.update)
if (!this.update.autoChecked) {
this.update.autoChecked = true
if (!this.update.autoChecked && this.config.app.autoChecked) {
this.update.autoChecked = true //
this.doCheckUpdate(false)
}
this.$api.info.get().then(ret => {

View File

@ -52,6 +52,32 @@
</a-radio-button>
</a-radio-group>
</a-form-item>
<a-form-item label="自动检查更新" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-radio-group v-model="config.app.autoChecked" default-value="light" button-style="solid">
<a-radio-button :value="true">
开启
</a-radio-button>
<a-radio-button :value="false">
关闭
</a-radio-button>
</a-radio-group>
<div class="form-help">
开启自动检查更新后每次应用启动时会检查一次更新如有新版本则会弹出提示
</div>
</a-form-item>
<a-form-item v-if="config.app.autoChecked" label="忽略预发布版本" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-radio-group v-model="config.app.skipPreRelease" default-value="light" button-style="solid">
<a-radio-button :value="true">
忽略
</a-radio-button>
<a-radio-button :value="false">
不忽略
</a-radio-button>
<div class="form-help">
预发布版本为版本号带有 Pre-release 的版本
</div>
</a-radio-group>
</a-form-item>
<a-form-item label="首页提示" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-radio-group v-model="config.app.showShutdownTip"
default-value="true" button-style="solid">