tauri_plugin_updater/
lib.rs1#![doc(
10 html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png",
11 html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
12)]
13
14use std::{ffi::OsString, sync::Arc};
15
16use http::{HeaderMap, HeaderName, HeaderValue};
17use semver::Version;
18use tauri::{
19 plugin::{Builder as PluginBuilder, TauriPlugin},
20 Manager, Runtime,
21};
22
23mod commands;
24mod config;
25mod error;
26mod updater;
27
28pub use config::Config;
29pub use error::{Error, Result};
30pub use updater::*;
31
32pub trait UpdaterExt<R: Runtime> {
34 fn updater_builder(&self) -> UpdaterBuilder;
51
52 fn updater(&self) -> Result<Updater>;
68}
69
70impl<R: Runtime, T: Manager<R>> UpdaterExt<R> for T {
71 fn updater_builder(&self) -> UpdaterBuilder {
72 let app = self.app_handle();
73 let UpdaterState {
74 config,
75 target,
76 version_comparator,
77 headers,
78 } = self.state::<UpdaterState>().inner();
79
80 let mut builder = UpdaterBuilder::new(app, config.clone()).headers(headers.clone());
81
82 if let Some(target) = target {
83 builder = builder.target(target);
84 }
85
86 let args = self.env().args_os;
87 if !args.is_empty() {
88 builder = builder.current_exe_args(args);
89 }
90
91 builder.version_comparator = version_comparator.clone();
92
93 #[cfg(any(
94 target_os = "linux",
95 target_os = "dragonfly",
96 target_os = "freebsd",
97 target_os = "netbsd",
98 target_os = "openbsd"
99 ))]
100 {
101 let env = app.env();
102 if let Some(appimage) = env.appimage {
103 builder = builder.executable_path(appimage);
104 }
105 }
106
107 let app_handle = app.app_handle().clone();
108 builder = builder.on_before_exit(move || {
109 app_handle.cleanup_before_exit();
110 });
111
112 builder
113 }
114
115 fn updater(&self) -> Result<Updater> {
116 self.updater_builder().build()
117 }
118}
119
120struct UpdaterState {
121 target: Option<String>,
122 config: Config,
123 version_comparator: Option<VersionComparator>,
124 headers: HeaderMap,
125}
126
127#[derive(Default)]
128pub struct Builder {
129 target: Option<String>,
130 pubkey: Option<String>,
131 installer_args: Vec<OsString>,
132 headers: HeaderMap,
133 default_version_comparator: Option<VersionComparator>,
134}
135
136impl Builder {
137 pub fn new() -> Self {
138 Self::default()
139 }
140
141 pub fn target(mut self, target: impl Into<String>) -> Self {
142 self.target.replace(target.into());
143 self
144 }
145
146 pub fn pubkey<S: Into<String>>(mut self, pubkey: S) -> Self {
147 self.pubkey.replace(pubkey.into());
148 self
149 }
150
151 pub fn installer_args<I, S>(mut self, args: I) -> Self
153 where
154 I: IntoIterator<Item = S>,
155 S: Into<OsString>,
156 {
157 self.installer_args.extend(args.into_iter().map(Into::into));
158 self
159 }
160
161 pub fn installer_arg<S>(mut self, arg: S) -> Self
163 where
164 S: Into<OsString>,
165 {
166 self.installer_args.push(arg.into());
167 self
168 }
169
170 pub fn clear_installer_args(mut self) -> Self {
175 self.installer_args.clear();
176 self
177 }
178
179 pub fn header<K, V>(mut self, key: K, value: V) -> Result<Self>
180 where
181 HeaderName: TryFrom<K>,
182 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
183 HeaderValue: TryFrom<V>,
184 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
185 {
186 let key: std::result::Result<HeaderName, http::Error> = key.try_into().map_err(Into::into);
187 let value: std::result::Result<HeaderValue, http::Error> =
188 value.try_into().map_err(Into::into);
189 self.headers.insert(key?, value?);
190
191 Ok(self)
192 }
193
194 pub fn headers(mut self, headers: HeaderMap) -> Self {
195 self.headers = headers;
196 self
197 }
198
199 pub fn default_version_comparator<
200 F: Fn(Version, RemoteRelease) -> bool + Send + Sync + 'static,
201 >(
202 mut self,
203 f: F,
204 ) -> Self {
205 self.default_version_comparator.replace(Arc::new(f));
206 self
207 }
208
209 pub fn build<R: Runtime>(self) -> TauriPlugin<R, Config> {
210 let pubkey = self.pubkey;
211 let target = self.target;
212 let version_comparator = self.default_version_comparator;
213 let installer_args = self.installer_args;
214 let headers = self.headers;
215 PluginBuilder::<R, Config>::new("updater")
216 .setup(move |app, api| {
217 let mut config = api.config().clone();
218 if let Some(pubkey) = pubkey {
219 config.pubkey = pubkey;
220 }
221 if let Some(windows) = &mut config.windows {
222 windows.installer_args.extend(installer_args);
223 }
224 app.manage(UpdaterState {
225 target,
226 config,
227 version_comparator,
228 headers,
229 });
230 Ok(())
231 })
232 .invoke_handler(tauri::generate_handler![
233 commands::check,
234 commands::download,
235 commands::install,
236 commands::download_and_install,
237 ])
238 .build()
239 }
240}