mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
[Core] WIP: Sessions
This commit is contained in:
parent
20dd94fe20
commit
0892587c0e
1 changed files with 102 additions and 112 deletions
|
@ -10,13 +10,7 @@ use bytes::Bytes;
|
||||||
// use tokio::runtime::{current_thread, current_thread::Handle};
|
// use tokio::runtime::{current_thread, current_thread::Handle};
|
||||||
|
|
||||||
// use futures::future::{IntoFuture, Remote};
|
// use futures::future::{IntoFuture, Remote};
|
||||||
use futures::{
|
use futures::{channel::mpsc, future, Future, Stream, StreamExt, TryFutureExt};
|
||||||
channel::mpsc,
|
|
||||||
// future::{IntoFuture, Remote},
|
|
||||||
Future,
|
|
||||||
Stream,
|
|
||||||
TryFutureExt,
|
|
||||||
};
|
|
||||||
use std::{
|
use std::{
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
|
@ -25,14 +19,14 @@ use std::{
|
||||||
use tokio::runtime::Handle;
|
use tokio::runtime::Handle;
|
||||||
|
|
||||||
use crate::apresolve::apresolve_or_fallback;
|
use crate::apresolve::apresolve_or_fallback;
|
||||||
use crate::audio_key::AudioKeyManager;
|
// use crate::audio_key::AudioKeyManager;
|
||||||
use crate::authentication::Credentials;
|
use crate::authentication::Credentials;
|
||||||
use crate::cache::Cache;
|
use crate::cache::Cache;
|
||||||
use crate::channel::ChannelManager;
|
// use crate::channel::ChannelManager;
|
||||||
use crate::component::Lazy;
|
// use crate::component::Lazy;
|
||||||
use crate::config::SessionConfig;
|
use crate::config::SessionConfig;
|
||||||
use crate::connection;
|
use crate::connection;
|
||||||
use crate::mercury::MercuryManager;
|
// use crate::mercury::MercuryManager;
|
||||||
|
|
||||||
struct SessionData {
|
struct SessionData {
|
||||||
country: String,
|
country: String,
|
||||||
|
@ -45,13 +39,12 @@ struct SessionInternal {
|
||||||
config: SessionConfig,
|
config: SessionConfig,
|
||||||
data: RwLock<SessionData>,
|
data: RwLock<SessionData>,
|
||||||
|
|
||||||
tx_connection: mpsc::UnboundedSender<(u8, Vec<u8>)>,
|
tx_connection: mpsc::UnboundedSender<io::Result<(u8, Vec<u8>)>>,
|
||||||
|
|
||||||
audio_key: Lazy<AudioKeyManager>,
|
// audio_key: Lazy<AudioKeyManager>,
|
||||||
channel: Lazy<ChannelManager>,
|
// channel: Lazy<ChannelManager>,
|
||||||
mercury: Lazy<MercuryManager>,
|
// mercury: Lazy<MercuryManager>,
|
||||||
cache: Option<Arc<Cache>>,
|
cache: Option<Arc<Cache>>,
|
||||||
|
|
||||||
handle: Mutex<Handle>,
|
handle: Mutex<Handle>,
|
||||||
session_id: usize,
|
session_id: usize,
|
||||||
}
|
}
|
||||||
|
@ -71,42 +64,44 @@ impl Session {
|
||||||
cache: Option<Cache>,
|
cache: Option<Cache>,
|
||||||
handle: Handle,
|
handle: Handle,
|
||||||
) -> Result<Session> {
|
) -> Result<Session> {
|
||||||
unimplemented!()
|
let access_point_addr =
|
||||||
// let access_point_addr =
|
apresolve_or_fallback::<io::Error>(&config.proxy, &config.ap_port).await?;
|
||||||
// apresolve_or_fallback::<io::Error>(&config.proxy, &config.ap_port).await?;
|
|
||||||
//
|
let proxy = config.proxy.clone();
|
||||||
// let proxy = config.proxy.clone();
|
info!("Connecting to AP \"{}\"", access_point_addr);
|
||||||
// info!("Connecting to AP \"{}\"", access_point_addr);
|
let connection = connection::connect(access_point_addr, &proxy);
|
||||||
// let connection = connection::connect(access_point_addr, &proxy);
|
|
||||||
//
|
let device_id = config.device_id.clone();
|
||||||
// let device_id = config.device_id.clone();
|
let authentication = connection.and_then(move |connection| {
|
||||||
// let authentication = connection.and_then(move |connection| {
|
connection::authenticate(connection, credentials, device_id)
|
||||||
// connection::authenticate(connection, credentials, device_id)
|
});
|
||||||
// });
|
|
||||||
//
|
let result = match authentication.await {
|
||||||
// let result = authentication.map(move |(transport, reusable_credentials)| {
|
Ok((transport, reusable_credentials)) => {
|
||||||
// info!("Authenticated as \"{}\" !", reusable_credentials.username);
|
info!("Authenticated as \"{}\" !", reusable_credentials.username);
|
||||||
// if let Some(ref cache) = cache {
|
if let Some(ref cache) = cache {
|
||||||
// cache.save_credentials(&reusable_credentials);
|
cache.save_credentials(&reusable_credentials);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// let (session, task) = Session::create(
|
let (session, tasks) = Session::create(
|
||||||
// &handle,
|
&handle,
|
||||||
// transport,
|
transport,
|
||||||
// config,
|
config,
|
||||||
// cache,
|
cache,
|
||||||
// reusable_credentials.username.clone(),
|
reusable_credentials.username.clone(),
|
||||||
// );
|
);
|
||||||
//
|
|
||||||
// tokio::spawn(task.map_err(|e| {
|
tokio::task::spawn_local(async move { tasks });
|
||||||
// error!("SessionError: {}", e.to_string());
|
|
||||||
// std::process::exit(0);
|
Ok(session)
|
||||||
// }));
|
}
|
||||||
//
|
Err(e) => {
|
||||||
// session
|
error!("Unable to Connect");
|
||||||
// });
|
Err(e.into())
|
||||||
//
|
}
|
||||||
// result
|
};
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create(
|
fn create(
|
||||||
|
@ -115,7 +110,7 @@ impl Session {
|
||||||
config: SessionConfig,
|
config: SessionConfig,
|
||||||
cache: Option<Cache>,
|
cache: Option<Cache>,
|
||||||
username: String,
|
username: String,
|
||||||
) -> (Session, Box<dyn Future<Output = Result<()>>>) {
|
) -> (Session, Box<dyn Future<Output = (Result<()>, Result<()>)>>) {
|
||||||
let (sink, stream) = transport.split();
|
let (sink, stream) = transport.split();
|
||||||
|
|
||||||
let (sender_tx, sender_rx) = mpsc::unbounded();
|
let (sender_tx, sender_rx) = mpsc::unbounded();
|
||||||
|
@ -124,7 +119,7 @@ impl Session {
|
||||||
debug!("new Session[{}]", session_id);
|
debug!("new Session[{}]", session_id);
|
||||||
|
|
||||||
let session = Session(Arc::new(SessionInternal {
|
let session = Session(Arc::new(SessionInternal {
|
||||||
config: config,
|
config,
|
||||||
data: RwLock::new(SessionData {
|
data: RwLock::new(SessionData {
|
||||||
country: String::new(),
|
country: String::new(),
|
||||||
canonical_username: username,
|
canonical_username: username,
|
||||||
|
@ -136,57 +131,52 @@ impl Session {
|
||||||
|
|
||||||
cache: cache.map(Arc::new),
|
cache: cache.map(Arc::new),
|
||||||
|
|
||||||
audio_key: Lazy::new(),
|
// audio_key: Lazy::new(),
|
||||||
channel: Lazy::new(),
|
// channel: Lazy::new(),
|
||||||
mercury: Lazy::new(),
|
// mercury: Lazy::new(),
|
||||||
|
|
||||||
handle: Mutex::new(handle.clone()),
|
handle: Mutex::new(handle.clone()),
|
||||||
session_id: session_id,
|
session_id,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let sender_task = sender_rx
|
let sender_task = sender_rx
|
||||||
.map_err(|e| -> io::Error { panic!(e) })
|
|
||||||
.forward(sink)
|
.forward(sink)
|
||||||
.map(|_| ());
|
.map_err(|e| -> Box<dyn std::error::Error> { Box::new(e) });
|
||||||
|
|
||||||
let receiver_task = DispatchTask(stream, session.weak());
|
let receiver_task = DispatchTask(stream, session.weak());
|
||||||
|
|
||||||
let task = Box::new(
|
let task = Box::new(future::join(receiver_task, sender_task));
|
||||||
(receiver_task, sender_task)
|
|
||||||
.into_future()
|
|
||||||
.map(|((), ())| ()),
|
|
||||||
);
|
|
||||||
|
|
||||||
(session, task)
|
(session, task)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn audio_key(&self) -> &AudioKeyManager {
|
// pub fn audio_key(&self) -> &AudioKeyManager {
|
||||||
self.0.audio_key.get(|| AudioKeyManager::new(self.weak()))
|
// self.0.audio_key.get(|| AudioKeyManager::new(self.weak()))
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn channel(&self) -> &ChannelManager {
|
// pub fn channel(&self) -> &ChannelManager {
|
||||||
self.0.channel.get(|| ChannelManager::new(self.weak()))
|
// self.0.channel.get(|| ChannelManager::new(self.weak()))
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn mercury(&self) -> &MercuryManager {
|
// pub fn mercury(&self) -> &MercuryManager {
|
||||||
self.0.mercury.get(|| MercuryManager::new(self.weak()))
|
// self.0.mercury.get(|| MercuryManager::new(self.weak()))
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn time_delta(&self) -> i64 {
|
pub fn time_delta(&self) -> i64 {
|
||||||
self.0.data.read().unwrap().time_delta
|
self.0.data.read().unwrap().time_delta
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn a future directly
|
// Spawn a future directly
|
||||||
pub fn spawn<F>(&self, f: F)
|
// pub fn spawn<F>(&self, f: F)
|
||||||
where
|
// where
|
||||||
F: Future<Output = ()> + Send + 'static,
|
// F: Future<Output = ()> + Send + 'static,
|
||||||
{
|
// {
|
||||||
let handle = self.0.handle.lock().unwrap();
|
// let handle = self.0.handle.lock().unwrap();
|
||||||
let spawn_res = handle.spawn(f);
|
// let spawn_res = handle.spawn(f);
|
||||||
match spawn_res {
|
// match spawn_res {
|
||||||
Ok(_) => (),
|
// Ok(_) => (),
|
||||||
Err(e) => error!("Session SpawnErr {:?}", e),
|
// Err(e) => error!("Session SpawnErr {:?}", e),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// pub fn spawn<F, R>(&self, f: F)
|
// pub fn spawn<F, R>(&self, f: F)
|
||||||
// where
|
// where
|
||||||
|
@ -218,7 +208,7 @@ impl Session {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
|
// #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
|
||||||
fn dispatch(&self, cmd: u8, data: Bytes) {
|
fn dispatch(&self, cmd: u8, data: Bytes) {
|
||||||
match cmd {
|
match cmd {
|
||||||
0x4 => {
|
0x4 => {
|
||||||
|
@ -241,15 +231,18 @@ impl Session {
|
||||||
self.0.data.write().unwrap().country = country;
|
self.0.data.write().unwrap().country = country;
|
||||||
}
|
}
|
||||||
|
|
||||||
0x9 | 0xa => self.channel().dispatch(cmd, data),
|
// 0x9 | 0xa => self.channel().dispatch(cmd, data),
|
||||||
0xd | 0xe => self.audio_key().dispatch(cmd, data),
|
// 0xd | 0xe => self.audio_key().dispatch(cmd, data),
|
||||||
0xb2..=0xb6 => self.mercury().dispatch(cmd, data),
|
// 0xb2..=0xb6 => self.mercury().dispatch(cmd, data),
|
||||||
_ => trace!("Unknown dispatch cmd :{:?} {:?}", cmd, data),
|
_ => trace!("Unknown dispatch cmd :{:?} {:?}", cmd, data),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_packet(&self, cmd: u8, data: Vec<u8>) {
|
pub fn send_packet(&self, cmd: u8, data: Vec<u8>) {
|
||||||
self.0.tx_connection.unbounded_send((cmd, data)).unwrap();
|
self.0
|
||||||
|
.tx_connection
|
||||||
|
.unbounded_send(Ok((cmd, data)))
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cache(&self) -> Option<&Arc<Cache>> {
|
pub fn cache(&self) -> Option<&Arc<Cache>> {
|
||||||
|
@ -283,8 +276,8 @@ impl Session {
|
||||||
pub fn shutdown(&self) {
|
pub fn shutdown(&self) {
|
||||||
debug!("Invalidating session[{}]", self.0.session_id);
|
debug!("Invalidating session[{}]", self.0.session_id);
|
||||||
self.0.data.write().unwrap().invalid = true;
|
self.0.data.write().unwrap().invalid = true;
|
||||||
self.mercury().shutdown();
|
// self.mercury().shutdown();
|
||||||
self.channel().shutdown();
|
// self.channel().shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_invalid(&self) -> bool {
|
pub fn is_invalid(&self) -> bool {
|
||||||
|
@ -311,40 +304,37 @@ impl Drop for SessionInternal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// type SErr = ::std::fmt::Debug;
|
|
||||||
|
|
||||||
struct DispatchTask<S>(S, SessionWeak)
|
struct DispatchTask<S>(S, SessionWeak)
|
||||||
where
|
where
|
||||||
S: Stream<Item = Result<((u8, Bytes), ())>>;
|
S: Stream<Item = io::Result<(u8, Bytes)>> + Unpin;
|
||||||
|
|
||||||
impl<S> Future for DispatchTask<S>
|
impl<S: Stream<Item = io::Result<(u8, Bytes)>>> Future for DispatchTask<S>
|
||||||
where
|
where
|
||||||
// SErr: ::std::fmt::Debug,
|
S: Stream<Item = io::Result<(u8, Bytes)>> + Unpin,
|
||||||
S: Stream<Item = Result<((u8, Bytes), ())>>,
|
|
||||||
{
|
{
|
||||||
type Output = Result<((), ())>;
|
type Output = Result<()>;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||||
let session = match self.1.try_upgrade() {
|
let session = match self.1.try_upgrade() {
|
||||||
Some(session) => session,
|
Some(session) => session,
|
||||||
None => return Poll::Ready(()),
|
None => return Poll::Ready(Ok(())),
|
||||||
};
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let (cmd, data) = match self.unwrap().0.poll() {
|
let (cmd, data) = match Pin::new(&mut self.0).poll_next(cx) {
|
||||||
Poll::Ready(Ok(Some(t))) => t,
|
Poll::Ready(Some(Ok(t))) => t,
|
||||||
Poll::Ready(Ok(None)) => {
|
Poll::Ready(Some(Err(e))) => {
|
||||||
|
warn!("Server Connectioned errored");
|
||||||
|
session.shutdown();
|
||||||
|
return Poll::Ready(Err(Box::new(e)));
|
||||||
|
}
|
||||||
|
Poll::Ready(None) => {
|
||||||
warn!("Connection to server closed.");
|
warn!("Connection to server closed.");
|
||||||
session.shutdown();
|
session.shutdown();
|
||||||
return Ok(Poll::Ready(()));
|
return Poll::Ready(Ok(()));
|
||||||
}
|
}
|
||||||
Poll::Pending => return Poll::Pending,
|
Poll::Pending => return Poll::Pending,
|
||||||
Poll::Ready(Err(e)) => {
|
|
||||||
session.shutdown();
|
|
||||||
return Err(From::from(e));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
session.dispatch(cmd, data);
|
session.dispatch(cmd, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -352,7 +342,7 @@ where
|
||||||
|
|
||||||
impl<S> Drop for DispatchTask<S>
|
impl<S> Drop for DispatchTask<S>
|
||||||
where
|
where
|
||||||
S: Stream<Item = Result<((u8, Bytes), ())>>,
|
S: Stream<Item = io::Result<(u8, Bytes)>> + Unpin,
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
debug!("drop Dispatch");
|
debug!("drop Dispatch");
|
||||||
|
|
Loading…
Reference in a new issue