From 716b4424580be4eef1c97b0bdc4c6efb197c8b27 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Fri, 15 Oct 2021 16:36:09 +0800 Subject: [PATCH] feat: add acme statics --- Cargo.lock | 13 ++++++- Cargo.toml | 3 +- src/main.rs | 8 +++++ src/statics.rs | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 src/statics.rs diff --git a/Cargo.lock b/Cargo.lock index 9563467..e6569d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "acme-client" -version = "0.6.0" +version = "0.6.1" dependencies = [ "acme-lib", "async-std", @@ -14,6 +14,7 @@ dependencies = [ "reqwest", "rust_util", "serde", + "simpledateformat", "tide", "trust-dns-resolver", "x509-parser", @@ -2053,6 +2054,16 @@ dependencies = [ "event-listener", ] +[[package]] +name = "simpledateformat" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd2436140481bbe945c4d6deab521cf1ac52d73766e3c5d28d2c65e2635ae115" +dependencies = [ + "chrono", + "quick-error", +] + [[package]] name = "slab" version = "0.4.4" diff --git a/Cargo.toml b/Cargo.toml index 4c59ed4..daab8fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "acme-client" -version = "0.6.0" +version = "0.6.1" authors = ["Hatter Jiang "] edition = "2018" description = "Acme auto challenge client, acme-client can issue certificates from Let's encrypt" @@ -19,6 +19,7 @@ deser-hjson = "0.1" x509-parser = "0.9" reqwest = { version = "0.11", features = ["blocking"] } trust-dns-resolver = "0.20" +simpledateformat = "0.1.3" [profile.release] codegen-units = 1 diff --git a/src/main.rs b/src/main.rs index 901a3fc..3b4c595 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ extern crate rust_util; mod config; mod x509; mod network; +mod statics; // mod simple_thread_pool; use std::env; @@ -29,6 +30,7 @@ use crate::config::{CertConfig, CERT_NAME, KEY_NAME}; use crate::x509::{X509PublicKeyAlgo, X509EcPublicKeyAlgo}; use std::path::PathBuf; use crate::network::{get_local_public_ip, get_resolver, resolve_first_ipv4}; +use crate::statics::{AcmeStatics, AcmeStatus}; const NAME: &str = env!("CARGO_PKG_NAME"); const VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -251,6 +253,7 @@ async fn main() -> tide::Result<()> { check_cert_config(&cert_config); return Ok(()); } + let mut acme_statics = AcmeStatics::start(); let filtered_cert_config = cert_config.filter_cert_config_items(30); for item in &filtered_cert_config.cert_items { if item.common_name.as_ref().map(|n| n.contains('*')).unwrap_or(false) @@ -275,9 +278,14 @@ async fn main() -> tide::Result<()> { }; if let Err(e) = request_acme_certificate(acme_request) { failure!("Request certificate: {}, by acme failed: {}", item.path, e); + acme_statics.add_item(dns_names.clone(), AcmeStatus::Fail(format!("{}", e))); + } else { + acme_statics.add_item(dns_names.clone(), AcmeStatus::Success); } } } + acme_statics.end(); + success!("Statics: \n{}", acme_statics); } } diff --git a/src/statics.rs b/src/statics.rs new file mode 100644 index 0000000..4f9d9d5 --- /dev/null +++ b/src/statics.rs @@ -0,0 +1,94 @@ +use std::time::SystemTime; +use std::fmt::{Display, Formatter, Result}; + +#[derive(Debug)] +pub struct AcmeStatics { + pub started: SystemTime, + pub ended: Option, + pub items: Vec, +} + +#[derive(Debug)] +pub enum AcmeStatus { + Success, + // Skipped, + Fail(String), +} + +impl Display for AcmeStatus { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + match self { + AcmeStatus::Success => write!(f, "Success"), + AcmeStatus::Fail(message) => write!(f, "Failed: {}", message), + } + } +} + +#[derive(Debug)] +pub struct AcmeItem { + pub domains: Vec, + pub status: AcmeStatus, +} + +impl Display for AcmeItem { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "Domains: {}; {}", self.domains.join(", "), &self.status) + } +} + +impl Display for AcmeStatics { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + let mut sb = String::with_capacity(512); + let df = simpledateformat::fmt("yyyy-MM-dd HH:mm:ss z").unwrap(); + let started_time = df.format_local(self.started.clone()); + sb.push_str(&format!("Started: {}", &started_time)); + if let Some(ended) = &self.ended { + let ended_time = df.format_local(ended.clone()); + sb.push_str(&format!("\nEnded: {}", &ended_time)); + let cost_result = ended.duration_since(self.started); + if let Ok(cost) = cost_result { + sb.push_str(&format!(", cost: {}", simpledateformat::format_human(cost))); + } + } + let mut success_count: i32 = 0; + let mut failed_count: i32 = 0; + for item in &self.items { + match &item.status { + AcmeStatus::Success => { + success_count += 1; + } + AcmeStatus::Fail(_) => { + failed_count += 1; + sb.push_str(&format!("\n - {}", &item)); + } + } + } + sb.push_str(&format!("\nTotal count: {}, success count: {}, failed count: {}", + success_count + failed_count, + success_count, + failed_count, + )); + write!(f, "{}", &sb) + } +} + +impl AcmeStatics { + pub fn start() -> AcmeStatics { + AcmeStatics { + started: SystemTime::now(), + ended: None, + items: Vec::new(), + } + } + + pub fn end(&mut self) { + self.ended = Some(SystemTime::now()); + } + + pub fn add_item(&mut self, domains: Vec, status: AcmeStatus) { + self.items.push(AcmeItem { + domains, + status, + }); + } +} \ No newline at end of file