Эх сурвалжийг харах

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 10 жил өмнө
parent
commit
5db141066a
4 өөрчлөгдсөн 59 нэмэгдсэн , 159 устгасан
  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"]
 #![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)]
 #![plugin(protobuf_macros)]
 #[macro_use] extern crate lazy_static;
 #[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 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 librespot_protocol as protocol;
 use mercury::{MercuryRequest, MercuryMethod};
 use mercury::{MercuryRequest, MercuryMethod};
 use util::{SpotifyId, FileId};
 use util::{SpotifyId, FileId};
 use session::Session;
 use session::Session;
 
 
-pub trait MetadataTrait : Send + Sized + Any + 'static {
+pub trait MetadataTrait : Send + 'static {
     type Message: protobuf::MessageStatic;
     type Message: protobuf::MessageStatic;
-    fn from_msg(msg: &Self::Message) -> Self;
+
     fn base_url() -> &'static str;
     fn base_url() -> &'static str;
-    fn request(r: MetadataRef<Self>) -> MetadataRequest;
+    fn parse(msg: &Self::Message) -> Self;
 }
 }
 
 
 #[derive(Debug)]
 #[derive(Debug)]
 pub struct Track {
 pub struct Track {
+    pub id: SpotifyId,
     pub name: String,
     pub name: String,
     pub album: SpotifyId,
     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 {
 impl MetadataTrait for Track {
     type Message = protocol::metadata::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 {
         Track {
+            id: SpotifyId::from_raw(msg.get_gid()),
             name: msg.get_name().to_owned(),
             name: msg.get_name().to_owned(),
             album: SpotifyId::from_raw(msg.get_album().get_gid()),
             album: SpotifyId::from_raw(msg.get_album().get_gid()),
             files: msg.get_file().iter()
             files: msg.get_file().iter()
@@ -40,25 +61,18 @@ impl MetadataTrait for Track {
                 .collect(),
                 .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 {
 impl MetadataTrait for Album {
     type Message = protocol::metadata::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 {
         Album {
+            id: SpotifyId::from_raw(msg.get_gid()),
             name: msg.get_name().to_owned(),
             name: msg.get_name().to_owned(),
             artists: msg.get_artist().iter()
             artists: msg.get_artist().iter()
                 .map(|a| SpotifyId::from_raw(a.get_gid()))
                 .map(|a| SpotifyId::from_raw(a.get_gid()))
@@ -72,160 +86,45 @@ impl MetadataTrait for Album {
                 .collect(),
                 .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 {
 impl MetadataTrait for Artist {
     type Message = protocol::metadata::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 {
     fn base_url() -> &'static str {
         "hm://metadata/3/artist"
         "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 {
 impl MetadataManager {
     pub fn new() -> MetadataManager {
     pub fn new() -> MetadataManager {
-        MetadataManager {
-            cache: HashMap::new()
-        }
+        MetadataManager
     }
     }
 
 
     pub fn get<T: MetadataTrait>(&mut self, session: &Session, id: SpotifyId)
     pub fn get<T: MetadataTrait>(&mut self, session: &Session, id: SpotifyId)
       -> MetadataRef<T> {
       -> 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,
             method: MercuryMethod::GET,
-            uri: format!("{}/{}", T::base_url(), object.id.to_base16()),
+            uri: format!("{}/{}", T::base_url(), id.to_base16()),
             content_type: None,
             content_type: None,
             payload: Vec::new()
             payload: Vec::new()
-        });
-
-        thread::spawn(move || {
-            let response = rx.await().unwrap();
-
+        }).and_then(|response| {
             let msg : T::Message = protobuf::parse_from_bytes(
             let msg : T::Message = protobuf::parse_from_bytes(
                 response.payload.first().unwrap()).unwrap();
                 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 std::thread;
 use vorbis;
 use vorbis;
 
 
-use metadata::TrackRef;
+use metadata::Track;
 use session::Session;
 use session::Session;
 use audio_decrypt::AudioDecrypt;
 use audio_decrypt::AudioDecrypt;
 use util::{self, SpotifyId, Subfile};
 use util::{self, SpotifyId, Subfile};
@@ -86,7 +86,7 @@ impl PlayerInternal {
 
 
         loop {
         loop {
             match self.commands.try_recv() {
             match self.commands.try_recv() {
-                Ok(PlayerCommand::Load(id, play, position)) => {
+                Ok(PlayerCommand::Load(track_id, play, position)) => {
                     self.update(|state| {
                     self.update(|state| {
                         if state.status == PlayStatus::kPlayStatusPlay {
                         if state.status == PlayStatus::kPlayStatusPlay {
                             stream.stop().unwrap();
                             stream.stop().unwrap();
@@ -98,10 +98,11 @@ impl PlayerInternal {
                         return true;
                         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(
                     decoder = Some(
                         vorbis::Decoder::new(
                         vorbis::Decoder::new(
                         Subfile::new(
                         Subfile::new(

+ 1 - 1
src/spirc.rs

@@ -91,7 +91,7 @@ impl <'s, D: SpircDelegate> SpircManager<'s, D> {
     }
     }
 
 
     pub fn run(&mut self) {
     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();
         let updates = self.delegate.updates();
 
 
         loop {
         loop {