Improve handling of missing audio keys by failing the future rather than crashing.

This commit is contained in:
Paul Lietar 2015-12-29 23:12:02 +01:00
parent 8c2aa28d43
commit 654a403459
3 changed files with 32 additions and 16 deletions

View file

@ -9,13 +9,16 @@ use session::Session;
use connection::PacketHandler; use connection::PacketHandler;
pub type AudioKey = [u8; 16]; pub type AudioKey = [u8; 16];
#[derive(Debug,Hash,PartialEq,Eq,Copy,Clone)]
pub struct AudioKeyError;
#[derive(Debug,Hash,PartialEq,Eq,Clone)] #[derive(Debug,Hash,PartialEq,Eq,Clone)]
struct AudioKeyId(SpotifyId, FileId); struct AudioKeyId(SpotifyId, FileId);
enum AudioKeyStatus { enum AudioKeyStatus {
Loading(Vec<eventual::Complete<AudioKey, ()>>), Loading(Vec<eventual::Complete<AudioKey, AudioKeyError>>),
Loaded(AudioKey) Loaded(AudioKey),
Failed(AudioKeyError)
} }
pub struct AudioKeyManager { pub struct AudioKeyManager {
@ -34,12 +37,15 @@ impl AudioKeyManager {
} }
pub fn request(&mut self, session: &Session, track: SpotifyId, file: FileId) pub fn request(&mut self, session: &Session, track: SpotifyId, file: FileId)
-> eventual::Future<AudioKey, ()> { -> eventual::Future<AudioKey, AudioKeyError> {
let id = AudioKeyId(track, file); let id = AudioKeyId(track, file);
self.cache.get_mut(&id).map(|status| match *status { self.cache.get_mut(&id).map(|status| match *status {
AudioKeyStatus::Failed(error) => {
eventual::Future::error(error)
}
AudioKeyStatus::Loaded(key) => { AudioKeyStatus::Loaded(key) => {
eventual::Future::of(key.clone()) eventual::Future::of(key)
} }
AudioKeyStatus::Loading(ref mut req) => { AudioKeyStatus::Loading(ref mut req) => {
let (tx, rx) = eventual::Future::pair(); let (tx, rx) = eventual::Future::pair();
@ -69,14 +75,14 @@ impl AudioKeyManager {
impl PacketHandler for AudioKeyManager { impl PacketHandler for AudioKeyManager {
fn handle(&mut self, cmd: u8, data: Vec<u8>) { fn handle(&mut self, cmd: u8, data: Vec<u8>) {
assert_eq!(cmd, 0xd);
let mut data = Cursor::new(data); let mut data = Cursor::new(data);
let seq = data.read_u32::<BigEndian>().unwrap(); let seq = data.read_u32::<BigEndian>().unwrap();
if let Some(status) = self.pending.remove(&seq).and_then(|id| { self.cache.get_mut(&id) }) {
if cmd == 0xd {
let mut key = [0u8; 16]; let mut key = [0u8; 16];
data.read_exact(&mut key).unwrap(); data.read_exact(&mut key).unwrap();
if let Some(status) = self.pending.remove(&seq).and_then(|id| { self.cache.get_mut(&id) }) {
let status = mem::replace(status, AudioKeyStatus::Loaded(key)); let status = mem::replace(status, AudioKeyStatus::Loaded(key));
if let AudioKeyStatus::Loading(cbs) = status { if let AudioKeyStatus::Loading(cbs) = status {
@ -84,6 +90,16 @@ impl PacketHandler for AudioKeyManager {
cb.complete(key); cb.complete(key);
} }
} }
} else if cmd == 0xe {
let error = AudioKeyError;
let status = mem::replace(status, AudioKeyStatus::Failed(error));
if let AudioKeyStatus::Loading(cbs) = status {
for cb in cbs {
cb.fail(error);
}
}
}
} }
} }
} }

View file

@ -92,7 +92,7 @@ impl MetadataTrait for Album {
"hm://metadata/3/album" "hm://metadata/3/album"
} }
fn parse(msg: &Self::Message, session: &Session) -> Self { fn parse(msg: &Self::Message, _: &Session) -> Self {
Album { Album {
id: SpotifyId::from_raw(msg.get_gid()), id: SpotifyId::from_raw(msg.get_gid()),
name: msg.get_name().to_owned(), name: msg.get_name().to_owned(),
@ -118,7 +118,7 @@ impl MetadataTrait for Artist {
"hm://metadata/3/artist" "hm://metadata/3/artist"
} }
fn parse(msg: &Self::Message, session: &Session) -> Self { fn parse(msg: &Self::Message, _: &Session) -> Self {
Artist { Artist {
id: SpotifyId::from_raw(msg.get_gid()), id: SpotifyId::from_raw(msg.get_gid()),
name: msg.get_name().to_owned(), name: msg.get_name().to_owned(),

View file

@ -14,7 +14,7 @@ use util::{SpotifyId, FileId, mkdir_existing};
use mercury::{MercuryManager, MercuryRequest, MercuryResponse}; use mercury::{MercuryManager, MercuryRequest, MercuryResponse};
use metadata::{MetadataManager, MetadataRef, MetadataTrait}; use metadata::{MetadataManager, MetadataRef, MetadataTrait};
use stream::{StreamManager, StreamEvent}; use stream::{StreamManager, StreamEvent};
use audio_key::{AudioKeyManager, AudioKey}; use audio_key::{AudioKeyManager, AudioKey, AudioKeyError};
use audio_file::{AudioFileManager, AudioFile}; use audio_file::{AudioFileManager, AudioFile};
use connection::PacketHandler; use connection::PacketHandler;
@ -189,7 +189,7 @@ impl Session {
self.0.tx_connection.lock().unwrap().send_packet(cmd, data) self.0.tx_connection.lock().unwrap().send_packet(cmd, data)
} }
pub fn audio_key(&self, track: SpotifyId, file: FileId) -> Future<AudioKey, ()> { pub fn audio_key(&self, track: SpotifyId, file: FileId) -> Future<AudioKey, AudioKeyError> {
self.0.audio_key.lock().unwrap().request(self, track, file) self.0.audio_key.lock().unwrap().request(self, track, file)
} }