Skip to content

Commit

Permalink
ability to upgrade to latest daemon while the app is running
Browse files Browse the repository at this point in the history
  • Loading branch information
alexfreska committed Jan 25, 2024
1 parent a9ea86a commit ed1c1ff
Show file tree
Hide file tree
Showing 18 changed files with 176 additions and 42 deletions.
1 change: 1 addition & 0 deletions hostd/electron-src/download.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export async function downloadRelease(): Promise<void> {

const release = releaseData.data
const asset = release.assets.find((asset) => asset.name === releaseAsset())
console.log(`Downloading ${releaseAsset()}`)

if (asset) {
console.log('Release name:', release.name)
Expand Down
7 changes: 5 additions & 2 deletions hostd/electron-src/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
getIsConfigured,
saveConfig,
} from './config'
import { downloadRelease } from './download'

export function initIpc() {
ipcMain.handle('open-browser', (_, url: string) => {
Expand All @@ -26,8 +27,10 @@ export function initIpc() {
await stopDaemon()
})
ipcMain.handle('daemon-is-running', (_) => {
const isDaemonRunning = getIsDaemonRunning()
return isDaemonRunning
return getIsDaemonRunning()
})
ipcMain.handle('daemon-update', async (_) => {
await downloadRelease()
})
ipcMain.handle('config-get', (_) => {
const config = getConfig()
Expand Down
1 change: 1 addition & 0 deletions hostd/electron-src/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ contextBridge.exposeInMainWorld('electron', {
checkIsDaemonRunning: () => ipcRenderer.invoke('daemon-is-running'),
daemonStart: () => ipcRenderer.invoke('daemon-start'),
daemonStop: () => ipcRenderer.invoke('daemon-stop'),
daemonUpdate: () => ipcRenderer.invoke('daemon-update'),
openBrowser: (url: string) => ipcRenderer.invoke('open-browser', url),
getConfig: () => ipcRenderer.invoke('config-get'),
saveConfig: (config: Config) => ipcRenderer.invoke('config-save', config),
Expand Down
8 changes: 7 additions & 1 deletion hostd/electron-src/startup.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { startDaemon } from './daemon'
import { getIsConfigured } from './config'
import { state } from './state'
import { state, system } from './state'

export function startup() {
// If the app is already configured, start the daemon and open browser
Expand All @@ -9,4 +9,10 @@ export function startup() {
startDaemon()
state.mainWindow?.close()
}

if (system.isDev) {
state.mainWindow?.setMaximumSize(2000, 2000)
state.mainWindow?.setSize(1000, 800)
state.mainWindow?.webContents.openDevTools()
}
}
3 changes: 3 additions & 0 deletions hostd/electron-src/state.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ChildProcess } from 'child_process'
import { BrowserWindow, Tray } from 'electron'
import isDev from 'electron-is-dev'

export let state: {
mainWindow: BrowserWindow | null
Expand All @@ -14,10 +15,12 @@ export let state: {
}

export const system: {
isDev: boolean
isDarwin: boolean
isLinux: boolean
isWindows: boolean
} = {
isDev,
isDarwin: process.platform === 'darwin',
isLinux: process.platform === 'linux',
isWindows: process.platform === 'win32',
Expand Down
3 changes: 1 addition & 2 deletions hostd/electron-src/tray.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import path from 'path'
import { app, Tray, Menu } from 'electron'
import isDev from 'electron-is-dev'
import { state, system } from './state'

export function initTray() {
const iconName = system.isDarwin ? 'tray.png' : 'tray-win.png'
const iconPath = isDev
const iconPath = system.isDev
? path.join(process.cwd(), 'assets', iconName)
: path.join(__dirname, '../assets', iconName)

Expand Down
9 changes: 1 addition & 8 deletions hostd/electron-src/window.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import path, { join } from 'path'
import { BrowserWindow, app } from 'electron'
import isDev from 'electron-is-dev'
import { format } from 'url'
import { state, system } from './state'

Expand Down Expand Up @@ -45,18 +44,12 @@ export function initWindow() {
return false
})

const url = isDev
const url = system.isDev
? 'http://localhost:8000/'
: format({
pathname: path.join(__dirname, '../renderer/out/index.html'),
protocol: 'file:',
slashes: true,
})
state.mainWindow.loadURL(url)

if (isDev) {
state.mainWindow.setMaximumSize(2000, 2000)
state.mainWindow.setSize(1000, 800)
state.mainWindow.webContents.openDevTools()
}
}
76 changes: 68 additions & 8 deletions hostd/renderer/components/UpdateBanner.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,81 @@
'use client'

import { Text } from '@siafoundation/design-system'
import {
LoadingDots,
Text,
triggerErrorToast,
triggerSuccessToast,
} from '@siafoundation/design-system'
import { Upgrade16 } from '@siafoundation/react-icons'
import { useLatestVersion } from './useLatestVersion'
import { useInstalledVersion } from './useInstalledVersion'
import { useCallback, useState } from 'react'

export function UpdateBanner() {
const latestVersion = useLatestVersion()
const installedVersion = useInstalledVersion()
const [isUpdating, setIsUpdating] = useState(false)
const [isRestarting, setIsRestarting] = useState(false)

const update = useCallback(async () => {
try {
setIsUpdating(true)
await window.electron.daemonUpdate()
} catch (e) {
console.log(e)
triggerErrorToast('Error downloading update. Please try again.')
setIsUpdating(false)
setIsRestarting(false)
return
}
try {
setIsRestarting(true)
await window.electron.daemonStart()
} catch (e) {
console.log(e)
triggerErrorToast('Error restarting daemon. Please try again.')
setIsUpdating(false)
setIsRestarting(false)
return
}
triggerSuccessToast(`Updated to hostd version ${installedVersion.data}.`)
setIsUpdating(false)
setIsRestarting(false)
}, [setIsUpdating, installedVersion.data])

if (latestVersion.data === installedVersion.data) {
return null
}

return (
<div className="flex w-full gap-2 items-center justify-center py-2 px-3 bg-amber-600 dark:bg-amber-500">
<Text color="lo">
<Upgrade16 />
</Text>
<Text size="14" color="lo">
An update to version {latestVersion.data} is available.
</Text>
<div
className="flex w-full gap-2 items-center justify-center py-2 px-3 bg-amber-600 dark:bg-amber-500 cursor-pointer"
onClick={update}
>
{isRestarting ? (
<>
<LoadingDots />
<Text size="14" color="lo">
Restarting hostd daemon {latestVersion.data}
</Text>
</>
) : isUpdating ? (
<>
<LoadingDots />
<Text size="14" color="lo">
Updating to hostd {latestVersion.data}
</Text>
</>
) : (
<>
<Text color="lo">
<Upgrade16 />
</Text>
<Text size="14" color="lo">
An update to hostd {latestVersion.data} is available.
</Text>
</>
)}
</div>
)
}
1 change: 1 addition & 0 deletions hostd/renderer/renderer.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface API {
openBrowser: (url: string) => Promise<void>
daemonStart: () => Promise<void>
daemonStop: () => Promise<void>
daemonUpdate: () => Promise<void>
getConfig: () => Promise<Config>
openDataDirectory: () => Promise<void>
getIsConfigured: () => Promise<boolean>
Expand Down
1 change: 1 addition & 0 deletions renterd/electron-src/download.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export async function downloadRelease(): Promise<void> {

const release = releaseData.data
const asset = release.assets.find((asset) => asset.name === releaseAsset())
console.log(`Downloading ${releaseAsset()}`)

if (asset) {
console.log('Release name:', release.name)
Expand Down
7 changes: 5 additions & 2 deletions renterd/electron-src/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
getIsConfigured,
saveConfig,
} from './config'
import { downloadRelease } from './download'

export function initIpc() {
ipcMain.handle('open-browser', (_, url: string) => {
Expand All @@ -26,8 +27,10 @@ export function initIpc() {
await stopDaemon()
})
ipcMain.handle('daemon-is-running', (_) => {
const isDaemonRunning = getIsDaemonRunning()
return isDaemonRunning
return getIsDaemonRunning()
})
ipcMain.handle('daemon-update', async (_) => {
await downloadRelease()
})
ipcMain.handle('config-get', (_) => {
const config = getConfig()
Expand Down
1 change: 1 addition & 0 deletions renterd/electron-src/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ contextBridge.exposeInMainWorld('electron', {
checkIsDaemonRunning: () => ipcRenderer.invoke('daemon-is-running'),
daemonStart: () => ipcRenderer.invoke('daemon-start'),
daemonStop: () => ipcRenderer.invoke('daemon-stop'),
daemonUpdate: () => ipcRenderer.invoke('daemon-update'),
openBrowser: (url: string) => ipcRenderer.invoke('open-browser', url),
getConfig: () => ipcRenderer.invoke('config-get'),
saveConfig: (config: Config) => ipcRenderer.invoke('config-save', config),
Expand Down
8 changes: 7 additions & 1 deletion renterd/electron-src/startup.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { shell } from 'electron'
import { startDaemon } from './daemon'
import { getConfig, getIsConfigured } from './config'
import { state } from './state'
import { state, system } from './state'

export function startup() {
// If the app is already configured, start the daemon and open browser
Expand All @@ -11,4 +11,10 @@ export function startup() {
state.mainWindow?.close()
shell.openExternal(`http://${getConfig().http.address}`)
}

if (system.isDev) {
state.mainWindow?.setMaximumSize(2000, 2000)
state.mainWindow?.setSize(1000, 800)
state.mainWindow?.webContents.openDevTools()
}
}
3 changes: 3 additions & 0 deletions renterd/electron-src/state.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ChildProcess } from 'child_process'
import { BrowserWindow, Tray } from 'electron'
import isDev from 'electron-is-dev'

export let state: {
mainWindow: BrowserWindow | null
Expand All @@ -14,10 +15,12 @@ export let state: {
}

export const system: {
isDev: boolean
isDarwin: boolean
isLinux: boolean
isWindows: boolean
} = {
isDev: isDev,
isDarwin: process.platform === 'darwin',
isLinux: process.platform === 'linux',
isWindows: process.platform === 'win32',
Expand Down
3 changes: 1 addition & 2 deletions renterd/electron-src/tray.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import path from 'path'
import { app, Tray, Menu } from 'electron'
import isDev from 'electron-is-dev'
import { state, system } from './state'

export function initTray() {
const iconName = system.isDarwin ? 'tray.png' : 'tray-win.png'
const iconPath = isDev
const iconPath = system.isDev
? path.join(process.cwd(), 'assets', iconName)
: path.join(__dirname, '../assets', iconName)

Expand Down
9 changes: 1 addition & 8 deletions renterd/electron-src/window.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import path, { join } from 'path'
import { BrowserWindow, app } from 'electron'
import isDev from 'electron-is-dev'
import { format } from 'url'
import { state, system } from './state'

Expand Down Expand Up @@ -45,18 +44,12 @@ export function initWindow() {
return false
})

const url = isDev
const url = system.isDev
? 'http://localhost:8000/'
: format({
pathname: path.join(__dirname, '../renderer/out/index.html'),
protocol: 'file:',
slashes: true,
})
state.mainWindow.loadURL(url)

if (isDev) {
state.mainWindow.setMaximumSize(2000, 2000)
state.mainWindow.setSize(1000, 800)
state.mainWindow.webContents.openDevTools()
}
}
Loading

0 comments on commit ed1c1ff

Please sign in to comment.