Skip to content

Commit 1d0d083

Browse files
Make project usable as a library by adding lib.rs (#8)
* add lib.rs and move main.rs code * upgrade deps * bump version * rename speedtest options to CLI options * add examples for library usage * make OutputFormat no longer optional * minor version bump * run examples and CLI in GitHub CI
1 parent 923f9f0 commit 1d0d083

File tree

10 files changed

+204
-124
lines changed

10 files changed

+204
-124
lines changed

.github/workflows/CI.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,11 @@ jobs:
2222
run: cargo build --verbose
2323
- name: Run tests
2424
run: cargo test --verbose
25+
- name: Run example - simple_speedtest
26+
run: cargo run --example simple_speedtest
27+
- name: Run example - download_test
28+
run: cargo run --example download_test
29+
- name: Run example - latency_test
30+
run: cargo run --example latency_test
31+
- name: Run CLI
32+
run: cargo run

Cargo.lock

Lines changed: 19 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cfspeedtest"
3-
version = "1.0.4"
3+
version = "1.1.0"
44
edition = "2021"
55
license = "MIT"
66
description = "Unofficial CLI for speed.cloudflare.com"

examples/download_test.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use cfspeedtest::speedtest::test_download;
2+
use cfspeedtest::OutputFormat;
3+
4+
fn main() {
5+
println!("Testing download speed with 10MB of payload");
6+
7+
let download_speed = test_download(
8+
&reqwest::blocking::Client::new(),
9+
10_000_000,
10+
OutputFormat::None, // don't write to stdout while running the test
11+
);
12+
13+
println!("download speed in mbit: {download_speed}")
14+
}

examples/latency_test.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use cfspeedtest::speedtest::run_latency_test;
2+
use cfspeedtest::OutputFormat;
3+
4+
fn main() {
5+
println!("Testing latency");
6+
7+
let (latency_results, avg_latency) = run_latency_test(
8+
&reqwest::blocking::Client::new(),
9+
25,
10+
OutputFormat::None, // don't write to stdout while running the test
11+
);
12+
13+
println!("average latancy in ms: {avg_latency}");
14+
15+
println!("all latency test results");
16+
for latency_result in latency_results {
17+
println!("latency in ms: {latency_result}");
18+
}
19+
}

examples/simple_speedtest.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use cfspeedtest::speedtest::speed_test;
2+
use cfspeedtest::speedtest::PayloadSize;
3+
use cfspeedtest::OutputFormat;
4+
use cfspeedtest::SpeedTestCLIOptions;
5+
6+
fn main() {
7+
// define speedtest options
8+
let options = SpeedTestCLIOptions {
9+
output_format: OutputFormat::None, // don't write to stdout
10+
ipv4: false, // don't force ipv4 usage
11+
ipv6: false, // don't force ipv6 usage
12+
verbose: false,
13+
nr_tests: 5,
14+
nr_latency_tests: 20,
15+
max_payload_size: PayloadSize::M10,
16+
};
17+
18+
let measurements = speed_test(reqwest::blocking::Client::new(), options);
19+
measurements
20+
.iter()
21+
.for_each(|measurement| println!("{measurement}"));
22+
}

src/lib.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
pub mod boxplot;
2+
pub mod measurements;
3+
pub mod progress;
4+
pub mod speedtest;
5+
use std::fmt;
6+
use std::fmt::Display;
7+
8+
use clap::Parser;
9+
use speedtest::PayloadSize;
10+
11+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12+
pub enum OutputFormat {
13+
Csv,
14+
Json,
15+
JsonPretty,
16+
StdOut,
17+
None,
18+
}
19+
20+
impl Display for OutputFormat {
21+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22+
write!(f, "{:?}", self)
23+
}
24+
}
25+
26+
impl OutputFormat {
27+
pub fn from(output_format_string: String) -> Result<Self, String> {
28+
match output_format_string.to_lowercase().as_str() {
29+
"csv" => Ok(Self::Csv),
30+
"json" => Ok(Self::Json),
31+
"json_pretty" | "json-pretty" => Ok(Self::JsonPretty),
32+
"stdout" => Ok(Self::StdOut),
33+
_ => Err("Value needs to be one of csv, json or json-pretty".to_string()),
34+
}
35+
}
36+
}
37+
38+
/// Unofficial CLI for speed.cloudflare.com
39+
#[derive(Parser, Debug)]
40+
#[command(author, version, about, long_about = None)]
41+
pub struct SpeedTestCLIOptions {
42+
/// Number of test runs per payload size. Needs to be at least 4
43+
#[arg(value_parser = clap::value_parser!(u32).range(4..1000), short, long, default_value_t = 10)]
44+
pub nr_tests: u32,
45+
46+
/// Number of latency tests to run
47+
#[arg(long, default_value_t = 25)]
48+
pub nr_latency_tests: u32,
49+
50+
/// The max payload size in bytes to use [100k, 1m, 10m, 25m or 100m]
51+
#[arg(value_parser = parse_payload_size, short, long, default_value_t = PayloadSize::M10)]
52+
pub max_payload_size: PayloadSize,
53+
54+
/// Set the output format [csv, json or json-pretty] >
55+
/// This silences all other output to stdout
56+
#[arg(value_parser = parse_output_format, short, long, default_value_t = OutputFormat::StdOut)]
57+
pub output_format: OutputFormat,
58+
59+
/// Enable verbose output i.e. print out boxplots of the measurements
60+
#[arg(short, long)]
61+
pub verbose: bool,
62+
63+
/// Force usage of IPv4
64+
#[arg(long)]
65+
pub ipv4: bool,
66+
67+
/// Force usage of IPv6
68+
#[arg(long)]
69+
pub ipv6: bool,
70+
}
71+
72+
fn parse_payload_size(input_string: &str) -> Result<PayloadSize, String> {
73+
PayloadSize::from(input_string.to_string())
74+
}
75+
76+
fn parse_output_format(input_string: &str) -> Result<OutputFormat, String> {
77+
OutputFormat::from(input_string.to_string())
78+
}

src/main.rs

Lines changed: 7 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,15 @@
1-
pub mod boxplot;
2-
pub mod measurements;
3-
pub mod progress;
4-
pub mod speedtest;
5-
1+
use cfspeedtest::speedtest;
2+
use cfspeedtest::OutputFormat;
3+
use cfspeedtest::SpeedTestCLIOptions;
64
use clap::Parser;
7-
use speedtest::speed_test;
8-
use speedtest::PayloadSize;
9-
10-
#[derive(Clone, Copy, Debug)]
11-
enum OutputFormat {
12-
Csv,
13-
Json,
14-
JsonPretty,
15-
}
16-
17-
impl OutputFormat {
18-
pub fn from(output_format_string: String) -> Result<Self, String> {
19-
match output_format_string.to_lowercase().as_str() {
20-
"csv" => Ok(Self::Csv),
21-
"json" => Ok(Self::Json),
22-
"json_pretty" | "json-pretty" => Ok(Self::JsonPretty),
23-
_ => Err("Value needs to be one of csv, json or json-pretty".to_string()),
24-
}
25-
}
26-
}
27-
28-
/// Unofficial CLI for speed.cloudflare.com
29-
#[derive(Parser, Debug)]
30-
#[command(author, version, about, long_about = None)]
31-
pub(crate) struct SpeedTestOptions {
32-
/// Number of test runs per payload size. Needs to be at least 4
33-
#[arg(value_parser = clap::value_parser!(u32).range(4..1000), short, long, default_value_t = 10)]
34-
nr_tests: u32,
35-
36-
/// Number of latency tests to run
37-
#[arg(long, default_value_t = 25)]
38-
nr_latency_tests: u32,
39-
40-
/// The max payload size in bytes to use [100k, 1m, 10m, 25m or 100m]
41-
#[arg(value_parser = parse_payload_size, short, long, default_value_t = PayloadSize::M10)]
42-
max_payload_size: PayloadSize,
43-
44-
/// Set the output format [csv, json or json-pretty] >
45-
/// This silences all other output to stdout
46-
#[arg(value_parser = parse_output_format, short, long)]
47-
output_format: Option<OutputFormat>,
48-
49-
/// Enable verbose output i.e. print out boxplots of the measurements
50-
#[arg(short, long)]
51-
verbose: bool,
5+
use std::net::IpAddr;
526

53-
/// Force usage of IPv4
54-
#[arg(long)]
55-
ipv4: bool,
7+
use speedtest::speed_test;
568

57-
/// Force usage of IPv6
58-
#[arg(long)]
59-
ipv6: bool,
60-
}
61-
use std::net::IpAddr;
629
fn main() {
6310
env_logger::init();
64-
let options = SpeedTestOptions::parse();
65-
if options.output_format.is_none() {
11+
let options = SpeedTestCLIOptions::parse();
12+
if options.output_format == OutputFormat::StdOut {
6613
println!("Starting Cloudflare speed test");
6714
}
6815
let client;
@@ -82,11 +29,3 @@ fn main() {
8229
options,
8330
);
8431
}
85-
86-
fn parse_payload_size(input_string: &str) -> Result<PayloadSize, String> {
87-
PayloadSize::from(input_string.to_string())
88-
}
89-
90-
fn parse_output_format(input_string: &str) -> Result<OutputFormat, String> {
91-
OutputFormat::from(input_string.to_string())
92-
}

0 commit comments

Comments
 (0)