forked from n0-computer/iroh
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: extract CLI code from main into run to compile fake for tes…
…ting purposes The code in `main` is moved into `run`, which now exposes two versions of run_cli, one enabled in production and the other one only for testing purposes, using a fake implementation of the `api` trait
- Loading branch information
Showing
5 changed files
with
357 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
async fn main_cli(cli: Cli) -> Result<()> { | ||
let cfg_path = iroh_config_path(CONFIG_FILE_NAME)?; | ||
let sources = vec![Some(cfg_path), cli.cfg.clone()]; | ||
let config = make_config( | ||
// default | ||
Config::default(), | ||
// potential config files | ||
sources, | ||
// env var prefix for this config | ||
ENV_PREFIX, | ||
// map of present command line arguments | ||
cli.make_overrides_map(), | ||
) | ||
.unwrap(); | ||
|
||
let client = Client::new(config.rpc_client).await?; | ||
|
||
let api = Api::new(&client).await?; | ||
|
||
run_cli_command(&api, cli).await | ||
} | ||
|
||
#[cfg(test)] | ||
async fn fake_cli(cli: Cli) -> Result<()> { | ||
let fake = crate::fake::FakeApi::default(); | ||
run_cli_command(&api, cli).await | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
use std::collections::{HashMap, HashSet}; | ||
use std::path::Path; | ||
|
||
use anyhow::Result; | ||
use async_trait::async_trait; | ||
use bytes::Bytes; | ||
use cid::Cid; | ||
use iroh::api; | ||
use libp2p::gossipsub::MessageId; | ||
use libp2p::{Multiaddr, PeerId}; | ||
|
||
pub struct FakeApi { | ||
failing: bool, | ||
} | ||
|
||
pub struct FakeP2p { | ||
failing: bool, | ||
} | ||
|
||
pub struct FakeStore { | ||
failing: bool, | ||
} | ||
|
||
impl FakeApi { | ||
pub fn new(failing: bool) -> Self { | ||
Self { failing } | ||
} | ||
} | ||
|
||
impl Default for FakeApi { | ||
fn default() -> Self { | ||
Self::new(false) | ||
} | ||
} | ||
|
||
impl FakeP2p { | ||
fn new(failing: bool) -> Self { | ||
Self { failing } | ||
} | ||
} | ||
|
||
impl Default for FakeP2p { | ||
fn default() -> Self { | ||
Self::new(false) | ||
} | ||
} | ||
|
||
impl FakeStore { | ||
fn new(failing: bool) -> Self { | ||
Self { failing } | ||
} | ||
} | ||
|
||
impl Default for FakeStore { | ||
fn default() -> Self { | ||
Self::new(false) | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl api::Accessors<FakeP2p, FakeStore> for FakeApi { | ||
fn p2p(&self) -> Result<FakeP2p> { | ||
Ok(FakeP2p::new(self.failing)) | ||
} | ||
|
||
fn store(&self) -> Result<FakeStore> { | ||
Ok(FakeStore::new(self.failing)) | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl api::Main for FakeApi { | ||
async fn version(&self) -> Result<String> { | ||
Ok("0.0.0".to_string()) | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl api::GetAdd for FakeApi { | ||
async fn get(&self, cid: &Cid, output: &Path) -> Result<()> { | ||
if self.failing { | ||
return Err(anyhow::anyhow!("failing")); | ||
} | ||
// XXX should really affect the file system | ||
Ok(()) | ||
} | ||
|
||
async fn add(&self, path: &Path) -> Result<Cid> { | ||
if self.failing { | ||
return Err(anyhow::anyhow!("failing")); | ||
} | ||
Ok(Cid::default()) | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl api::P2pConnectDisconnect for FakeP2p { | ||
async fn connect(&self, peer_id: &PeerId, addrs: &[Multiaddr]) -> Result<()> { | ||
Ok(()) | ||
} | ||
|
||
async fn disconnect(&self, peer_id: &PeerId) -> Result<()> { | ||
Ok(()) | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl api::P2pId for FakeP2p { | ||
async fn p2p_version(&self) -> Result<String> { | ||
Ok("0.0.0".to_string()) | ||
} | ||
|
||
async fn local_peer_id(&self) -> Result<PeerId> { | ||
Ok(PeerId::from_bytes(&[ | ||
0, 32, 213, 223, 174, 101, 171, 227, 94, 23, 72, 55, 121, 197, 126, 154, 49, 64, 153, | ||
109, 184, 172, 249, 168, 157, 71, 59, 151, 11, 77, 147, 45, 125, 158, | ||
])?) | ||
} | ||
|
||
async fn addrs_listen(&self) -> Result<Vec<Multiaddr>> { | ||
Ok(vec![]) | ||
} | ||
|
||
async fn addrs_local(&self) -> Result<Vec<Multiaddr>> { | ||
Ok(vec![]) | ||
} | ||
|
||
async fn id(&self) -> Result<api::Id> { | ||
Ok(api::Id { | ||
peer_id: self.local_peer_id().await?, | ||
listen_addrs: self.addrs_listen().await?, | ||
local_addrs: self.addrs_local().await?, | ||
}) | ||
} | ||
|
||
async fn peers(&self) -> Result<HashMap<PeerId, Vec<Multiaddr>>> { | ||
let mut m: HashMap<PeerId, Vec<Multiaddr>> = HashMap::new(); | ||
let addr1: Multiaddr = "/ip4/127.0.0.1".parse().unwrap(); | ||
let addr2: Multiaddr = "/ip4/192.168.1.1".parse().unwrap(); | ||
let addr3: Multiaddr = "/ip4/192.168.1.2".parse().unwrap(); | ||
let addr4: Multiaddr = "/ip4/192.168.1.4".parse().unwrap(); | ||
m.insert( | ||
PeerId::from_bytes(&[ | ||
0, 32, 15, 231, 162, 148, 52, 155, 40, 187, 217, 170, 125, 185, 68, 142, 156, 196, | ||
145, 178, 64, 74, 19, 27, 9, 171, 111, 35, 88, 236, 103, 150, 96, 66, | ||
])?, | ||
vec![addr1, addr2], | ||
); | ||
m.insert( | ||
PeerId::from_bytes(&[ | ||
0, 32, 144, 137, 53, 144, 57, 13, 191, 157, 254, 110, 136, 212, 131, 241, 179, 29, | ||
38, 29, 207, 62, 126, 215, 213, 49, 248, 43, 143, 40, 123, 93, 248, 222, | ||
])?, | ||
vec![addr3, addr4], | ||
); | ||
Ok(m) | ||
} | ||
|
||
async fn ping(&self, ping_args: &[api::Ping], count: usize) -> Result<()> { | ||
Ok(()) | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl api::P2pFetch for FakeP2p { | ||
async fn fetch_bitswap(&self, cid: &Cid, providers: &[PeerId]) -> Result<Bytes> { | ||
Ok(Bytes::default()) | ||
} | ||
|
||
async fn fetch_providers(&self, cid: &Cid) -> Result<HashSet<PeerId>> { | ||
Ok(HashSet::new()) | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl api::P2pGossipsub for FakeP2p { | ||
async fn publish(&self, topic: &str, file: Option<&Path>) -> Result<MessageId> { | ||
Ok(MessageId::new(&[])) | ||
} | ||
|
||
async fn subscribe(&self, topic: &str) -> Result<bool> { | ||
Ok(true) | ||
} | ||
|
||
async fn unsubscribe(&self, topic: &str) -> Result<bool> { | ||
Ok(true) | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl api::StoreMain for FakeStore { | ||
async fn store_version(&self) -> Result<String> { | ||
Ok("0.0.0".to_string()) | ||
} | ||
|
||
async fn get_links(&self, cid: &Cid) -> Result<Option<Vec<Cid>>> { | ||
Ok(Some(vec![])) | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl api::StoreBlock for FakeStore { | ||
async fn block_get(&self, cid: &Cid) -> Result<Option<Bytes>> { | ||
Ok(Some(Bytes::default())) | ||
} | ||
|
||
async fn block_put(&self, data: &Bytes) -> Result<Cid> { | ||
Ok(Cid::default()) | ||
} | ||
|
||
async fn block_has(&self, cid: &Cid) -> Result<bool> { | ||
Ok(false) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,9 @@ | ||
pub mod config; | ||
#[cfg(test)] | ||
mod fake; | ||
pub mod gateway; | ||
pub mod metrics; | ||
pub mod p2p; | ||
pub mod run; | ||
pub mod status; | ||
pub mod store; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,97 +1,10 @@ | ||
use std::collections::HashMap; | ||
use std::path::PathBuf; | ||
|
||
use anyhow::Result; | ||
use clap::{Parser, Subcommand}; | ||
use iroh::{api, Api}; | ||
use iroh_ctl::{ | ||
gateway::{run_command as run_gateway_command, Gateway}, | ||
p2p::{run_command as run_p2p_command, P2p}, | ||
store::{run_command as run_store_command, Store}, | ||
}; | ||
use iroh_rpc_client::Client; | ||
use iroh_util::{iroh_config_path, make_config}; | ||
|
||
use iroh_ctl::{ | ||
config::{Config, CONFIG_FILE_NAME, ENV_PREFIX}, | ||
status, | ||
}; | ||
|
||
#[derive(Parser, Debug, Clone)] | ||
#[clap(version, about, long_about = None, propagate_version = true)] | ||
struct Cli { | ||
#[clap(long)] | ||
cfg: Option<PathBuf>, | ||
#[clap(long = "no-metrics")] | ||
no_metrics: bool, | ||
#[clap(subcommand)] | ||
command: Commands, | ||
} | ||
|
||
impl Cli { | ||
fn make_overrides_map(&self) -> HashMap<String, String> { | ||
let mut map = HashMap::new(); | ||
map.insert("metrics.debug".to_string(), self.no_metrics.to_string()); | ||
map | ||
} | ||
} | ||
|
||
#[derive(Subcommand, Debug, Clone)] | ||
enum Commands { | ||
/// status checks the health of the different processes | ||
// #[clap(about = "Check the health of the different iroh processes.")] | ||
// Status { | ||
// #[clap(short, long)] | ||
// /// when true, updates the status table whenever a change in a process's status occurs | ||
// watch: bool, | ||
// }, | ||
Version, | ||
P2p(P2p), | ||
Store(Store), | ||
Gateway(Gateway), | ||
} | ||
use clap::Parser; | ||
|
||
#[tokio::main(flavor = "multi_thread")] | ||
async fn main() -> anyhow::Result<()> { | ||
let cli = Cli::parse(); | ||
|
||
let cfg_path = iroh_config_path(CONFIG_FILE_NAME)?; | ||
let sources = vec![Some(cfg_path), cli.cfg.clone()]; | ||
let config = make_config( | ||
// default | ||
Config::default(), | ||
// potential config files | ||
sources, | ||
// env var prefix for this config | ||
ENV_PREFIX, | ||
// map of present command line arguments | ||
cli.make_overrides_map(), | ||
) | ||
.unwrap(); | ||
|
||
let client = Client::new(config.rpc_client).await?; | ||
|
||
let api = Api::new(&client).await?; | ||
|
||
run_cli_command(&api, cli).await | ||
} | ||
|
||
async fn run_cli_command<A: api::Api<P, S>, P: api::P2p, S: api::Store>( | ||
api: &A, | ||
cli: Cli, | ||
) -> Result<()> { | ||
match cli.command { | ||
// Commands::Status { watch } => { | ||
// crate::status::status(client, watch).await?; | ||
// } | ||
Commands::Version => { | ||
let version = api.version().await?; | ||
println!("v{}", version); | ||
} | ||
Commands::P2p(p2p) => run_p2p_command(api.p2p()?, p2p).await?, | ||
Commands::Store(store) => run_store_command(api.store()?, store).await?, | ||
Commands::Gateway(gateway) => run_gateway_command(gateway).await?, | ||
}; | ||
|
||
Ok(()) | ||
async fn main() -> Result<()> { | ||
let cli = iroh_ctl::run::Cli::parse(); | ||
// run_cli exists in two versions, one for real client interaction, | ||
// and one for testing purposes using a fake API implementation | ||
iroh_ctl::run::run_cli(cli).await | ||
} |
Oops, something went wrong.