Files
ddns/src/dns.rs
2026-08-29 14:36:14 +02:00

94 lines
2.0 KiB
Rust

use std::error::Error;
use reqwest::Client;
use serde::Deserialize;
use serde_json::json;
use crate::config::Auth;
pub struct Record {
pub id: String,
pub record_type: String,
pub domain: String,
pub subdomain: String,
pub value: String,
pub ttl: String,
}
const API: &str = "https://api.porkbun.com/api/json/v3";
#[derive(Deserialize)]
struct RecordsResponse {
records: Vec<RecordResponse>,
}
#[derive(Deserialize)]
struct RecordResponse {
id: String,
#[serde(rename = "type")]
record_type: String,
name: String,
content: String,
ttl: String,
}
impl RecordResponse {
fn into_model(self, domain: &str) -> Record {
let subdomain = self.name
.strip_suffix(domain).unwrap()
.strip_suffix(".").unwrap_or("");
Record {
id: self.id,
record_type: self.record_type,
domain: domain.to_string(),
subdomain: subdomain.to_string(),
value: self.content,
ttl: self.ttl,
}
}
}
pub async fn get_records(
client: &Client,
auth: &Auth,
domain: &str,
) -> Result<Vec<Record>, Box<dyn Error>> {
let body = json!({
"apikey": auth.key,
"secretapikey": auth.secret_key,
});
let request = client.post(format!("{API}/dns/retrieve/{domain}"))
.json(&body)
.send().await?;
let response = request.json::<RecordsResponse>().await?;
let records = response.records
.into_iter()
.map(|it| it.into_model(domain))
.collect();
Ok(records)
}
pub async fn update_record(
client: &Client,
auth: &Auth,
record: &Record,
value: &str,
) -> Result<(), Box<dyn Error>> {
let body = json!({
"apikey": auth.key,
"secretapikey": auth.secret_key,
"type": record.record_type,
"name": record.subdomain,
"content": value,
"ttl": record.ttl,
});
client.post(format!("{API}/dns/edit/{domain}/{id}", domain = record.domain, id = record.id))
.json(&body)
.send().await?;
Ok(())
}