Skip to content

Commit 2942f8e

Browse files
committed
chore(init): init repo
0 parents  commit 2942f8e

File tree

11 files changed

+548
-0
lines changed

11 files changed

+548
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/target
2+
Cargo.lock

Cargo.toml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[package]
2+
name = "iroh-test"
3+
version = "0.0.1"
4+
edition = "2021"
5+
authors = ["arqu <[email protected]>"]
6+
license = "Apache-2.0/MIT"
7+
repository = "https://github.com/n0-computer/iroh-test"
8+
description = "iroh test tools"
9+
rust-version = "1.65"
10+
11+
[dependencies]
12+
anyhow = { version = "1", features = ["backtrace"] }
13+
clap = { version = "4.0.9", features = ["derive"] }
14+
tokio = { version = "1", features = ["full"] }
15+
serde = { version = "1", features = ["derive"] }
16+
bincode = "1.3.3"
17+
tempfile = "3.3.0"
18+
futures = "0.3.21"
19+
bytes = "1.1.0"
20+
rand = "0.8.5"
21+
22+
iroh-api = { git = "https://github.com/n0-computer/iroh", rev = "925b6f7614d7e37b1784e3f9bce039dbb2ce0bd4"}
23+
iroh-util = { git = "https://github.com/n0-computer/iroh", rev = "925b6f7614d7e37b1784e3f9bce039dbb2ce0bd4"}
24+
iroh-share = { git = "https://github.com/n0-computer/iroh", rev = "925b6f7614d7e37b1784e3f9bce039dbb2ce0bd4"}
25+
iroh-one = { git = "https://github.com/n0-computer/iroh", rev = "925b6f7614d7e37b1784e3f9bce039dbb2ce0bd4"}
26+
iroh-rpc-types = { git = "https://github.com/n0-computer/iroh", rev = "925b6f7614d7e37b1784e3f9bce039dbb2ce0bd4", default-features = false}
27+
iroh-rpc-client = { git = "https://github.com/n0-computer/iroh", rev = "925b6f7614d7e37b1784e3f9bce039dbb2ce0bd4", default-features = false}

LICENSE-APACHE

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2+
3+
http://www.apache.org/licenses/LICENSE-2.0
4+
5+
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

LICENSE-MIT

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
The MIT License (MIT)
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is
8+
furnished to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in
11+
all copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Chuck
2+
3+
A place to chuck in various integration type tests and benchmarks.

fixtures/10MiB.car

10 MB
Binary file not shown.

src/iroh.rs

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
use anyhow::{Context, Result};
2+
use iroh_rpc_client::Client;
3+
use serde::{Deserialize, Serialize};
4+
use std::{collections::HashMap, path::PathBuf};
5+
6+
use iroh_api::{ChunkerConfig, Cid, IpfsPath, Multiaddr, PeerId, DEFAULT_CHUNKS_SIZE};
7+
use iroh_one::config::{Config, CONFIG_FILE_NAME, ENV_PREFIX};
8+
use iroh_rpc_types::Addr;
9+
use iroh_util::{iroh_config_path, make_config};
10+
use tokio::{sync::mpsc, task::JoinHandle, time::Instant};
11+
12+
use crate::service::{self, DEFAULT_SERVICE_SERVER_PORT, RequestTopic};
13+
14+
pub struct Node {
15+
pub config: Config,
16+
pub p2p_task: JoinHandle<()>,
17+
pub store_task: JoinHandle<()>,
18+
}
19+
20+
impl Node {
21+
pub async fn new(port: u16, server: bool) -> Self {
22+
let cfg_path = iroh_config_path(CONFIG_FILE_NAME).unwrap();
23+
let sources = [Some(cfg_path.as_path())];
24+
let mut config = make_config(
25+
// default
26+
Config::default(),
27+
// potential config files
28+
&sources,
29+
// env var prefix for this config
30+
ENV_PREFIX,
31+
// map of present command line arguments
32+
HashMap::<&str, String>::new(),
33+
)
34+
.unwrap();
35+
36+
let store_dir = tempfile::tempdir().unwrap();
37+
let store_db = store_dir.path().join("store");
38+
config.store.path = store_db;
39+
40+
let keystore_db = store_dir.path().join("keystore");
41+
config.p2p.key_store_path = keystore_db;
42+
43+
let listening_multiaddrs = vec![
44+
format!("/ip4/0.0.0.0/tcp/{}", port).parse().unwrap(),
45+
format!("/ip4/0.0.0.0/udp/{}/quic-v1", port + 1)
46+
.parse()
47+
.unwrap(),
48+
];
49+
50+
config.p2p.libp2p.listening_multiaddrs = listening_multiaddrs;
51+
if server {
52+
config.p2p.libp2p.bitswap_client = false;
53+
config.p2p.libp2p.bitswap_server = true;
54+
} else {
55+
config.p2p.libp2p.bitswap_client = true;
56+
config.p2p.libp2p.bitswap_server = false;
57+
}
58+
59+
#[cfg(unix)]
60+
{
61+
match iroh_util::increase_fd_limit() {
62+
Ok(soft) => println!("NOFILE limit: soft = {}", soft),
63+
Err(err) => eprintln!("Error increasing NOFILE limit: {}", err),
64+
}
65+
}
66+
67+
let (store, p2p) = {
68+
let store_recv = Addr::new_mem();
69+
let store_sender = store_recv.clone();
70+
let p2p_recv = Addr::new_mem();
71+
let p2p_sender = p2p_recv.clone();
72+
config.rpc_client.store_addr = Some(store_sender);
73+
config.rpc_client.p2p_addr = Some(p2p_sender);
74+
config.synchronize_subconfigs();
75+
76+
let store_rpc = iroh_one::mem_store::start(store_recv, config.store.clone()).await;
77+
if let Err(store_rpc) = store_rpc {
78+
eprintln!("Error starting store: {}", store_rpc);
79+
std::process::exit(1);
80+
}
81+
let store_rpc = store_rpc.unwrap();
82+
83+
let p2p_rpc = iroh_one::mem_p2p::start(p2p_recv, config.p2p.clone())
84+
.await
85+
.unwrap();
86+
(store_rpc, p2p_rpc)
87+
};
88+
89+
Self {
90+
config,
91+
p2p_task: p2p,
92+
store_task: store,
93+
}
94+
}
95+
}
96+
97+
pub async fn run_server(node: &Node, target_host: String) -> Result<()> {
98+
println!("starting iroh server");
99+
let mut api_cfg = iroh_api::config::Config::default();
100+
api_cfg.rpc_client = node.config.rpc_client.clone();
101+
let api = iroh_api::Api::new_from_config(api_cfg).await?;
102+
let path = PathBuf::from("./fixtures/10MiB.car");
103+
let cid = api
104+
.add(&path, false, ChunkerConfig::Fixed(DEFAULT_CHUNKS_SIZE))
105+
.await?;
106+
println!("cid: {:?}", cid);
107+
108+
let p2p_rpc = Client::new(node.config.p2p.rpc_client.clone())
109+
.await?
110+
.try_p2p()
111+
.unwrap();
112+
let (peer_id, addrs) = p2p_rpc
113+
.get_listening_addrs()
114+
.await
115+
.context("getting p2p info")?;
116+
117+
println!("peer_id: {:?}", peer_id);
118+
println!("addrs: {:?}", addrs);
119+
120+
let cid_req = CidRequest {
121+
cid,
122+
peer_id,
123+
addrs,
124+
};
125+
126+
let mut service = service::Client::new(target_host.clone()).await;
127+
let req = service::Request::new(RequestTopic::CidRequest, cid_req.as_bytes());
128+
service.send(req).await?;
129+
Ok(())
130+
}
131+
132+
pub async fn run_client(node: &Node) -> Result<()> {
133+
println!("starting iroh client");
134+
let (tx, mut rx) = mpsc::channel(32);
135+
let mut service =
136+
service::Server::new(format!("0.0.0.0:{}", DEFAULT_SERVICE_SERVER_PORT), tx).await?;
137+
tokio::spawn(async move {
138+
if let Err(e) = service.run().await {
139+
eprintln!("failed to run service; err = {:?}", e);
140+
}
141+
});
142+
143+
while let Some(request) = rx.recv().await {
144+
println!("got request");
145+
match request.topic {
146+
RequestTopic::CidRequest => {
147+
let cid_req = CidRequest::from_bytes(&request.data)?;
148+
handle_cid(&cid_req, &node).await?;
149+
}
150+
_ => {
151+
println!("unknown topic: {:?}", request.topic);
152+
continue;
153+
}
154+
}
155+
}
156+
Ok(())
157+
}
158+
159+
async fn handle_cid(cid_req: &CidRequest, node: &Node) -> Result<()> {
160+
let cid = cid_req.cid.clone();
161+
println!("handling cid: {:?}", cid);
162+
let mut api_cfg = iroh_api::config::Config::default();
163+
api_cfg.rpc_client = node.config.rpc_client.clone();
164+
let api = iroh_api::Api::new_from_config(api_cfg).await?;
165+
166+
let p2p_rpc = Client::new(node.config.p2p.rpc_client.clone())
167+
.await?
168+
.try_p2p()
169+
.unwrap();
170+
println!("connecting to peer: {:?}", cid_req.peer_id);
171+
172+
let current = Instant::now();
173+
174+
p2p_rpc
175+
.connect(cid_req.peer_id, cid_req.addrs.clone())
176+
.await?;
177+
println!("connected to peer: {:?}", cid_req.peer_id);
178+
179+
let path = IpfsPath::from_cid(cid.clone());
180+
let blocks = api.get(&path).unwrap();
181+
182+
let temp_dir = tempfile::tempdir().unwrap();
183+
let output = Some(temp_dir.path().join("test.car"));
184+
let root_path = iroh_api::fs::write_get_stream(&path, blocks, output.as_deref()).await?;
185+
let duration = current.elapsed();
186+
println!("done");
187+
println!("saving file(s) to {}", root_path.to_str().unwrap());
188+
println!("duration: {:?}", duration);
189+
Ok(())
190+
}
191+
192+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
193+
struct CidRequest {
194+
pub cid: Cid,
195+
pub peer_id: PeerId,
196+
pub addrs: Vec<Multiaddr>,
197+
}
198+
199+
impl CidRequest {
200+
pub fn as_bytes(&self) -> Vec<u8> {
201+
bincode::serialize(self).expect("failed to serialize")
202+
}
203+
204+
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
205+
let cidreq = bincode::deserialize(bytes)?;
206+
Ok(cidreq)
207+
}
208+
}

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub mod iroh;
2+
pub mod memesync;
3+
pub mod service;

src/main.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use anyhow::{Context, Result};
2+
use clap::{Parser, Subcommand};
3+
use iroh_test::{iroh, memesync};
4+
5+
#[derive(Parser, Debug)]
6+
#[clap(author, version, about, long_about = None)]
7+
struct Args {
8+
#[clap(subcommand)]
9+
command: Commands,
10+
}
11+
12+
#[derive(Debug, Subcommand)]
13+
enum Commands {
14+
#[clap(arg_required_else_help = true)]
15+
MemesyncReceiver { port: u16 },
16+
#[clap(arg_required_else_help = true)]
17+
MemesyncSender {
18+
target_host: String,
19+
bytes: u64,
20+
filename: String,
21+
},
22+
#[clap(arg_required_else_help = true)]
23+
IrohServer { target_host: String },
24+
#[clap(arg_required_else_help = false)]
25+
IrohClient {},
26+
}
27+
28+
#[tokio::main(flavor = "multi_thread")]
29+
async fn main() -> Result<()> {
30+
let args = Args::parse();
31+
match args.command {
32+
Commands::MemesyncReceiver { port } => {
33+
let mut receiver = memesync::MemesyncReceiver::new(port).await;
34+
receiver.run().await?;
35+
}
36+
Commands::MemesyncSender {
37+
target_host,
38+
bytes,
39+
filename,
40+
} => {
41+
let mut sender = memesync::MemesyncSender::new(target_host).await;
42+
sender
43+
.send_file(bytes, filename)
44+
.await
45+
.context("failed to send file")?;
46+
}
47+
Commands::IrohServer { target_host } => {
48+
let node = iroh::Node::new(4444, true).await;
49+
iroh::run_server(&node, target_host)
50+
.await
51+
.context("failed to run server")?;
52+
}
53+
Commands::IrohClient {} => {
54+
let node = iroh::Node::new(4454, false).await;
55+
iroh::run_client(&node)
56+
.await
57+
.context("failed to run client")?;
58+
}
59+
}
60+
iroh_util::block_until_sigint().await;
61+
Ok(())
62+
}

0 commit comments

Comments
 (0)