diff options
| -rw-r--r-- | src/bot/master.rs | 6 | ||||
| -rw-r--r-- | src/bot/music.rs | 42 | ||||
| -rw-r--r-- | src/teamspeak.rs | 69 |
3 files changed, 106 insertions, 11 deletions
diff --git a/src/bot/master.rs b/src/bot/master.rs index 641938a..007abea 100644 --- a/src/bot/master.rs +++ b/src/bot/master.rs @@ -1,10 +1,10 @@ +use std::collections::HashMap; use std::future::Future; use std::sync::{Arc, Mutex}; -use std::collections::HashMap; use futures::future::{FutureExt, TryFutureExt}; use futures01::future::Future as Future01; -use log::{info}; +use log::info; use serde::{Deserialize, Serialize}; use tsclientlib::{ClientId, ConnectOptions, Identity, MessageTarget}; @@ -13,7 +13,7 @@ use crate::teamspeak::TeamSpeakConnection; use crate::Args; -use crate::bot::{MusicBot, MusicBotMessage, MusicBotArgs}; +use crate::bot::{MusicBot, MusicBotArgs, MusicBotMessage}; pub struct MasterBot { config: MasterConfig, diff --git a/src/bot/music.rs b/src/bot/music.rs index 4d67f88..94e7350 100644 --- a/src/bot/music.rs +++ b/src/bot/music.rs @@ -6,9 +6,9 @@ use std::thread; use log::{debug, info}; use structopt::StructOpt; use tokio02::sync::mpsc::UnboundedSender; -use tsclientlib::{ClientId, ConnectOptions, Identity, Invoker, MessageTarget}; +use tsclientlib::{data, ChannelId, ClientId, ConnectOptions, Identity, Invoker, MessageTarget}; -use crate::audio_player::{AudioPlayerError, AudioPlayer, PollResult}; +use crate::audio_player::{AudioPlayer, AudioPlayerError, PollResult}; use crate::command::Command; use crate::playlist::Playlist; use crate::teamspeak::TeamSpeakConnection; @@ -32,6 +32,14 @@ pub enum State { #[derive(Debug)] pub enum MusicBotMessage { TextMessage(Message), + ClientChannel { + client: ClientId, + old_channel: ChannelId, + }, + ClientDisconnected { + id: ClientId, + client: data::Client, + }, StateChange(State), Quit(String), } @@ -179,6 +187,20 @@ impl MusicBot { } } + fn my_channel(&self) -> ChannelId { + self.teamspeak + .as_ref() + .map(|ts| ts.my_channel()) + .expect("my_channel needs ts") + } + + fn user_count(&self, channel: ChannelId) -> u32 { + self.teamspeak + .as_ref() + .map(|ts| ts.user_count(channel)) + .expect("user_count needs ts") + } + fn send_message(&self, text: &str) { debug!("Sending message to TeamSpeak: {}", text); @@ -307,6 +329,22 @@ impl MusicBot { self.on_text(message).await?; } } + MusicBotMessage::ClientChannel { + client: _, + old_channel, + } => { + let my_channel = self.my_channel(); + if old_channel == my_channel && self.user_count(my_channel) <= 1 { + self.quit(String::from("Channel is empty")); + } + } + MusicBotMessage::ClientDisconnected { id: _, client } => { + let old_channel = client.channel; + let my_channel = self.my_channel(); + if old_channel == my_channel && self.user_count(my_channel) <= 1 { + self.quit(String::from("Channel is empty")); + } + } MusicBotMessage::StateChange(state) => { self.on_state(state)?; } diff --git a/src/teamspeak.rs b/src/teamspeak.rs index f1abaec..f49f7a6 100644 --- a/src/teamspeak.rs +++ b/src/teamspeak.rs @@ -19,17 +19,53 @@ pub struct TeamSpeakConnection { conn: Connection, } -fn get_message<'a>(event: &Event) -> Option<Message> { +fn get_message<'a>(event: &Event) -> Option<MusicBotMessage> { + use tsclientlib::events::{PropertyId, PropertyValue}; + match event { Event::Message { from: target, invoker: sender, message: msg, - } => Some(Message { - target: target.clone(), + } => Some(MusicBotMessage::TextMessage(Message { + target: *target, invoker: sender.clone(), text: msg.clone(), - }), + })), + Event::PropertyChanged { + id: property, + old: from, + invoker: _, + } => match property { + PropertyId::ClientChannel(client) => { + if let PropertyValue::ChannelId(from) = from { + Some(MusicBotMessage::ClientChannel { + client: *client, + old_channel: *from, + }) + } else { + None + } + } + _ => None, + }, + Event::PropertyRemoved { + id: property, + old: client, + invoker: _, + } => match property { + PropertyId::Client(id) => { + if let PropertyValue::Client(client) = client { + Some(MusicBotMessage::ClientDisconnected { + id: *id, + client: client.clone(), + }) + } else { + None + } + } + _ => None, + }, _ => None, } } @@ -49,8 +85,9 @@ impl TeamSpeakConnection { if let ConEvents(_conn, events) = e { for event in *events { if let Some(msg) = get_message(event) { - let tx = tx.lock().unwrap(); - tx.send(MusicBotMessage::TextMessage(msg)).unwrap(); + let tx = tx.lock().expect("Mutex was not poisoned"); + // Ignore the result because the receiver might get dropped first. + let _ = tx.send(msg); } } } @@ -108,6 +145,26 @@ impl TeamSpeakConnection { path } + pub fn my_channel(&self) -> ChannelId { + let conn = self.conn.lock(); + conn.clients + .get(&conn.own_client) + .expect("can find myself") + .channel + } + + pub fn user_count(&self, channel: ChannelId) -> u32 { + let conn = self.conn.lock(); + let mut count = 0; + for (_, client) in &conn.clients { + if client.channel == channel { + count += 1; + } + } + + count + } + pub fn set_nickname(&self, name: &str) { tokio::spawn( self.conn |
