mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-04-05 10:13:00 +02:00
192 lines
4.8 KiB
TypeScript
192 lines
4.8 KiB
TypeScript
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
/**
|
|
* Customize the auto updater flow.
|
|
*
|
|
* This package is also accessible with `window.__TAURI__.updater` when [`build.withGlobalTauri`](https://tauri.app/v1/api/config/#buildconfig.withglobaltauri) in `tauri.conf.json` is set to `true`.
|
|
* @module
|
|
*/
|
|
|
|
import { once, listen, emit, UnlistenFn } from './event'
|
|
|
|
type UpdateStatus = 'PENDING' | 'ERROR' | 'DONE' | 'UPTODATE'
|
|
|
|
interface UpdateStatusResult {
|
|
error?: string
|
|
status: UpdateStatus
|
|
}
|
|
|
|
interface UpdateManifest {
|
|
version: string
|
|
date: string
|
|
body: string
|
|
}
|
|
|
|
interface UpdateResult {
|
|
manifest?: UpdateManifest
|
|
shouldUpdate: boolean
|
|
}
|
|
|
|
/**
|
|
* Listen to an updater event.
|
|
* @example
|
|
* ```typescript
|
|
* import { onUpdaterEvent } from "@tauri-apps/api/updater";
|
|
* const unlisten = await onUpdaterEvent(({ error, status }) => {
|
|
* console.log('Updater event', error, status);
|
|
* });
|
|
*
|
|
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
|
|
* unlisten();
|
|
* ```
|
|
*
|
|
* @param handler
|
|
* @returns A promise resolving to a function to unlisten to the event.
|
|
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
|
|
*/
|
|
async function onUpdaterEvent(
|
|
handler: (status: UpdateStatusResult) => void
|
|
): Promise<UnlistenFn> {
|
|
return listen('tauri://update-status', (data: { payload: any }) => {
|
|
handler(data?.payload as UpdateStatusResult)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Install the update if there's one available.
|
|
* @example
|
|
* ```typescript
|
|
* import { checkUpdate, installUpdate } from '@tauri-apps/api/updater';
|
|
* const update = await checkUpdate();
|
|
* if (update.shouldUpdate) {
|
|
* console.log(`Installing update ${update.manifest?.version}, ${update.manifest?.date}, ${update.manifest.body}`);
|
|
* await installUpdate();
|
|
* }
|
|
* ```
|
|
*
|
|
* @return A promise indicating the success or failure of the operation.
|
|
*/
|
|
async function installUpdate(): Promise<void> {
|
|
let unlistenerFn: UnlistenFn | undefined
|
|
|
|
function cleanListener(): void {
|
|
if (unlistenerFn) {
|
|
unlistenerFn()
|
|
}
|
|
unlistenerFn = undefined
|
|
}
|
|
|
|
return new Promise((resolve, reject) => {
|
|
function onStatusChange(statusResult: UpdateStatusResult): void {
|
|
if (statusResult.error) {
|
|
cleanListener()
|
|
return reject(statusResult.error)
|
|
}
|
|
|
|
// install complete
|
|
if (statusResult.status === 'DONE') {
|
|
cleanListener()
|
|
return resolve()
|
|
}
|
|
}
|
|
|
|
// listen status change
|
|
onUpdaterEvent(onStatusChange)
|
|
.then((fn) => {
|
|
unlistenerFn = fn
|
|
})
|
|
.catch((e) => {
|
|
cleanListener()
|
|
// dispatch the error to our checkUpdate
|
|
throw e
|
|
})
|
|
|
|
// start the process we dont require much security as it's
|
|
// handled by rust
|
|
emit('tauri://update-install').catch((e) => {
|
|
cleanListener()
|
|
// dispatch the error to our checkUpdate
|
|
throw e
|
|
})
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Checks if an update is available.
|
|
* @example
|
|
* ```typescript
|
|
* import { checkUpdate } from '@tauri-apps/api/updater';
|
|
* const update = await checkUpdate();
|
|
* // now run installUpdate() if needed
|
|
* ```
|
|
*
|
|
* @return Promise resolving to the update status.
|
|
*/
|
|
async function checkUpdate(): Promise<UpdateResult> {
|
|
let unlistenerFn: UnlistenFn | undefined
|
|
|
|
function cleanListener(): void {
|
|
if (unlistenerFn) {
|
|
unlistenerFn()
|
|
}
|
|
unlistenerFn = undefined
|
|
}
|
|
|
|
return new Promise((resolve, reject) => {
|
|
function onUpdateAvailable(manifest: UpdateManifest): void {
|
|
cleanListener()
|
|
return resolve({
|
|
manifest,
|
|
shouldUpdate: true
|
|
})
|
|
}
|
|
|
|
function onStatusChange(statusResult: UpdateStatusResult): void {
|
|
if (statusResult.error) {
|
|
cleanListener()
|
|
return reject(statusResult.error)
|
|
}
|
|
|
|
if (statusResult.status === 'UPTODATE') {
|
|
cleanListener()
|
|
return resolve({
|
|
shouldUpdate: false
|
|
})
|
|
}
|
|
}
|
|
|
|
// wait to receive the latest update
|
|
once('tauri://update-available', (data: { payload: any }) => {
|
|
onUpdateAvailable(data?.payload as UpdateManifest)
|
|
}).catch((e) => {
|
|
cleanListener()
|
|
// dispatch the error to our checkUpdate
|
|
throw e
|
|
})
|
|
|
|
// listen status change
|
|
onUpdaterEvent(onStatusChange)
|
|
.then((fn) => {
|
|
unlistenerFn = fn
|
|
})
|
|
.catch((e) => {
|
|
cleanListener()
|
|
// dispatch the error to our checkUpdate
|
|
throw e
|
|
})
|
|
|
|
// start the process
|
|
emit('tauri://update').catch((e) => {
|
|
cleanListener()
|
|
// dispatch the error to our checkUpdate
|
|
throw e
|
|
})
|
|
})
|
|
}
|
|
|
|
export type { UpdateStatus, UpdateStatusResult, UpdateManifest, UpdateResult }
|
|
|
|
export { onUpdaterEvent, installUpdate, checkUpdate }
|