use serde_json::Value;
use std::sync::mpsc::{self, Sender as MpscSender};
use super::{AudioReceiver, AudioSource};
use super::connection_info::ConnectionInfo;
use super::Status as VoiceStatus;
use ::constants::VoiceOpCode;
use ::model::{ChannelId, GuildId, UserId, VoiceState};
use super::threading;
#[derive(Clone, Debug)]
pub struct Handler {
pub channel_id: Option<ChannelId>,
pub endpoint: Option<String>,
pub guild_id: GuildId,
pub self_deaf: bool,
pub self_mute: bool,
sender: MpscSender<VoiceStatus>,
pub session_id: Option<String>,
pub token: Option<String>,
pub user_id: UserId,
ws: Option<MpscSender<Value>>,
}
impl Handler {
#[inline]
pub(crate) fn new(guild_id: GuildId, ws: MpscSender<Value>, user_id: UserId) -> Self {
Self::new_raw(guild_id, Some(ws), user_id)
}
#[inline]
pub fn standalone(guild_id: GuildId, user_id: UserId) -> Self {
Self::new_raw(guild_id, None, user_id)
}
pub fn connect(&mut self) -> bool {
if self.endpoint.is_none() || self.session_id.is_none() || self.token.is_none() {
return false;
}
let endpoint = self.endpoint.clone().unwrap();
let guild_id = self.guild_id;
let session_id = self.session_id.clone().unwrap();
let token = self.token.clone().unwrap();
let user_id = self.user_id;
self.send(VoiceStatus::Connect(ConnectionInfo {
endpoint: endpoint,
guild_id: guild_id,
session_id: session_id,
token: token,
user_id: user_id,
}));
true
}
pub fn deafen(&mut self, deaf: bool) {
self.self_deaf = deaf;
if self.channel_id.is_some() {
self.update();
}
}
pub fn join(&mut self, channel_id: ChannelId) {
self.channel_id = Some(channel_id);
self.send_join();
}
pub fn leave(&mut self) {
if self.channel_id.is_some() {
self.channel_id = None;
self.update();
}
}
pub fn listen<O: Into<Option<Box<AudioReceiver>>>>(&mut self, receiver: O) {
self.send(VoiceStatus::SetReceiver(receiver.into()))
}
pub fn mute(&mut self, mute: bool) {
self.self_mute = mute;
if self.channel_id.is_some() {
self.update();
}
}
pub fn play(&mut self, source: Box<AudioSource>) {
self.send(VoiceStatus::SetSender(Some(source)))
}
pub fn stop(&mut self) {
self.send(VoiceStatus::SetSender(None))
}
pub fn switch_to(&mut self, channel_id: ChannelId) {
match self.channel_id {
Some(current_id) if current_id == channel_id => {
return;
},
_ => {
self.channel_id = Some(channel_id);
self.update();
},
}
}
pub fn update_server(&mut self, endpoint: &Option<String>, token: &str) {
self.token = Some(token.to_owned());
if let Some(endpoint) = endpoint.clone() {
self.endpoint = Some(endpoint);
if self.session_id.is_some() {
self.connect();
}
} else {
self.leave();
}
}
pub fn update_state(&mut self, voice_state: &VoiceState) {
if self.user_id != voice_state.user_id.0 {
return;
}
self.channel_id = voice_state.channel_id;
if voice_state.channel_id.is_some() {
self.session_id = Some(voice_state.session_id.clone());
if self.endpoint.is_some() && self.token.is_some() {
self.connect();
}
} else {
self.leave();
}
}
fn new_raw(guild_id: GuildId, ws: Option<MpscSender<Value>>, user_id: UserId) -> Self {
let (tx, rx) = mpsc::channel();
threading::start(guild_id, rx);
Handler {
channel_id: None,
endpoint: None,
guild_id: guild_id,
self_deaf: false,
self_mute: false,
sender: tx,
session_id: None,
token: None,
user_id: user_id,
ws: ws,
}
}
fn send(&mut self, status: VoiceStatus) {
if let Err(mpsc::SendError(status)) = self.sender.send(status) {
let (tx, rx) = mpsc::channel();
self.sender = tx;
self.sender.send(status).unwrap();
threading::start(self.guild_id, rx);
self.update();
}
}
fn send_join(&self) {
if self.channel_id.is_none() {
return;
}
self.update();
}
fn update(&self) {
if let Some(ref ws) = self.ws {
let map = json!({
"op": VoiceOpCode::SessionDescription.num(),
"d": {
"channel_id": self.channel_id.map(|c| c.0),
"guild_id": self.guild_id.0,
"self_deaf": self.self_deaf,
"self_mute": self.self_mute,
}
});
let _ = ws.send(map);
}
}
}
impl Drop for Handler {
fn drop(&mut self) {
self.leave();
}
}