twitchchat 0.14.8

interface to the irc-side of twitch's chat system
use crate::rate_limit::{RateClass, RateLimit};
use futures_lite::{AsyncWrite, AsyncWriteExt};
use std::{collections::VecDeque, time::Duration};

pub struct RateLimitedEncoder {
    pub(crate) rate_limit: RateLimit,
    pub(crate) queue: VecDeque<Box<[u8]>>,
}

impl RateLimitedEncoder {
    pub async fn drain_until_blocked<W>(
        &mut self,
        name: &str,
        limit: &mut u64,
        sink: &mut W,
    ) -> std::io::Result<()>
    where
        W: AsyncWrite + Send + Sync + Unpin + ?Sized,
    {
        while let Some(data) = self.queue.pop_front() {
            match self.rate_limit.consume(1) {
                Ok(..) => {
                    *limit = limit.saturating_sub(1);
                    log::trace!(
                        target: "twitchchat::encoder",
                        "> {}",
                        std::str::from_utf8(&*data).unwrap().escape_debug()
                    );
                    sink.write_all(&*data).await?;
                }
                Err(..) => {
                    log::warn!(
                        target: "twitchchat::rate_limit",
                        "local rate limit for '{}' hit",
                        name
                    );
                    break;
                }
            }
            if *limit == 0 {
                break;
            }
        }

        Ok(())
    }

    pub fn enqueue(&mut self, msg: Box<[u8]>) {
        self.queue.push_back(msg);
    }
}

pub struct PreviousRate {
    pub cap: u64,
    pub period: Duration,
}

impl Default for PreviousRate {
    fn default() -> Self {
        Self {
            cap: RateClass::Regular.tickets(),
            period: RateClass::period(),
        }
    }
}