为了保留日志记录,我们可以使用 Rust 的 log 和 env_logger 库来记录程序的运行情况。以下是一个修改后的示例程序,展示了如何实现这一功能。
首先,确保你已经安装了 reqwest、tokio、serde、serde_json、toml、log 和 env_logger 库。你可以在 Cargo.toml 文件中添加以下依赖项:
[dependencies]
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
toml = "0.5"
log = "0.4"
env_logger = "0.9"然后,你可以编写以下 Rust 代码来实现动态域名解析并记录日志:
use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::fs;
use std::time::Duration;
use tokio::time::interval;
use log::{info, error};
#[derive(Serialize, Deserialize, Debug)]
struct Config {
api_key: String,
api_secret: String,
domain: String,
record_type: String,
record_name: String,
}
#[derive(Serialize, Deserialize, Debug)]
struct DnsRecord {
data: String,
ttl: u32,
}
async fn get_public_ip() -> Result<String, Box<dyn std::error::Error>> {
let response = reqwest::get("https://api.ipify.org")
.await?
.text()
.await?;
Ok(response)
}
async fn update_dns_record(
client: &Client,
api_key: &str,
api_secret: &str,
domain: &str,
record_type: &str,
record_name: &str,
new_ip: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let record = DnsRecord {
data: new_ip.to_string(),
ttl: 600,
};
let url = format!(
"https://api.godaddy.com/v1/domains/{}/records/{}/{}",
domain, record_type, record_name
);
let response = client
.put(&url)
.header("Authorization", format!("sso-key {}:{}", api_key, api_secret))
.json(&[record])
.send()
.await?;
if response.status().is_success() {
info!("DNS record updated successfully!");
} else {
error!("Failed to update DNS record: {:?}", response.text().await?);
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 初始化日志记录
env_logger::init();
// 读取配置文件
let config_str = fs::read_to_string("config.toml")?;
let config: Config = toml::from_str(&config_str)?;
// 创建一个HTTP客户端
let client = Client::new();
// 设置定时任务
let mut interval = interval(Duration::from_secs(60 * 10)); // 每10分钟检查一次
loop {
interval.tick().await;
// 获取当前机器的公共IP地址
let public_ip = match get_public_ip().await {
Ok(ip) => ip,
Err(e) => {
error!("Failed to get public IP: {}", e);
continue;
}
};
// 更新DNS记录
if let Err(e) = update_dns_record(
&client,
&config.api_key,
&config.api_secret,
&config.domain,
&config.record_type,
&config.record_name,
&public_ip,
)
.await
{
error!("Failed to update DNS record: {}", e);
}
}
}在这个示例中,我们使用了 log 和 env_logger 库来记录程序的运行情况。你需要在程序启动时初始化日志记录器,并在适当的地方使用 info! 和 error! 宏来记录信息和错误。
运行这个程序之前,确保你已经安装了所有依赖项,并且配置文件 config.toml 位于程序的运行目录中。你可以使用以下命令来运行程序:
RUST_LOG=info cargo run这样,你就可以使用配置文件来管理 API 密钥、域名和记录信息,并实现动态域名解析,同时保留日志记录了。
当然,让我们详细解析一下 async fn update_dns_record() 这段代码。
函数签名
async fn update_dns_record(
client: &Client,
api_key: &str,
api_secret: &str,
domain: &str,
record_type: &str,
record_name: &str,
new_ip: &str,
) -> Result<(), Box<dyn std::error::Error>> {async fn: 这是一个异步函数,意味着它可以在等待 I/O 操作时让出执行权,从而允许其他任务运行。client: &Client: 这是一个reqwest::Client的引用,用于发送 HTTP 请求。api_key: &str,api_secret: &str: 这是 GoDaddy API 的密钥和密钥,用于身份验证。domain: &str,record_type: &str,record_name: &str: 这些参数用于指定要更新的 DNS 记录的域名、记录类型和记录名称。new_ip: &str: 这是要更新的新 IP 地址。-> Result<(), Box<dyn std::error::Error>>: 这个函数返回一个Result类型,如果成功则返回Ok(()),如果失败则返回一个错误。
函数体
-
创建 DNS 记录对象
let record = DnsRecord { data: new_ip.to_string(), ttl: 600, };这里创建了一个
DnsRecord对象,其中data字段是新的 IP 地址,ttl字段是 600 秒(10分钟)。 -
构建请求 URL
let url = format!( "https://api.godaddy.com/v1/domains/{}/records/{}/{}", domain, record_type, record_name );这里使用
format!宏构建了 GoDaddy API 的 URL,指定了要更新的域名、记录类型和记录名称。 -
发送 HTTP PUT 请求
let response = client .put(&url) .header("Authorization", format!("sso-key {}:{}", api_key, api_secret)) .json(&[record]) .send() .await?;client.put(&url): 使用reqwest::Client发送一个 PUT 请求到指定的 URL。.header("Authorization", format!("sso-key {}:{}", api_key, api_secret)): 添加一个 Authorization 头,用于身份验证。.json(&[record]): 将DnsRecord对象序列化为 JSON 并作为请求体发送。.send().await?: 发送请求并等待响应。如果发生错误,使用?操作符将错误传播出去。
-
处理响应
if response.status().is_success() { info!("DNS record updated successfully!"); } else { error!("Failed to update DNS record: {:?}", response.text().await?); }response.status().is_success(): 检查响应的状态码是否表示成功。info!("DNS record updated successfully!");: 如果成功,记录一条信息日志。error!("Failed to update DNS record: {:?}", response.text().await?);: 如果失败,记录一条错误日志,并包含响应的文本内容。
-
返回结果
Ok(())最后,返回
Ok(())表示函数成功执行。
总结
async fn update_dns_record() 函数的主要功能是使用 GoDaddy API 更新 DNS 记录。它构建了一个包含新 IP 地址的 DNS 记录对象,发送一个 PUT 请求到 GoDaddy API,并根据响应的状态码记录成功或失败的信息。