Turn ChangeString into a PeerChange enum (#263)

* Turn ChangeString into a PeerChange enum, don't print NAT traversal reattempt as a modification

* Remove the ChangeString type

* Fix a stupid copy-paste error
pull/175/head
Brian Schwind 2023-06-01 12:11:31 +09:00 committed by GitHub
parent bd4aabe787
commit 0057a703ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 100 additions and 53 deletions

View File

@ -3,7 +3,9 @@ use colored::*;
use indoc::eprintdoc; use indoc::eprintdoc;
use log::{Level, LevelFilter}; use log::{Level, LevelFilter};
use serde::{de::DeserializeOwned, Serialize}; use serde::{de::DeserializeOwned, Serialize};
use shared::{interface_config::ServerInfo, Interface, PeerDiff, INNERNET_PUBKEY_HEADER}; use shared::{
interface_config::ServerInfo, Interface, PeerChange, PeerDiff, INNERNET_PUBKEY_HEADER,
};
use std::{ffi::OsStr, io, path::Path, time::Duration}; use std::{ffi::OsStr, io, path::Path, time::Duration};
use ureq::{Agent, AgentBuilder}; use ureq::{Agent, AgentBuilder};
@ -137,13 +139,30 @@ pub fn permissions_helptext(config_dir: &Path, data_dir: &Path, e: &io::Error) {
} }
} }
#[derive(Debug, Copy, Clone, PartialEq)]
enum ChangeAction {
Added,
Modified,
Removed,
}
impl ChangeAction {
fn colored_output(&self) -> ColoredString {
match self {
Self::Added => "added".green(),
Self::Modified => "modified".yellow(),
Self::Removed => "removed".red(),
}
}
}
pub fn print_peer_diff(store: &DataStore, diff: &PeerDiff) { pub fn print_peer_diff(store: &DataStore, diff: &PeerDiff) {
let public_key = diff.public_key().to_base64(); let public_key = diff.public_key().to_base64();
let text = match (diff.old, diff.new) { let change_action = match (diff.old, diff.new) {
(None, Some(_)) => "added".green(), (None, Some(_)) => ChangeAction::Added,
(Some(_), Some(_)) => "modified".yellow(), (Some(_), Some(_)) => ChangeAction::Modified,
(Some(_), None) => "removed".red(), (Some(_), None) => ChangeAction::Removed,
_ => unreachable!("PeerDiff can't be None -> None"), _ => unreachable!("PeerDiff can't be None -> None"),
}; };
@ -158,16 +177,31 @@ pub fn print_peer_diff(store: &DataStore, diff: &PeerDiff) {
}; };
let peer_name = peer_hostname.as_deref().unwrap_or("[unknown]"); let peer_name = peer_hostname.as_deref().unwrap_or("[unknown]");
if change_action == ChangeAction::Modified
&& diff
.changes()
.iter()
.all(|c| *c == PeerChange::NatTraverseReattempt)
{
// If this peer was "modified" but the only change is a NAT Traversal Reattempt,
// don't bother printing this peer.
return;
}
log::info!( log::info!(
" peer {} ({}...) was {}.", " peer {} ({}...) was {}.",
peer_name.yellow(), peer_name.yellow(),
&public_key[..10].dimmed(), &public_key[..10].dimmed(),
text change_action.colored_output(),
); );
for change in diff.changes() { for change in diff.changes() {
if let PeerChange::Endpoint { .. } = change {
log::info!(" {}", change);
} else {
log::debug!(" {}", change); log::debug!(" {}", change);
} }
}
} }
pub fn all_installed(config_dir: &Path) -> Result<Vec<Interface>, std::io::Error> { pub fn all_installed(config_dir: &Path) -> Result<Vec<Interface>, std::io::Error> {

View File

@ -519,35 +519,55 @@ impl Display for Peer {
} }
} }
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct ChangeString { pub enum PeerChange {
name: &'static str, AllowedIPs {
old: Option<String>, old: Vec<AllowedIp>,
new: Option<String>, new: Vec<AllowedIp>,
},
PersistentKeepalive {
old: Option<u16>,
new: Option<u16>,
},
Endpoint {
old: Option<SocketAddr>,
new: Option<SocketAddr>,
},
NatTraverseReattempt,
} }
impl Display for ChangeString { impl Display for PeerChange {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!( match self {
Self::AllowedIPs { old, new } => write!(f, "Allowed IPs: {:?} => {:?}", old, new),
Self::PersistentKeepalive { old, new } => write!(
f, f,
"{}: {} => {}", "Persistent Keepalive: {} => {}",
self.name, old.display_string(),
self.old.as_deref().unwrap_or("[none]"), new.display_string()
self.new.as_deref().unwrap_or("[none]") ),
) Self::Endpoint { old, new } => write!(
f,
"Endpoint: {} => {}",
old.display_string(),
new.display_string()
),
Self::NatTraverseReattempt => write!(f, "NAT Traversal Reattempt"),
}
} }
} }
impl ChangeString { trait OptionExt {
pub fn new<T, U>(name: &'static str, old: Option<T>, new: Option<U>) -> Self fn display_string(&self) -> String;
where }
T: fmt::Debug,
U: fmt::Debug, impl<T: std::fmt::Debug> OptionExt for Option<T> {
{ fn display_string(&self) -> String {
Self { match self {
name, Some(x) => {
old: old.map(|t| format!("{t:?}")), format!("{:?}", x)
new: new.map(|t| format!("{t:?}")), },
None => "[none]".to_string(),
} }
} }
} }
@ -559,7 +579,7 @@ pub struct PeerDiff<'a> {
pub old: Option<&'a PeerConfig>, pub old: Option<&'a PeerConfig>,
pub new: Option<&'a Peer>, pub new: Option<&'a Peer>,
builder: PeerConfigBuilder, builder: PeerConfigBuilder,
changes: Vec<ChangeString>, changes: Vec<PeerChange>,
} }
impl<'a> PeerDiff<'a> { impl<'a> PeerDiff<'a> {
@ -588,14 +608,14 @@ impl<'a> PeerDiff<'a> {
self.builder.public_key() self.builder.public_key()
} }
pub fn changes(&self) -> &[ChangeString] { pub fn changes(&self) -> &[PeerChange] {
&self.changes &self.changes
} }
fn peer_config_builder( fn peer_config_builder(
old_info: Option<&PeerInfo>, old_info: Option<&PeerInfo>,
new: Option<&Peer>, new: Option<&Peer>,
) -> Option<(PeerConfigBuilder, Vec<ChangeString>)> { ) -> Option<(PeerConfigBuilder, Vec<PeerChange>)> {
let old = old_info.map(|p| &p.config); let old = old_info.map(|p| &p.config);
let public_key = match (old, new) { let public_key = match (old, new) {
(Some(old), _) => old.public_key.clone(), (Some(old), _) => old.public_key.clone(),
@ -622,11 +642,10 @@ impl<'a> PeerDiff<'a> {
builder = builder builder = builder
.replace_allowed_ips() .replace_allowed_ips()
.add_allowed_ips(new_allowed_ips); .add_allowed_ips(new_allowed_ips);
changes.push(ChangeString::new( changes.push(PeerChange::AllowedIPs {
"AllowedIPs", old: old.map(|o| o.allowed_ips.clone()).unwrap_or_else(Vec::new),
old.map(|o| &o.allowed_ips[..]), new: new_allowed_ips.to_vec(),
Some(&new_allowed_ips[0]), });
));
} }
if old.is_none() if old.is_none()
@ -636,11 +655,10 @@ impl<'a> PeerDiff<'a> {
Some(interval) => builder.set_persistent_keepalive_interval(interval), Some(interval) => builder.set_persistent_keepalive_interval(interval),
None => builder.unset_persistent_keepalive(), None => builder.unset_persistent_keepalive(),
}; };
changes.push(ChangeString::new( changes.push(PeerChange::PersistentKeepalive {
"PersistentKeepalive", old: old.and_then(|p| p.persistent_keepalive_interval),
old.and_then(|p| p.persistent_keepalive_interval), new: new.persistent_keepalive_interval,
new.persistent_keepalive_interval, });
));
} }
// We won't update the endpoint if there's already a stable connection. // We won't update the endpoint if there's already a stable connection.
@ -653,20 +671,15 @@ impl<'a> PeerDiff<'a> {
if let Some(addr) = resolved { if let Some(addr) = resolved {
if old.is_none() || matches!(old, Some(old) if old.endpoint != resolved) { if old.is_none() || matches!(old, Some(old) if old.endpoint != resolved) {
builder = builder.set_endpoint(addr); builder = builder.set_endpoint(addr);
changes.push(ChangeString::new( changes.push(PeerChange::Endpoint {
"Endpoint", old: old.and_then(|p| p.endpoint),
old.and_then(|p| p.endpoint), new: Some(addr),
Some(addr), });
));
endpoint_changed = true; endpoint_changed = true;
} }
} }
if !endpoint_changed && !new.candidates.is_empty() { if !endpoint_changed && !new.candidates.is_empty() {
changes.push(ChangeString::new( changes.push(PeerChange::NatTraverseReattempt)
"Connection status",
"Disconnected".into(),
"NAT traverse reattempt".into(),
));
} }
} }