use anyhow::Context;
use clap::Parser;
use tokio::time::Instant;
#[derive(clap::Parser)]
struct Args {
#[arg(env = "DUCKITY_PROTECTION_PROFILE_ID")]
protection_profile_id: String,
#[arg(env = "DUCKITY_APPLICATION_SECRET")]
application_secret: String,
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
dotenvy::dotenv().ok();
let args = Args::parse();
println!("Welcome to the Duckity-rs example!");
println!();
println!(
"This example will fetch a challenge from the Duckling API, solve it, and validate it."
);
println!("It may take some seconds depending on the challenge, your internet connection, and");
println!("your device.");
println!("Timings will be displayed at the end.");
println!();
if cfg!(debug_assertions) {
println!("By the way, you're running this example in debug mode, which is considerably ");
println!("slower than release mode.");
println!("If you want to see the best performance, run this example in release mode by ");
println!("running it with `cargo run --example timings --release` instead.");
println!();
}
println!("----------------------------------------------");
println!();
println!("Fetching the challenge...");
let challenge_start = Instant::now();
let challenge = duckity::solve(&args.protection_profile_id)
.send()
.await
.context("Could not get the challenge from the duckling API.")?;
let decoded =
duckity::core::decode(&challenge).context("Could not decode the challenge string.")?;
let challenge_elapsed = challenge_start.elapsed();
println!("Solving the challenge...");
let solution_start = Instant::now();
let decoded_copy = decoded.clone();
let solution = tokio::task::spawn_blocking(move || {
let solution = duckity::core::solve(&decoded);
let encoded = duckity::core::encode(&challenge, &solution)?;
anyhow::Ok(encoded)
})
.await
.context("Could not solve the fetched challenge from the duckling API.")?
.context("Could not encode the fetched challenge from the duckling API.")?;
let solution_elapsed = solution_start.elapsed();
let validation_start = Instant::now();
let is_valid = duckity::validate(
&solution,
decoded_copy.ip,
&args.application_secret,
&args.protection_profile_id,
)
.base_url("https://quack.duckity.dev/v1")
.await
.context("Could not validate challenge solution.")?;
let validation_elapsed = validation_start.elapsed();
println!("Done!");
println!();
println!("----------------------------------------------");
println!();
println!("Timings:");
println!("Fetching the challenge took: {:?}", challenge_elapsed);
println!("Solving the challenge took: {:?}", solution_elapsed);
println!(
"Validating the solution took: {:?} Is Valid? {:?}",
validation_elapsed, is_valid
);
println!();
println!("----------------------------------------------");
println!();
println!("The solution is:");
println!("{}", solution);
Ok(())
}