Struct tauri::updater::RemoteRelease
source · pub struct RemoteRelease { /* private fields */ }
Available on crate feature
updater
only.Expand description
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.
Implementations§
source§impl RemoteRelease
impl RemoteRelease
sourcepub fn version(&self) -> &Version
pub fn version(&self) -> &Version
The release version.
Examples found in repository?
src/updater/core.rs (line 427)
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
pub async fn build(mut self) -> Result<Update<R>> {
let mut remote_release: Option<RemoteRelease> = None;
// make sure we have at least one url
if self.urls.is_empty() {
return Err(Error::Builder(
"Unable to check update, `url` is required.".into(),
));
};
// If no executable path provided, we use current_exe from tauri_utils
let executable_path = self.executable_path.unwrap_or(current_exe()?);
let arch = get_updater_arch().ok_or(Error::UnsupportedArch)?;
// `target` is the `{{target}}` variable we replace in the endpoint
// `json_target` is the value we search if the updater server returns a JSON with the `platforms` object
let (target, json_target) = if let Some(target) = self.target {
(target.clone(), target)
} else {
let target = get_updater_target().ok_or(Error::UnsupportedOs)?;
(target.to_string(), format!("{}-{}", target, arch))
};
// Get the extract_path from the provided executable_path
let extract_path = extract_path_from_executable(&self.app.state::<Env>(), &executable_path);
// Set SSL certs for linux if they aren't available.
// We do not require to recheck in the download_and_install as we use
// ENV variables, we can expect them to be set for the second call.
#[cfg(target_os = "linux")]
{
if env::var_os("SSL_CERT_FILE").is_none() {
env::set_var("SSL_CERT_FILE", "/etc/ssl/certs/ca-certificates.crt");
}
if env::var_os("SSL_CERT_DIR").is_none() {
env::set_var("SSL_CERT_DIR", "/etc/ssl/certs");
}
}
// we want JSON only
let mut headers = self.headers;
headers.insert("Accept", HeaderValue::from_str("application/json").unwrap());
// Allow fallback if more than 1 urls is provided
let mut last_error: Option<Error> = None;
for url in &self.urls {
// replace {{current_version}}, {{target}} and {{arch}} in the provided URL
// this is useful if we need to query example
// https://releases.myapp.com/update/{{target}}/{{arch}}/{{current_version}}
// will be translated into ->
// https://releases.myapp.com/update/darwin/aarch64/1.0.0
// The main objective is if the update URL is defined via the Cargo.toml
// the URL will be generated dynamically
let fixed_link = url
.replace("{{current_version}}", &self.current_version.to_string())
.replace("{{target}}", &target)
.replace("{{arch}}", arch);
let mut request = HttpRequestBuilder::new("GET", &fixed_link)?.headers(headers.clone());
if let Some(timeout) = self.timeout {
request = request.timeout(timeout);
}
let resp = ClientBuilder::new().build()?.send(request).await;
// If we got a success, we stop the loop
// and we set our remote_release variable
if let Ok(res) = resp {
let res = res.read().await?;
// got status code 2XX
if StatusCode::from_u16(res.status)
.map_err(|e| Error::Builder(e.to_string()))?
.is_success()
{
// if we got 204
if StatusCode::NO_CONTENT.as_u16() == res.status {
// return with `UpToDate` error
// we should catch on the client
return Err(Error::UpToDate);
};
// Convert the remote result to our local struct
let built_release = serde_json::from_value(res.data).map_err(Into::into);
// make sure all went well and the remote data is compatible
// with what we need locally
match built_release {
Ok(release) => {
last_error = None;
remote_release = Some(release);
break;
}
Err(err) => last_error = Some(err),
}
} // if status code is not 2XX we keep loopin' our urls
}
}
// Last error is cleaned on success -- shouldn't be triggered if
// we have a successful call
if let Some(error) = last_error {
return Err(error);
}
// Extracted remote metadata
let final_release = remote_release.ok_or(Error::ReleaseNotFound)?;
// is the announced version greater than our current one?
let should_update = if let Some(comparator) = self.should_install.take() {
comparator(&self.current_version, &final_release)
} else {
final_release.version() > &self.current_version
};
headers.remove("Accept");
// create our new updater
Ok(Update {
app: self.app,
target,
extract_path,
should_update,
version: final_release.version().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(),
signature: final_release.signature(&json_target)?.to_owned(),
#[cfg(target_os = "windows")]
with_elevated_task: final_release.with_elevated_task(&json_target)?,
timeout: self.timeout,
headers,
})
}
sourcepub fn notes(&self) -> Option<&String>
pub fn notes(&self) -> Option<&String>
The release notes.
Examples found in repository?
src/updater/core.rs (line 442)
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
pub async fn build(mut self) -> Result<Update<R>> {
let mut remote_release: Option<RemoteRelease> = None;
// make sure we have at least one url
if self.urls.is_empty() {
return Err(Error::Builder(
"Unable to check update, `url` is required.".into(),
));
};
// If no executable path provided, we use current_exe from tauri_utils
let executable_path = self.executable_path.unwrap_or(current_exe()?);
let arch = get_updater_arch().ok_or(Error::UnsupportedArch)?;
// `target` is the `{{target}}` variable we replace in the endpoint
// `json_target` is the value we search if the updater server returns a JSON with the `platforms` object
let (target, json_target) = if let Some(target) = self.target {
(target.clone(), target)
} else {
let target = get_updater_target().ok_or(Error::UnsupportedOs)?;
(target.to_string(), format!("{}-{}", target, arch))
};
// Get the extract_path from the provided executable_path
let extract_path = extract_path_from_executable(&self.app.state::<Env>(), &executable_path);
// Set SSL certs for linux if they aren't available.
// We do not require to recheck in the download_and_install as we use
// ENV variables, we can expect them to be set for the second call.
#[cfg(target_os = "linux")]
{
if env::var_os("SSL_CERT_FILE").is_none() {
env::set_var("SSL_CERT_FILE", "/etc/ssl/certs/ca-certificates.crt");
}
if env::var_os("SSL_CERT_DIR").is_none() {
env::set_var("SSL_CERT_DIR", "/etc/ssl/certs");
}
}
// we want JSON only
let mut headers = self.headers;
headers.insert("Accept", HeaderValue::from_str("application/json").unwrap());
// Allow fallback if more than 1 urls is provided
let mut last_error: Option<Error> = None;
for url in &self.urls {
// replace {{current_version}}, {{target}} and {{arch}} in the provided URL
// this is useful if we need to query example
// https://releases.myapp.com/update/{{target}}/{{arch}}/{{current_version}}
// will be translated into ->
// https://releases.myapp.com/update/darwin/aarch64/1.0.0
// The main objective is if the update URL is defined via the Cargo.toml
// the URL will be generated dynamically
let fixed_link = url
.replace("{{current_version}}", &self.current_version.to_string())
.replace("{{target}}", &target)
.replace("{{arch}}", arch);
let mut request = HttpRequestBuilder::new("GET", &fixed_link)?.headers(headers.clone());
if let Some(timeout) = self.timeout {
request = request.timeout(timeout);
}
let resp = ClientBuilder::new().build()?.send(request).await;
// If we got a success, we stop the loop
// and we set our remote_release variable
if let Ok(res) = resp {
let res = res.read().await?;
// got status code 2XX
if StatusCode::from_u16(res.status)
.map_err(|e| Error::Builder(e.to_string()))?
.is_success()
{
// if we got 204
if StatusCode::NO_CONTENT.as_u16() == res.status {
// return with `UpToDate` error
// we should catch on the client
return Err(Error::UpToDate);
};
// Convert the remote result to our local struct
let built_release = serde_json::from_value(res.data).map_err(Into::into);
// make sure all went well and the remote data is compatible
// with what we need locally
match built_release {
Ok(release) => {
last_error = None;
remote_release = Some(release);
break;
}
Err(err) => last_error = Some(err),
}
} // if status code is not 2XX we keep loopin' our urls
}
}
// Last error is cleaned on success -- shouldn't be triggered if
// we have a successful call
if let Some(error) = last_error {
return Err(error);
}
// Extracted remote metadata
let final_release = remote_release.ok_or(Error::ReleaseNotFound)?;
// is the announced version greater than our current one?
let should_update = if let Some(comparator) = self.should_install.take() {
comparator(&self.current_version, &final_release)
} else {
final_release.version() > &self.current_version
};
headers.remove("Accept");
// create our new updater
Ok(Update {
app: self.app,
target,
extract_path,
should_update,
version: final_release.version().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(),
signature: final_release.signature(&json_target)?.to_owned(),
#[cfg(target_os = "windows")]
with_elevated_task: final_release.with_elevated_task(&json_target)?,
timeout: self.timeout,
headers,
})
}
sourcepub fn pub_date(&self) -> Option<&OffsetDateTime>
pub fn pub_date(&self) -> Option<&OffsetDateTime>
The release date.
Examples found in repository?
src/updater/core.rs (line 439)
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
pub async fn build(mut self) -> Result<Update<R>> {
let mut remote_release: Option<RemoteRelease> = None;
// make sure we have at least one url
if self.urls.is_empty() {
return Err(Error::Builder(
"Unable to check update, `url` is required.".into(),
));
};
// If no executable path provided, we use current_exe from tauri_utils
let executable_path = self.executable_path.unwrap_or(current_exe()?);
let arch = get_updater_arch().ok_or(Error::UnsupportedArch)?;
// `target` is the `{{target}}` variable we replace in the endpoint
// `json_target` is the value we search if the updater server returns a JSON with the `platforms` object
let (target, json_target) = if let Some(target) = self.target {
(target.clone(), target)
} else {
let target = get_updater_target().ok_or(Error::UnsupportedOs)?;
(target.to_string(), format!("{}-{}", target, arch))
};
// Get the extract_path from the provided executable_path
let extract_path = extract_path_from_executable(&self.app.state::<Env>(), &executable_path);
// Set SSL certs for linux if they aren't available.
// We do not require to recheck in the download_and_install as we use
// ENV variables, we can expect them to be set for the second call.
#[cfg(target_os = "linux")]
{
if env::var_os("SSL_CERT_FILE").is_none() {
env::set_var("SSL_CERT_FILE", "/etc/ssl/certs/ca-certificates.crt");
}
if env::var_os("SSL_CERT_DIR").is_none() {
env::set_var("SSL_CERT_DIR", "/etc/ssl/certs");
}
}
// we want JSON only
let mut headers = self.headers;
headers.insert("Accept", HeaderValue::from_str("application/json").unwrap());
// Allow fallback if more than 1 urls is provided
let mut last_error: Option<Error> = None;
for url in &self.urls {
// replace {{current_version}}, {{target}} and {{arch}} in the provided URL
// this is useful if we need to query example
// https://releases.myapp.com/update/{{target}}/{{arch}}/{{current_version}}
// will be translated into ->
// https://releases.myapp.com/update/darwin/aarch64/1.0.0
// The main objective is if the update URL is defined via the Cargo.toml
// the URL will be generated dynamically
let fixed_link = url
.replace("{{current_version}}", &self.current_version.to_string())
.replace("{{target}}", &target)
.replace("{{arch}}", arch);
let mut request = HttpRequestBuilder::new("GET", &fixed_link)?.headers(headers.clone());
if let Some(timeout) = self.timeout {
request = request.timeout(timeout);
}
let resp = ClientBuilder::new().build()?.send(request).await;
// If we got a success, we stop the loop
// and we set our remote_release variable
if let Ok(res) = resp {
let res = res.read().await?;
// got status code 2XX
if StatusCode::from_u16(res.status)
.map_err(|e| Error::Builder(e.to_string()))?
.is_success()
{
// if we got 204
if StatusCode::NO_CONTENT.as_u16() == res.status {
// return with `UpToDate` error
// we should catch on the client
return Err(Error::UpToDate);
};
// Convert the remote result to our local struct
let built_release = serde_json::from_value(res.data).map_err(Into::into);
// make sure all went well and the remote data is compatible
// with what we need locally
match built_release {
Ok(release) => {
last_error = None;
remote_release = Some(release);
break;
}
Err(err) => last_error = Some(err),
}
} // if status code is not 2XX we keep loopin' our urls
}
}
// Last error is cleaned on success -- shouldn't be triggered if
// we have a successful call
if let Some(error) = last_error {
return Err(error);
}
// Extracted remote metadata
let final_release = remote_release.ok_or(Error::ReleaseNotFound)?;
// is the announced version greater than our current one?
let should_update = if let Some(comparator) = self.should_install.take() {
comparator(&self.current_version, &final_release)
} else {
final_release.version() > &self.current_version
};
headers.remove("Accept");
// create our new updater
Ok(Update {
app: self.app,
target,
extract_path,
should_update,
version: final_release.version().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(),
signature: final_release.signature(&json_target)?.to_owned(),
#[cfg(target_os = "windows")]
with_elevated_task: final_release.with_elevated_task(&json_target)?,
timeout: self.timeout,
headers,
})
}
sourcepub fn download_url(&self, target: &str) -> Result<&Url, Error>
pub fn download_url(&self, target: &str) -> Result<&Url, Error>
The release’s download URL for the given target.
Examples found in repository?
src/updater/core.rs (line 441)
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
pub async fn build(mut self) -> Result<Update<R>> {
let mut remote_release: Option<RemoteRelease> = None;
// make sure we have at least one url
if self.urls.is_empty() {
return Err(Error::Builder(
"Unable to check update, `url` is required.".into(),
));
};
// If no executable path provided, we use current_exe from tauri_utils
let executable_path = self.executable_path.unwrap_or(current_exe()?);
let arch = get_updater_arch().ok_or(Error::UnsupportedArch)?;
// `target` is the `{{target}}` variable we replace in the endpoint
// `json_target` is the value we search if the updater server returns a JSON with the `platforms` object
let (target, json_target) = if let Some(target) = self.target {
(target.clone(), target)
} else {
let target = get_updater_target().ok_or(Error::UnsupportedOs)?;
(target.to_string(), format!("{}-{}", target, arch))
};
// Get the extract_path from the provided executable_path
let extract_path = extract_path_from_executable(&self.app.state::<Env>(), &executable_path);
// Set SSL certs for linux if they aren't available.
// We do not require to recheck in the download_and_install as we use
// ENV variables, we can expect them to be set for the second call.
#[cfg(target_os = "linux")]
{
if env::var_os("SSL_CERT_FILE").is_none() {
env::set_var("SSL_CERT_FILE", "/etc/ssl/certs/ca-certificates.crt");
}
if env::var_os("SSL_CERT_DIR").is_none() {
env::set_var("SSL_CERT_DIR", "/etc/ssl/certs");
}
}
// we want JSON only
let mut headers = self.headers;
headers.insert("Accept", HeaderValue::from_str("application/json").unwrap());
// Allow fallback if more than 1 urls is provided
let mut last_error: Option<Error> = None;
for url in &self.urls {
// replace {{current_version}}, {{target}} and {{arch}} in the provided URL
// this is useful if we need to query example
// https://releases.myapp.com/update/{{target}}/{{arch}}/{{current_version}}
// will be translated into ->
// https://releases.myapp.com/update/darwin/aarch64/1.0.0
// The main objective is if the update URL is defined via the Cargo.toml
// the URL will be generated dynamically
let fixed_link = url
.replace("{{current_version}}", &self.current_version.to_string())
.replace("{{target}}", &target)
.replace("{{arch}}", arch);
let mut request = HttpRequestBuilder::new("GET", &fixed_link)?.headers(headers.clone());
if let Some(timeout) = self.timeout {
request = request.timeout(timeout);
}
let resp = ClientBuilder::new().build()?.send(request).await;
// If we got a success, we stop the loop
// and we set our remote_release variable
if let Ok(res) = resp {
let res = res.read().await?;
// got status code 2XX
if StatusCode::from_u16(res.status)
.map_err(|e| Error::Builder(e.to_string()))?
.is_success()
{
// if we got 204
if StatusCode::NO_CONTENT.as_u16() == res.status {
// return with `UpToDate` error
// we should catch on the client
return Err(Error::UpToDate);
};
// Convert the remote result to our local struct
let built_release = serde_json::from_value(res.data).map_err(Into::into);
// make sure all went well and the remote data is compatible
// with what we need locally
match built_release {
Ok(release) => {
last_error = None;
remote_release = Some(release);
break;
}
Err(err) => last_error = Some(err),
}
} // if status code is not 2XX we keep loopin' our urls
}
}
// Last error is cleaned on success -- shouldn't be triggered if
// we have a successful call
if let Some(error) = last_error {
return Err(error);
}
// Extracted remote metadata
let final_release = remote_release.ok_or(Error::ReleaseNotFound)?;
// is the announced version greater than our current one?
let should_update = if let Some(comparator) = self.should_install.take() {
comparator(&self.current_version, &final_release)
} else {
final_release.version() > &self.current_version
};
headers.remove("Accept");
// create our new updater
Ok(Update {
app: self.app,
target,
extract_path,
should_update,
version: final_release.version().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(),
signature: final_release.signature(&json_target)?.to_owned(),
#[cfg(target_os = "windows")]
with_elevated_task: final_release.with_elevated_task(&json_target)?,
timeout: self.timeout,
headers,
})
}
sourcepub fn signature(&self, target: &str) -> Result<&String, Error>
pub fn signature(&self, target: &str) -> Result<&String, Error>
The release’s signature for the given target.
Examples found in repository?
src/updater/core.rs (line 443)
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
pub async fn build(mut self) -> Result<Update<R>> {
let mut remote_release: Option<RemoteRelease> = None;
// make sure we have at least one url
if self.urls.is_empty() {
return Err(Error::Builder(
"Unable to check update, `url` is required.".into(),
));
};
// If no executable path provided, we use current_exe from tauri_utils
let executable_path = self.executable_path.unwrap_or(current_exe()?);
let arch = get_updater_arch().ok_or(Error::UnsupportedArch)?;
// `target` is the `{{target}}` variable we replace in the endpoint
// `json_target` is the value we search if the updater server returns a JSON with the `platforms` object
let (target, json_target) = if let Some(target) = self.target {
(target.clone(), target)
} else {
let target = get_updater_target().ok_or(Error::UnsupportedOs)?;
(target.to_string(), format!("{}-{}", target, arch))
};
// Get the extract_path from the provided executable_path
let extract_path = extract_path_from_executable(&self.app.state::<Env>(), &executable_path);
// Set SSL certs for linux if they aren't available.
// We do not require to recheck in the download_and_install as we use
// ENV variables, we can expect them to be set for the second call.
#[cfg(target_os = "linux")]
{
if env::var_os("SSL_CERT_FILE").is_none() {
env::set_var("SSL_CERT_FILE", "/etc/ssl/certs/ca-certificates.crt");
}
if env::var_os("SSL_CERT_DIR").is_none() {
env::set_var("SSL_CERT_DIR", "/etc/ssl/certs");
}
}
// we want JSON only
let mut headers = self.headers;
headers.insert("Accept", HeaderValue::from_str("application/json").unwrap());
// Allow fallback if more than 1 urls is provided
let mut last_error: Option<Error> = None;
for url in &self.urls {
// replace {{current_version}}, {{target}} and {{arch}} in the provided URL
// this is useful if we need to query example
// https://releases.myapp.com/update/{{target}}/{{arch}}/{{current_version}}
// will be translated into ->
// https://releases.myapp.com/update/darwin/aarch64/1.0.0
// The main objective is if the update URL is defined via the Cargo.toml
// the URL will be generated dynamically
let fixed_link = url
.replace("{{current_version}}", &self.current_version.to_string())
.replace("{{target}}", &target)
.replace("{{arch}}", arch);
let mut request = HttpRequestBuilder::new("GET", &fixed_link)?.headers(headers.clone());
if let Some(timeout) = self.timeout {
request = request.timeout(timeout);
}
let resp = ClientBuilder::new().build()?.send(request).await;
// If we got a success, we stop the loop
// and we set our remote_release variable
if let Ok(res) = resp {
let res = res.read().await?;
// got status code 2XX
if StatusCode::from_u16(res.status)
.map_err(|e| Error::Builder(e.to_string()))?
.is_success()
{
// if we got 204
if StatusCode::NO_CONTENT.as_u16() == res.status {
// return with `UpToDate` error
// we should catch on the client
return Err(Error::UpToDate);
};
// Convert the remote result to our local struct
let built_release = serde_json::from_value(res.data).map_err(Into::into);
// make sure all went well and the remote data is compatible
// with what we need locally
match built_release {
Ok(release) => {
last_error = None;
remote_release = Some(release);
break;
}
Err(err) => last_error = Some(err),
}
} // if status code is not 2XX we keep loopin' our urls
}
}
// Last error is cleaned on success -- shouldn't be triggered if
// we have a successful call
if let Some(error) = last_error {
return Err(error);
}
// Extracted remote metadata
let final_release = remote_release.ok_or(Error::ReleaseNotFound)?;
// is the announced version greater than our current one?
let should_update = if let Some(comparator) = self.should_install.take() {
comparator(&self.current_version, &final_release)
} else {
final_release.version() > &self.current_version
};
headers.remove("Accept");
// create our new updater
Ok(Update {
app: self.app,
target,
extract_path,
should_update,
version: final_release.version().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(),
signature: final_release.signature(&json_target)?.to_owned(),
#[cfg(target_os = "windows")]
with_elevated_task: final_release.with_elevated_task(&json_target)?,
timeout: self.timeout,
headers,
})
}
sourcepub fn with_elevated_task(&self, target: &str) -> Result<bool, Error>
pub fn with_elevated_task(&self, target: &str) -> Result<bool, Error>
Optional: Windows only try to use elevated task
Examples found in repository?
src/updater/core.rs (line 445)
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
pub async fn build(mut self) -> Result<Update<R>> {
let mut remote_release: Option<RemoteRelease> = None;
// make sure we have at least one url
if self.urls.is_empty() {
return Err(Error::Builder(
"Unable to check update, `url` is required.".into(),
));
};
// If no executable path provided, we use current_exe from tauri_utils
let executable_path = self.executable_path.unwrap_or(current_exe()?);
let arch = get_updater_arch().ok_or(Error::UnsupportedArch)?;
// `target` is the `{{target}}` variable we replace in the endpoint
// `json_target` is the value we search if the updater server returns a JSON with the `platforms` object
let (target, json_target) = if let Some(target) = self.target {
(target.clone(), target)
} else {
let target = get_updater_target().ok_or(Error::UnsupportedOs)?;
(target.to_string(), format!("{}-{}", target, arch))
};
// Get the extract_path from the provided executable_path
let extract_path = extract_path_from_executable(&self.app.state::<Env>(), &executable_path);
// Set SSL certs for linux if they aren't available.
// We do not require to recheck in the download_and_install as we use
// ENV variables, we can expect them to be set for the second call.
#[cfg(target_os = "linux")]
{
if env::var_os("SSL_CERT_FILE").is_none() {
env::set_var("SSL_CERT_FILE", "/etc/ssl/certs/ca-certificates.crt");
}
if env::var_os("SSL_CERT_DIR").is_none() {
env::set_var("SSL_CERT_DIR", "/etc/ssl/certs");
}
}
// we want JSON only
let mut headers = self.headers;
headers.insert("Accept", HeaderValue::from_str("application/json").unwrap());
// Allow fallback if more than 1 urls is provided
let mut last_error: Option<Error> = None;
for url in &self.urls {
// replace {{current_version}}, {{target}} and {{arch}} in the provided URL
// this is useful if we need to query example
// https://releases.myapp.com/update/{{target}}/{{arch}}/{{current_version}}
// will be translated into ->
// https://releases.myapp.com/update/darwin/aarch64/1.0.0
// The main objective is if the update URL is defined via the Cargo.toml
// the URL will be generated dynamically
let fixed_link = url
.replace("{{current_version}}", &self.current_version.to_string())
.replace("{{target}}", &target)
.replace("{{arch}}", arch);
let mut request = HttpRequestBuilder::new("GET", &fixed_link)?.headers(headers.clone());
if let Some(timeout) = self.timeout {
request = request.timeout(timeout);
}
let resp = ClientBuilder::new().build()?.send(request).await;
// If we got a success, we stop the loop
// and we set our remote_release variable
if let Ok(res) = resp {
let res = res.read().await?;
// got status code 2XX
if StatusCode::from_u16(res.status)
.map_err(|e| Error::Builder(e.to_string()))?
.is_success()
{
// if we got 204
if StatusCode::NO_CONTENT.as_u16() == res.status {
// return with `UpToDate` error
// we should catch on the client
return Err(Error::UpToDate);
};
// Convert the remote result to our local struct
let built_release = serde_json::from_value(res.data).map_err(Into::into);
// make sure all went well and the remote data is compatible
// with what we need locally
match built_release {
Ok(release) => {
last_error = None;
remote_release = Some(release);
break;
}
Err(err) => last_error = Some(err),
}
} // if status code is not 2XX we keep loopin' our urls
}
}
// Last error is cleaned on success -- shouldn't be triggered if
// we have a successful call
if let Some(error) = last_error {
return Err(error);
}
// Extracted remote metadata
let final_release = remote_release.ok_or(Error::ReleaseNotFound)?;
// is the announced version greater than our current one?
let should_update = if let Some(comparator) = self.should_install.take() {
comparator(&self.current_version, &final_release)
} else {
final_release.version() > &self.current_version
};
headers.remove("Accept");
// create our new updater
Ok(Update {
app: self.app,
target,
extract_path,
should_update,
version: final_release.version().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(),
signature: final_release.signature(&json_target)?.to_owned(),
#[cfg(target_os = "windows")]
with_elevated_task: final_release.with_elevated_task(&json_target)?,
timeout: self.timeout,
headers,
})
}
Trait Implementations§
source§impl Debug for RemoteRelease
impl Debug for RemoteRelease
source§impl<'de> Deserialize<'de> for RemoteRelease
impl<'de> Deserialize<'de> for RemoteRelease
source§fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
Deserialize this value from the given Serde deserializer. Read more