From 5e3404137f223feecf0ecdcfcb91048fb4402dc4 Mon Sep 17 00:00:00 2001 From: Simon Persson Date: Wed, 17 Feb 2016 15:24:40 +0100 Subject: [PATCH] Add support for replacing tracks. Make a builder out of send_cmd. --- src/spirc.rs | 202 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 135 insertions(+), 67 deletions(-) diff --git a/src/spirc.rs b/src/spirc.rs index 5c3a873..28831c2 100644 --- a/src/spirc.rs +++ b/src/spirc.rs @@ -1,5 +1,5 @@ use eventual::Async; -use protobuf::{self, Message}; +use protobuf::{self, Message, RepeatedField}; use util; use session::Session; @@ -116,34 +116,54 @@ impl SpircManager { pub fn send_play(&mut self, recipient: &str) { let mut internal = self.0.lock().unwrap(); - send_cmd(&mut *internal, - protocol::spirc::MessageType::kMessageTypePlay, - Some(recipient), - None); + CommandSender::new(&mut *internal, + protocol::spirc::MessageType::kMessageTypePlay) + .recipient(recipient) + .send(); } pub fn send_pause(&mut self, recipient: &str) { let mut internal = self.0.lock().unwrap(); - send_cmd(&mut *internal, - protocol::spirc::MessageType::kMessageTypePause, - Some(recipient), - None); + CommandSender::new(&mut *internal, + protocol::spirc::MessageType::kMessageTypePause) + .recipient(recipient) + .send(); } pub fn send_prev(&mut self, recipient: &str) { let mut internal = self.0.lock().unwrap(); - send_cmd(&mut *internal, - protocol::spirc::MessageType::kMessageTypePrev, - Some(recipient), - None); + CommandSender::new(&mut *internal, + protocol::spirc::MessageType::kMessageTypePrev) + .recipient(recipient) + .send(); } pub fn send_next(&mut self, recipient: &str) { let mut internal = self.0.lock().unwrap(); - send_cmd(&mut *internal, - protocol::spirc::MessageType::kMessageTypeNext, - Some(recipient), - None); + CommandSender::new(&mut *internal, + protocol::spirc::MessageType::kMessageTypeNext) + .recipient(recipient) + .send(); + } + + pub fn send_replace_tracks, I: Iterator>(&mut self, + recipient: &str, + track_ids: I) { + let tracks: Vec = track_ids.map(|i| { + protobuf_init!(protocol::spirc::TrackRef::new(), { gid: SpotifyId::from_base62(i.as_ref()).to_raw().to_vec()}) + }) + .collect(); + + let state = protobuf_init!(protocol::spirc::State::new(), { + track: RepeatedField::from_vec(tracks) + }); + + let mut internal = self.0.lock().unwrap(); + CommandSender::new(&mut *internal, + protocol::spirc::MessageType::kMessageTypeReplace) + .recipient(recipient) + .state(state) + .send(); } } @@ -241,28 +261,37 @@ impl SpircInternal { } fn notify(&mut self, hello: bool, recipient: Option<&str>) { - send_cmd(self, - if hello { - MessageType::kMessageTypeHello - } else { - MessageType::kMessageTypeNotify - }, - recipient, - None); + let cs = CommandSender::new(self, + if hello { + MessageType::kMessageTypeHello + } else { + MessageType::kMessageTypeNotify + }); + if let Some(s) = recipient { + cs.recipient(&s) + .send() + } else { + cs.send() + } } fn notify_with_player_state(&mut self, hello: bool, recipient: Option<&str>, player_state: &PlayerState) { - send_cmd(self, - if hello { - MessageType::kMessageTypeHello - } else { - MessageType::kMessageTypeNotify - }, - recipient, - Some(player_state)); + let cs = CommandSender::new(self, + if hello { + MessageType::kMessageTypeHello + } else { + MessageType::kMessageTypeNotify + }) + .player_state(player_state); + if let Some(s) = recipient { + cs.recipient(&s) + .send() + } else { + cs.send() + } } fn spirc_state(&self, player_state: &PlayerState) -> protocol::spirc::State { @@ -355,42 +384,81 @@ impl SpircInternal { } } -fn send_cmd(spirc_internal: &mut SpircInternal, - cmd: protocol::spirc::MessageType, - recipient: Option<&str>, - player_state: Option<&PlayerState>) { - let mut pkt = protobuf_init!(protocol::spirc::Frame::new(), { - version: 1, - ident: spirc_internal.ident.clone(), - protocol_version: "2.0.0".to_owned(), - seq_nr: { spirc_internal.seq_nr += 1; spirc_internal.seq_nr }, - typ: cmd, - recipient: protobuf::RepeatedField::from_vec( - recipient.map(|r| vec![r.to_owned()] ).unwrap_or(vec![]) - ), - }); +struct CommandSender<'a> { + spirc_internal: &'a mut SpircInternal, + cmd: protocol::spirc::MessageType, + recipient: Option<&'a str>, + player_state: Option<&'a PlayerState>, + state: Option, +} - if let Some(s) = player_state { - pkt.set_device_state(spirc_internal.device_state(s)); - pkt.set_state_update_id(s.update_time() as i64); - if spirc_internal.is_active { - pkt.set_state(spirc_internal.spirc_state(s)); - } - } else { - let s = &*spirc_internal.player.state(); - pkt.set_device_state(spirc_internal.device_state(s)); - pkt.set_state_update_id(s.update_time() as i64); - if spirc_internal.is_active { - pkt.set_state(spirc_internal.spirc_state(s)); +impl<'a> CommandSender<'a> { + fn new(spirc_internal: &'a mut SpircInternal, + cmd: protocol::spirc::MessageType) + -> CommandSender { + CommandSender { + spirc_internal: spirc_internal, + cmd: cmd, + recipient: None, + player_state: None, + state: None, } } - spirc_internal.session - .mercury(MercuryRequest { - method: MercuryMethod::SEND, - uri: spirc_internal.uri(), - content_type: None, - payload: vec![pkt.write_to_bytes().unwrap()], - }) - .fire(); + fn recipient(mut self, r: &'a str) -> CommandSender { + self.recipient = Some(r); + self + } + + fn player_state(mut self, s: &'a PlayerState) -> CommandSender { + self.player_state = Some(s); + self + } + + fn state(mut self, s: protocol::spirc::State) -> CommandSender<'a> { + self.state = Some(s); + self + } + + fn send(self) { + let mut pkt = protobuf_init!(protocol::spirc::Frame::new(), { + version: 1, + ident: self.spirc_internal.ident.clone(), + protocol_version: "2.0.0".to_owned(), + seq_nr: { self.spirc_internal.seq_nr += 1; self.spirc_internal.seq_nr }, + typ: self.cmd, + recipient: protobuf::RepeatedField::from_vec( + self.recipient.map(|r| vec![r.to_owned()] ).unwrap_or(vec![]) + ), + }); + + if let Some(s) = self.player_state { + pkt.set_device_state(self.spirc_internal.device_state(s)); + pkt.set_state_update_id(s.update_time() as i64); + if self.spirc_internal.is_active { + pkt.set_state(self.spirc_internal.spirc_state(s)); + } + } else { + let s = &*self.spirc_internal.player.state(); + pkt.set_device_state(self.spirc_internal.device_state(s)); + pkt.set_state_update_id(s.update_time() as i64); + if self.spirc_internal.is_active { + pkt.set_state(self.spirc_internal.spirc_state(s)); + } + } + + if let Some(s) = self.state { + pkt.set_state(s); + } + + self.spirc_internal + .session + .mercury(MercuryRequest { + method: MercuryMethod::SEND, + uri: self.spirc_internal.uri(), + content_type: None, + payload: vec![pkt.write_to_bytes().unwrap()], + }) + .fire(); + } }