wiki 0.0.3

Library for interacting with MediaWiki APIs
Documentation
use std::pin::Pin;
use std::task::Poll;

use chrono::{DateTime, Duration, Utc};
use futures_util::{Future, Stream};

use super::{GeneratorStream, RecentChangesGenerator, WikiGenerator};
use crate::api::RecentChangesResult;
use crate::req::rc::{ListRc, RcProp, RcType};
use crate::req::Limit;
use crate::Bot;

#[pin_project::pin_project(project = StateProj)]
pub enum State {
    Stream(#[pin] GeneratorStream<RecentChangesGenerator<Bot>>),
    Sleep(Pin<Box<tokio::time::Sleep>>),
}

#[pin_project::pin_project]
pub struct RecentChangesPatroller {
    bot: Bot,
    prev_time: DateTime<Utc>,
    #[pin]
    state: State,
    interval: tokio::time::Duration,
    errored: bool,
    prop: RcProp,
    ty: RcType,
}

impl RecentChangesPatroller {
    pub fn new(bot: Bot, interval: tokio::time::Duration, prop: RcProp, ty: RcType) -> Self {
        let prev_time = Self::now();
        let state = State::Sleep(Box::pin(tokio::time::sleep(interval)));
        Self {
            bot,
            prev_time,
            state,
            interval,
            errored: false,
            prop,
            ty,
        }
    }
    fn now() -> DateTime<Utc> {
        Utc::now() - Duration::seconds(1)
    }
}

impl Stream for RecentChangesPatroller {
    type Item = crate::Result<RecentChangesResult>;
    fn poll_next(
        mut self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Option<Self::Item>> {
        let this = self.as_mut().project();
        if *this.errored {
            return Poll::Ready(None);
        }
        match this.state.project() {
            StateProj::Sleep(s) => match s.as_mut().poll(cx) {
                Poll::Pending => Poll::Pending,
                Poll::Ready(()) => {
                    let timestamp = Self::now();
                    let gen = RecentChangesGenerator::new(
                        self.bot.clone(),
                        ListRc {
                            start: Some(timestamp.into()),
                            end: Some(self.prev_time.into()),
                            limit: Limit::Max,
                            prop: self.prop,
                            ty: self.ty,
                        },
                    );
                    self.prev_time = timestamp;
                    self.state = State::Stream(gen.into_stream());
                    self.poll_next(cx)
                }
            },
            StateProj::Stream(s) => match s.poll_next(cx) {
                Poll::Pending => Poll::Pending,
                Poll::Ready(None) => {
                    self.state = State::Sleep(Box::pin(tokio::time::sleep(self.interval)));
                    self.poll_next(cx)
                }
                Poll::Ready(Some(Err(e))) => {
                    *this.errored = true;
                    Poll::Ready(Some(Err(e)))
                }
                Poll::Ready(Some(Ok(i))) => Poll::Ready(Some(Ok(i))),
            },
        }
    }
}