1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
//! Interact with ChanServ
use crate::LockedState;
use irc::client::Client;
use std::sync::Arc;
use tokio::sync::mpsc::UnboundedReceiver;
use tokio::time::{interval, Duration};

/// Messages that go over the ChanServ channel
#[derive(Clone, Debug)]
pub enum Message {
    /// /cs flags <#channel>
    Flags(String),
    /// A NOTICE from ChanServ
    Notice(String),
}

/// Listen to messages on the ChanServ channel
pub async fn listen(
    rx: &mut UnboundedReceiver<Message>,
    state: LockedState,
    client: Arc<Client>,
) {
    while let Some(notice) = rx.recv().await {
        match notice {
            Message::Flags(channel) => {
                if state.read().await.chanserv.is_some() {
                    // Someone else is reading from chanserv, please wait
                    // TODO: add a timeout here, don't lock indefinitely
                    let mut interval = interval(Duration::from_millis(200));
                    loop {
                        if state.read().await.chanserv.is_none() {
                            break;
                        }
                        interval.tick().await;
                    }
                }
                {
                    let mut w = state.write().await;
                    w.chanserv = Some(Message::Flags(channel.to_string()));
                }
                client
                    .send_privmsg("ChanServ", format!("flags {}", &channel))
                    .unwrap();
                continue;
            }
            Message::Notice(notice) => {
                // Clone instead of locking since we need to get the
                // write lock inside to clear it
                let looking = state.read().await.chanserv.clone();
                if notice.starts_with("--------------")
                    || notice.starts_with("Entry    Nickname/Host")
                {
                    continue;
                }
                if let Some(Message::Flags(channel)) = &looking {
                    if notice.starts_with("End of") {
                        let mut w = state.write().await;
                        w.channels.get_mut(channel).unwrap().flags_done = true;
                        w.chanserv = None;
                    } else {
                        let mut w = state.write().await;
                        let managed =
                            w.channels.entry(channel.to_string()).or_default();
                        match managed.add_flags_from_chanserv(&notice) {
                            Ok(_) => {}
                            Err(e) => {
                                dbg!(e);
                            }
                        }
                    }
                }
            }
        };
    }
}