updater.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Copyright 2019-2021 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. /**
  5. * Customize the auto updater flow.
  6. *
  7. * This package is also accessible with `window.__TAURI__.updater` when `tauri.conf.json > build > withGlobalTauri` is set to true.
  8. * @module
  9. */
  10. import { once, listen, emit, UnlistenFn } from './event'
  11. type UpdateStatus = 'PENDING' | 'ERROR' | 'DONE' | 'UPTODATE'
  12. interface UpdateStatusResult {
  13. error?: string
  14. status: UpdateStatus
  15. }
  16. interface UpdateManifest {
  17. version: string
  18. date: string
  19. body: string
  20. }
  21. interface UpdateResult {
  22. manifest?: UpdateManifest
  23. shouldUpdate: boolean
  24. }
  25. /**
  26. * Install the update if there's one available.
  27. *
  28. * @return A promise indicating the success or failure of the operation.
  29. */
  30. async function installUpdate(): Promise<void> {
  31. let unlistenerFn: UnlistenFn | undefined
  32. function cleanListener(): void {
  33. if (unlistenerFn) {
  34. unlistenerFn()
  35. }
  36. unlistenerFn = undefined
  37. }
  38. return new Promise((resolve, reject) => {
  39. function onStatusChange(statusResult: UpdateStatusResult): void {
  40. if (statusResult.error) {
  41. cleanListener()
  42. return reject(statusResult.error)
  43. }
  44. // install complete
  45. if (statusResult.status === 'DONE') {
  46. cleanListener()
  47. return resolve()
  48. }
  49. }
  50. // listen status change
  51. listen('tauri://update-status', (data: { payload: any }) => {
  52. onStatusChange(data?.payload as UpdateStatusResult)
  53. })
  54. .then((fn) => {
  55. unlistenerFn = fn
  56. })
  57. .catch((e) => {
  58. cleanListener()
  59. // dispatch the error to our checkUpdate
  60. throw e
  61. })
  62. // start the process we dont require much security as it's
  63. // handled by rust
  64. emit('tauri://update-install').catch((e) => {
  65. cleanListener()
  66. // dispatch the error to our checkUpdate
  67. throw e
  68. })
  69. })
  70. }
  71. /**
  72. * Checks if an update is available.
  73. *
  74. * @return Promise resolving to the update status.
  75. */
  76. async function checkUpdate(): Promise<UpdateResult> {
  77. let unlistenerFn: UnlistenFn | undefined
  78. function cleanListener(): void {
  79. if (unlistenerFn) {
  80. unlistenerFn()
  81. }
  82. unlistenerFn = undefined
  83. }
  84. return new Promise((resolve, reject) => {
  85. function onUpdateAvailable(manifest: UpdateManifest): void {
  86. cleanListener()
  87. return resolve({
  88. manifest,
  89. shouldUpdate: true
  90. })
  91. }
  92. function onStatusChange(statusResult: UpdateStatusResult): void {
  93. if (statusResult.error) {
  94. cleanListener()
  95. return reject(statusResult.error)
  96. }
  97. if (statusResult.status === 'UPTODATE') {
  98. cleanListener()
  99. return resolve({
  100. shouldUpdate: false
  101. })
  102. }
  103. }
  104. // wait to receive the latest update
  105. once('tauri://update-available', (data: { payload: any }) => {
  106. onUpdateAvailable(data?.payload as UpdateManifest)
  107. }).catch((e) => {
  108. cleanListener()
  109. // dispatch the error to our checkUpdate
  110. throw e
  111. })
  112. // listen status change
  113. listen('tauri://update-status', (data: { payload: any }) => {
  114. onStatusChange(data?.payload as UpdateStatusResult)
  115. })
  116. .then((fn) => {
  117. unlistenerFn = fn
  118. })
  119. .catch((e) => {
  120. cleanListener()
  121. // dispatch the error to our checkUpdate
  122. throw e
  123. })
  124. // start the process
  125. emit('tauri://update').catch((e) => {
  126. cleanListener()
  127. // dispatch the error to our checkUpdate
  128. throw e
  129. })
  130. })
  131. }
  132. export type { UpdateStatus, UpdateStatusResult, UpdateManifest, UpdateResult }
  133. export { installUpdate, checkUpdate }