Files
songbird/src/driver/tasks/mod.rs
Kyle Simpson aaab97511d Library: Add compatibility for legacy Tokio 0.2 (#40)
Adds support to the library for tokio 0.2 backward-compatibility. This should hopefully benefit, and prevent lavalink-rs from being blocked on this feature.

These can be reached using, e.g., `gateway-tokio-02`, `driver-tokio-02`, `serenity-rustls-tokio-02`, and `serenity-native-tokio-02` features.

Naturally, this requires some jiggering about with features and the underlying CI, which has been taken care of. Twilight can't be handled in this way, as their last tokio 0.2 version uses the deprecated Discord Gateway v6.
2021-02-04 02:34:07 +00:00

210 lines
7.5 KiB
Rust

#![allow(missing_docs)]
pub(crate) mod disposal;
pub mod error;
mod events;
pub mod message;
pub mod mixer;
pub(crate) mod udp_rx;
pub(crate) mod udp_tx;
pub(crate) mod ws;
use super::{
connection::{error::Error as ConnectionError, Connection},
Config,
};
use crate::events::CoreContext;
use flume::{Receiver, RecvError, Sender};
use message::*;
#[cfg(not(feature = "tokio-02-marker"))]
use tokio::{runtime::Handle, spawn};
#[cfg(feature = "tokio-02-marker")]
use tokio_compat::{runtime::Handle, spawn};
use tracing::{error, info, instrument};
pub(crate) fn start(config: Config, rx: Receiver<CoreMessage>, tx: Sender<CoreMessage>) {
spawn(async move {
info!("Driver started.");
runner(config, rx, tx).await;
info!("Driver finished.");
});
}
fn start_internals(core: Sender<CoreMessage>, config: Config) -> Interconnect {
let (evt_tx, evt_rx) = flume::unbounded();
let (mix_tx, mix_rx) = flume::unbounded();
let interconnect = Interconnect {
core,
events: evt_tx,
mixer: mix_tx,
};
let ic = interconnect.clone();
spawn(async move {
info!("Event processor started.");
events::runner(ic, evt_rx).await;
info!("Event processor finished.");
});
let ic = interconnect.clone();
let handle = Handle::current();
std::thread::spawn(move || {
info!("Mixer started.");
mixer::runner(ic, mix_rx, handle, config);
info!("Mixer finished.");
});
interconnect
}
#[instrument(skip(rx, tx))]
async fn runner(mut config: Config, rx: Receiver<CoreMessage>, tx: Sender<CoreMessage>) {
let mut next_config: Option<Config> = None;
let mut connection = None;
let mut interconnect = start_internals(tx, config.clone());
loop {
match rx.recv_async().await {
Ok(CoreMessage::ConnectWithResult(info, tx)) => {
config = if let Some(new_config) = next_config.take() {
let _ = interconnect
.mixer
.send(MixerMessage::SetConfig(new_config.clone()));
new_config
} else {
config
};
connection = match Connection::new(info, &interconnect, &config).await {
Ok(connection) => {
// Other side may not be listening: this is fine.
let _ = tx.send(Ok(()));
let _ = interconnect
.events
.send(EventMessage::FireCoreEvent(CoreContext::DriverConnect));
Some(connection)
},
Err(why) => {
// See above.
let _ = tx.send(Err(why));
let _ = interconnect.events.send(EventMessage::FireCoreEvent(
CoreContext::DriverConnectFailed,
));
None
},
};
},
Ok(CoreMessage::Disconnect) => {
connection = None;
let _ = interconnect.mixer.send(MixerMessage::DropConn);
let _ = interconnect.mixer.send(MixerMessage::RebuildEncoder);
},
Ok(CoreMessage::SetTrack(s)) => {
let _ = interconnect.mixer.send(MixerMessage::SetTrack(s));
},
Ok(CoreMessage::AddTrack(s)) => {
let _ = interconnect.mixer.send(MixerMessage::AddTrack(s));
},
Ok(CoreMessage::SetBitrate(b)) => {
let _ = interconnect.mixer.send(MixerMessage::SetBitrate(b));
},
Ok(CoreMessage::SetConfig(mut new_config)) => {
next_config = Some(new_config.clone());
new_config.make_safe(&config, connection.is_some());
let _ = interconnect.mixer.send(MixerMessage::SetConfig(new_config));
},
Ok(CoreMessage::AddEvent(evt)) => {
let _ = interconnect.events.send(EventMessage::AddGlobalEvent(evt));
},
Ok(CoreMessage::RemoveGlobalEvents) => {
let _ = interconnect.events.send(EventMessage::RemoveGlobalEvents);
},
Ok(CoreMessage::Mute(m)) => {
let _ = interconnect.mixer.send(MixerMessage::SetMute(m));
},
Ok(CoreMessage::Reconnect) => {
if let Some(mut conn) = connection.take() {
// try once: if interconnect, try again.
// if still issue, full connect.
let info = conn.info.clone();
let full_connect = match conn.reconnect().await {
Ok(()) => {
connection = Some(conn);
false
},
Err(ConnectionError::InterconnectFailure(_)) => {
interconnect.restart_volatile_internals();
match conn.reconnect().await {
Ok(()) => {
connection = Some(conn);
false
},
_ => true,
}
},
_ => true,
};
if full_connect {
connection = Connection::new(info, &interconnect, &config)
.await
.map_err(|e| {
error!("Catastrophic connection failure. Stopping. {:?}", e);
let _ = interconnect.events.send(EventMessage::FireCoreEvent(
CoreContext::DriverReconnectFailed,
));
e
})
.ok();
}
if connection.is_some() {
let _ = interconnect
.events
.send(EventMessage::FireCoreEvent(CoreContext::DriverReconnect));
}
}
},
Ok(CoreMessage::FullReconnect) =>
if let Some(conn) = connection.take() {
let info = conn.info.clone();
connection = Connection::new(info, &interconnect, &config)
.await
.map_err(|e| {
error!("Catastrophic connection failure. Stopping. {:?}", e);
let _ = interconnect.events.send(EventMessage::FireCoreEvent(
CoreContext::DriverReconnectFailed,
));
e
})
.ok();
if connection.is_some() {
let _ = interconnect
.events
.send(EventMessage::FireCoreEvent(CoreContext::DriverReconnect));
}
},
Ok(CoreMessage::RebuildInterconnect) => {
interconnect.restart_volatile_internals();
},
Err(RecvError::Disconnected) | Ok(CoreMessage::Poison) => {
break;
},
}
}
info!("Main thread exited");
interconnect.poison_all();
}