use std::fmt::{Debug, Display, Write}; use anyhow::{bail, Result}; use log::*; use reqwest::Response; use serde::Deserialize; use crate::Consul; impl Consul { pub(crate) async fn get_with_index Deserialize<'de>>( &self, mut url: String, last_index: Option, ) -> Result> { if let Some(i) = last_index { if url.contains('?') { write!(&mut url, "&index={}", i).unwrap(); } else { write!(&mut url, "?index={}", i).unwrap(); } } debug!("GET {} as {}", url, std::any::type_name::()); let http = self.client.get(&url).send().await?; Ok(WithIndex::::index_from(&http)?.value(http.json().await?)) } } /// Wraps the returned value of an [API call with blocking /// possibility](https://developer.hashicorp.com/consul/api-docs/features/blocking) with the /// returned Consul index pub struct WithIndex { pub(crate) value: T, pub(crate) index: usize, } impl WithIndex { /// (for internal use, mostly) pub fn index_from(resp: &Response) -> Result> { let index = match resp.headers().get("X-Consul-Index") { Some(v) => v.to_str()?.parse::()?, None => bail!("X-Consul-Index header not found"), }; Ok(WithIndexBuilder { index, _phantom: Default::default(), }) } /// Returns the inner value, discarding the index pub fn into_inner(self) -> T { self.value } /// Returns the Consul index, to be used in future calls to the same API endpoint to make them /// blocking pub fn index(&self) -> usize { self.index } } impl std::convert::AsRef for WithIndex { fn as_ref(&self) -> &T { &self.value } } impl std::borrow::Borrow for WithIndex { fn borrow(&self) -> &T { &self.value } } impl std::ops::Deref for WithIndex { type Target = T; fn deref(&self) -> &T { &self.value } } impl Debug for WithIndex { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ::fmt(self, f) } } impl Display for WithIndex { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ::fmt(self, f) } } /// (for internal use, mostly) pub struct WithIndexBuilder { _phantom: std::marker::PhantomData, index: usize, } impl WithIndexBuilder { /// (for internal use, mostly) pub fn value(self, value: T) -> WithIndex { WithIndex { value, index: self.index, } } }