1use async_trait::async_trait;
16use pingap_certificate::rcgen;
17use snafu::Snafu;
18use substring::Substring;
19
20pub static LOG_TARGET: &str = "pingap::acme";
22
23#[derive(Debug, Snafu)]
25pub enum Error {
26 #[snafu(display("ACME instant error: {source}, category: {category}"))]
28 Instant {
29 category: String,
30 source: instant_acme::Error,
31 },
32
33 #[snafu(display(
35 "Certificate generation error: {source}, category: {category}"
36 ))]
37 Rcgen {
38 category: String,
39 source: rcgen::Error,
40 },
41
42 #[snafu(display("ACME challenge not found: {message}"))]
44 NotFound { message: String },
45
46 #[snafu(display(
48 "Let's Encrypt operation failed: {message}, category: {category}"
49 ))]
50 Fail { category: String, message: String },
51}
52
53pub type Result<T, E = Error> = std::result::Result<T, E>;
55
56fn get_value_from_env(value: &str) -> String {
57 if value.is_empty() {
58 return value.to_string();
59 }
60 let key_prefix = "$ENV:";
61 if value.starts_with(key_prefix) {
62 std::env::var(value.substring(key_prefix.len(), value.len()))
63 .unwrap_or(value.to_string())
64 } else {
65 value.to_string()
66 }
67}
68
69#[async_trait]
71pub trait AcmeDnsTask: Sync + Send {
72 async fn add_txt_record(&self, domain: &str, value: &str) -> Result<()>;
74 async fn done(&self) -> Result<()>;
76}
77
78mod dns_ali;
79mod dns_cf;
80mod dns_huawei;
81mod dns_manual;
82mod dns_tencent;
83mod lets_encrypt;
84
85pub use lets_encrypt::{handle_lets_encrypt, new_lets_encrypt_service};