use std::borrow::Cow;
use futures::{future, Future as StdFuture, stream, Stream as StdStream};
use hyper::client::Connect;
use ::{Client, Stash};
use super::{Batched, Stream};
#[derive(Clone, Debug)]
pub struct Stashes<C>
where C: Clone + Connect
{
client: Client<C>,
}
impl<C: Clone + Connect> Stashes<C> {
#[inline]
pub(crate) fn new(client: Client<C>) -> Self {
Stashes { client }
}
}
impl<C: Clone + Connect> Stashes<C> {
#[inline]
pub fn all(&self) -> Stream<Batched<Stash>> {
self.get_stashes_stream(None)
}
#[inline]
pub fn since<Cid>(&self, change_id: Cid) -> Stream<Batched<Stash>>
where Cid: Into<String>
{
self.get_stashes_stream(Some(change_id.into()))
}
fn get_stashes_stream(&self, change_id: Option<String>) -> Stream<Batched<Stash>> {
enum State {
Start{change_id: Option<String>},
Next{change_id: String},
End,
}
let this = self.clone();
Box::new(
stream::unfold(State::Start{change_id}, move |state| {
let change_id = match state {
State::Start{change_id} => change_id,
State::Next{change_id} => Some(change_id),
State::End => return None,
};
let url: Cow<str> = match change_id.as_ref() {
Some(cid) => format!("{}?id={}", STASHES_URL, cid).into(),
None => STASHES_URL.into(),
};
Some(this.client.get(url).and_then(move |resp: PublicStashTabsResponse| {
let stashes = {
let curr_cid = change_id.clone();
let next_cid = resp.next_change_id.clone();
resp.stashes.into_iter().map(move |entry| Batched{
entry,
curr_token: curr_cid.clone(),
next_token: next_cid.clone(),
})
};
let next_state = match resp.next_change_id {
Some(next_cid) => {
let same_cid = change_id.as_ref().map(|cid| cid == &next_cid)
.unwrap_or(false);
if same_cid { State::End } else {
State::Next{change_id: next_cid}
}
}
None => {
warn!("No next_change_id found in stash tabs' response");
State::End
}
};
future::ok((stream::iter_ok(stashes), next_state))
}))
})
.flatten()
)
}
}
const STASHES_URL: &str = "/public-stash-tabs";
#[derive(Debug, Deserialize)]
struct PublicStashTabsResponse {
next_change_id: Option<String>,
stashes: Vec<Stash>,
}