use crossterm::event::Event;
use seer_core::RecordType;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Focus {
#[default]
Nav,
Pane,
}
impl Focus {
pub fn toggled(self) -> Self {
match self {
Focus::Nav => Focus::Pane,
Focus::Pane => Focus::Nav,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EditTarget {
Target,
DiffB,
FollowInterval,
FollowCount,
BulkPath,
BulkDomains,
WatchAdd,
TldFilter,
LensFilter,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum InputMode {
#[default]
Normal,
Command(crate::tui::line_editor::LineEditor),
Field {
target: EditTarget,
buf: crate::tui::line_editor::LineEditor,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FetchReq {
Overview(String),
Whois(String),
RdapDomain(String),
RdapIp(String),
RdapAsn(u32),
Dns {
domain: String,
record_type: RecordType,
nameserver: Option<String>,
},
Dnssec(String),
Compare {
domain: String,
record_type: RecordType,
a: String,
b: String,
},
Trace {
domain: String,
record_type: RecordType,
},
Ssl(String),
Status(String),
Prop(String),
Reverse(String),
Avail(String),
Tld(String),
Diff {
a: String,
b: String,
},
Watch,
History,
Subdomains(String),
Headers(String),
Takeover(String),
}
impl FetchReq {
pub fn lens_key(&self) -> &'static str {
match self {
FetchReq::Overview(_) => "overview",
FetchReq::Whois(_) => "whois",
FetchReq::RdapDomain(_) | FetchReq::RdapIp(_) | FetchReq::RdapAsn(_) => "rdap",
FetchReq::Dns { .. } => "dns",
FetchReq::Dnssec(_) | FetchReq::Compare { .. } | FetchReq::Trace { .. } => "dns",
FetchReq::Ssl(_) => "ssl",
FetchReq::Status(_) => "status",
FetchReq::Prop(_) => "propagation",
FetchReq::Reverse(_) => "reverse",
FetchReq::Avail(_) => "avail",
FetchReq::Tld(_) => "tld",
FetchReq::Diff { .. } => "diff",
FetchReq::Watch => "watch",
FetchReq::History => "history",
FetchReq::Subdomains(_) => "subdomains",
FetchReq::Headers(_) => "headers",
FetchReq::Takeover(_) => "takeover",
}
}
pub fn tab(&self) -> usize {
match self {
FetchReq::RdapIp(_) | FetchReq::Dnssec(_) => 1,
FetchReq::RdapAsn(_) | FetchReq::Compare { .. } => 2,
FetchReq::Trace { .. } => 3,
_ => 0,
}
}
pub fn target(&self) -> String {
match self {
FetchReq::Overview(d)
| FetchReq::Whois(d)
| FetchReq::RdapDomain(d)
| FetchReq::RdapIp(d)
| FetchReq::Dnssec(d)
| FetchReq::Ssl(d)
| FetchReq::Status(d)
| FetchReq::Prop(d)
| FetchReq::Reverse(d)
| FetchReq::Avail(d)
| FetchReq::Tld(d)
| FetchReq::Subdomains(d)
| FetchReq::Headers(d)
| FetchReq::Takeover(d) => d.clone(),
FetchReq::RdapAsn(n) => format!("AS{n}"),
FetchReq::Dns { domain, .. }
| FetchReq::Compare { domain, .. }
| FetchReq::Trace { domain, .. } => domain.clone(),
FetchReq::Diff { a, b } => format!("{a} ⇄ {b}"),
FetchReq::Watch => "watchlist".to_string(),
FetchReq::History => "history".to_string(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FollowParams {
pub domain: String,
pub iterations: usize,
pub interval_secs: u64,
pub gen: u64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BulkParams {
pub op: String, pub domains: Vec<String>,
pub gen: u64,
}
#[derive(Debug, Clone)]
pub enum Action {
Quit,
Fetch {
req: FetchReq,
gen: u64,
},
Copy {
text: String,
label: String,
},
StartFollow(FollowParams),
StopFollow,
StartBulk(BulkParams),
StopBulk,
StartBulkFromFile {
op: String,
path: String,
gen: u64,
},
WriteCsv {
path: String,
contents: String,
},
WatchMutate {
add: Option<String>,
remove: Option<String>,
gen: u64,
},
HistoryClear {
gen: u64,
},
}
pub use crate::payload::Payload as LensData;
#[derive(Debug, Clone, Default)]
pub enum LensState {
#[default]
Idle,
Loading,
Loaded(LensData),
Error(String),
}
#[derive(Debug)]
pub enum Msg {
Input(Event),
Tick,
Data {
lens: String,
gen: u64,
result: Result<LensData, String>,
},
CopyResult {
ok: bool,
label: String,
},
Toast {
tone: &'static str,
msg: String,
},
FollowStep {
gen: u64,
it: Box<seer_core::dns::FollowIteration>,
},
FollowDone {
gen: u64,
},
BulkStep {
gen: u64,
result: Box<seer_core::bulk::BulkResult>,
},
BulkDone {
gen: u64,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fetch_req_lens_keys() {
assert_eq!(FetchReq::RdapIp("1.2.3.4".into()).lens_key(), "rdap");
assert_eq!(FetchReq::Dnssec("x".into()).lens_key(), "dns");
assert_eq!(
FetchReq::Compare {
domain: "x".into(),
record_type: RecordType::A,
a: "8.8.8.8".into(),
b: "1.1.1.1".into()
}
.lens_key(),
"dns"
);
let trace = FetchReq::Trace {
domain: "x".into(),
record_type: RecordType::A,
};
assert_eq!(trace.lens_key(), "dns");
assert_eq!(trace.tab(), 3, "the DNS lens's Trace tab");
assert_eq!(trace.target(), "x");
assert_eq!(FetchReq::Tld(".com".into()).lens_key(), "tld");
assert_eq!(FetchReq::Headers("x".into()).lens_key(), "headers");
assert_eq!(FetchReq::Takeover("x".into()).lens_key(), "takeover");
}
#[test]
fn fetch_req_tabs_match_the_lens_sub_tabs() {
assert_eq!(FetchReq::RdapDomain("x".into()).tab(), 0);
assert_eq!(FetchReq::RdapIp("1.2.3.4".into()).tab(), 1);
assert_eq!(FetchReq::RdapAsn(15169).tab(), 2);
assert_eq!(FetchReq::Dnssec("x".into()).tab(), 1);
assert_eq!(FetchReq::Whois("x".into()).tab(), 0);
assert_eq!(FetchReq::RdapAsn(15169).target(), "AS15169");
}
#[test]
fn input_mode_default_and_focus() {
assert_eq!(InputMode::Normal, InputMode::default());
assert_eq!(Focus::Nav.toggled(), Focus::Pane);
}
}