use std::env;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use protobuf_codegen::Customize;
const UPROTOCOL_BASE_URI: &str =
"https://raw.githubusercontent.com/eclipse-uprotocol/up-spec/v1.6.0-alpha.2/up-core-api/";
const UPROTOCOL_REL_PATH: &str = "uprotocol/";
fn main() -> Result<(), Box<dyn std::error::Error>> {
get_and_build_protos(
&[
format!("{}{}uoptions.proto", UPROTOCOL_BASE_URI, UPROTOCOL_REL_PATH).as_str(),
format!("{}{}v1/uuid.proto", UPROTOCOL_BASE_URI, UPROTOCOL_REL_PATH).as_str(),
format!("{}{}v1/uri.proto", UPROTOCOL_BASE_URI, UPROTOCOL_REL_PATH).as_str(),
format!(
"{}{}v1/uattributes.proto",
UPROTOCOL_BASE_URI, UPROTOCOL_REL_PATH
)
.as_str(),
format!("{}{}v1/ucode.proto", UPROTOCOL_BASE_URI, UPROTOCOL_REL_PATH).as_str(),
format!(
"{}{}v1/umessage.proto",
UPROTOCOL_BASE_URI, UPROTOCOL_REL_PATH
)
.as_str(),
format!(
"{}{}v1/ustatus.proto",
UPROTOCOL_BASE_URI, UPROTOCOL_REL_PATH
)
.as_str(),
format!("{}{}v1/file.proto", UPROTOCOL_BASE_URI, UPROTOCOL_REL_PATH).as_str(),
#[cfg(feature = "udiscovery")]
format!(
"{}{}core/udiscovery/v3/udiscovery.proto",
UPROTOCOL_BASE_URI, UPROTOCOL_REL_PATH
)
.as_str(),
#[cfg(feature = "usubscription")]
format!(
"{}{}core/usubscription/v3/usubscription.proto",
UPROTOCOL_BASE_URI, UPROTOCOL_REL_PATH
)
.as_str(),
#[cfg(feature = "utwin")]
format!(
"{}{}core/utwin/v2/utwin.proto",
UPROTOCOL_BASE_URI, UPROTOCOL_REL_PATH
)
.as_str(),
],
"uprotocol",
)
.map_err(|e| {
println!(
"failed to generate types from uProtocol proto3 definitions: {}",
e
);
e
})
}
fn get_and_build_protos(
urls: &[&str],
output_folder: &str,
) -> core::result::Result<(), Box<dyn std::error::Error>> {
let out_dir = env::var_os("OUT_DIR").unwrap();
let proto_folder = Path::new(&out_dir).join("proto");
let mut proto_files = Vec::new();
for url in urls {
let filename = url.strip_prefix(UPROTOCOL_BASE_URI).unwrap_or_default();
let dest_path = proto_folder.join(filename);
download_and_write_file(url, &dest_path)?;
proto_files.push(dest_path);
}
protobuf_codegen::Codegen::new()
.protoc()
.protoc_path(&protoc_bin_vendored::protoc_bin_path().unwrap())
.customize(Customize::default().tokio_bytes(true))
.include(proto_folder)
.inputs(proto_files)
.cargo_out_dir(output_folder)
.run_from_script();
Ok(())
}
fn download_and_write_file(
url: &str,
dest_path: &PathBuf,
) -> core::result::Result<(), Box<dyn std::error::Error>> {
reqwest::blocking::get(url)
.map_err(Box::from)
.and_then(|mut response| {
if let Some(parent_path) = dest_path.parent() {
std::fs::create_dir_all(parent_path)?;
}
let mut out_file = fs::File::create(dest_path)?;
response
.copy_to(&mut out_file)
.map(|_| ())
.map_err(|e| e.to_string().into())
})
}