use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; use futures::sync::oneshot; use futures::{Async, Future, Poll}; use std::collections::HashMap; use std::io::Write; use tokio_core::io::EasyBuf; use util::SeqGenerator; use util::{SpotifyId, FileId}; #[derive(Debug,Hash,PartialEq,Eq,Copy,Clone)] pub struct AudioKey(pub [u8; 16]); #[derive(Debug,Hash,PartialEq,Eq,Copy,Clone)] pub struct AudioKeyError; component! { AudioKeyManager : AudioKeyManagerInner { sequence: SeqGenerator = SeqGenerator::new(0), pending: HashMap>> = HashMap::new(), } } impl AudioKeyManager { pub fn dispatch(&self, cmd: u8, mut data: EasyBuf) { let seq = BigEndian::read_u32(data.drain_to(4).as_ref()); let sender = self.lock(|inner| inner.pending.remove(&seq)); if let Some(sender) = sender { match cmd { 0xd => { let mut key = [0u8; 16]; key.copy_from_slice(data.as_ref()); sender.complete(Ok(AudioKey(key))); } 0xe => { warn!("error audio key {:x} {:x}", data.as_ref()[0], data.as_ref()[1]); sender.complete(Err(AudioKeyError)); } _ => (), } } } pub fn request(&self, track: SpotifyId, file: FileId) -> AudioKeyFuture { let (tx, rx) = oneshot::channel(); let seq = self.lock(move |inner| { let seq = inner.sequence.get(); inner.pending.insert(seq, tx); seq }); self.send_key_request(seq, track, file); AudioKeyFuture(rx) } fn send_key_request(&self, seq: u32, track: SpotifyId, file: FileId) { let mut data: Vec = Vec::new(); data.write(&file.0).unwrap(); data.write(&track.to_raw()).unwrap(); data.write_u32::(seq).unwrap(); data.write_u16::(0x0000).unwrap(); self.session().send_packet(0xc, data) } } pub struct AudioKeyFuture(oneshot::Receiver>); impl Future for AudioKeyFuture { type Item = T; type Error = AudioKeyError; fn poll(&mut self) -> Poll { match self.0.poll() { Ok(Async::Ready(Ok(value))) => Ok(Async::Ready(value)), Ok(Async::Ready(Err(err))) => Err(err), Ok(Async::NotReady) => Ok(Async::NotReady), Err(oneshot::Canceled) => Err(AudioKeyError), } } }