about summary refs log tree commit diff stats
path: root/pkgs/by-name/ge/generate_moz_extension/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/by-name/ge/generate_moz_extension/src/main.rs')
-rw-r--r--pkgs/by-name/ge/generate_moz_extension/src/main.rs138
1 files changed, 138 insertions, 0 deletions
diff --git a/pkgs/by-name/ge/generate_moz_extension/src/main.rs b/pkgs/by-name/ge/generate_moz_extension/src/main.rs
new file mode 100644
index 00000000..bde986a3
--- /dev/null
+++ b/pkgs/by-name/ge/generate_moz_extension/src/main.rs
@@ -0,0 +1,138 @@
+use std::env::args;
+
+use anyhow::{bail, Context};
+use futures::StreamExt;
+use reqwest::Client;
+use serde_json::{json, Map, Value};
+
+pub mod types;
+
+macro_rules! get_json_value {
+    ($key:expr, $json_value:ident, $type:ident, $get:ident) => {
+        match $json_value.get($key) {
+            Some(resp) => {
+                let resp = resp.to_owned();
+                if resp.$type() {
+                    resp.$get().expect(
+                        "The should have been checked in the if guard, so unpacking here is fine",
+                    ).to_owned()
+                } else {
+                    bail!(
+                        "Value {} => \n{}\n is not of type: {}",
+                        $key,
+                        resp,
+                        stringify!($type)
+                    );
+                }
+            }
+            None => {
+                bail!(
+                    "There seems to be no '{}' in your json data (json value: '{}')\n Has the api changend?",
+                    $key, serde_json::to_string_pretty(&$json_value).expect("Will always work")
+                );
+            }
+        }
+    };
+}
+
+use futures::stream::futures_unordered::FuturesUnordered;
+use types::{Extension, InputExtension};
+
+#[tokio::main]
+async fn main() -> anyhow::Result<()> {
+    let mut extensions: Vec<InputExtension> = vec![];
+    for input_extension in args()
+        .skip(1)
+        .map(|str| InputExtension::try_from(str))
+        .collect::<Vec<anyhow::Result<InputExtension>>>()
+    {
+        extensions.push(input_extension?);
+    }
+
+    let resulting_extensions = process_extensions(extensions).await?;
+
+    let mut output = Map::new();
+    for extension in resulting_extensions {
+        output.insert(extension.pname.clone(), json!(extension));
+    }
+
+    println!(
+        "{}",
+        serde_json::to_string_pretty(&serde_json::Value::Object(output)).expect(
+            "This is constructed from json, it should also be possible to serialize it again"
+        )
+    );
+    Ok(())
+}
+
+async fn process_extensions(extensions: Vec<InputExtension>) -> anyhow::Result<Vec<Extension>> {
+    let mut output = Vec::with_capacity(extensions.len());
+
+    let client = Client::new();
+    for extension in extensions
+        .iter()
+        .map(|ext| {
+            let local_client = &client;
+            index_extension(ext, local_client)
+        })
+        .collect::<FuturesUnordered<_>>()
+        .collect::<Vec<_>>()
+        .await
+    {
+        output.push(extension?);
+    }
+    Ok(output)
+}
+
+async fn index_extension(extension: &InputExtension, client: &Client) -> anyhow::Result<Extension> {
+    let response = client
+        .get(format!(
+            "https://addons.mozilla.org/api/v5/addons/addon/{}",
+            extension,
+        ))
+        .send()
+        .await
+        .context("Accessing the mozzila extenios api failed with error: {e}")?;
+
+    eprintln!("Indexing {} ({})...", extension, response.status());
+    let response: Value = serde_json::from_str(
+        &response
+            .text()
+            .await
+            .context("Turning the response to text fail with error: {e}")?,
+    )
+    .context("Deserializing the response failed! Error: {e}")?;
+
+    if let Some(detail) = response.get("detail") {
+        if detail == "Not found." {
+            bail!("Your extension ('{}') was not found!", extension);
+        }
+    };
+
+    let release = { get_json_value!("current_version", response, is_object, as_object) };
+
+    #[allow(non_snake_case)]
+    let addonId = { get_json_value!("guid", response, is_string, as_str) };
+
+    let version = { get_json_value!("version", release, is_string, as_str) };
+    let file = { get_json_value!("file", release, is_object, as_object) };
+
+    let url = { get_json_value!("url", file, is_string, as_str) };
+    let sha256 = {
+        let hash = get_json_value!("hash", file, is_string, as_str);
+        if hash.starts_with("sha256:") {
+            hash
+        } else {
+            bail!("This hash type is unhandled: {}", hash);
+        }
+    };
+
+    Ok(Extension {
+        pname: extension.moz_name.clone(),
+        default_area: extension.default_area,
+        version,
+        addonId,
+        url,
+        sha256,
+    })
+}