Selaa lähdekoodia

Use eventual’s futures in metadata instead of rolling our own.

For now the object cache has been removed. It may be added back later.
Paul Lietar 9 vuotta sitten
vanhempi
commit
5db141066a
4 muutettua tiedostoa jossa 59 lisäystä ja 159 poistoa
  1. 1 1
      src/lib.rs
  2. 51 152
      src/metadata.rs
  3. 6 5
      src/player.rs
  4. 1 1
      src/spirc.rs

+ 1 - 1
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;

+ 51 - 152
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<Self>) -> MetadataRequest;
+    fn parse(msg: &Self::Message) -> Self;
 }
 
 #[derive(Debug)]
 pub struct Track {
+    pub id: SpotifyId,
     pub name: String,
     pub album: SpotifyId,
-    pub files: Vec<FileId>
+    pub files: Vec<FileId>,
+}
+
+#[derive(Debug)]
+pub struct Album {
+    pub id: SpotifyId,
+    pub name: String,
+    pub artists: Vec<SpotifyId>,
+    pub covers: Vec<FileId>
 }
 
+#[derive(Debug)]
+pub struct Artist {
+    pub id: SpotifyId,
+    pub name: String,
+}
+
+pub type MetadataRef<T> = Future<T, ()>;
+pub type TrackRef = MetadataRef<Track>;
+pub type AlbumRef = MetadataRef<Album>;
+pub type ArtistRef = MetadataRef<Artist>;
+
 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<Self>) -> MetadataRequest {
-        MetadataRequest::Track(r)
-    }
-}
-
-#[derive(Debug)]
-pub struct Album {
-    pub name: String,
-    pub artists: Vec<SpotifyId>,
-    pub covers: Vec<FileId>
 }
 
 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<Self>) -> 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<Self>) -> MetadataRequest {
-        MetadataRequest::Artist(r)
-    }
-}
-
-#[derive(Debug)]
-pub enum MetadataState<T> {
-    Loading,
-    Loaded(T),
-    Error,
-}
-
-pub struct Metadata<T: MetadataTrait> {
-    id: SpotifyId,
-    state: Mutex<MetadataState<T>>,
-    cond: Condvar
-}
-
-pub type MetadataRef<T> = Arc<Metadata<T>>;
-
-pub type TrackRef = MetadataRef<Track>;
-pub type AlbumRef = MetadataRef<Album>;
-pub type ArtistRef = MetadataRef<Artist>;
-
-impl <T: MetadataTrait> Metadata<T> {
-    pub fn id(&self) -> SpotifyId {
-        self.id
-    }
-
-    pub fn lock(&self) -> MutexGuard<MetadataState<T>> {
-        self.state.lock().unwrap()
-    }
-
-    pub fn wait(&self) -> MutexGuard<MetadataState<T>> {
-        let mut handle = self.lock();
-        while handle.is_loading() {
-            handle = self.cond.wait(handle).unwrap();
-        }
-        handle
-    }
-
-    pub fn set(&self, state: MetadataState<T>) {
-        let mut handle = self.lock();
-        *handle = state;
-        self.cond.notify_all();
-    }
-}
-
-impl <T: MetadataTrait + fmt::Debug> fmt::Debug for Metadata<T> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
-        write!(f, "Metadata<>({:?}, {:?})", self.id, *self.lock())
-    }
-}
-
-impl <T: MetadataTrait> MetadataState<T> {
-    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<Any + Send + 'static>>
-}
+pub struct MetadataManager;
 
 impl MetadataManager {
     pub fn new() -> MetadataManager {
-        MetadataManager {
-            cache: HashMap::new()
-        }
+        MetadataManager
     }
 
     pub fn get<T: MetadataTrait>(&mut self, session: &Session, id: SpotifyId)
       -> MetadataRef<T> {
-        let key = (id, TypeId::of::<T>());
-
-        self.cache.get(&key)
-            .and_then(|x| x.downcast_ref::<Weak<Metadata<T>>>())
-            .and_then(|x| x.upgrade())
-            .unwrap_or_else(|| {
-                let x : MetadataRef<T> = 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<T: MetadataTrait> (&self, session: &Session, object: MetadataRef<T>) {
-        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))
+        })
     }
 }
 

+ 6 - 5
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>(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(

+ 1 - 1
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 {