#![forbid(bad_style, exceeding_bitshifts, mutable_transmutes, no_mangle_const_items,
unknown_crate_types, warnings)]
#![deny(deprecated, improper_ctypes, missing_docs,
non_shorthand_field_patterns, overflowing_literals, plugin_as_library,
private_no_mangle_fns, private_no_mangle_statics, stable_features, unconditional_recursion,
unknown_lints, unsafe_code, unused, unused_allocation, unused_attributes,
unused_comparisons, unused_features, unused_parens, while_true)]
#![warn(trivial_casts, trivial_numeric_casts, unused_extern_crates, unused_import_braces,
unused_qualifications, unused_results)]
#![allow(box_pointers, fat_ptr_transmutes, missing_copy_implementations,
missing_debug_implementations, variant_size_differences)]
#![cfg_attr(feature="cargo-clippy", deny(clippy, clippy_pedantic))]
#![cfg_attr(feature="cargo-clippy", allow(use_debug, print_stdout, missing_docs_in_private_items))]
extern crate docopt;
extern crate rand;
extern crate rustc_serialize;
extern crate futures;
extern crate routing;
extern crate rust_sodium;
#[macro_use]
extern crate safe_core;
extern crate tokio_core;
extern crate maidsafe_utilities;
#[macro_use]
extern crate unwrap;
use docopt::Docopt;
use futures::Future;
use futures::stream::{self, Stream};
use futures::sync::mpsc;
use rand::{Rng, SeedableRng};
use routing::{ImmutableData, MutableData};
use rust_sodium::crypto::sign::PublicKey;
use safe_core::{Client, CoreMsg, FutureExt, event_loop};
use tokio_core::reactor::Core;
#[cfg_attr(rustfmt, rustfmt_skip)]
static USAGE: &'static str = "
Usage:
client_stress_test [options]
Options:
-i <count>, --immutable=<count> Number of ImmutableData chunks to Put and
Get [default: 100].
-m <count>, --mutable=<count> Number of MutableData chunks to Put and
Get [default: 100].
--seed <seed> Seed for a pseudo-random number generator.
--get-only Only Get the data, don't Put it.
--invite INVITATION Use the given invite.
-h, --help Display this help message and exit.
";
#[derive(Debug, RustcDecodable)]
struct Args {
flag_immutable: Option<usize>,
flag_mutable: Option<usize>,
flag_seed: Option<u32>,
flag_get_only: bool,
flag_invite: Option<String>,
flag_help: bool,
}
fn random_mutable_data<R: Rng>(type_tag: u64, public_key: &PublicKey, rng: &mut R) -> MutableData {
let permissions = btree_map![];
let data = btree_map![];
unwrap!(MutableData::new(
rng.gen(),
type_tag,
permissions,
data,
btree_set![*public_key],
))
}
enum Data {
Mutable(MutableData),
Immutable(ImmutableData),
}
fn main() {
unwrap!(maidsafe_utilities::log::init(true));
let args: Args = Docopt::new(USAGE)
.and_then(|docopt| docopt.decode())
.unwrap_or_else(|error| error.exit());
let immutable_data_count = unwrap!(args.flag_immutable);
let mutable_data_count = unwrap!(args.flag_mutable);
let mut rng = rand::XorShiftRng::from_seed(match args.flag_seed {
Some(seed) => [0, 0, 0, seed],
None => {
[
rand::random(),
rand::random(),
rand::random(),
rand::random(),
]
}
});
let el = unwrap!(Core::new());
let el_h = el.handle();
let (core_tx, core_rx) = mpsc::unbounded();
let (net_tx, _net_rx) = mpsc::unbounded();
let secret_0: String = rng.gen_ascii_chars().take(20).collect();
let secret_1: String = rng.gen_ascii_chars().take(20).collect();
let mut invitation = rng.gen_ascii_chars().take(20).collect();
if let Some(i) = args.flag_invite.clone() {
invitation = i;
}
let client = if args.flag_get_only {
unwrap!(Client::login(
&secret_0,
&secret_1,
el_h,
core_tx.clone(),
net_tx,
))
} else {
println!("\n\tAccount Creation");
println!("\t================");
println!("\nTrying to create an account ...");
unwrap!(Client::registered(
&secret_0,
&secret_1,
&invitation,
el_h,
core_tx.clone(),
net_tx,
))
};
println!("Logged in successfully!");
let public_key = unwrap!(client.public_signing_key());
let core_tx_clone = core_tx.clone();
unwrap!(core_tx.send(CoreMsg::new(move |client, _| {
let mut stored_data = Vec::with_capacity(mutable_data_count + immutable_data_count);
for _ in 0..immutable_data_count {
let data = ImmutableData::new(rng.gen_iter().take(1024).collect());
stored_data.push(Data::Immutable(data));
}
for _ in immutable_data_count..(immutable_data_count + mutable_data_count) {
let mutable_data = random_mutable_data(100000, &public_key, &mut rng);
stored_data.push(Data::Mutable(mutable_data));
}
let message = format!(
"Generated {} items ({} immutable, {} mutable)",
stored_data.len(),
immutable_data_count,
mutable_data_count
);
let underline = (0..message.len()).map(|_| "=").collect::<String>();
println!("\n\t{}\n\t{}", message, underline);
stream::iter(stored_data.into_iter().enumerate().map(Ok))
.fold((client.clone(), args, rng), |(client, args, rng),
(i, data)| {
let c2 = client.clone();
let c3 = client.clone();
let c4 = client.clone();
match data {
Data::Immutable(data) => {
let fut = if args.flag_get_only {
futures::finished(data).into_box()
} else {
c2.put_idata(data.clone())
.and_then(move |_| {
println!("Put ImmutableData chunk #{}: {:?}", i, data.name());
c3.get_idata(*data.name()).map(move |retrieved_data| {
assert_eq!(data, retrieved_data);
retrieved_data
})
})
.and_then(move |retrieved_data| {
println!(
"Retrieved ImmutableData chunk #{}: {:?}",
i,
retrieved_data.name()
);
Ok(retrieved_data)
})
.into_box()
};
fut.and_then(move |data| {
c4.get_idata(*data.name()).map(move |retrieved_data| {
assert_eq!(data, retrieved_data);
println!("Retrieved chunk #{}: {:?}", i, data.name());
(args, rng)
})
}).map(move |(args, rng)| (client, args, rng))
.map_err(|e| println!("Error: {:?}", e))
.into_box()
}
Data::Mutable(data) => {
let fut = if args.flag_get_only {
futures::finished(data).into_box()
} else {
c2.put_mdata(data.clone())
.and_then(move |_| {
println!("Put MutableData chunk #{}: {:?}", i, data.name());
c3.get_mdata_shell(*data.name(), data.tag()).map(
move |retrieved_data| {
assert_eq!(data, retrieved_data);
retrieved_data
},
)
})
.and_then(move |retrieved_data| {
println!(
"Retrieved MutableData chunk #{}: {:?}",
i,
retrieved_data.name()
);
Ok(retrieved_data)
})
.into_box()
};
fut.and_then(move |data| {
c4.get_mdata_shell(*data.name(), data.tag()).map(
move |retrieved_data| {
assert_eq!(data, retrieved_data);
println!("Retrieved chunk #{}: {:?}", i, data.name());
(args, rng)
},
)
}).map(move |(args, rng)| (client, args, rng))
.map_err(|e| println!("Error: {:?}", e))
.into_box()
}
}
})
.map(move |_| {
unwrap!(core_tx_clone.send(CoreMsg::build_terminator()))
})
.into_box()
.into()
})));
event_loop::run(el, &client, &(), core_rx);
}