ecli_lib/runner/
helper.rs

1//!  SPDX-License-Identifier: MIT
2//!
3//! Copyright (c) 2023, eunomia-bpf
4//! All rights reserved.
5//!
6
7use anyhow::anyhow;
8use anyhow::Context;
9use bpf_oci::{
10    oci_distribution::{secrets::RegistryAuth, Reference},
11    pull_wasm_image,
12};
13use log::{debug, info};
14use std::path::PathBuf;
15
16use crate::{config::ProgramType, error::Error};
17
18/// Load the binary of the given url, and guess its program type
19/// If failed to guess, will just return None
20/// It will try the following order
21/// - Test if the provided string is a local file. If matches, read it
22/// - If the string is a URL, then treat it as a HTTP URL, and download it.
23/// - If the string is not an url, treat it as an OCI image tag
24pub async fn try_load_program_buf_and_guess_type(
25    url: impl AsRef<str>,
26) -> anyhow::Result<(Vec<u8>, Option<ProgramType>)> {
27    let url = url.as_ref();
28    // Is it a local path?
29    let path = PathBuf::from(url);
30    let (buf, prog_type) = if path.exists() && path.is_file() {
31        debug!("Read from local file: {}", url);
32        let buf = tokio::fs::read(path.as_path())
33            .await
34            .with_context(|| anyhow!("Failed to read local file: {}", url))?;
35        let prog_type = ProgramType::try_from(url).ok();
36
37        (buf, prog_type)
38    } else if let Ok(url) = url::Url::parse(url) {
39        debug!("URL parse ok");
40        debug!("Download from {:?}", url);
41        let resp = reqwest::get(url.clone()).await.map_err(|e| {
42            Error::Http(format!("Failed to send request to {}: {}", url.as_str(), e))
43        })?;
44        let data = resp.bytes().await.map_err(|e| {
45            Error::Http(format!(
46                "Failed to read response from {}: {}",
47                url.as_str(),
48                e
49            ))
50        })?;
51        let prog_type = match ProgramType::try_from(url.as_str()) {
52            Ok(v) => Some(v),
53            Err(e) => {
54                info!(
55                    "Failed to guess program type from `{}`: {}",
56                    url.as_str(),
57                    e
58                );
59                None
60            }
61        };
62
63        (data.to_vec(), prog_type)
64    } else {
65        debug!("Trying OCI tag: {}", url);
66        let image = Reference::try_from(url)
67            .with_context(|| anyhow!("Failed to parse `{}` into an OCI image reference", url))?;
68
69        let data = pull_wasm_image(&image, &RegistryAuth::Anonymous, None)
70            .await
71            .with_context(|| anyhow!("Failed to pull OCI image from `{}`", url))?;
72        (data, Some(ProgramType::WasmModule))
73    };
74    Ok((buf, prog_type))
75}