Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 56 additions & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ ic-ledger-types = "0.16.0"
ic-management-canister-types = { version = "0.9.0" }
ic-utils = { version = "0.49.1" }
icp = { path = "crates/icp" }
icp-app = { path = "crates/icp-app" }
icp-canister-interfaces = { path = "crates/icp-canister-interfaces" }
icp-events = { path = "crates/icp-events" }
icp-sync-plugin = { path = "crates/icp-sync-plugin" }
Expand Down
86 changes: 86 additions & 0 deletions crates/icp-app/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
[package]
name = "icp-app"
version.workspace = true
edition = { workspace = true }
license = { workspace = true }
publish.workspace = true

[features]
# `clap::ValueEnum` derives on the settings/identity enums used as CLI value
# types. Enabled by `icp-cli`.
clap = ["dep:clap", "icp/clap"]
# Exposes this crate's mocks, as `icp`'s own feature does for its seams.
test-util = ["icp/test-util"]
Comment thread
adamspofford-dfinity marked this conversation as resolved.

[dependencies]
async-dropper = { workspace = true }
async-trait = { workspace = true }
base64 = { workspace = true }
backoff = { workspace = true }
bigdecimal = { workspace = true }
bip32 = { workspace = true }
bollard = { workspace = true }
camino = { workspace = true }
camino-tempfile = { workspace = true }
candid = { workspace = true }
clap = { workspace = true, optional = true }
crypto-bigint = { workspace = true }
directories = { workspace = true }
dunce = { workspace = true }
ed25519-consensus = { workspace = true }
elliptic-curve = { workspace = true }
flate2 = { workspace = true }
futures = { workspace = true }
hex = { workspace = true }
hmac = { workspace = true }
hybrid-array = { workspace = true }
ic-agent = { workspace = true }
ic-ed25519 = { workspace = true }
ic-identity-hsm = { workspace = true }
ic-ledger-types = { workspace = true }
ic-management-canister-types = { workspace = true }
ic-utils = { workspace = true }
icp = { workspace = true }
icp-canister-interfaces = { workspace = true }
icp-events = { workspace = true }
icrc-ledger-types = { workspace = true }
itertools = { workspace = true }
k256 = { workspace = true }
keyring = { workspace = true }
notify = { workspace = true }
num-bigint = { workspace = true }
num-traits = { workspace = true }
p256 = { workspace = true }
pem = { workspace = true }
phf = { workspace = true }
pkcs8 = { workspace = true }
rand = { workspace = true }
reqwest = { workspace = true }
scrypt = { workspace = true }
sec1 = { workspace = true }
semver = { workspace = true }
serde = { workspace = true }
serde_cbor = { workspace = true }
serde_json = { workspace = true }
sha2 = { workspace = true }
snafu = { workspace = true }
strum = { workspace = true }
sysinfo = { workspace = true }
tar = { workspace = true }
time = { workspace = true }
tiny-bip39 = { workspace = true }
tokio = { workspace = true, features = ["sync", "macros", "rt", "time", "io-util", "io-std", "process", "signal"] }
tracing = { workspace = true }
url = { workspace = true }
uuid = { workspace = true }
wslpath2 = { workspace = true }
zeroize = { workspace = true }

[target.'cfg(windows)'.dependencies]
winreg = { workspace = true }

[dev-dependencies]
httptest = { workspace = true }
icp = { workspace = true, features = ["test-util"] }
indexmap = { workspace = true }
indoc = { workspace = true }
70 changes: 70 additions & 0 deletions crates/icp-app/src/agent.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use std::{sync::Arc, time::Duration};

use async_trait::async_trait;
use ic_agent::{Agent, AgentError, Identity};
use snafu::prelude::*;

use icp::prelude::*;

#[derive(Debug, Snafu)]
pub enum CreateAgentError {
#[snafu(display("failed to create agent"))]
Agent { source: AgentError },
}

/// How far ahead of now an agent dates the messages it expires, unless the
/// caller pins something else.
const DEFAULT_INGRESS_EXPIRY: Duration = Duration::from_secs(4 * MINUTE);

#[async_trait]
pub trait Create: Sync + Send {
/// Builds an agent talking to `url` as `id`.
///
/// `ingress_expiry` pins how far ahead of now the agent dates the messages it
/// derives an expiry for. Pass `None` for the default. Pass `Some` only when
/// the expiry is itself part of the output — signing a message here for
/// another machine to submit, where the call envelope and the pre-signed
/// `request_status` that accompanies it have to land in the same submission
/// window. A pinned expiry is used verbatim, so the
/// `ICP_CLI_TEST_ADVANCE_TIME_MS` clock offset applies to the default only.
async fn create(
&self,
id: Arc<dyn Identity>,
url: &str,
ingress_expiry: Option<Duration>,
) -> Result<Agent, CreateAgentError>;
}

pub struct Creator;

#[async_trait]
impl Create for Creator {
async fn create(
&self,
id: Arc<dyn Identity>,
url: &str,
ingress_expiry: Option<Duration>,
) -> Result<Agent, CreateAgentError> {
let ingress_expiry =
ingress_expiry.unwrap_or_else(|| DEFAULT_INGRESS_EXPIRY + test_time_advance());

let b = Agent::builder()
.with_url(url)
.with_arc_identity(id)
.with_ingress_expiry(ingress_expiry);

Ok(b.build().context(AgentSnafu)?)
}
}

/// How far a test has advanced the replica's clock past this machine's, so the
/// default ingress expiry stays ahead of replica time.
fn test_time_advance() -> Duration {
match std::env::var("ICP_CLI_TEST_ADVANCE_TIME_MS") {
Ok(ms) => Duration::from_millis(
ms.parse::<u64>()
.expect("ICP_CLI_TEST_ADVANCE_TIME_MS must be set to an int"),
),
Err(_) => Duration::ZERO,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@ use std::{env::current_dir, sync::Arc};

use snafu::prelude::*;

use crate::canister::build::Builder;
use crate::canister::recipe::fetch::RecipeFetcher;
use crate::canister::sync::Syncer;
use crate::context::Context;
use crate::directories::{Access as _, Directories};
use crate::prelude::*;
use crate::store_artifact::ArtifactStore;
use crate::recipe::RecipeFetcher;
use icp::canister::build::Builder;
use icp::canister::sync::Syncer;
use icp::prelude::*;
use icp::store_artifact::ArtifactStore;
use std::time::Duration;

use crate::{
Lazy, ProjectLoadImpl, agent, host::Host, identity, identity::PasswordFunc, manifest, network,
store_id,
};
use crate::{agent, identity, identity::PasswordFunc};
use icp::{Lazy, ProjectLoadImpl, host::Host, manifest, store_id};

#[derive(Debug, Snafu)]
pub enum ContextInitError {
Expand All @@ -30,10 +28,10 @@ pub enum ContextInitError {
Utf8Path { source: FromPathBufError },

#[snafu(display("failed to lock identity directory"))]
IdentityDirectory { source: crate::fs::lock::LockError },
IdentityDirectory { source: icp::fs::lock::LockError },

#[snafu(display("failed to lock package cache directory"))]
PackageCache { source: crate::fs::lock::LockError },
PackageCache { source: icp::fs::lock::LockError },
}

pub fn initialize(
Expand Down Expand Up @@ -87,8 +85,16 @@ pub fn initialize(
// Prepare http client
let http_client = reqwest::Client::new();

// Package cache
let pkg_cache = dirs.package_cache().context(PackageCacheSnafu)?;
// Package cache. One instance, shared by everything that reads or writes
// it, so the directory lock is taken once per process rather than once per
// holder.
let pkg_cache = Arc::new(dirs.package_cache().context(PackageCacheSnafu)?);

// Wasm modules named by a manifest but not contained in the project
let wasm = Arc::new(crate::wasm::Fetcher::new(
http_client.clone(),
pkg_cache.clone(),
));

// Recipes
let recipe = Arc::new(RecipeFetcher {
Expand All @@ -97,10 +103,10 @@ pub fn initialize(
});

// Canister builder
let builder = Arc::new(Builder);
let builder = Arc::new(Builder::new(wasm.clone()));

// Canister syncer
let syncer = Arc::new(Syncer::host());
let syncer = Arc::new(Syncer::host(wasm.clone()));

// Project loader
let pload = ProjectLoadImpl {
Expand Down Expand Up @@ -133,7 +139,7 @@ pub fn initialize(
let agent_creator = Arc::new(agent::Creator);

// Network accessor
let netaccess = Arc::new(network::Accessor {
let netaccess = Arc::new(crate::network::Accessor {
project_root_locate: project_root_locate.clone(),
descriptors: dirs.port_descriptor(),
agent: agent_creator.clone(),
Expand All @@ -147,13 +153,16 @@ pub fn initialize(
artifacts,
builder,
syncer,
network: netaccess,
telemetry_data,
wasm,
network: netaccess.clone(),
observer: telemetry_data.clone(),
},
dirs,
network_dirs: netaccess.clone(),
identity: idload,
agent: agent_creator,
debug,
telemetry_data,
password_func,
})
}
Expand Down
Loading
Loading