@@ -331,6 +331,8 @@ mod core;
331331mod error;
332332
333333pub use self :: error:: Error ;
334+ /// Alias for [`std::result::Result`] using our own [`Error`].
335+ pub type Result < T > = std:: result:: Result < T , Error > ;
334336
335337use crate :: {
336338 api:: dialog:: blocking:: ask, runtime:: EventLoopProxy , utils:: config:: UpdaterConfig , AppHandle ,
@@ -370,6 +372,43 @@ struct UpdateManifest {
370372 body : String ,
371373}
372374
375+ /// The response of an updater [`check`].
376+ pub struct UpdateResponse < R : Runtime > {
377+ update : core:: Update ,
378+ handle : AppHandle < R > ,
379+ }
380+
381+ impl < R : Runtime > Clone for UpdateResponse < R > {
382+ fn clone ( & self ) -> Self {
383+ Self {
384+ update : self . update . clone ( ) ,
385+ handle : self . handle . clone ( ) ,
386+ }
387+ }
388+ }
389+
390+ impl < R : Runtime > UpdateResponse < R > {
391+ /// Whether the updater found a newer release or not.
392+ pub fn is_update_available ( & self ) -> bool {
393+ self . update . should_update
394+ }
395+
396+ /// The current version of the application as read by the updater.
397+ pub fn current_version ( & self ) -> & str {
398+ & self . update . current_version
399+ }
400+
401+ /// The latest version of the application found by the updater.
402+ pub fn latest_version ( & self ) -> & str {
403+ & self . update . version
404+ }
405+
406+ /// Downloads and installs the update.
407+ pub async fn download_and_install ( self ) -> Result < ( ) > {
408+ download_and_install ( self . handle , self . update ) . await
409+ }
410+ }
411+
373412/// Check if there is any new update with builtin dialog.
374413pub ( crate ) async fn check_update_with_dialog < R : Runtime > (
375414 updater_config : UpdaterConfig ,
@@ -417,103 +456,112 @@ pub(crate) async fn check_update_with_dialog<R: Runtime>(
417456 }
418457}
419458
420- /// Experimental listener
459+ /// Updater listener
421460/// This function should be run on the main thread once.
422- pub ( crate ) fn listener < R : Runtime > (
423- updater_config : UpdaterConfig ,
424- package_info : crate :: PackageInfo ,
425- handle : & AppHandle < R > ,
426- ) {
427- let handle_ = handle. clone ( ) ;
428-
461+ pub ( crate ) fn listener < R : Runtime > ( handle : AppHandle < R > ) {
429462 // Wait to receive the event `"tauri://update"`
463+ let handle_ = handle. clone ( ) ;
430464 handle. listen_global ( EVENT_CHECK_UPDATE , move |_msg| {
431- let handle = handle_. clone ( ) ;
432- let package_info = package_info. clone ( ) ;
433-
434- // prepare our endpoints
435- let endpoints = updater_config
436- . endpoints
437- . as_ref ( )
438- . expect ( "Something wrong with endpoints" )
439- . iter ( )
440- . map ( |e| e. to_string ( ) )
441- . collect :: < Vec < String > > ( ) ;
442-
443- let pubkey = updater_config. pubkey . clone ( ) ;
444-
445- // check updates
465+ let handle_ = handle_. clone ( ) ;
446466 crate :: async_runtime:: spawn ( async move {
447- let handle = handle. clone ( ) ;
448- let handle_ = handle. clone ( ) ;
449- let pubkey = pubkey. clone ( ) ;
450- let env = handle. state :: < Env > ( ) . inner ( ) . clone ( ) ;
451-
452- match self :: core:: builder ( env)
453- . urls ( & endpoints[ ..] )
454- . current_version ( & package_info. version )
455- . build ( )
456- . await
457- {
458- Ok ( updater) => {
459- // send notification if we need to update
460- if updater. should_update {
461- let body = updater. body . clone ( ) . unwrap_or_else ( || String :: from ( "" ) ) ;
462-
463- // Emit `tauri://update-available`
464- let _ = handle. emit_all (
465- EVENT_UPDATE_AVAILABLE ,
466- UpdateManifest {
467- body : body. clone ( ) ,
468- date : updater. date . clone ( ) ,
469- version : updater. version . clone ( ) ,
470- } ,
471- ) ;
472- let _ = handle. create_proxy ( ) . send_event ( EventLoopMessage :: Updater (
473- UpdaterEvent :: UpdateAvailable {
474- body,
475- date : updater. date . clone ( ) ,
476- version : updater. version . clone ( ) ,
477- } ,
478- ) ) ;
479-
480- // Listen for `tauri://update-install`
481- handle. once_global ( EVENT_INSTALL_UPDATE , move |_msg| {
482- let handle = handle_. clone ( ) ;
483- let updater = updater. clone ( ) ;
484-
485- // Start installation
486- crate :: async_runtime:: spawn ( async move {
487- // emit {"status": "PENDING"}
488- send_status_update ( & handle, UpdaterEvent :: Pending ) ;
489-
490- // Launch updater download process
491- // macOS we display the `Ready to restart dialog` asking to restart
492- // Windows is closing the current App and launch the downloaded MSI when ready (the process stop here)
493- // Linux we replace the AppImage by launching a new install, it start a new AppImage instance, so we're closing the previous. (the process stop here)
494- let update_result = updater. clone ( ) . download_and_install ( pubkey. clone ( ) ) . await ;
495-
496- if let Err ( err) = update_result {
497- // emit {"status": "ERROR", "error": "The error message"}
498- send_status_update ( & handle, UpdaterEvent :: Error ( err. to_string ( ) ) ) ;
499- } else {
500- // emit {"status": "DONE"}
501- send_status_update ( & handle, UpdaterEvent :: Updated ) ;
502- }
503- } ) ;
504- } ) ;
505- } else {
506- send_status_update ( & handle, UpdaterEvent :: AlreadyUpToDate ) ;
507- }
508- }
509- Err ( e) => {
510- send_status_update ( & handle, UpdaterEvent :: Error ( e. to_string ( ) ) ) ;
511- }
512- }
467+ let _ = check ( handle_. clone ( ) ) . await ;
513468 } ) ;
514469 } ) ;
515470}
516471
472+ pub ( crate ) async fn download_and_install < R : Runtime > (
473+ handle : AppHandle < R > ,
474+ update : core:: Update ,
475+ ) -> Result < ( ) > {
476+ let update = update. clone ( ) ;
477+
478+ // Start installation
479+ // emit {"status": "PENDING"}
480+ send_status_update ( & handle, UpdaterEvent :: Pending ) ;
481+
482+ // Launch updater download process
483+ // macOS we display the `Ready to restart dialog` asking to restart
484+ // Windows is closing the current App and launch the downloaded MSI when ready (the process stop here)
485+ // Linux we replace the AppImage by launching a new install, it start a new AppImage instance, so we're closing the previous. (the process stop here)
486+ let update_result = update
487+ . clone ( )
488+ . download_and_install ( handle. config ( ) . tauri . updater . pubkey . clone ( ) )
489+ . await ;
490+
491+ if let Err ( err) = & update_result {
492+ // emit {"status": "ERROR", "error": "The error message"}
493+ send_status_update ( & handle, UpdaterEvent :: Error ( err. to_string ( ) ) ) ;
494+ } else {
495+ // emit {"status": "DONE"}
496+ send_status_update ( & handle, UpdaterEvent :: Updated ) ;
497+ }
498+ update_result
499+ }
500+
501+ pub ( crate ) async fn check < R : Runtime > ( handle : AppHandle < R > ) -> Result < UpdateResponse < R > > {
502+ let updater_config = & handle. config ( ) . tauri . updater ;
503+ let package_info = handle. package_info ( ) . clone ( ) ;
504+
505+ // prepare our endpoints
506+ let endpoints = updater_config
507+ . endpoints
508+ . as_ref ( )
509+ . expect ( "Something wrong with endpoints" )
510+ . iter ( )
511+ . map ( |e| e. to_string ( ) )
512+ . collect :: < Vec < String > > ( ) ;
513+
514+ // check updates
515+ let env = handle. state :: < Env > ( ) . inner ( ) . clone ( ) ;
516+
517+ match self :: core:: builder ( env)
518+ . urls ( & endpoints[ ..] )
519+ . current_version ( & package_info. version )
520+ . build ( )
521+ . await
522+ {
523+ Ok ( update) => {
524+ // send notification if we need to update
525+ if update. should_update {
526+ let body = update. body . clone ( ) . unwrap_or_else ( || String :: from ( "" ) ) ;
527+
528+ // Emit `tauri://update-available`
529+ let _ = handle. emit_all (
530+ EVENT_UPDATE_AVAILABLE ,
531+ UpdateManifest {
532+ body : body. clone ( ) ,
533+ date : update. date . clone ( ) ,
534+ version : update. version . clone ( ) ,
535+ } ,
536+ ) ;
537+ let _ = handle. create_proxy ( ) . send_event ( EventLoopMessage :: Updater (
538+ UpdaterEvent :: UpdateAvailable {
539+ body,
540+ date : update. date . clone ( ) ,
541+ version : update. version . clone ( ) ,
542+ } ,
543+ ) ) ;
544+
545+ // Listen for `tauri://update-install`
546+ let handle_ = handle. clone ( ) ;
547+ let update_ = update. clone ( ) ;
548+ handle. once_global ( EVENT_INSTALL_UPDATE , move |_msg| {
549+ crate :: async_runtime:: spawn ( async move {
550+ let _ = download_and_install ( handle_, update_) . await ;
551+ } ) ;
552+ } ) ;
553+ } else {
554+ send_status_update ( & handle, UpdaterEvent :: AlreadyUpToDate ) ;
555+ }
556+ Ok ( UpdateResponse { update, handle } )
557+ }
558+ Err ( e) => {
559+ send_status_update ( & handle, UpdaterEvent :: Error ( e. to_string ( ) ) ) ;
560+ Err ( e)
561+ }
562+ }
563+ }
564+
517565// Send a status update via `tauri://update-status` event.
518566fn send_status_update < R : Runtime > ( handle : & AppHandle < R > , message : UpdaterEvent ) {
519567 let _ = handle. emit_all (
@@ -543,7 +591,7 @@ async fn prompt_for_install<R: Runtime>(
543591 app_name : & str ,
544592 body : & str ,
545593 pubkey : String ,
546- ) -> crate :: Result < ( ) > {
594+ ) -> Result < ( ) > {
547595 // remove single & double quote
548596 let escaped_body = body. replace ( & [ '\"' , '\'' ] [ ..] , "" ) ;
549597 let windows = handle. windows ( ) ;
0 commit comments