mum_cli/state/
channel.rs

1use crate::state::user::User;
2
3use mumble_protocol::control::msgs;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7#[derive(Clone, Debug, Default, Deserialize, Serialize)]
8pub struct Channel {
9    description: Option<String>,
10    links: Vec<u32>,
11    max_users: u32,
12    name: String,
13    parent: Option<u32>,
14    position: i32,
15}
16
17impl Channel {
18    pub fn new(mut msg: msgs::ChannelState) -> Self {
19        Self {
20            description: if msg.has_description() {
21                Some(msg.take_description())
22            } else {
23                None
24            },
25            links: Vec::new(),
26            max_users: msg.get_max_users(),
27            name: msg.take_name(),
28            parent: if msg.has_parent() {
29                Some(msg.get_parent())
30            } else {
31                None
32            },
33            position: msg.get_position(),
34        }
35    }
36
37    pub fn parse_channel_state(&mut self, mut msg: msgs::ChannelState) {
38        if msg.has_description() {
39            self.description = Some(msg.take_description());
40        }
41        self.links = msg.take_links();
42        if msg.has_max_users() {
43            self.max_users = msg.get_max_users();
44        }
45        if msg.has_name() {
46            self.name = msg.take_name();
47        }
48        if msg.has_parent() {
49            self.parent = Some(msg.get_parent());
50        }
51        if msg.has_position() {
52            self.position = msg.get_position();
53        }
54    }
55
56    pub fn name(&self) -> &str {
57        &self.name
58    }
59
60    pub fn path(&self, channels: &HashMap<u32, Channel>) -> String {
61        match &self.parent {
62            Some(t) => format!("{}/{}", channels.get(t).unwrap().path(channels), self.name),
63            None => self.name.clone(),
64        }
65    }
66}
67
68#[derive(Debug)]
69struct ProtoTree<'a> {
70    channel: Option<&'a Channel>,
71    children: HashMap<u32, ProtoTree<'a>>,
72    users: Vec<&'a User>,
73}
74
75impl<'a> ProtoTree<'a> {
76    fn walk_and_add(
77        &mut self,
78        channel: &'a Channel,
79        users: &HashMap<u32, Vec<&'a User>>,
80        walk: &[u32],
81    ) {
82        match walk {
83            [] => unreachable!("Walks should always have at least one element"),
84            &[node] => {
85                let pt = self.children.entry(node).or_insert(ProtoTree {
86                    channel: None,
87                    children: HashMap::new(),
88                    users: Vec::new(),
89                });
90                pt.channel = Some(channel);
91                pt.users = users.get(&node).cloned().unwrap_or_default();
92            }
93            longer => {
94                self.children
95                    .entry(longer[0])
96                    .or_insert(ProtoTree {
97                        channel: None,
98                        children: HashMap::new(),
99                        users: Vec::new(),
100                    })
101                    .walk_and_add(channel, users, &walk[1..]);
102            }
103        }
104    }
105}
106
107impl<'a> From<&ProtoTree<'a>> for mumlib::state::Channel {
108    fn from(tree: &ProtoTree<'a>) -> Self {
109        let mut channel = mumlib::state::Channel::from(tree.channel.unwrap());
110        let mut children = tree
111            .children
112            .iter()
113            .map(|e| {
114                (
115                    e.1.channel.unwrap().position,
116                    mumlib::state::Channel::from(e.1),
117                )
118            })
119            .collect::<Vec<_>>();
120        children.sort_by_key(|e| (e.0, e.1.name.clone()));
121        channel.children = children.into_iter().map(|e| e.1).collect();
122        channel.users = tree.users.iter().map(|e| (*e).into()).collect();
123        channel
124    }
125}
126
127pub fn into_channel(
128    channels: &HashMap<u32, Channel>,
129    users: &HashMap<u32, User>,
130) -> mumlib::state::Channel {
131    let mut walks = Vec::new();
132
133    let mut channel_lookup = HashMap::new();
134
135    for user in users.values() {
136        channel_lookup
137            .entry(user.channel())
138            .or_insert_with(Vec::new)
139            .push(user);
140    }
141
142    for (channel_id, channel) in channels {
143        let mut walk = Vec::new();
144        let mut current = *channel_id;
145        while let Some(next) = channels.get(&current).unwrap().parent {
146            walk.push(current);
147            current = next;
148        }
149        walk.reverse();
150
151        if !walk.is_empty() {
152            walks.push((walk, channel));
153        }
154    }
155
156    //root node is ignored because of how walk_and_add is implemented on ProtoTree
157    let mut proto_tree = ProtoTree {
158        channel: Some(channels.get(&0).unwrap()),
159        children: HashMap::new(),
160        users: channel_lookup.get(&0).cloned().unwrap_or_default(),
161    };
162
163    for (walk, channel) in walks {
164        proto_tree.walk_and_add(channel, &channel_lookup, &walk);
165    }
166
167    (&proto_tree).into()
168}
169
170impl From<&Channel> for mumlib::state::Channel {
171    fn from(channel: &Channel) -> Self {
172        mumlib::state::Channel::new(
173            channel.name.clone(),
174            channel.description.clone(),
175            channel.max_users,
176        )
177    }
178}