use std::{
collections::{hash_map::Entry, HashMap},
time::Duration,
};
use futures::Future;
use robespierre_models::id::ChannelId;
use tokio::time::Instant;
use crate::{ConnectionMessage, ConnectionMessanger};
#[derive(Clone, Debug)]
#[must_use = "Has to be dropped when the typing session ends"]
pub struct TypingSession {
channel_id: ChannelId,
messanger: ConnectionMessanger,
}
impl TypingSession {
pub fn new(channel_id: ChannelId, messanger: ConnectionMessanger) -> Self {
Self {
channel_id,
messanger,
}
}
}
impl Drop for TypingSession {
fn drop(&mut self) {
self.messanger.send(ConnectionMessage::StopTyping {
channel: self.channel_id,
})
}
}
pub struct TypingSessionManager {
sessions: HashMap<ChannelId, usize>,
interval: tokio::time::Interval,
}
impl TypingSessionManager {
pub fn new() -> Self {
Self {
sessions: HashMap::new(),
interval: tokio::time::interval(Duration::new(2, 500_000_000)),
}
}
pub fn start_typing(&mut self, channel: ChannelId) {
*self.sessions.entry(channel).or_insert(0) += 1;
}
pub fn stop_typing(&mut self, channel: ChannelId) -> bool {
match self.sessions.entry(channel) {
Entry::Occupied(mut entry) => {
*entry.get_mut() -= 1;
if *entry.get() == 0 {
entry.remove();
return true;
}
}
Entry::Vacant(_) => {
tracing::debug!("Trying to stop typing, but no session for the channel");
}
}
false
}
pub fn current_sessions(&self) -> ChannelIdIter {
ChannelIdIter(self.sessions.keys())
}
pub fn tick<'a>(&'a mut self) -> impl Future<Output = Instant> + 'a {
self.interval.tick()
}
}
pub struct ChannelIdIter<'a>(std::collections::hash_map::Keys<'a, ChannelId, usize>);
impl<'a> Iterator for ChannelIdIter<'a> {
type Item = &'a ChannelId;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}