From 5db141066a488076e2a16d30db8bb10bc177735a Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Mon, 28 Dec 2015 16:53:54 +0100 Subject: [PATCH] =?UTF-8?q?Use=20eventual=E2=80=99s=20futures=20in=20metad?= =?UTF-8?q?ata=20instead=20of=20rolling=20our=20own.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For now the object cache has been removed. It may be added back later. --- src/lib.rs | 2 +- src/metadata.rs | 203 ++++++++++++------------------------------------ src/player.rs | 11 +-- src/spirc.rs | 2 +- 4 files changed, 59 insertions(+), 159 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 70f70450..3dd25f8f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![crate_name = "librespot"] -#![feature(plugin,zero_one,iter_arith,slice_bytes,mpsc_select,clone_from_slice)] +#![feature(plugin,zero_one,iter_arith,mpsc_select,clone_from_slice)] #![plugin(protobuf_macros)] #[macro_use] extern crate lazy_static; diff --git a/src/metadata.rs b/src/metadata.rs index 81e84f75..16250fbc 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -1,34 +1,55 @@ -use eventual::Async; +use eventual::{Async, Future}; use protobuf; -use std::any::{Any, TypeId}; -use std::collections::HashMap; -use std::fmt; -use std::sync::{Arc, Condvar, Mutex, MutexGuard, Weak}; -use std::thread; use librespot_protocol as protocol; use mercury::{MercuryRequest, MercuryMethod}; use util::{SpotifyId, FileId}; use session::Session; -pub trait MetadataTrait : Send + Sized + Any + 'static { +pub trait MetadataTrait : Send + 'static { type Message: protobuf::MessageStatic; - fn from_msg(msg: &Self::Message) -> Self; + fn base_url() -> &'static str; - fn request(r: MetadataRef) -> MetadataRequest; + fn parse(msg: &Self::Message) -> Self; } #[derive(Debug)] pub struct Track { + pub id: SpotifyId, pub name: String, pub album: SpotifyId, - pub files: Vec + pub files: Vec, } +#[derive(Debug)] +pub struct Album { + pub id: SpotifyId, + pub name: String, + pub artists: Vec, + pub covers: Vec +} + +#[derive(Debug)] +pub struct Artist { + pub id: SpotifyId, + pub name: String, +} + +pub type MetadataRef = Future; +pub type TrackRef = MetadataRef; +pub type AlbumRef = MetadataRef; +pub type ArtistRef = MetadataRef; + impl MetadataTrait for Track { type Message = protocol::metadata::Track; - fn from_msg(msg: &Self::Message) -> Self { + + fn base_url() -> &'static str { + "hm://metadata/3/track" + } + + fn parse(msg: &Self::Message) -> Self { Track { + id: SpotifyId::from_raw(msg.get_gid()), name: msg.get_name().to_owned(), album: SpotifyId::from_raw(msg.get_album().get_gid()), files: msg.get_file().iter() @@ -40,25 +61,18 @@ impl MetadataTrait for Track { .collect(), } } - fn base_url() -> &'static str { - "hm://metadata/3/track" - } - fn request(r: MetadataRef) -> MetadataRequest { - MetadataRequest::Track(r) - } -} - -#[derive(Debug)] -pub struct Album { - pub name: String, - pub artists: Vec, - pub covers: Vec } impl MetadataTrait for Album { type Message = protocol::metadata::Album; - fn from_msg(msg: &Self::Message) -> Self { + + fn base_url() -> &'static str { + "hm://metadata/3/album" + } + + fn parse(msg: &Self::Message) -> Self { Album { + id: SpotifyId::from_raw(msg.get_gid()), name: msg.get_name().to_owned(), artists: msg.get_artist().iter() .map(|a| SpotifyId::from_raw(a.get_gid())) @@ -72,160 +86,45 @@ impl MetadataTrait for Album { .collect(), } } - fn base_url() -> &'static str { - "hm://metadata/3/album" - } - fn request(r: MetadataRef) -> MetadataRequest { - MetadataRequest::Album(r) - } } -#[derive(Debug)] -pub struct Artist { - pub name: String, -} impl MetadataTrait for Artist { type Message = protocol::metadata::Artist; - fn from_msg(msg: &Self::Message) -> Self { - Artist { - name: msg.get_name().to_owned(), - } - } + fn base_url() -> &'static str { "hm://metadata/3/artist" } - fn request(r: MetadataRef) -> MetadataRequest { - MetadataRequest::Artist(r) - } -} -#[derive(Debug)] -pub enum MetadataState { - Loading, - Loaded(T), - Error, -} - -pub struct Metadata { - id: SpotifyId, - state: Mutex>, - cond: Condvar -} - -pub type MetadataRef = Arc>; - -pub type TrackRef = MetadataRef; -pub type AlbumRef = MetadataRef; -pub type ArtistRef = MetadataRef; - -impl Metadata { - pub fn id(&self) -> SpotifyId { - self.id - } - - pub fn lock(&self) -> MutexGuard> { - self.state.lock().unwrap() - } - - pub fn wait(&self) -> MutexGuard> { - let mut handle = self.lock(); - while handle.is_loading() { - handle = self.cond.wait(handle).unwrap(); - } - handle - } - - pub fn set(&self, state: MetadataState) { - let mut handle = self.lock(); - *handle = state; - self.cond.notify_all(); - } -} - -impl fmt::Debug for Metadata { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(f, "Metadata<>({:?}, {:?})", self.id, *self.lock()) - } -} - -impl MetadataState { - pub fn is_loading(&self) -> bool { - match *self { - MetadataState::Loading => true, - _ => false - } - } - - pub fn is_loaded(&self) -> bool { - match *self { - MetadataState::Loaded(_) => true, - _ => false - } - } - - pub fn unwrap(&self) -> &T { - match *self { - MetadataState::Loaded(ref data) => data, - _ => panic!("Not loaded") + fn parse(msg: &Self::Message) -> Self { + Artist { + id: SpotifyId::from_raw(msg.get_gid()), + name: msg.get_name().to_owned(), } } } -#[derive(Debug)] -pub enum MetadataRequest { - Artist(ArtistRef), - Album(AlbumRef), - Track(TrackRef) -} - -pub struct MetadataManager { - cache: HashMap<(SpotifyId, TypeId), Box> -} +pub struct MetadataManager; impl MetadataManager { pub fn new() -> MetadataManager { - MetadataManager { - cache: HashMap::new() - } + MetadataManager } pub fn get(&mut self, session: &Session, id: SpotifyId) -> MetadataRef { - let key = (id, TypeId::of::()); - self.cache.get(&key) - .and_then(|x| x.downcast_ref::>>()) - .and_then(|x| x.upgrade()) - .unwrap_or_else(|| { - let x : MetadataRef = Arc::new(Metadata{ - id: id, - state: Mutex::new(MetadataState::Loading), - cond: Condvar::new() - }); - - self.cache.insert(key, Box::new(Arc::downgrade(&x))); - self.load(session, x.clone()); - x - }) - } - - fn load (&self, session: &Session, object: MetadataRef) { - let rx = session.mercury(MercuryRequest { + session.mercury(MercuryRequest { method: MercuryMethod::GET, - uri: format!("{}/{}", T::base_url(), object.id.to_base16()), + uri: format!("{}/{}", T::base_url(), id.to_base16()), content_type: None, payload: Vec::new() - }); - - thread::spawn(move || { - let response = rx.await().unwrap(); - + }).and_then(|response| { let msg : T::Message = protobuf::parse_from_bytes( response.payload.first().unwrap()).unwrap(); - object.set(MetadataState::Loaded(T::from_msg(&msg))); - }); + Ok(T::parse(&msg)) + }) } } diff --git a/src/player.rs b/src/player.rs index 5d455b0a..b611867b 100644 --- a/src/player.rs +++ b/src/player.rs @@ -4,7 +4,7 @@ use std::sync::{mpsc, Mutex, Arc, Condvar, MutexGuard}; use std::thread; use vorbis; -use metadata::TrackRef; +use metadata::Track; use session::Session; use audio_decrypt::AudioDecrypt; use util::{self, SpotifyId, Subfile}; @@ -86,7 +86,7 @@ impl PlayerInternal { loop { match self.commands.try_recv() { - Ok(PlayerCommand::Load(id, play, position)) => { + Ok(PlayerCommand::Load(track_id, play, position)) => { self.update(|state| { if state.status == PlayStatus::kPlayStatusPlay { stream.stop().unwrap(); @@ -98,10 +98,11 @@ impl PlayerInternal { return true; }); - let track : TrackRef = self.session.metadata(id); - let file_id = *track.wait().unwrap().files.first().unwrap(); + let track = self.session.metadata::(track_id).await().unwrap(); - let key = self.session.audio_key(track.id(), file_id).await().unwrap(); + let file_id = track.files[0]; + + let key = self.session.audio_key(track.id, file_id).await().unwrap(); decoder = Some( vorbis::Decoder::new( Subfile::new( diff --git a/src/spirc.rs b/src/spirc.rs index cd2b90d0..de038849 100644 --- a/src/spirc.rs +++ b/src/spirc.rs @@ -91,7 +91,7 @@ impl <'s, D: SpircDelegate> SpircManager<'s, D> { } pub fn run(&mut self) { - let rx = self.session.mercury_sub(format!("hm://remote/user/{}/", self.username)); + let rx = self.session.mercury_sub(format!("hm://remote/3/user/{}/", self.username)); let updates = self.delegate.updates(); loop {