Documentation
# idoh

```rust
#![feature(doc_auto_cfg)]
#![feature(doc_cfg)]

mod post;
use std::sync::{
  Arc,
  atomic::{AtomicU8, Ordering},
};

pub use post::{Answer, DohError, post};
use defer_lite::defer;
use aok::{OK, Result};
use tracing::error;
use tokio::time::{Duration, sleep};

pub static DOH_LI: &[&str] = &[
  "doh.pub/resolve", // 腾讯
  "dns.google/resolve",
  "dns0.eu",
  "cloudflare-dns.com/dns-query",
  "doh.sb/dns-query",
  "doh.360.cn/resolve",
  "dns.nextdns.io",
  "dns.twnic.tw/dns-query",
  "dns.alidns.com/resolve",
];

pub async fn resolve<T: Send + 'static>(
  name: impl AsRef<str>,
  record_type: impl AsRef<str>,
  extract: fn(Vec<Answer>) -> Result<Option<T>>,
) -> Result<T> {
  let query = format!("?name={}&type={}", name.as_ref(), record_type.as_ref());
  let (send, recv) = kanal::bounded_async(1);

  let spawn = tokio::spawn(async move {
    let ing = Arc::new(AtomicU8::new(DOH_LI.len() as _));

    for doh in riter::iter(DOH_LI) {
      let query = query.clone();
      let send = send.clone();
      let ing = ing.clone();
      tokio::spawn(async move {
        let r = post(doh, &query).await;
        let runing = ing.fetch_sub(1, Ordering::Relaxed);

        macro_rules! send_err {
          ($err: expr) => {{
            let err = $err;
            error!("{runing} : {doh} {err}");
            if runing == 1 {
              xerr::log!(send.send(Err(err)).await);
            }
          }};
        }

        match r {
          Ok(res) => match extract(res) {
            Ok(res) => {
              if let Some(res) = res {
                let _ = send.send(Ok::<_, aok::Error>(res)).await;
              }
            }
            Err(err) => send_err!(err),
          },
          Err(err) => {
            send_err!(err);
          }
        }
        OK
      });
      sleep(Duration::from_millis(700)).await;
    }
  });

  defer! {
    spawn.abort();
  }

  recv.recv().await?
}
```

## About

This project is an open-source component of [i18n.site ⋅ Internationalization Solution](https://i18n.site).

* [i18 : MarkDown Command Line Translation Tool]https://i18n.site/i18

  The translation perfectly maintains the Markdown format.

  It recognizes file changes and only translates the modified files.

  The translated Markdown content is editable; if you modify the original text and translate it again, manually edited translations will not be overwritten (as long as the original text has not been changed).

* [i18n.site : MarkDown Multi-language Static Site Generator]https://i18n.site/i18n.site

  Optimized for a better reading experience

## 关于

本项目为 [i18n.site ⋅ 国际化解决方案](https://i18n.site) 的开源组件。

* [i18 :  MarkDown命令行翻译工具]https://i18n.site/i18

  翻译能够完美保持 Markdown 的格式。能识别文件的修改,仅翻译有变动的文件。

  Markdown 翻译内容可编辑;如果你修改原文并再次机器翻译,手动修改过的翻译不会被覆盖(如果这段原文没有被修改)。

* [i18n.site : MarkDown多语言静态站点生成器]https://i18n.site/i18n.site 为阅读体验而优化。