Skip to content

Commit

Permalink
Rewrite the pinger library
Browse files Browse the repository at this point in the history
  • Loading branch information
orf committed Dec 15, 2024
1 parent 8abb126 commit eec4808
Show file tree
Hide file tree
Showing 14 changed files with 579 additions and 329 deletions.
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jobs:
runs-on: ${{ matrix.os }}
container: ${{ matrix.container }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
include:
Expand Down
114 changes: 101 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions gping/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crossterm::{
};
use dns_lookup::lookup_host;
use itertools::{Itertools, MinMaxResult};
use pinger::{ping_with_interval, PingResult};
use pinger::{ping, PingOptions, PingResult};
use std::io;
use std::io::BufWriter;
use std::iter;
Expand Down Expand Up @@ -310,7 +310,8 @@ fn start_ping_thread(
) -> Result<JoinHandle<Result<()>>> {
let interval = Duration::from_millis((watch_interval.unwrap_or(0.2) * 1000.0) as u64);
// Pump ping messages into the queue
let stream = ping_with_interval(host, interval, interface)?;
let ping_opts = PingOptions::new(host, interval, interface);
let stream = ping(ping_opts)?;
Ok(thread::spawn(move || -> Result<()> {
while !kill_event.load(Ordering::Acquire) {
match stream.recv() {
Expand Down
7 changes: 3 additions & 4 deletions pinger/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ description = "A small cross-platform library to execute the ping command and pa
repository = "https://github.com/orf/pinger/"

[dependencies]
anyhow = "1.0.94"
thiserror = "2.0.6"
thiserror = "2.0.7"
rand = "0.8.5"
lazy-regex = "3.1.0"
lazy-regex = "3.3.0"

[target.'cfg(windows)'.dependencies]
winping = "0.10.1"
dns-lookup = "2.0.0"

[dev-dependencies]
os_info = "3.9.0"
ntest = "0.9.3"
6 changes: 4 additions & 2 deletions pinger/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ A full example of using the library can be found in the `examples/` directory, b
interface is quite simple:

```rust
use pinger::ping;
use std::time::Duration;
use pinger::{ping, PingOptions};

fn ping_google() {
let stream = ping("google.com", None).expect("Error pinging");
let options = PingOptions::new("google.com", Duration::from_secs(1), None);
let stream = ping(options).expect("Error pinging");
for message in stream {
match message {
pinger::PingResult::Pong(duration, _) => {
Expand Down
13 changes: 8 additions & 5 deletions pinger/examples/simple-ping.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
use pinger::ping_with_interval;
use pinger::{ping, PingOptions};

const LIMIT: usize = 3;

pub fn main() {
let target = "tomforb.es".to_string();
let interval = std::time::Duration::from_secs(1);
let stream = ping_with_interval(target, interval, None).expect("Error pinging");
for message in stream {
let interval = std::time::Duration::from_millis(500);
let options = PingOptions::new(target, interval, None);
let stream = ping(options).expect("Error pinging");
for message in stream.into_iter().take(LIMIT) {
match message {
pinger::PingResult::Pong(duration, line) => {
println!("Duration: {:?}\t\t(raw: {:?})", duration, line)
}
pinger::PingResult::Timeout(line) => println!("Timeout! (raw: {line:?})"),
pinger::PingResult::Unknown(line) => println!("Unknown line: {:?}", line),
pinger::PingResult::PingExited(code, stderr) => {
println!("Ping exited! Code: {:?}. Stderr: {:?}", code, stderr)
panic!("Ping exited! Code: {:?}. Stderr: {:?}", code, stderr)
}
}
}
Expand Down
53 changes: 24 additions & 29 deletions pinger/src/bsd.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,44 @@
use crate::{Parser, PingResult, Pinger};
use crate::{extract_regex, PingCreationError, PingOptions, PingResult, Pinger};
use lazy_regex::*;
use std::time::Duration;

pub static RE: Lazy<Regex> = lazy_regex!(r"time=(?:(?P<ms>[0-9]+).(?P<ns>[0-9]+)\s+ms)");

pub struct BSDPinger {
interval: Duration,
interface: Option<String>,
options: PingOptions,
}

pub(crate) fn parse_bsd(line: String) -> Option<PingResult> {
if line.starts_with("PING ") {
return None;
}
if line.starts_with("Request timeout") {
return Some(PingResult::Timeout(line));
}
extract_regex(&RE, line)
}

impl Pinger for BSDPinger {
type Parser = BSDParser;
fn from_options(options: PingOptions) -> Result<Self, PingCreationError>
where
Self: Sized,
{
Ok(Self { options })
}

fn new(interval: Duration, interface: Option<String>) -> Self {
Self {
interface,
interval,
}
fn parse_fn(&self) -> fn(String) -> Option<PingResult> {
parse_bsd
}

fn ping_args(&self, target: String) -> (&str, Vec<String>) {
fn ping_args(&self) -> (&str, Vec<String>) {
let mut args = vec![format!(
"-i{:.1}",
self.interval.as_millis() as f32 / 1_000_f32
self.options.interval.as_millis() as f32 / 1_000_f32
)];
if let Some(interface) = &self.interface {
if let Some(interface) = &self.options.interface {
args.push("-I".into());
args.push(interface.clone());
}
args.push(target);
args.push(self.options.target.to_string());
("ping", args)
}
}

#[derive(Default)]
pub struct BSDParser {}

impl Parser for BSDParser {
fn parse(&self, line: String) -> Option<PingResult> {
if line.starts_with("PING ") {
return None;
}
if line.starts_with("Request timeout") {
return Some(PingResult::Timeout(line));
}
self.extract_regex(&RE, line)
}
}
Loading

0 comments on commit eec4808

Please sign in to comment.