Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(updateChecker):optimize automatic updates and add a progress bar #1314

Merged
merged 1 commit into from
Jun 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import { app, protocol, BrowserWindow, ipcMain, shell, Menu } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
import { quitAndRenameLogger } from './utils/logger'
import updateChecker, { createUpdateWindow } from './main/updateChecker'
import { createUpdateWindow, autoDownload } from './main/updateDownloader'
import { getCurrentLang } from './main/updateChecker'
import getMenuTemplate from './main/getMenuTemplate'
import saveFile from './main/saveFile'
import saveExcel from './main/saveExcel'
import newWindow from './main/newWindow'
import { onSystemThemeChanged } from './main/systemTheme'
import useConnection, { initOptionModel } from '@/database/useConnection'
import useServices from '@/database/useServices'
import { dialog } from 'electron'

declare const __static: string

Expand Down Expand Up @@ -49,8 +51,8 @@ function handleIpcMessages() {
Menu.setApplicationMenu(menu)
}
})
ipcMain.on('checkUpdate', () => {
updateChecker(false)
ipcMain.on('clickUpdate', (event: Electron.IpcMainEvent) => {
event.sender.send('clickUpdate')
})
ipcMain.on('exportData', (event: Electron.IpcMainEvent, ...args: any[]) => {
const [filename, content, type] = args
Expand All @@ -73,6 +75,20 @@ function handleIpcMessages() {
event.sender.send('getWindowSize', win.getBounds())
}
})
ipcMain.on('startDownloadProgress', (event, updateDetail) => {
getCurrentLang().then((lang) => {
electronStore.set('isShow', false)
autoDownload(event, updateDetail, lang)
})
})
ipcMain.on('showMsg', (event) => {
dialog.showMessageBox({
type: 'info',
title: '',
buttons: ['OK'],
message: 'There are currently no updates available.',
})
})
}

// handle event when APP quit
Expand Down Expand Up @@ -154,10 +170,6 @@ async function createWindow() {
beforeAppQuit()
})
handleIpcMessages()
if (autoCheckUpdate) {
updateChecker()
}
// updateWindow
electronStore.get('isShow') && createUpdateWindow()
}

Expand Down
2 changes: 1 addition & 1 deletion src/lang/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import huLocale from 'element-ui/lib/locale/lang/hu'
import { formati18n } from '@/utils/i18n'

const supportLang: SupportLangModel = ['zh', 'en', 'ja', 'tr', 'hu']
const i18nModules: i18nLocaleModel = ['connections', 'settings', 'common', 'about', 'script', 'log', 'help']
const i18nModules: i18nLocaleModel = ['connections', 'settings', 'common', 'about', 'script', 'log', 'help', 'update']

const { en, zh, ja, tr, hu }: VueI18n.LocaleMessages = formati18n(i18nModules, supportLang)

Expand Down
65 changes: 65 additions & 0 deletions src/lang/update.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
export default {
updateTitle: {
zh: '有可用更新',
en: 'Update Available',
ja: '利用可能な更新',
tr: 'Güncelleme Mevcut',
hu: 'Frissítés elérhető',
},
ignoreVersion: {
zh: '忽略',
en: 'Dismiss',
ja: '却下',
tr: 'Reddet',
hu: 'Elutasít',
},
nextRemind: {
zh: '稍后提醒',
en: 'Remind me Later',
ja: '後でリマインドしてください',
tr: 'Bana daha sonra hatırlat',
hu: 'Emlékeztessen később',
},
update: {
zh: '更新',
en: 'Update',
ja: '更新',
tr: 'Güncelle',
hu: 'Frissítés',
},
downloadProgress: {
zh: '下载进度',
en: 'Download Progress',
ja: 'ダウンロード進行状況',
tr: 'İndirme İlerlemesi',
hu: 'Letöltési Előrehaladás',
},
downloading: {
zh: '下载更新中...',
en: 'Downloading Update...',
ja: '更新をダウンロード中...',
tr: 'Güncelleme indiriliyor...',
hu: 'Frissítés letöltése...',
},
downloaded: {
zh: '安装并重启',
en: 'Restart and Install Update',
ja: '再起動してアップデートをインストール',
tr: 'Yeniden Başlat ve Güncellemeyi Yükle',
hu: 'Újraindítás és Frissítés Telepítése',
},
cancel: {
zh: '取消更新',
en: 'Cancel Update',
ja: '更新をキャンセル',
tr: 'Güncellemeyi iptal et',
hu: 'Frissítés megszakítása',
},
install: {
zh: '安装并重启',
en: 'Install and Relunch',
ja: 'インストールして再起動',
tr: 'Kur ve Tekrar Başlat',
hu: 'Telepítés és újraindítás',
},
}
3 changes: 1 addition & 2 deletions src/main/getMenuTemplate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { app, shell, BrowserWindow } from 'electron'
import updateChecker from './updateChecker'
import translations from '../lang/menu'

const isMac = process.platform === 'darwin'
Expand Down Expand Up @@ -35,7 +34,7 @@ const getMenuTemplate = (win: BrowserWindow, lang?: Language): $TSFixed => {
{
label: labels.checkForUpdate,
click: () => {
updateChecker(false)
win.webContents.send('clickUpdate')
},
},
{ type: 'separator' },
Expand Down
121 changes: 33 additions & 88 deletions src/main/updateChecker.ts
Original file line number Diff line number Diff line change
@@ -1,109 +1,54 @@
import { dialog, BrowserWindow } from 'electron'
import axios from 'axios'
import version from '@/version'
import useServices from '@/database/useServices'

const { autoUpdater } = require('electron-updater')
const Store = require('electron-store')
const electronStore = new Store()

const release = 'https://api.github.com/repos/emqx/MQTTX/releases/latest'
let language: string = 'en'

const isUpdate = (latest: string, current: string): boolean => {
const latestVersion: number[] = latest.split('.').map((item) => parseInt(item, 10))
const currentVersion: number[] = current.split('.').map((item) => parseInt(item, 10))
let update: boolean = false

for (let i: number = 0; i < 3; i++) {
if (currentVersion[i] < latestVersion[i]) {
update = true
}
}

return update
export interface versionDetail {
version: string
detail: string
}

const autoDownload = (latest: string, language: string): void => {
const urlLang = language === 'zh' ? 'zh' : 'en'
const downloadUrl = `https://www.emqx.com/${urlLang}/downloads/MQTTX/${latest}`
autoUpdater.setFeedURL(downloadUrl)
autoUpdater.checkForUpdatesAndNotify()
autoUpdater.on('checking-for-update', () => {})
autoUpdater.on('update-available', () => {})
autoUpdater.on('update-not-available', () => {})
autoUpdater.on('error', () => {})
autoUpdater.on('download-progress', () => {})
autoUpdater.on('update-downloaded', () => {
electronStore.set('isShow', true)
dialog
.showMessageBox({
type: 'info',
title: 'New Version',
buttons: ['Install', 'No'],
message: `Update available: ${latest}`,
})
.then((res) => {
if (res.response === 0) {
// if selected yes
autoUpdater.quitAndInstall()
} else {
dialog.showMessageBox({
type: 'info',
message: 'Automatic update on do not shut down the computer immediately',
})
}
})
})
}

const updateChecker = async (isAuto: boolean = true): Promise<void | boolean> => {
const response = await axios.get(release)
export const getCurrentLang = async (): Promise<string> => {
let language: string = 'en'
const { settingService } = useServices()
await settingService.set()
const setting = await settingService.get()
if (setting) {
language = setting.currentLang
}
if (response.status === 200) {
const latest: string = response.data.name
const isPrerelease: boolean = response.data.prerelease
if (latest && isUpdate(latest.slice(1, 6), version) && !isPrerelease) {
autoDownload(latest, language)
} else {
if (!isAuto) {
dialog.showMessageBox({
type: 'info',
title: '',
buttons: ['OK'],
message: 'There are currently no updates available.',
})
return language === 'zh' ? 'zh' : 'en'
}

const getUpdateDtail = async (current: string): Promise<versionDetail | null> => {
const tagsUrl = 'https://api.github.com/repos/emqx/MQTTX/tags'
const tagsRes = await axios.get(tagsUrl)
if (tagsRes.status === 200) {
const tagsList: string[] = tagsRes.data.map((item: any) => item.name)
const latestTagsList: string[] = tagsList.slice(0, tagsList.indexOf(current))
while (latestTagsList.length > 0) {
const latestVersion = latestTagsList.shift()
const versionRes = await axios.get(
`https://community-sites.emqx.com/api/v1/changelogs?product=MQTTX&version=${latestVersion}`,
)
if (latestVersion && versionRes.status === 200) {
return {
version: latestVersion,
detail: versionRes.data.data.changelog,
}
}
}
} else {
return false
}
return null
}
//what's new window
export async function createUpdateWindow() {
const updateWindow = new BrowserWindow({
width: 600,
height: 500,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true,
},
})
const { settingService } = useServices()
await settingService.set()
const setting = await settingService.get()
if (setting) {
language = setting.currentLang

export const updateChecker = async (isAuto: boolean = true): Promise<void | versionDetail | boolean> => {
const currentVersion = `v${version}`
const updateDetail: versionDetail | null = await getUpdateDtail(currentVersion)
const language: string = await getCurrentLang()
if (updateDetail && (!isAuto || electronStore.get('isIgnore') !== updateDetail.version)) {
return updateDetail
}
let link: string = 'https://mqttx.app'
link = language === 'zh' ? `${link}/zh` : link
updateWindow.loadURL(`${link}/changelogs/v${version}`)
electronStore.set('isShow', false)
return false
}
export default updateChecker
54 changes: 54 additions & 0 deletions src/main/updateDownloader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { BrowserWindow, IpcMainEvent, ipcMain } from 'electron'
import version from '@/version'
import { getCurrentLang, versionDetail } from './updateChecker'

const { autoUpdater } = require('electron-updater')
const Store = require('electron-store')
const electronStore = new Store()

export const autoDownload = (event: IpcMainEvent, updateDetail: versionDetail, language: string) => {
const downloadUrl = `https://www.emqx.com/${language}/downloads/MQTTX/${updateDetail.version}`
autoUpdater.setFeedURL(downloadUrl)
autoUpdater.autoDownload = false
autoUpdater.autoInstallOnAppQuit = false
autoUpdater.checkForUpdatesAndNotify()
autoUpdater.on('update-available', () => {
autoUpdater.downloadUpdate()
})
autoUpdater.on('error', (e: any) => {
console.log(e)
})
autoUpdater.on('download-progress', (progressObj: any) => {
event.sender.send('downloadProgressPercent', progressObj.percent)
})
autoUpdater.on('update-downloaded', () => {
event.sender.send('downloadProgressPercent', 100)
})
ipcMain.on('toQuitAndInstall', () => {
electronStore.set('isShow', true)
autoUpdater.quitAndInstall()
})
ipcMain.on('cancelDownload', () => {
autoUpdater.removeAllListeners()
autoUpdater.autoDownload = false
autoUpdater.autoInstallOnAppQuit = false
autoUpdater.autoCheckForUpdates = false
})
}

export async function createUpdateWindow() {
const updateWindow = new BrowserWindow({
width: 600,
height: 500,
Comment on lines +41 to +42
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this an update window size?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true,
},
})
const language: string = await getCurrentLang()
let link: string = 'https://mqttx.app'
link = language === 'zh' ? `${link}/zh` : link
updateWindow.loadURL(`${link}/changelogs/v${version}`)
electronStore.set('isShow', false)
}
2 changes: 1 addition & 1 deletion src/types/locale.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ declare module 'element-ui/lib/locale/lang/ja' {}
declare module 'element-ui/lib/locale/lang/tr-TR' {}
declare module 'element-ui/lib/locale/lang/hu' {}

type i18nLocaleModel = ['connections', 'settings', 'common', 'about', 'script', 'log', 'help']
type i18nLocaleModel = ['connections', 'settings', 'common', 'about', 'script', 'log', 'help', 'update']
type SupportLangModel = ['zh', 'en', 'ja', 'tr', 'hu']

declare module '*.json' {
Expand Down
4 changes: 2 additions & 2 deletions src/utils/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import {
Row,
Col,
// Upload,
// Progress,
Progress,
Badge,
Card,
// Rate,
Expand Down Expand Up @@ -124,7 +124,7 @@ export default (Vue: typeof _Vue) => {
Vue.use(Row)
Vue.use(Col)
// Vue.use(Upload)
// Vue.use(Progress)
Vue.use(Progress)
Vue.use(Badge)
Vue.use(Card)
// Vue.use(Rate)
Expand Down
1 change: 1 addition & 0 deletions src/utils/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const formati18n = (transItems: i18nLocaleModel, langs: SupportLangModel)
script: {},
log: {},
help: {},
update: {},
}
})
transItems.forEach((item) => {
Expand Down
Loading