initial commit
This commit is contained in:
commit
6757ad28f8
8 changed files with 225 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
Cargo.lock
|
32
Cargo.toml
Normal file
32
Cargo.toml
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
[package]
|
||||||
|
name = "yapilt"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Jan Christian Grünhage <jan.christian@gruenhage.xyz>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
description = "Yet another public IP lookup tool - Get your public IP"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "yapilt4"
|
||||||
|
path = "src/bin/yapilt4.rs"
|
||||||
|
required-features = ["reqwest-client", "tokio-threaded"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "yapilt6"
|
||||||
|
path = "src/bin/yapilt6.rs"
|
||||||
|
required-features = ["reqwest-client", "tokio-threaded"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
reqwest-client = ["reqwest"]
|
||||||
|
tokio-threaded = ["tokio"]
|
||||||
|
default = ["reqwest-client"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
http = "0.2.1"
|
||||||
|
log = "0.4.8"
|
||||||
|
reqwest = { version = "0.10.4", optional = true }
|
||||||
|
tokio = { version = "0.2.18", features = ["rt-threaded", "macros"], optional = true }
|
||||||
|
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
reqwest = "0.10.4"
|
4
src/bin/yapilt4.rs
Normal file
4
src/bin/yapilt4.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
println!("{}", yapilt::reqwest_client::ipv4(&mut reqwest::Client::new()).await);
|
||||||
|
}
|
4
src/bin/yapilt6.rs
Normal file
4
src/bin/yapilt6.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
println!("{}", yapilt::reqwest_client::ipv6(&mut reqwest::Client::new()).await);
|
||||||
|
}
|
30
src/error.rs
Normal file
30
src/error.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
use crate::{IpType, Provider};
|
||||||
|
|
||||||
|
use std::convert::From;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
Unsupported(IpType, Provider),
|
||||||
|
Http(http::Error),
|
||||||
|
#[cfg(feature = "reqwest-client")]
|
||||||
|
Reqwest(reqwest::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(IpType, &Provider)> for Error {
|
||||||
|
fn from(tuple: (IpType, &Provider)) -> Self {
|
||||||
|
Self::Unsupported(tuple.0, tuple.1.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<http::Error> for Error {
|
||||||
|
fn from(error: http::Error) -> Self {
|
||||||
|
Self::Http(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "reqwest-client")]
|
||||||
|
impl From<reqwest::Error> for Error {
|
||||||
|
fn from(error: reqwest::Error) -> Self {
|
||||||
|
Self::Reqwest(error)
|
||||||
|
}
|
||||||
|
}
|
12
src/ip_type.rs
Normal file
12
src/ip_type.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub enum IpType { V4, V6 }
|
||||||
|
|
||||||
|
impl ToString for IpType {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
Self::V4 => String::from("IPv4"),
|
||||||
|
Self::V6 => String::from("IPv6"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
83
src/lib.rs
Normal file
83
src/lib.rs
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
|
||||||
|
mod error;
|
||||||
|
mod provider;
|
||||||
|
mod ip_type;
|
||||||
|
|
||||||
|
pub use error::Error;
|
||||||
|
pub use provider::Provider;
|
||||||
|
pub use ip_type::IpType;
|
||||||
|
|
||||||
|
pub mod http {
|
||||||
|
use crate::{Error, IpType, Provider};
|
||||||
|
use std::default::Default;
|
||||||
|
|
||||||
|
pub fn ipv4() -> http::Request<&'static [u8]> {
|
||||||
|
ip(IpType::V4, Provider::default()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ipv6() -> http::Request<&'static [u8]> {
|
||||||
|
ip(IpType::V6, Provider::default()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ip<T: Into<Provider>>(ip_type: IpType, provider: T) -> Result<http::Request<&'static [u8]>, Error> {
|
||||||
|
let provider : Provider = provider.into();
|
||||||
|
provider.ip(ip_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "reqwest-client")]
|
||||||
|
pub mod reqwest_client {
|
||||||
|
use reqwest::Client;
|
||||||
|
|
||||||
|
use crate::{Error, IpType, Provider, http::ip as http_ip};
|
||||||
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||||
|
use std::default::Default;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
pub async fn ipv4(client: &mut Client) -> Ipv4Addr {
|
||||||
|
match ip(client, IpType::V4, Provider::default()).await.unwrap() {
|
||||||
|
IpAddr::V4(ip) => ip,
|
||||||
|
_ => {
|
||||||
|
log::error!("This should be unreachable, if the provider is working and configured correctly");
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn ipv6(client: &mut Client) -> Ipv6Addr {
|
||||||
|
match ip(client, IpType::V6, Provider::default()).await.unwrap() {
|
||||||
|
IpAddr::V6(ip) => ip,
|
||||||
|
_ => {
|
||||||
|
log::error!("This should be unreachable, if the provider is working and configured correctly");
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn ip<T: Into<Provider>>(client: &mut Client, ip_type: IpType, provider: T) -> Result<IpAddr, Error> {
|
||||||
|
let request = http_ip(ip_type, provider)?;
|
||||||
|
let response = client
|
||||||
|
.execute(request.try_into().unwrap())
|
||||||
|
.await?
|
||||||
|
.text()
|
||||||
|
.await?;
|
||||||
|
Ok(match ip_type {
|
||||||
|
IpType::V4 => {
|
||||||
|
let addr : Ipv4Addr = response.parse().unwrap();
|
||||||
|
IpAddr::from(addr)
|
||||||
|
},
|
||||||
|
IpType::V6 => {
|
||||||
|
let addr : Ipv6Addr = response.parse().unwrap();
|
||||||
|
IpAddr::from(addr)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
assert_eq!(2 + 2, 4);
|
||||||
|
}
|
||||||
|
}
|
58
src/provider.rs
Normal file
58
src/provider.rs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
use crate::{Error, IpType};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub struct Provider {
|
||||||
|
pub v4: Option<&'static str>,
|
||||||
|
pub v6: Option<&'static str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Provider {
|
||||||
|
pub fn ipify_org() -> Self {
|
||||||
|
Self { v4: Some("https://api.ipify.org"), v6: Some("https://api6.ipify.org") }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ident_me() -> Self {
|
||||||
|
Self { v4: Some("https://v4.ident.me"), v6: Some("https://v6.ident.me") }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ip(&self, ip_type: IpType) -> Result<http::Request<&'static [u8]>, Error> {
|
||||||
|
let uri = match ip_type {
|
||||||
|
IpType::V4 => self.v4.ok_or((ip_type, self))?,
|
||||||
|
IpType::V6 => self.v6.ok_or((ip_type, self))?,
|
||||||
|
};
|
||||||
|
Ok(http::Request::get(uri).body(&[][..] as &'static [u8])?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Provider {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::ident_me()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Provider {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||||
|
let provider = match self {
|
||||||
|
provider if provider == &Self::ipify_org() => String::from("ipify.org"),
|
||||||
|
provider if provider == &Self::ident_me() => String::from("ident.me"),
|
||||||
|
_ => String::from("unknown"),
|
||||||
|
};
|
||||||
|
write!(f, "{}", provider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Provider> for String {
|
||||||
|
fn into(self) -> Provider {
|
||||||
|
match self.as_ref() {
|
||||||
|
"ipify.org" => Provider::ipify_org(),
|
||||||
|
"ident.me" => Provider::ident_me(),
|
||||||
|
provider => {
|
||||||
|
// TODO: Handle this better
|
||||||
|
// I tried using TryInto here, but I couldn't figure out how to
|
||||||
|
// implement From<<T as TryInto<Provider>>::Error>.
|
||||||
|
log::error!("Couldn't find provider {}, falling back to the default", provider);
|
||||||
|
Provider::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue