1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use anyhow::Result;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::app::console::{Console, ConsoleOpts};
use crate::app::resolver::{NameBuilder, NameBuilderOpts};
use crate::app::{self, AppConfig, ExitStatus};
pub mod check;
pub mod discover;
pub mod get_server_lists;
pub mod lookup;
pub type PartialResult<T> = std::result::Result<T, PartialError>;
pub trait PartialResultExt {
fn into_result(self) -> anyhow::Result<ExitStatus>;
}
impl PartialResultExt for PartialResult<ExitStatus> {
fn into_result(self) -> anyhow::Result<ExitStatus> {
match self {
Ok(exit_status) => Ok(exit_status),
Err(PartialError::Failed(exit_status)) => Ok(exit_status),
Err(err @ PartialError::Err { .. }) => Err(err.into()),
}
}
}
#[derive(Debug, Error)]
pub enum PartialError {
#[error("module step failed")]
Failed(app::ExitStatus),
#[error(transparent)]
Err(#[from] anyhow::Error),
}
impl From<crate::error::Error> for PartialError {
fn from(err: crate::error::Error) -> Self {
PartialError::Err(anyhow::Error::new(err))
}
}
impl From<crate::resolver::error::Error> for PartialError {
fn from(err: crate::resolver::error::Error) -> Self {
PartialError::Err(anyhow::Error::new(err))
}
}
impl From<crate::services::error::Error> for PartialError {
fn from(err: crate::services::error::Error) -> Self {
PartialError::Err(anyhow::Error::new(err))
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct RunInfo {
pub start_time: DateTime<Utc>,
pub command_line: String,
pub version: &'static str,
}
impl RunInfo {
pub fn now() -> Self {
let args: Vec<_> = std::env::args().skip(1).collect();
let command_line = args.join(" ");
RunInfo {
start_time: Utc::now(),
command_line,
version: env!("CARGO_PKG_VERSION"),
}
}
}
pub struct Environment<'a, T> {
pub run_info: RunInfo,
pub app_config: &'a AppConfig,
pub mod_config: &'a T,
pub console: Console,
pub name_builder: NameBuilder,
}
impl<'a, T> Environment<'a, T> {
pub fn new(
app_config: &'a AppConfig,
mod_config: &'a T,
console: Console,
name_builder: NameBuilder,
) -> Environment<'a, T> {
Environment {
run_info: RunInfo::now(),
app_config,
mod_config,
console,
name_builder,
}
}
}
pub trait AppModule<T: ModConfig> {
fn init_env<'a>(app_config: &'a AppConfig, config: &'a T) -> Result<Environment<'a, T>> {
let console_opts = ConsoleOpts::from(app_config).with_partial_results(config.partial_results());
let console = Console::new(console_opts);
let name_builder_ops = if let Some(ref search_domain) = app_config.search_domain {
NameBuilderOpts::new(app_config.ndots, search_domain.as_ref())
} else {
NameBuilderOpts::from_hostname(app_config.ndots)
}?;
let name_builder = NameBuilder::new(name_builder_ops);
let env = Environment::new(app_config, config, console, name_builder);
Ok(env)
}
}
pub trait ModConfig {
fn partial_results(&self) -> bool {
false
}
}