oxide_cli/addons/
install.rs1use std::path::Path;
2
3use anyhow::Result;
4use serde::Deserialize;
5
6use crate::{
7 AppContext, BACKEND_URL,
8 auth::token::get_auth_user,
9 utils::archive::download_and_extract,
10};
11
12use super::{
13 cache::{get_cached_addon, update_addons_cache},
14 manifest::AddonManifest,
15};
16
17#[derive(Deserialize)]
18struct AddonUrlResponse {
19 archive_url: String,
20 commit_sha: String,
21}
22
23async fn get_addon_url(ctx: &AppContext, addon_id: &str) -> Result<AddonUrlResponse> {
24 let user = get_auth_user(&ctx.paths.auth)?;
25
26 let res: AddonUrlResponse = ctx
27 .client
28 .get(format!("{BACKEND_URL}/addon/{addon_id}/url"))
29 .bearer_auth(user.token)
30 .header("Content-Type", "application/json")
31 .send()
32 .await?
33 .error_for_status()?
34 .json()
35 .await?;
36
37 Ok(res)
38}
39
40pub async fn install_addon(ctx: &AppContext, addon_id: &str) -> Result<AddonManifest> {
41 let info = get_addon_url(ctx, addon_id).await?;
42
43 let dest = ctx.paths.addons.join(addon_id);
44
45 if let Some(cached) = get_cached_addon(&ctx.paths.addons, addon_id)?
47 && cached.commit_sha == info.commit_sha
48 && dest.exists()
49 {
50 let manifest_path = dest.join("oxide.addon.json");
51 let content = std::fs::read_to_string(&manifest_path)?;
52 let manifest: AddonManifest = serde_json::from_str(&content)?;
53 println!("Addon '{}' is already up to date", addon_id);
54 return Ok(manifest);
55 }
56
57 {
58 let mut guard = ctx.cleanup_state.lock().unwrap_or_else(|e| e.into_inner());
59 *guard = Some(dest.clone());
60 }
61
62 download_and_extract(&ctx.client, &info.archive_url, &dest, None).await?;
63
64 {
65 let mut guard = ctx.cleanup_state.lock().unwrap_or_else(|e| e.into_inner());
66 *guard = None;
67 }
68
69 let manifest_path = dest.join("oxide.addon.json");
70 let content = std::fs::read_to_string(&manifest_path)?;
71 let manifest: AddonManifest = serde_json::from_str(&content)?;
72
73 update_addons_cache(&ctx.paths.addons, addon_id, &manifest, &info.commit_sha)?;
74 println!("Addon '{}' successfully downloaded", addon_id);
75
76 Ok(manifest)
77}
78
79pub fn read_cached_manifest(addons_dir: &Path, addon_id: &str) -> Result<AddonManifest> {
80 let manifest_path = addons_dir.join(addon_id).join("oxide.addon.json");
81 let content = std::fs::read_to_string(&manifest_path)?;
82 Ok(serde_json::from_str(&content)?)
83}