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
152 where
153 I: IntoIterator<Item = S>,
154 S: Into<OsString>,
155 {
156 self.installer_args.extend(args.into_iter().map(Into::into));
157 self
158 }
159
160 pub fn installer_arg<S>(mut self, arg: S) -> Self
161 where
162 S: Into<OsString>,
163 {
164 self.installer_args.push(arg.into());
165 self
166 }
167
168 pub fn clear_installer_args(mut self) -> Self {
169 self.installer_args.clear();
170 self
171 }
172
173 pub fn header<K, V>(mut self, key: K, value: V) -> Result<Self>
174 where
175 HeaderName: TryFrom<K>,
176 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
177 HeaderValue: TryFrom<V>,
178 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
179 {
180 let key: std::result::Result<HeaderName, http::Error> = key.try_into().map_err(Into::into);
181 let value: std::result::Result<HeaderValue, http::Error> =
182 value.try_into().map_err(Into::into);
183 self.headers.insert(key?, value?);
184
185 Ok(self)
186 }
187
188 pub fn headers(mut self, headers: HeaderMap) -> Self {
189 self.headers = headers;
190 self
191 }
192
193 pub fn default_version_comparator<
194 F: Fn(Version, RemoteRelease) -> bool + Send + Sync + 'static,
195 >(
196 mut self,
197 f: F,
198 ) -> Self {
199 self.default_version_comparator.replace(Arc::new(f));
200 self
201 }
202
203 pub fn build<R: Runtime>(self) -> TauriPlugin<R, Config> {
204 let pubkey = self.pubkey;
205 let target = self.target;
206 let version_comparator = self.default_version_comparator;
207 let installer_args = self.installer_args;
208 let headers = self.headers;
209 PluginBuilder::<R, Config>::new("updater")
210 .setup(move |app, api| {
211 let mut config = api.config().clone();
212 if let Some(pubkey) = pubkey {
213 config.pubkey = pubkey;
214 }
215 if let Some(windows) = &mut config.windows {
216 windows.installer_args.extend(installer_args);
217 }
218 app.manage(UpdaterState {
219 target,
220 config,
221 version_comparator,
222 headers,
223 });
224 Ok(())
225 })
226 .invoke_handler(tauri::generate_handler![
227 commands::check,
228 commands::download,
229 commands::install,
230 commands::download_and_install,
231 ])
232 .build()
233 }
234}