Skip to content

Commit

Permalink
Merge pull request #28 from axodotdev/mix_sync_async_apis
Browse files Browse the repository at this point in the history
feat: use async APIs by default
  • Loading branch information
mistydemeo authored Mar 6, 2024
2 parents ae4715d + 70fdce4 commit 78e016c
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 32 deletions.
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,25 @@ axoupdater can also be used as a library within your own applications in order t
To check for updates and notify the user:

```rust
if AxoUpdater::new_for("axolotlsay").load_receipt()?.is_update_needed()? {
if AxoUpdater::new_for("axolotlsay").load_receipt()?.is_update_needed_sync()? {
eprintln!("axolotlsay is outdated; please upgrade!");
}
```

To automatically perform an update if the program isn't up to date:

```rust
if AxoUpdater::new_for("axolotlsay").load_receipt()?.run()? {
if AxoUpdater::new_for("axolotlsay").load_receipt()?.run_sync()? {
eprintln!("Update installed!");
} else {
eprintln!("axolotlsay already up to date");
}
```

Asynchronous versions of `is_update_needed()` and `run()` are also provided:

```rust
if AxoUpdater::new_for("axolotlsay").load_receipt()?.run().await? {
eprintln!("Update installed!");
} else {
eprintln!("axolotlsay already up to date");
Expand All @@ -47,7 +57,7 @@ To build as a standalone binary, follow these steps:

Licensed under either of

* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or [apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0))
* MIT license ([LICENSE-MIT](LICENSE-MIT) or [opensource.org/licenses/MIT](https://opensource.org/licenses/MIT))
- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or [apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0))
- MIT license ([LICENSE-MIT](LICENSE-MIT) or [opensource.org/licenses/MIT](https://opensource.org/licenses/MIT))

at your option.
2 changes: 1 addition & 1 deletion axoupdater-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ readme = "../README.md"

[dependencies]
axocli = "0.2.0"
axoupdater = { version = "=0.1.0", path = "../axoupdater" }
axoupdater = { version = "=0.1.0", path = "../axoupdater", features = ["blocking"] }

# errors
miette = "7.1.0"
Expand Down
2 changes: 1 addition & 1 deletion axoupdater-cli/src/bin/axoupdater/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fn real_main(_cli: &CliApp<CliArgs>) -> Result<(), miette::Report> {

if AxoUpdater::new_for_updater_executable()?
.load_receipt()?
.run()?
.run_sync()?
{
eprintln!("New release installed!")
} else {
Expand Down
2 changes: 1 addition & 1 deletion axoupdater/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ path = "src/lib.rs"
[features]
default = ["axo_releases", "github_releases"]
axo_releases = ["gazenot", "tokio"]
blocking = ["tokio"]
github_releases = ["reqwest"]

[dependencies]
Expand All @@ -35,7 +36,6 @@ tokio = { version = "1.36.0", features = ["full"], optional = true }

# github releases
reqwest = { version = "0.11", default-features = false, features = [
"blocking",
"rustls-tls",
"json",
], optional = true }
Expand Down
79 changes: 54 additions & 25 deletions axoupdater/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ impl AxoUpdater {
/// This can only be performed if the `current_version` field has been
/// set, either by loading the install receipt or by specifying it using
/// `set_current_version`.
pub fn is_update_needed(&mut self) -> AxoupdateResult<bool> {
pub async fn is_update_needed(&mut self) -> AxoupdateResult<bool> {
let Some(current_version) = self.current_version.to_owned() else {
return Err(AxoupdateError::NotConfigured {
missing_field: "current_version".to_owned(),
Expand All @@ -128,27 +128,38 @@ impl AxoUpdater {
let release = match &self.latest_release {
Some(r) => r,
None => {
self.fetch_latest_release()?;
self.fetch_latest_release().await?;
self.latest_release.as_ref().unwrap()
}
};

Ok(current_version != release.version())
}

/// Identical to Axoupdater::is_update_needed(), but performed synchronously.
pub fn is_update_needed_sync(&mut self) -> AxoupdateResult<bool> {
tokio::runtime::Builder::new_current_thread()
.worker_threads(1)
.max_blocking_threads(128)
.enable_all()
.build()
.expect("Initializing tokio runtime failed")
.block_on(self.is_update_needed())
}

/// Attempts to perform an update. The return value specifies whether an
/// update was actually performed or not; false indicates "no update was
/// needed", while an error indicates that an update couldn't be performed
/// due to an error.
pub fn run(&mut self) -> AxoupdateResult<bool> {
if !self.is_update_needed()? {
pub async fn run(&mut self) -> AxoupdateResult<bool> {
if !self.is_update_needed().await? {
return Ok(false);
}

let release = match &self.latest_release {
Some(r) => r,
None => {
self.fetch_latest_release()?;
self.fetch_latest_release().await?;
self.latest_release.as_ref().unwrap()
}
};
Expand Down Expand Up @@ -184,12 +195,14 @@ impl AxoUpdater {
installer_file.set_permissions(perms)?;
}

let client = reqwest::blocking::Client::new();
let client = reqwest::Client::new();
let download = client
.get(&installer_url.browser_download_url)
.header(ACCEPT, "application/octet-stream")
.send()?
.text()?;
.send()
.await?
.text()
.await?;

LocalAsset::write_new_all(&download, &installer_path)?;

Expand All @@ -207,7 +220,18 @@ impl AxoUpdater {
Ok(true)
}

fn fetch_latest_release(&mut self) -> AxoupdateResult<()> {
/// Identical to Axoupdater::run(), but performed synchronously.
pub fn run_sync(&mut self) -> AxoupdateResult<bool> {
tokio::runtime::Builder::new_current_thread()
.worker_threads(1)
.max_blocking_threads(128)
.enable_all()
.build()
.expect("Initializing tokio runtime failed")
.block_on(self.run())
}

async fn fetch_latest_release(&mut self) -> AxoupdateResult<()> {
let Some(app_name) = &self.name else {
return Err(AxoupdateError::NotConfigured {
missing_field: "app_name".to_owned(),
Expand All @@ -224,7 +248,8 @@ impl AxoUpdater {
&source.owner,
&source.app_name,
&source.release_type,
)?
)
.await?
else {
return Err(AxoupdateError::NoStableReleases {
app_name: app_name.to_owned(),
Expand Down Expand Up @@ -451,17 +476,23 @@ pub struct InstallReceipt {
}

#[cfg(feature = "github_releases")]
fn get_github_releases(name: &str, owner: &str, app_name: &str) -> AxoupdateResult<Vec<Release>> {
let client = reqwest::blocking::Client::new();
async fn get_github_releases(
name: &str,
owner: &str,
app_name: &str,
) -> AxoupdateResult<Vec<Release>> {
let client = reqwest::Client::new();
let resp: Vec<Release> = client
.get(format!("{GITHUB_API}/repos/{owner}/{name}/releases"))
.header(ACCEPT, "application/json")
.header(
USER_AGENT,
format!("axoupdate/{}", env!("CARGO_PKG_VERSION")),
)
.send()?
.json()?;
.send()
.await?
.json()
.await?;

Ok(resp
.into_iter()
Expand All @@ -474,15 +505,13 @@ fn get_github_releases(name: &str, owner: &str, app_name: &str) -> AxoupdateResu
}

#[cfg(feature = "axo_releases")]
fn get_axo_releases(name: &str, owner: &str, app_name: &str) -> AxoupdateResult<Vec<Release>> {
async fn get_axo_releases(
name: &str,
owner: &str,
app_name: &str,
) -> AxoupdateResult<Vec<Release>> {
let abyss = Gazenot::new_unauthed("github".to_string(), owner)?;
let release_lists = tokio::runtime::Builder::new_current_thread()
.worker_threads(1)
.max_blocking_threads(128)
.enable_all()
.build()
.expect("Initializing tokio runtime failed")
.block_on(abyss.list_releases_many(vec![app_name.to_owned()]))?;
let release_lists = abyss.list_releases_many(vec![app_name.to_owned()]).await?;
let Some(our_release) = release_lists.iter().find(|rl| rl.package_name == app_name) else {
return Err(AxoupdateError::ReleaseNotFound {
name: name.to_owned(),
Expand All @@ -501,23 +530,23 @@ fn get_axo_releases(name: &str, owner: &str, app_name: &str) -> AxoupdateResult<
Ok(releases)
}

fn get_latest_stable_release(
async fn get_latest_stable_release(
name: &str,
owner: &str,
app_name: &str,
release_type: &ReleaseSourceType,
) -> AxoupdateResult<Option<Release>> {
let releases = match release_type {
#[cfg(feature = "github_releases")]
ReleaseSourceType::GitHub => get_github_releases(name, owner, app_name)?,
ReleaseSourceType::GitHub => get_github_releases(name, owner, app_name).await?,
#[cfg(not(feature = "github_releases"))]
ReleaseSourceType::GitHub => {
return Err(AxoupdateError::BackendDisabled {
backend: "github".to_owned(),
})
}
#[cfg(feature = "axo_releases")]
ReleaseSourceType::Axo => get_axo_releases(name, owner, app_name)?,
ReleaseSourceType::Axo => get_axo_releases(name, owner, app_name).await?,
#[cfg(not(feature = "axo_releases"))]
ReleaseSourceType::Axo => {
return Err(AxoupdateError::BackendDisabled {
Expand Down

0 comments on commit 78e016c

Please sign in to comment.