瀏覽代碼

refactor(updater): strong type for the `pub_date` field, ref #4162 (#4218)

Lucas Fernandes Nogueira 3 年之前
父節點
當前提交
ac7656ab19

+ 5 - 0
.changes/update-available-refactor.md

@@ -0,0 +1,5 @@
+---
+"tauri": patch
+---
+
+**Breaking change:** The `tauri::UpdaterEvent::UpdateEvent` date field is now an `Option<time::OffsetDateTime>`.

+ 5 - 0
.changes/update-date-strong-type.md

@@ -0,0 +1,5 @@
+---
+"tauri": patch
+---
+
+**Breaking change:** The updater response `pub_date` now must be a valid RFC 3339 string.

+ 2 - 0
core/tauri/Cargo.toml

@@ -84,6 +84,7 @@ os_pipe = { version = "1.0", optional = true }
 rfd = { version = "0.8", optional = true }
 raw-window-handle = "0.4.2"
 minisign-verify = { version = "0.2", optional = true }
+time = { version = "0.3", features = ["parsing", "formatting"], optional = true }
 os_info = { version = "3.2.0", optional = true }
 futures-lite = "1.12"
 regex = { version = "1.5.5", optional = true }
@@ -138,6 +139,7 @@ isolation = [ "tauri-utils/isolation", "tauri-macros/isolation" ]
 custom-protocol = [ "tauri-macros/custom-protocol" ]
 updater = [
   "minisign-verify",
+  "time",
   "base64",
   "http-api",
   "dialog-ask",

+ 1 - 1
core/tauri/src/lib.rs

@@ -265,7 +265,7 @@ pub enum UpdaterEvent {
     /// The update body.
     body: String,
     /// The update release date.
-    date: String,
+    date: Option<time::OffsetDateTime>,
     /// The update version.
     version: String,
   },

+ 19 - 15
core/tauri/src/updater/core.rs

@@ -18,6 +18,7 @@ use minisign_verify::{PublicKey, Signature};
 use semver::Version;
 use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize};
 use tauri_utils::{platform::current_exe, Env};
+use time::OffsetDateTime;
 use url::Url;
 
 #[cfg(feature = "updater")]
@@ -57,16 +58,15 @@ pub enum RemoteReleaseInner {
 /// Information about a release returned by the remote update server.
 ///
 /// This type can have one of two shapes: Server Format (Dynamic Format) and Static Format.
-#[derive(Debug, Serialize)]
+#[derive(Debug)]
 pub struct RemoteRelease {
   /// Version to install.
   version: Version,
   /// Release notes.
   notes: Option<String>,
   /// Release date.
-  pub_date: String,
+  pub_date: Option<OffsetDateTime>,
   /// Release data.
-  #[serde(flatten)]
   data: RemoteReleaseInner,
 }
 
@@ -75,17 +75,12 @@ impl<'de> Deserialize<'de> for RemoteRelease {
   where
     D: Deserializer<'de>,
   {
-    fn default_pub_date() -> String {
-      "N/A".to_string()
-    }
-
     #[derive(Deserialize)]
     struct InnerRemoteRelease {
       #[serde(alias = "name", deserialize_with = "parse_version")]
       version: Version,
       notes: Option<String>,
-      #[serde(default = "default_pub_date")]
-      pub_date: String,
+      pub_date: Option<String>,
       platforms: Option<HashMap<String, ReleaseManifestPlatform>>,
       // dynamic platform response
       url: Option<Url>,
@@ -97,10 +92,19 @@ impl<'de> Deserialize<'de> for RemoteRelease {
 
     let release = InnerRemoteRelease::deserialize(deserializer)?;
 
+    let pub_date = if let Some(date) = release.pub_date {
+      Some(
+        OffsetDateTime::parse(&date, &time::format_description::well_known::Rfc3339)
+          .map_err(|e| DeError::custom(format!("invalid value for `pub_date`: {}", e)))?,
+      )
+    } else {
+      None
+    };
+
     Ok(RemoteRelease {
       version: release.version,
       notes: release.notes,
-      pub_date: release.pub_date,
+      pub_date,
       data: if let Some(platforms) = release.platforms {
         RemoteReleaseInner::Static { platforms }
       } else {
@@ -152,8 +156,8 @@ impl RemoteRelease {
   }
 
   /// The release date.
-  pub fn pub_date(&self) -> &String {
-    &self.pub_date
+  pub fn pub_date(&self) -> Option<&OffsetDateTime> {
+    self.pub_date.as_ref()
   }
 
   /// The release's download URL for the given target.
@@ -431,7 +435,7 @@ impl<R: Runtime> UpdateBuilder<R> {
       extract_path,
       should_update,
       version: final_release.version().to_string(),
-      date: final_release.pub_date().to_string(),
+      date: final_release.pub_date().cloned(),
       current_version: self.current_version,
       download_url: final_release.download_url(&json_target)?.to_owned(),
       body: final_release.notes().cloned(),
@@ -461,7 +465,7 @@ pub struct Update<R: Runtime> {
   /// Running version
   pub current_version: Version,
   /// Update publish date
-  pub date: String,
+  pub date: Option<OffsetDateTime>,
   /// Target
   #[allow(dead_code)]
   target: String,
@@ -489,7 +493,7 @@ impl<R: Runtime> Clone for Update<R> {
       should_update: self.should_update,
       version: self.version.clone(),
       current_version: self.current_version.clone(),
-      date: self.date.clone(),
+      date: self.date,
       target: self.target.clone(),
       extract_path: self.extract_path.clone(),
       download_url: self.download_url.clone(),

+ 8 - 7
core/tauri/src/updater/mod.rs

@@ -136,7 +136,7 @@
 //!   tauri::RunEvent::Updater(updater_event) => {
 //!     match updater_event {
 //!       tauri::UpdaterEvent::UpdateAvailable { body, date, version } => {
-//!         println!("update available {} {} {}", body, date, version);
+//!         println!("update available {} {:?} {}", body, date, version);
 //!       }
 //!       _ => (),
 //!     }
@@ -246,7 +246,7 @@
 //!   tauri::RunEvent::Updater(updater_event) => {
 //!     match updater_event {
 //!       tauri::UpdaterEvent::UpdateAvailable { body, date, version } => {
-//!         println!("update available {} {} {}", body, date, version);
+//!         println!("update available {} {:?} {}", body, date, version);
 //!       }
 //!       tauri::UpdaterEvent::Pending => {
 //!         println!("update is pending!");
@@ -450,6 +450,7 @@ use std::time::Duration;
 
 use http::header::{HeaderName, HeaderValue};
 use semver::Version;
+use time::OffsetDateTime;
 
 pub use self::{core::RemoteRelease, error::Error};
 /// Alias for [`std::result::Result`] using our own [`Error`].
@@ -509,7 +510,7 @@ struct DownloadProgressEvent {
 #[derive(Clone, serde::Serialize)]
 struct UpdateManifest {
   version: String,
-  date: String,
+  date: Option<String>,
   body: String,
 }
 
@@ -686,14 +687,14 @@ impl<R: Runtime> UpdateBuilder<R> {
               EVENT_UPDATE_AVAILABLE,
               UpdateManifest {
                 body: body.clone(),
-                date: update.date.clone(),
+                date: update.date.map(|d| d.to_string()),
                 version: update.version.clone(),
               },
             );
             let _ = handle.create_proxy().send_event(EventLoopMessage::Updater(
               UpdaterEvent::UpdateAvailable {
                 body,
-                date: update.date.clone(),
+                date: update.date,
                 version: update.version.clone(),
               },
             ));
@@ -751,8 +752,8 @@ impl<R: Runtime> UpdateResponse<R> {
   }
 
   /// The update date.
-  pub fn date(&self) -> &str {
-    &self.update.date
+  pub fn date(&self) -> Option<&OffsetDateTime> {
+    self.update.date.as_ref()
   }
 
   /// The update description.

+ 1 - 0
core/tests/app-updater/Cargo.toml

@@ -11,6 +11,7 @@ serde = { version = "1", features = ["derive"] }
 serde_json = "1"
 tiny_http = "0.11"
 tauri = { path = "../../tauri", features = ["updater"] }
+time = { version = "0.3", features = ["formatting"] }
 
 [features]
 default = ["custom-protocol"]

+ 4 - 0
core/tests/app-updater/tests/update.rs

@@ -35,6 +35,7 @@ struct PlatformUpdate {
 #[derive(Serialize)]
 struct Update {
   version: &'static str,
+  date: String,
   platforms: HashMap<String, PlatformUpdate>,
 }
 
@@ -178,6 +179,9 @@ fn update_app() {
             );
             let body = serde_json::to_vec(&Update {
               version: "1.0.0",
+              date: time::OffsetDateTime::now_utc()
+                .format(&time::format_description::well_known::Rfc3339)
+                .unwrap(),
               platforms,
             })
             .unwrap();