eager_package_config/
pkg_resolver.rsuse fuchsia_url::UnpinnedAbsolutePackageUrl;
use omaha_client::cup_ecdsa::PublicKeys;
use omaha_client::version::Version;
use serde::{Deserialize, Serialize};
#[cfg(target_os = "fuchsia")]
use {fidl_fuchsia_io as fio, futures::stream::StreamExt as _, std::collections::HashSet};
#[cfg(target_os = "fuchsia")]
const EAGER_PACKAGE_CONFIG_PATH: &str = "/config/data/eager_package_config.json";
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct EagerPackageConfigs {
pub packages: Vec<EagerPackageConfig>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct EagerPackageConfig {
pub url: UnpinnedAbsolutePackageUrl,
#[serde(default, skip_serializing_if = "is_false")]
pub executable: bool,
pub public_keys: PublicKeys,
pub minimum_required_version: Version,
#[serde(default = "return_true", skip_serializing_if = "bool::clone")]
pub cache_fallback: bool,
}
#[cfg(target_os = "fuchsia")]
impl EagerPackageConfigs {
pub async fn from_namespace() -> Result<Self, EagerPackageConfigsError> {
Self::from_path(EAGER_PACKAGE_CONFIG_PATH).await
}
async fn from_path(path: &str) -> Result<Self, EagerPackageConfigsError> {
let proxy = fuchsia_fs::file::open_in_namespace(
path,
fio::PERM_READABLE | fio::Flags::FLAG_SEND_REPRESENTATION,
)
.map_err(EagerPackageConfigsError::Open)?;
match fuchsia_fs::file::read(&proxy).await {
Ok(json) => Self::from_json(&json),
Err(e) => {
match proxy.take_event_stream().next().await {
Some(Ok(fio::FileEvent::OnOpen_ { s, .. }))
if s == zx::Status::NOT_FOUND.into_raw() =>
{
Ok(EagerPackageConfigs { packages: Vec::new() })
}
Some(Err(fidl::Error::ClientChannelClosed { status, .. }))
if status == zx::Status::NOT_FOUND =>
{
Ok(EagerPackageConfigs { packages: Vec::new() })
}
_ => Err(EagerPackageConfigsError::Read(e)),
}
}
}
}
fn from_json(json: &[u8]) -> Result<Self, EagerPackageConfigsError> {
let configs: Self = serde_json::from_slice(json)?;
if configs.packages.iter().map(|config| config.url.path()).collect::<HashSet<_>>().len()
< configs.packages.len()
{
return Err(EagerPackageConfigsError::DuplicatePath);
}
Ok(configs)
}
}
#[cfg(target_os = "fuchsia")]
#[derive(Debug, thiserror::Error)]
pub enum EagerPackageConfigsError {
#[error("open eager package config")]
Open(#[from] fuchsia_fs::node::OpenError),
#[error("read eager package config")]
Read(#[from] fuchsia_fs::file::ReadError),
#[error("parse eager package config from json")]
Json(#[from] serde_json::Error),
#[error("eager package URL must have unique path")]
DuplicatePath,
}
fn return_true() -> bool {
true
}
fn is_false(b: &bool) -> bool {
!b
}
#[cfg(test)]
mod tests {
use super::*;
use assert_matches::assert_matches;
use fuchsia_async as fasync;
use omaha_client::cup_ecdsa::test_support::{
make_default_json_public_keys_for_test, make_default_public_keys_for_test,
};
#[fasync::run_singlethreaded(test)]
async fn not_found_tmp() {
let configs = EagerPackageConfigs::from_path("/tmp/not-found").await.unwrap();
assert_eq!(configs.packages, vec![]);
}
#[fasync::run_singlethreaded(test)]
async fn not_found_pkg() {
let configs = EagerPackageConfigs::from_path("/pkg/not-found").await.unwrap();
assert_eq!(configs.packages, vec![]);
}
#[fasync::run_singlethreaded(test)]
async fn success() {
let json = serde_json::json!({
"packages":[
{
"url": "fuchsia-pkg://example.com/package_service_1",
"public_keys": make_default_json_public_keys_for_test(),
"minimum_required_version": "1.2.3.4"
}
]
});
assert_eq!(
EagerPackageConfigs::from_json(json.to_string().as_bytes()).unwrap(),
EagerPackageConfigs {
packages: vec![EagerPackageConfig {
url: "fuchsia-pkg://example.com/package_service_1".parse().unwrap(),
executable: false,
public_keys: make_default_public_keys_for_test(),
minimum_required_version: [1, 2, 3, 4].into(),
cache_fallback: true,
}]
}
);
}
#[fasync::run_singlethreaded(test)]
async fn duplicate_path() {
let json = serde_json::json!({
"packages":[
{
"url": "fuchsia-pkg://example.com/package_service_1",
"public_keys": make_default_json_public_keys_for_test(),
"minimum_required_version": "1.2.3.4"
},
{
"url": "fuchsia-pkg://another-example.com/package_service_1",
"public_keys": make_default_json_public_keys_for_test(),
"minimum_required_version": "1.2.3.4"
}
]
});
assert_matches!(
EagerPackageConfigs::from_json(json.to_string().as_bytes()),
Err(EagerPackageConfigsError::DuplicatePath)
);
}
}