use crate::client::ConsulXClient;
use crate::errors::Result;
use std::time::Duration;
fn reconcile(prev: Option<u64>, mut new_index: u64) -> (u64, bool) {
if let Some(prev) = prev {
if new_index < prev {
new_index = 0; }
(new_index, new_index != prev)
} else {
(new_index, true) }
}
pub async fn cmd_watch_key(client: &ConsulXClient, key: &str) -> Result<()> {
println!("Watching key '{key}' (Ctrl+C to stop)...");
let mut index: Option<u64> = None;
loop {
let (raw_index, value) = client.kv_watch(key, index).await?;
let (new_index, changed) = reconcile(index, raw_index);
if changed {
match value {
Some(v) => println!("UPDATED [{key}] -> {v}"),
None => println!("UPDATED [{key}] -> <nil>"),
}
}
index = Some(new_index);
if new_index == 0 {
tokio::time::sleep(Duration::from_secs(2)).await;
}
}
}
pub async fn cmd_watch_prefix(client: &ConsulXClient, prefix: &str) -> Result<()> {
println!("Watching prefix '{prefix}' (Ctrl+C to stop)...");
let mut index: Option<u64> = None;
loop {
let (raw_index, keys) = client.kv_watch_prefix(prefix, index).await?;
let (new_index, changed) = reconcile(index, raw_index);
if changed {
println!("UPDATED PREFIX [{prefix}]:");
if keys.is_empty() {
println!(" <empty>");
} else {
for k in keys {
println!(" {k}");
}
}
}
index = Some(new_index);
if new_index == 0 {
tokio::time::sleep(Duration::from_secs(2)).await;
}
}
}
#[cfg(test)]
mod tests {
use super::reconcile;
#[test]
fn first_observation_always_changes() {
assert_eq!(reconcile(None, 42), (42, true));
assert_eq!(reconcile(None, 0), (0, true));
}
#[test]
fn same_index_is_no_change() {
assert_eq!(reconcile(Some(42), 42), (42, false));
}
#[test]
fn advancing_index_is_a_change() {
assert_eq!(reconcile(Some(42), 43), (43, true));
}
#[test]
fn backwards_index_resets_to_zero_and_changes() {
assert_eq!(reconcile(Some(100), 5), (0, true));
}
#[test]
fn backwards_to_zero_still_resets() {
assert_eq!(reconcile(Some(100), 0), (0, true));
}
}