use std::collections::HashMap; use std::sync::mpsc; use std::io::{Cursor, Write}; use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt}; use readall::ReadAllExt; use connection::Packet; use util::{SpotifyId, FileId}; use util::Either::{Left, Right}; use subsystem::Subsystem; pub struct AudioKeyRequest { pub track: SpotifyId, pub file: FileId, pub callback: AudioKeyCallback, } pub type AudioKey = [u8; 16]; pub struct AudioKeyResponse(pub AudioKey); pub type AudioKeyCallback = mpsc::Sender; type AudioKeyId = u32; pub struct AudioKeyManager { next_seq: AudioKeyId, callbacks: HashMap, requests: mpsc::Receiver, packet_rx: mpsc::Receiver, packet_tx: mpsc::Sender, } impl AudioKeyManager { pub fn new(tx: mpsc::Sender) -> (AudioKeyManager, mpsc::Sender, mpsc::Sender) { let (req_tx, req_rx) = mpsc::channel(); let (pkt_tx, pkt_rx) = mpsc::channel(); (AudioKeyManager { next_seq: 1, callbacks: HashMap::new(), requests: req_rx, packet_rx: pkt_rx, packet_tx: tx }, req_tx, pkt_tx) } fn request(&mut self, req: AudioKeyRequest) { let seq = self.next_seq; self.next_seq += 1; let mut data : Vec = Vec::new(); data.write(&req.file).unwrap(); data.write(&req.track.to_raw()).unwrap(); data.write_u32::(seq).unwrap(); data.write_u16::(0x0000).unwrap(); self.packet_tx.send(Packet { cmd: 0xc, data: data }).unwrap(); self.callbacks.insert(seq, req.callback); } fn packet(&mut self, packet: Packet) { assert_eq!(packet.cmd, 0xd); let mut data = Cursor::new(&packet.data as &[u8]); let seq = data.read_u32::().unwrap(); let mut key = [0u8; 16]; data.read_all(&mut key).unwrap(); match self.callbacks.remove(&seq) { Some(callback) => callback.send(AudioKeyResponse(key)).unwrap(), None => () }; } } impl Subsystem for AudioKeyManager { fn run(mut self) { loop { match { let requests = &self.requests; let packets = &self.packet_rx; select!{ r = requests.recv() => { Left(r.unwrap()) }, p = packets.recv() => { Right(p.unwrap()) } } } { Left(req) => { self.request(req); } Right(pkt) => { self.packet(pkt); } } } } }