mirror of
https://github.com/librespot-org/librespot.git
synced 2024-11-08 16:45:43 +00:00
mercury: Register subscription for all channel aliases
When subscribing to a channel, we may actually end up subscribed to other alias channels. We must track these as well in order to redirect received messages properly.
This commit is contained in:
parent
877f4f7b93
commit
4806f3e85a
4 changed files with 44 additions and 19 deletions
|
@ -43,6 +43,7 @@ fn main() {
|
||||||
&proto.join("authentication.proto"),
|
&proto.join("authentication.proto"),
|
||||||
&proto.join("mercury.proto"),
|
&proto.join("mercury.proto"),
|
||||||
&proto.join("metadata.proto"),
|
&proto.join("metadata.proto"),
|
||||||
|
&proto.join("pubsub.proto"),
|
||||||
&proto.join("spirc.proto"),
|
&proto.join("spirc.proto"),
|
||||||
]).unwrap();
|
]).unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,5 +7,6 @@ mod_path! keyexchange (concat!(env!("OUT_DIR"), "/keyexchange.rs"));
|
||||||
mod_path! authentication (concat!(env!("OUT_DIR"), "/authentication.rs"));
|
mod_path! authentication (concat!(env!("OUT_DIR"), "/authentication.rs"));
|
||||||
mod_path! mercury (concat!(env!("OUT_DIR"), "/mercury.rs"));
|
mod_path! mercury (concat!(env!("OUT_DIR"), "/mercury.rs"));
|
||||||
mod_path! metadata (concat!(env!("OUT_DIR"), "/metadata.rs"));
|
mod_path! metadata (concat!(env!("OUT_DIR"), "/metadata.rs"));
|
||||||
|
mod_path! pubsub (concat!(env!("OUT_DIR"), "/pubsub.rs"));
|
||||||
mod_path! spirc (concat!(env!("OUT_DIR"), "/spirc.rs"));
|
mod_path! spirc (concat!(env!("OUT_DIR"), "/spirc.rs"));
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
|
use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
|
||||||
use eventual::{self, Async};
|
use eventual;
|
||||||
use protobuf::{self, Message};
|
use protobuf::{self, Message};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io::{Cursor, Read, Write};
|
use std::io::{Cursor, Read, Write};
|
||||||
|
@ -9,7 +9,6 @@ use std::sync::mpsc;
|
||||||
use librespot_protocol as protocol;
|
use librespot_protocol as protocol;
|
||||||
use session::Session;
|
use session::Session;
|
||||||
use connection::PacketHandler;
|
use connection::PacketHandler;
|
||||||
use util::IgnoreExt;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum MercuryMethod {
|
pub enum MercuryMethod {
|
||||||
|
@ -32,10 +31,16 @@ pub struct MercuryResponse {
|
||||||
pub payload: Vec<Vec<u8>>
|
pub payload: Vec<Vec<u8>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum MercuryCallback {
|
||||||
|
Future(eventual::Complete<MercuryResponse, ()>),
|
||||||
|
Subscription(mpsc::Sender<MercuryResponse>),
|
||||||
|
Channel,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct MercuryPending {
|
pub struct MercuryPending {
|
||||||
parts: Vec<Vec<u8>>,
|
parts: Vec<Vec<u8>>,
|
||||||
partial: Option<Vec<u8>>,
|
partial: Option<Vec<u8>>,
|
||||||
callback: Option<eventual::Complete<MercuryResponse, ()>>
|
callback: MercuryCallback
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MercuryManager {
|
pub struct MercuryManager {
|
||||||
|
@ -64,9 +69,10 @@ impl MercuryManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request(&mut self, session: &Session, req: MercuryRequest)
|
fn request_with_callback(&mut self,
|
||||||
-> eventual::Future<MercuryResponse, ()> {
|
session: &Session,
|
||||||
|
req: MercuryRequest,
|
||||||
|
cb: MercuryCallback) {
|
||||||
let mut seq = [0u8; 4];
|
let mut seq = [0u8; 4];
|
||||||
BigEndian::write_u32(&mut seq, self.next_seq);
|
BigEndian::write_u32(&mut seq, self.next_seq);
|
||||||
self.next_seq += 1;
|
self.next_seq += 1;
|
||||||
|
@ -80,27 +86,30 @@ impl MercuryManager {
|
||||||
|
|
||||||
session.send_packet(cmd, &data).unwrap();
|
session.send_packet(cmd, &data).unwrap();
|
||||||
|
|
||||||
let (tx, rx) = eventual::Future::pair();
|
|
||||||
self.pending.insert(seq.to_vec(), MercuryPending{
|
self.pending.insert(seq.to_vec(), MercuryPending{
|
||||||
parts: Vec::new(),
|
parts: Vec::new(),
|
||||||
partial: None,
|
partial: None,
|
||||||
callback: Some(tx),
|
callback: cb,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn request(&mut self, session: &Session, req: MercuryRequest)
|
||||||
|
-> eventual::Future<MercuryResponse, ()> {
|
||||||
|
let (tx, rx) = eventual::Future::pair();
|
||||||
|
self.request_with_callback(session, req, MercuryCallback::Future(tx));
|
||||||
rx
|
rx
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscribe(&mut self, session: &Session, uri: String)
|
pub fn subscribe(&mut self, session: &Session, uri: String)
|
||||||
-> mpsc::Receiver<MercuryResponse> {
|
-> mpsc::Receiver<MercuryResponse> {
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
self.subscriptions.insert(uri.clone(), tx);
|
|
||||||
|
|
||||||
self.request(session, MercuryRequest{
|
self.request_with_callback(session, MercuryRequest{
|
||||||
method: MercuryMethod::SUB,
|
method: MercuryMethod::SUB,
|
||||||
uri: uri,
|
uri: uri,
|
||||||
content_type: None,
|
content_type: None,
|
||||||
payload: Vec::new()
|
payload: Vec::new()
|
||||||
}).fire();
|
}, MercuryCallback::Subscription(tx));
|
||||||
|
|
||||||
rx
|
rx
|
||||||
}
|
}
|
||||||
|
@ -113,7 +122,17 @@ impl MercuryManager {
|
||||||
buffer
|
buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
fn complete_request(&mut self, cmd: u8, mut pending: MercuryPending) {
|
fn complete_subscription(&mut self,
|
||||||
|
response: MercuryResponse,
|
||||||
|
tx: mpsc::Sender<MercuryResponse>) {
|
||||||
|
for sub_data in response.payload {
|
||||||
|
if let Ok(mut sub) = protobuf::parse_from_bytes::<protocol::pubsub::Subscription>(&sub_data) {
|
||||||
|
self.subscriptions.insert(sub.take_uri(), tx.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete_request(&mut self, mut pending: MercuryPending) {
|
||||||
let header_data = pending.parts.remove(0);
|
let header_data = pending.parts.remove(0);
|
||||||
let header : protocol::mercury::Header =
|
let header : protocol::mercury::Header =
|
||||||
protobuf::parse_from_bytes(&header_data).unwrap();
|
protobuf::parse_from_bytes(&header_data).unwrap();
|
||||||
|
@ -123,10 +142,14 @@ impl MercuryManager {
|
||||||
payload: pending.parts
|
payload: pending.parts
|
||||||
};
|
};
|
||||||
|
|
||||||
if cmd == 0xb5 {
|
match pending.callback {
|
||||||
self.subscriptions.get(header.get_uri()).map(|ch| ch.send(response).ignore());
|
MercuryCallback::Future(tx) => tx.complete(response),
|
||||||
} else {
|
MercuryCallback::Subscription(tx) => self.complete_subscription(response, tx),
|
||||||
pending.callback.map(|cb| cb.complete(response));
|
MercuryCallback::Channel => {
|
||||||
|
self.subscriptions
|
||||||
|
.get(header.get_uri()).unwrap()
|
||||||
|
.send(response).unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +199,7 @@ impl PacketHandler for MercuryManager {
|
||||||
MercuryPending {
|
MercuryPending {
|
||||||
parts: Vec::new(),
|
parts: Vec::new(),
|
||||||
partial: None,
|
partial: None,
|
||||||
callback: None,
|
callback: MercuryCallback::Channel,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("Ignore seq {:?} cmd {}", seq, cmd);
|
println!("Ignore seq {:?} cmd {}", seq, cmd);
|
||||||
|
@ -198,7 +221,7 @@ impl PacketHandler for MercuryManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags == 0x1 {
|
if flags == 0x1 {
|
||||||
self.complete_request(cmd, pending);
|
self.complete_request(pending);
|
||||||
} else {
|
} else {
|
||||||
self.pending.insert(seq, pending);
|
self.pending.insert(seq, pending);
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ impl <'s, D: SpircDelegate> SpircManager<'s, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
let rx = self.session.mercury_sub(format!("hm://remote/3/user/{}/",
|
let rx = self.session.mercury_sub(format!("hm://remote/user/{}/",
|
||||||
self.session.0.data.read().unwrap().canonical_username.clone()));
|
self.session.0.data.read().unwrap().canonical_username.clone()));
|
||||||
let updates = self.delegate.updates();
|
let updates = self.delegate.updates();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue