From f8060fad42508259828780d308367007c1006287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Barmore-Gen=C3=A7?= Date: Wed, 1 Feb 2023 00:21:02 -0500 Subject: [PATCH] Avoid multiple main versions & concurrently get ipv4 and ipv6 addresses (#87) * Avoid having multiple versions of main run function * Concurrently get ipv4 and ipv6 addresses --- src/ip_source/icanhazip.rs | 15 +++++++++------ src/ip_source/ip_source.rs | 4 ++-- src/ip_source/ipify.rs | 12 +++++++----- src/main.rs | 24 +++++++++++++----------- 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/ip_source/icanhazip.rs b/src/ip_source/icanhazip.rs index 6957b41..77394c3 100644 --- a/src/ip_source/icanhazip.rs +++ b/src/ip_source/icanhazip.rs @@ -2,7 +2,7 @@ use async_trait::async_trait; use super::ip_source::IPSource; -pub(crate) struct IPSourceIcanhazip {} +pub(crate) struct IPSourceIcanhazip; async fn get_ip(api_url: &str) -> anyhow::Result { let response = reqwest::get(api_url).await?; @@ -12,14 +12,14 @@ async fn get_ip(api_url: &str) -> anyhow::Result { #[async_trait] impl IPSource for IPSourceIcanhazip { - async fn get_ipv4() -> anyhow::Result { + async fn get_ipv4(&self) -> anyhow::Result { Ok(get_ip("https://ipv4.icanhazip.com") .await? // icanazip puts a newline at the end .trim() .to_string()) } - async fn get_ipv6() -> anyhow::Result { + async fn get_ipv6(&self) -> anyhow::Result { Ok(get_ip("https://ipv6.icanhazip.com") .await? // icanazip puts a newline at the end @@ -32,13 +32,15 @@ impl IPSource for IPSourceIcanhazip { mod tests { use regex::Regex; - use super::IPSource; + use crate::ip_source::ip_source::IPSource; + use super::IPSourceIcanhazip; #[tokio::test] #[ignore] async fn ipv4_test() { - let ipv4 = IPSourceIcanhazip::get_ipv4() + let ipv4 = IPSourceIcanhazip + .get_ipv4() .await .expect("Failed to get the IP address"); assert!(Regex::new(r"^\d+[.]\d+[.]\d+[.]\d+$") @@ -49,7 +51,8 @@ mod tests { #[tokio::test] #[ignore] async fn ipv6_test() { - let ipv6 = IPSourceIcanhazip::get_ipv6() + let ipv6 = IPSourceIcanhazip + .get_ipv6() .await .expect("Failed to get the IP address"); assert!(Regex::new(r"^([0-9a-fA-F]*:){7}[0-9a-fA-F]*$") diff --git a/src/ip_source/ip_source.rs b/src/ip_source/ip_source.rs index 13185b4..e3e49fc 100644 --- a/src/ip_source/ip_source.rs +++ b/src/ip_source/ip_source.rs @@ -2,6 +2,6 @@ use async_trait::async_trait; #[async_trait] pub trait IPSource { - async fn get_ipv4() -> anyhow::Result; - async fn get_ipv6() -> anyhow::Result; + async fn get_ipv4(&self) -> anyhow::Result; + async fn get_ipv6(&self) -> anyhow::Result; } diff --git a/src/ip_source/ipify.rs b/src/ip_source/ipify.rs index 14cba47..19fb8eb 100644 --- a/src/ip_source/ipify.rs +++ b/src/ip_source/ipify.rs @@ -2,7 +2,7 @@ use async_trait::async_trait; use super::ip_source::IPSource; -pub(crate) struct IPSourceIpify {} +pub(crate) struct IPSourceIpify; async fn get_ip(api_url: &str) -> anyhow::Result { let response = reqwest::get(api_url).await?; @@ -12,10 +12,10 @@ async fn get_ip(api_url: &str) -> anyhow::Result { #[async_trait] impl IPSource for IPSourceIpify { - async fn get_ipv4() -> anyhow::Result { + async fn get_ipv4(&self) -> anyhow::Result { get_ip("https://api.ipify.org").await } - async fn get_ipv6() -> anyhow::Result { + async fn get_ipv6(&self) -> anyhow::Result { get_ip("https://api6.ipify.org").await } } @@ -30,7 +30,8 @@ mod tests { #[tokio::test] #[ignore] async fn ipv4_test() { - let ipv4 = IPSourceIpify::get_ipv4() + let ipv4 = IPSourceIpify + .get_ipv4() .await .expect("Failed to get the IP address"); assert!(Regex::new(r"^\d+[.]\d+[.]\d+[.]\d+$") @@ -41,7 +42,8 @@ mod tests { #[tokio::test] #[ignore] async fn ipv6_test() { - let ipv6 = IPSourceIpify::get_ipv6() + let ipv6 = IPSourceIpify + .get_ipv6() .await .expect("Failed to get the IP address"); assert!(Regex::new(r"^([0-9a-fA-F]*:){7}[0-9a-fA-F]*$") diff --git a/src/main.rs b/src/main.rs index 1402676..58eafee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ use ip_source::icanhazip::IPSourceIcanhazip; use reqwest::{header, Client, ClientBuilder, StatusCode}; use serde::Serialize; use std::{num::NonZeroU32, sync::Arc, time::Duration}; +use tokio::join; use tokio::{self, task::JoinHandle, time::sleep}; mod config; mod gandi; @@ -39,11 +40,10 @@ pub struct APIPayload { pub rrset_ttl: u32, } -async fn run(base_url: &str, conf: &Config) -> anyhow::Result<()> { +async fn run(base_url: &str, ip_source: &Box, conf: &Config) -> anyhow::Result<()> { config::validate_config(conf).die_with(|error| format!("Invalid config: {}", error)); println!("Finding out the IP address..."); - let ipv4_result = IP::get_ipv4().await; - let ipv6_result = IP::get_ipv6().await; + let (ipv4_result, ipv6_result) = join!(ip_source.get_ipv4(), ip_source.get_ipv6()); let ipv4 = ipv4_result.as_ref(); let ipv6 = ipv6_result.as_ref(); println!("Found these:"); @@ -136,10 +136,11 @@ async fn main() -> anyhow::Result<()> { } async fn run_dispatch(conf: &Config) -> anyhow::Result<()> { - match conf.ip_source { - IPSourceName::Ipify => run::("https://api.gandi.net", conf).await, - IPSourceName::Icanhazip => run::("https://api.gandi.net", conf).await, - } + let ip_source: Box = match conf.ip_source { + IPSourceName::Ipify => Box::new(IPSourceIpify), + IPSourceName::Icanhazip => Box::new(IPSourceIcanhazip), + }; + run("https://api.gandi.net", &ip_source, conf).await } #[cfg(test)] @@ -151,14 +152,14 @@ mod tests { use httpmock::MockServer; use tokio::fs; - struct IPSourceMock {} + struct IPSourceMock; #[async_trait] impl IPSource for IPSourceMock { - async fn get_ipv4() -> anyhow::Result { + async fn get_ipv4(&self) -> anyhow::Result { Ok("192.168.0.0".to_string()) } - async fn get_ipv6() -> anyhow::Result { + async fn get_ipv6(&self) -> anyhow::Result { Ok("fe80:0000:0208:74ff:feda:625c".to_string()) } } @@ -194,7 +195,8 @@ mod tests { ..Opts::default() }; let conf = config::load_config(&opts).expect("Failed to load config"); - run::(server.base_url().as_str(), &conf) + let ip_source: Box = Box::new(IPSourceMock); + run(server.base_url().as_str(), &ip_source, &conf) .await .expect("Failed when running the update");