aboutsummaryrefslogtreecommitdiff
path: root/src/voice/manager.rs
blob: 34d2a406b284a47eb2368f70035973ca034bba9b (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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use serde_json::Value;
use std::collections::HashMap;
use std::sync::mpsc::Sender as MpscSender;
use super::Handler;
use model::{ChannelId, GuildId, UserId};

/// A manager is a struct responsible for managing [`Handler`]s which belong to
/// a single [`Shard`]. This is a fairly complex key-value store,
/// with a bit of extra utility for easily joining a "target".
///
/// The "target" used by the Manager is determined based on the `guild_id` and
/// `channel_id` provided. If a `guild_id` is _not_ provided to methods that
/// optionally require it, then the target is a group or 1-on-1 call with a
/// user. The `channel_id` is then used as the target.
///
/// If a `guild_id` is provided, then the target is the guild, as a user
/// can not be connected to two channels within one guild simultaneously.
///
/// [`Group`]: ../../model/struct.Group.html
/// [`Handler`]: struct.Handler.html
/// [guild's channel]: ../../model/enum.ChannelType.html#variant.Voice
/// [`Shard`]: ../gateway/struct.Shard.html
#[derive(Clone, Debug)]
pub struct Manager {
    handlers: HashMap<GuildId, Handler>,
    user_id: UserId,
    ws: MpscSender<Value>,
}

impl Manager {
    pub(crate) fn new(ws: MpscSender<Value>, user_id: UserId) -> Manager {
        Manager {
            handlers: HashMap::new(),
            user_id: user_id,
            ws: ws,
        }
    }

    /// Retrieves a mutable handler for the given target, if one exists.
    pub fn get<G: Into<GuildId>>(&mut self, guild_id: G) -> Option<&mut Handler> {
        self.handlers.get_mut(&guild_id.into())
    }

    /// Connects to a target by retrieving its relevant [`Handler`] and
    /// connecting, or creating the handler if required.
    ///
    /// This can also switch to the given channel, if a handler already exists
    /// for the target and the current connected channel is not equal to the
    /// given channel.
    ///
    /// In the case of channel targets, the same channel is used to connect to.
    ///
    /// In the case of guilds, the provided channel is used to connect to. The
    /// channel _must_ be in the provided guild. This is _not_ checked by the
    /// library, and will result in an error. If there is already a connected
    /// handler for the guild, _and_ the provided channel is different from the
    /// channel that the connection is already connected to, then the handler
    /// will switch the connection to the provided channel.
    ///
    /// If you _only_ need to retrieve the handler for a target, then use
    /// [`get`].
    ///
    /// [`Handler`]: struct.Handler.html
    /// [`get`]: #method.get
    #[allow(map_entry)]
    pub fn join<C, G>(&mut self, guild_id: G, channel_id: C) -> &mut Handler
        where C: Into<ChannelId>, G: Into<GuildId> {
        let channel_id = channel_id.into();
        let guild_id = guild_id.into();

        {
            let mut found = false;

            if let Some(handler) = self.handlers.get_mut(&guild_id) {
                handler.switch_to(channel_id);

                found = true;
            }

            if found {
                // Actually safe, as the key has already been found above.
                return self.handlers.get_mut(&guild_id).unwrap();
            }
        }

        let mut handler = Handler::new(guild_id, self.ws.clone(), self.user_id);
        handler.join(channel_id);

        self.handlers.insert(guild_id, handler);

        // Actually safe, as the key would have been inserted above.
        self.handlers.get_mut(&guild_id).unwrap()
    }

    /// Retrieves the [handler][`Handler`] for the given target and leaves the
    /// associated voice channel, if connected.
    ///
    /// This will _not_ drop the handler, and will preserve it and its settings.
    ///
    /// This is a wrapper around [getting][`get`] a handler and calling
    /// [`leave`] on it.
    ///
    /// [`Handler`]: struct.Handler.html
    /// [`get`]: #method.get
    /// [`leave`]: struct.Handler.html#method.leave
    pub fn leave<G: Into<GuildId>>(&mut self, guild_id: G) {
        if let Some(handler) = self.handlers.get_mut(&guild_id.into()) {
            handler.leave();
        }
    }

    /// Retrieves the [`Handler`] for the given target and leaves the associated
    /// voice channel, if connected.
    ///
    /// The handler is then dropped, removing settings for the target.
    ///
    /// [`Handler`]: struct.Handler.html
    pub fn remove<G: Into<GuildId>>(&mut self, guild_id: G) {
        let guild_id = guild_id.into();

        self.leave(guild_id);

        self.handlers.remove(&guild_id);
    }
}