aboutsummaryrefslogtreecommitdiff
path: root/src/voice/threading.rs
blob: 55e3651e86520b39a2d1737d88642b1070c8086a (plain) (blame)
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use internal::Timer;
use model::id::GuildId;
use std::{
    sync::mpsc::{Receiver as MpscReceiver, TryRecvError},
    thread::Builder as ThreadBuilder
};
use super::{
    connection::Connection,
    Status
};

pub(crate) fn start(guild_id: GuildId, rx: MpscReceiver<Status>) {
    let name = format!("Serenity Voice (G{})", guild_id);

    ThreadBuilder::new()
        .name(name)
        .spawn(move || runner(&rx))
        .expect(&format!("[Voice] Error starting guild: {:?}", guild_id));
}

fn runner(rx: &MpscReceiver<Status>) {
    let mut senders = Vec::new();
    let mut receiver = None;
    let mut connection = None;
    let mut timer = Timer::new(20);

    'runner: loop {
        loop {
            match rx.try_recv() {
                Ok(Status::Connect(info)) => {
                    connection = match Connection::new(info) {
                        Ok(connection) => Some(connection),
                        Err(why) => {
                            warn!("[Voice] Error connecting: {:?}", why);

                            None
                        },
                    };
                },
                Ok(Status::Disconnect) => {
                    connection = None;
                },
                Ok(Status::SetReceiver(r)) => {
                    receiver = r;
                },
                Ok(Status::SetSender(s)) => {
                    senders.clear();

                    if let Some(aud) = s {
                        senders.push(aud);
                    }
                },
                Ok(Status::AddSender(s)) => {
                    senders.push(s);
                },
                Err(TryRecvError::Empty) => {
                    // If we received nothing, then we can perform an update.
                    break;
                },
                Err(TryRecvError::Disconnected) => {
                    break 'runner;
                },
            }
        }

        // Overall here, check if there's an error.
        //
        // If there is a connection, try to send an update. This should not
        // error. If there is though for some spurious reason, then set `error`
        // to `true`.
        //
        // Otherwise, wait out the timer and do _not_ error and wait to receive
        // another event.
        let error = match connection.as_mut() {
            Some(connection) => {
                let cycle = connection.cycle(&mut senders, &mut receiver, &mut timer);

                match cycle {
                    Ok(()) => false,
                    Err(why) => {
                        error!(
                            "(╯°□°)╯︵ ┻━┻ Error updating connection: {:?}",
                            why
                        );

                        true
                    },
                }
            },
            None => {
                timer.await();

                false
            },
        };

        // If there was an error, then just reset the connection and try to get
        // another.
        if error {
            connection = None;
        }
    }
}