Skip to content

Commit

Permalink
Merge pull request #1 from Xuanwo/add
Browse files Browse the repository at this point in the history
feat: Add HickoryResolver support
  • Loading branch information
Xuanwo committed Jan 25, 2024
2 parents d046670 + 33b812a commit e1489ec
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 27 deletions.
10 changes: 7 additions & 3 deletions Cargo.toml
Expand Up @@ -2,11 +2,15 @@
authors = ["Xuanwo <github@xuanwo.io>>"]
categories = ["command-line-utilities"]
description = "Replace with description"
documentation = "https://docs.rs/formwork"
repository = "https://github.com/Xuanwo/formwork"
documentation = "https://docs.rs/reqwest-hickory-resolver"
repository = "https://github.com/Xuanwo/reqwest-hickory-resolver"
edition = "2021"
license = "Apache-2.0"
name = "formwork"
name = "reqwest-hickory-resolver"
version = "0.0.1"

[dependencies]
hickory-resolver = "0.24.0"
reqwest = { version = "0.11", default-features = false }
hyper = {version = "0.14", default-features = false, features = ["client", "tcp"] }
once_cell = "1.19.0"
26 changes: 8 additions & 18 deletions README.md
@@ -1,33 +1,23 @@
# formwork &emsp; [![Build Status]][actions] [![Latest Version]][crates.io]
# reqwest-hickory-resolver &emsp; [![Build Status]][actions] [![Latest Version]][crates.io]

[Build Status]: https://img.shields.io/github/actions/workflow/status/Xuanwo/formwork/ci.yml
[actions]: https://github.com/Xuanwo/formwork/actions?query=branch%3Amain
[Latest Version]: https://img.shields.io/crates/v/formwork.svg
[crates.io]: https://crates.io/crates/formwork
[Build Status]: https://img.shields.io/github/actions/workflow/status/Xuanwo/reqwest-hickory-resolver/ci.yml
[actions]: https://github.com/Xuanwo/reqwest-hickory-resolver/actions?query=branch%3Amain
[Latest Version]: https://img.shields.io/crates/v/reqwest-hickory-resolver.svg
[crates.io]: https://crates.io/crates/reqwest-hickory-resolver

`formwork` is my favourite rust template.

> Please replace with valid value.
`reqwest-hickory-resolver` is the resolver for [reqwest](https://github.com/seanmonstar/reqwest) based on [`hickory-dns`](https://github.com/hickory-dns/hickory-dns).

## Quick Start

Replace all placeholder with valid values, for example:

- `Xuanwo` => github login
- `github@xuanwo.io` => email
- `formwork` => crate name

```rust
// Replace with quick Start here
```
TODO

## Contributing

Check out the [CONTRIBUTING.md](./CONTRIBUTING.md) guide for more details on getting started with contributing to this project.

## Getting help

Submit [issues](https://github.com/Xuanwo/formwork/issues/new/choose) for bug report or asking questions in [discussion](https://github.com/Xuanwo/formwork/discussions/new?category=q-a).
Submit [issues](https://github.com/Xuanwo/reqwest-hickory-resolver/issues/new/choose) for bug report or asking questions in [discussion](https://github.com/Xuanwo/reqwest-hickory-resolver/discussions/new?category=q-a).

#### License

Expand Down
7 changes: 7 additions & 0 deletions rustfmt.toml
@@ -1,2 +1,9 @@
edition = "2021"
reorder_imports = true

#format_code_in_doc_comments = true
#group_imports = "StdExternalCrate"
#imports_granularity = "Item"
#overflow_delimited_expr = true
#trailing_comma = "Vertical"
#where_single_line = true
108 changes: 102 additions & 6 deletions src/lib.rs
@@ -1,8 +1,104 @@
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
//! This crate provides [`HickoryResolver`] that implements reqwest [`Resolve`] so that we
//! can use it as reqwest's DNS resolver.
//!
//! # Examples
//!
//! Init client with `HickoryResolver`.
//!
//! ```
//! use std::sync::Arc;
//!
//! use reqwest::ClientBuilder;
//! use reqwest_hickory_resolver::HickoryResolver;
//!
//! fn init_with_hickory_resolver() -> reqwest::Result<()> {
//! let mut builder = ClientBuilder::new();
//! builder = builder.dns_resolver(Arc::new(HickoryResolver::default()));
//! builder.build()?;
//! Ok(())
//! }
//! ```
//!
//! [`HickoryResolver`] has cache support, we can share the same resolver across different client
//! for better performance.
//!
//! ```
//! use std::sync::Arc;
//!
//! use once_cell::sync::Lazy;
//! use reqwest::ClientBuilder;
//! use reqwest_hickory_resolver::HickoryResolver;
//!
//! static GLOBAL_RESOLVER: Lazy<Arc<HickoryResolver>> =
//! Lazy::new(|| Arc::new(HickoryResolver::default()));
//!
//! fn init_with_hickory_resolver() -> reqwest::Result<()> {
//! let mut builder = ClientBuilder::new();
//! builder = builder.dns_resolver(GLOBAL_RESOLVER.clone());
//! builder.build()?;
//! Ok(())
//! }
//! ```

use std::io;
use std::net::SocketAddr;
use std::sync::Arc;

pub use hickory_resolver::config::ResolverConfig;
pub use hickory_resolver::config::ResolverOpts;
use hickory_resolver::lookup_ip::LookupIpIntoIter;
use hickory_resolver::system_conf;
use hickory_resolver::TokioAsyncResolver;
use hyper::client::connect::dns::Name;
use once_cell::sync::OnceCell;
use reqwest::dns::Addrs;
use reqwest::dns::Resolve;
use reqwest::dns::Resolving;

/// HickoryResolver implements reqwest [`Resolve`] so that we can use it as reqwest's DNS resolver.
#[derive(Debug, Default, Clone)]
pub struct HickoryResolver {
/// Since we might not have been called in the context of a
/// Tokio Runtime in initialization, so we must delay the actual
/// construction of the resolver.
state: Arc<OnceCell<TokioAsyncResolver>>,
}

struct SocketAddrs {
iter: LookupIpIntoIter,
}

impl Resolve for HickoryResolver {
fn resolve(&self, name: Name) -> Resolving {
let resolver = self.clone();
Box::pin(async move {
let resolver = resolver.state.get_or_try_init(new_resolver)?;

let lookup = resolver.lookup_ip(name.as_str()).await?;
let addrs: Addrs = Box::new(SocketAddrs {
iter: lookup.into_iter(),
});
Ok(addrs)
})
}
}

impl Iterator for SocketAddrs {
type Item = SocketAddr;

fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|ip_addr| SocketAddr::new(ip_addr, 0))
}
}

/// Create a new resolver with the default configuration,
/// which reads from `/etc/resolve.conf`.
fn new_resolver() -> io::Result<TokioAsyncResolver> {
let (config, opts) = system_conf::read_system_conf().map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("error reading DNS system conf: {}", e),
)
})?;
Ok(TokioAsyncResolver::tokio(config, opts))
}

0 comments on commit e1489ec

Please sign in to comment.