Browse Source

cache audio keys in memory

Paul Lietar 9 years ago
parent
commit
28a7db26be
1 changed files with 50 additions and 20 deletions
  1. 50 20
      src/audio_key.rs

+ 50 - 20
src/audio_key.rs

@@ -1,47 +1,72 @@
-use std::collections::HashMap;
+use std::collections::{HashMap, LinkedList};
 use std::sync::{mpsc, Future};
 use std::io::{Cursor, Write};
 use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
 use readall::ReadAllExt;
+use std::mem;
 
 use util::{SpotifyId, FileId, IgnoreExt};
 use session::Session;
 use connection::PacketHandler;
 
 pub type AudioKey = [u8; 16];
-type AudioKeyId = u32;
+
+#[derive(Debug,Hash,PartialEq,Eq,Clone)]
+struct AudioKeyId(SpotifyId, FileId);
+
+enum AudioKeyStatus {
+    Loading(LinkedList<mpsc::Sender<AudioKey>>),
+    Loaded(AudioKey)
+}
 
 pub struct AudioKeyManager {
-    next_seq: AudioKeyId,
-    callbacks: HashMap<AudioKeyId, mpsc::Sender<AudioKey>>,
+    next_seq: u32,
+    pending: HashMap<u32, AudioKeyId>, 
+    cache: HashMap<AudioKeyId, AudioKeyStatus>,
 }
 
 impl AudioKeyManager {
     pub fn new() -> AudioKeyManager {
         AudioKeyManager {
             next_seq: 1,
-            callbacks: HashMap::new(),
+            pending: HashMap::new(),
+            cache: HashMap::new()
         }
     }
 
     pub fn request(&mut self, session: &Session, track: SpotifyId, file: FileId)
         -> Future<AudioKey> {
-        let (tx, rx) = mpsc::channel();
 
-        let seq = self.next_seq;
-        self.next_seq += 1;
+        let id = AudioKeyId(track, file);
+        self.cache.get_mut(&id).map(|status| match status {
+            &mut AudioKeyStatus::Loaded(key) => {
+                Future::from_value(key.clone())
+            }
+            &mut AudioKeyStatus::Loading(ref mut req) => {
+                let (tx, rx) = mpsc::channel();
+                req.push_front(tx);
+                Future::from_receiver(rx)
+            }
+        }).unwrap_or_else(|| {
+            let seq = self.next_seq;
+            self.next_seq += 1;
 
-        let mut data : Vec<u8> = Vec::new();
-        data.write(&file).unwrap();
-        data.write(&track.to_raw()).unwrap();
-        data.write_u32::<BigEndian>(seq).unwrap();
-        data.write_u16::<BigEndian>(0x0000).unwrap();
+            let mut data : Vec<u8> = Vec::new();
+            data.write(&file).unwrap();
+            data.write(&track.to_raw()).unwrap();
+            data.write_u32::<BigEndian>(seq).unwrap();
+            data.write_u16::<BigEndian>(0x0000).unwrap();
 
-        session.send_packet(0xc, &data).unwrap();
+            session.send_packet(0xc, &data).unwrap();
 
-        self.callbacks.insert(seq, tx);
+            self.pending.insert(seq, id.clone());
 
-        Future::from_receiver(rx)
+            let (tx, rx) = mpsc::channel();
+            let mut req = LinkedList::new();
+            req.push_front(tx);
+            self.cache.insert(id, AudioKeyStatus::Loading(req));
+            Future::from_receiver(rx)
+        })
     }
 }
 
@@ -54,10 +79,15 @@ impl PacketHandler for AudioKeyManager {
         let mut key = [0u8; 16];
         data.read_all(&mut key).unwrap();
 
-        match self.callbacks.remove(&seq) {
-            Some(callback) => callback.send(key).ignore(),
-            None => ()
-        };
+        if let Some(status) = self.pending.remove(&seq).and_then(|id| { self.cache.get_mut(&id) }) {
+            let status = mem::replace(status, AudioKeyStatus::Loaded(key));
+
+            if let AudioKeyStatus::Loading(cbs) = status {
+                for cb in cbs {
+                    cb.send(key).unwrap();
+                }
+            }
+        }
     }
 }