mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Use PacketType
instead of hex identifiers
This commit is contained in:
parent
4fe1183a80
commit
0703630041
12 changed files with 160 additions and 42 deletions
50
Cargo.lock
generated
50
Cargo.lock
generated
|
@ -635,7 +635,7 @@ dependencies = [
|
||||||
"gstreamer-sys",
|
"gstreamer-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"muldiv",
|
"muldiv",
|
||||||
"num-rational",
|
"num-rational 0.3.2",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"paste",
|
"paste",
|
||||||
"pretty-hex",
|
"pretty-hex",
|
||||||
|
@ -1223,7 +1223,9 @@ dependencies = [
|
||||||
"hyper-proxy",
|
"hyper-proxy",
|
||||||
"librespot-protocol",
|
"librespot-protocol",
|
||||||
"log",
|
"log",
|
||||||
|
"num",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
|
"num-derive",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
@ -1475,6 +1477,20 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-rational 0.4.0",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint"
|
name = "num-bigint"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
@ -1487,6 +1503,15 @@ dependencies = [
|
||||||
"rand",
|
"rand",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-derive"
|
name = "num-derive"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
@ -1508,6 +1533,17 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-rational"
|
name = "num-rational"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
@ -1519,6 +1555,18 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
|
|
|
@ -7,6 +7,7 @@ use byteorder::{BigEndian, WriteBytesExt};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
use librespot_core::channel::{Channel, ChannelData};
|
use librespot_core::channel::{Channel, ChannelData};
|
||||||
|
use librespot_core::packet::PacketType;
|
||||||
use librespot_core::session::Session;
|
use librespot_core::session::Session;
|
||||||
use librespot_core::spotify_id::FileId;
|
use librespot_core::spotify_id::FileId;
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
|
@ -46,7 +47,7 @@ pub fn request_range(session: &Session, file: FileId, offset: usize, length: usi
|
||||||
data.write_u32::<BigEndian>(start as u32).unwrap();
|
data.write_u32::<BigEndian>(start as u32).unwrap();
|
||||||
data.write_u32::<BigEndian>(end as u32).unwrap();
|
data.write_u32::<BigEndian>(end as u32).unwrap();
|
||||||
|
|
||||||
session.send_packet(0x8, data);
|
session.send_packet(PacketType::StreamChunk, data);
|
||||||
|
|
||||||
channel
|
channel
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,9 @@ http = "0.2"
|
||||||
hyper = { version = "0.14", features = ["client", "tcp", "http1"] }
|
hyper = { version = "0.14", features = ["client", "tcp", "http1"] }
|
||||||
hyper-proxy = { version = "0.9.1", default-features = false }
|
hyper-proxy = { version = "0.9.1", default-features = false }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
num = "0.4"
|
||||||
num-bigint = { version = "0.4", features = ["rand"] }
|
num-bigint = { version = "0.4", features = ["rand"] }
|
||||||
|
num-derive = "0.3"
|
||||||
num-integer = "0.1"
|
num-integer = "0.1"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
once_cell = "1.5.2"
|
once_cell = "1.5.2"
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::collections::HashMap;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
|
|
||||||
|
use crate::packet::PacketType;
|
||||||
use crate::spotify_id::{FileId, SpotifyId};
|
use crate::spotify_id::{FileId, SpotifyId};
|
||||||
use crate::util::SeqGenerator;
|
use crate::util::SeqGenerator;
|
||||||
|
|
||||||
|
@ -21,19 +22,19 @@ component! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AudioKeyManager {
|
impl AudioKeyManager {
|
||||||
pub(crate) fn dispatch(&self, cmd: u8, mut data: Bytes) {
|
pub(crate) fn dispatch(&self, cmd: PacketType, mut data: Bytes) {
|
||||||
let seq = BigEndian::read_u32(data.split_to(4).as_ref());
|
let seq = BigEndian::read_u32(data.split_to(4).as_ref());
|
||||||
|
|
||||||
let sender = self.lock(|inner| inner.pending.remove(&seq));
|
let sender = self.lock(|inner| inner.pending.remove(&seq));
|
||||||
|
|
||||||
if let Some(sender) = sender {
|
if let Some(sender) = sender {
|
||||||
match cmd {
|
match cmd {
|
||||||
0xd => {
|
PacketType::AesKey => {
|
||||||
let mut key = [0u8; 16];
|
let mut key = [0u8; 16];
|
||||||
key.copy_from_slice(data.as_ref());
|
key.copy_from_slice(data.as_ref());
|
||||||
let _ = sender.send(Ok(AudioKey(key)));
|
let _ = sender.send(Ok(AudioKey(key)));
|
||||||
}
|
}
|
||||||
0xe => {
|
PacketType::AesKeyError => {
|
||||||
warn!(
|
warn!(
|
||||||
"error audio key {:x} {:x}",
|
"error audio key {:x} {:x}",
|
||||||
data.as_ref()[0],
|
data.as_ref()[0],
|
||||||
|
@ -66,6 +67,6 @@ impl AudioKeyManager {
|
||||||
data.write_u32::<BigEndian>(seq).unwrap();
|
data.write_u32::<BigEndian>(seq).unwrap();
|
||||||
data.write_u16::<BigEndian>(0x0000).unwrap();
|
data.write_u16::<BigEndian>(0x0000).unwrap();
|
||||||
|
|
||||||
self.session().send_packet(0xc, data)
|
self.session().send_packet(PacketType::RequestKey, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,10 @@ use bytes::Bytes;
|
||||||
use futures_core::Stream;
|
use futures_core::Stream;
|
||||||
use futures_util::lock::BiLock;
|
use futures_util::lock::BiLock;
|
||||||
use futures_util::{ready, StreamExt};
|
use futures_util::{ready, StreamExt};
|
||||||
|
use num_traits::FromPrimitive;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
|
use crate::packet::PacketType;
|
||||||
use crate::util::SeqGenerator;
|
use crate::util::SeqGenerator;
|
||||||
|
|
||||||
component! {
|
component! {
|
||||||
|
@ -66,7 +68,7 @@ impl ChannelManager {
|
||||||
(seq, channel)
|
(seq, channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn dispatch(&self, cmd: u8, mut data: Bytes) {
|
pub(crate) fn dispatch(&self, cmd: PacketType, mut data: Bytes) {
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
|
|
||||||
let id: u16 = BigEndian::read_u16(data.split_to(2).as_ref());
|
let id: u16 = BigEndian::read_u16(data.split_to(2).as_ref());
|
||||||
|
@ -87,7 +89,7 @@ impl ChannelManager {
|
||||||
inner.download_measurement_bytes += data.len();
|
inner.download_measurement_bytes += data.len();
|
||||||
|
|
||||||
if let Entry::Occupied(entry) = inner.channels.entry(id) {
|
if let Entry::Occupied(entry) = inner.channels.entry(id) {
|
||||||
let _ = entry.get().send((cmd, data));
|
let _ = entry.get().send((cmd as u8, data));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -109,7 +111,8 @@ impl Channel {
|
||||||
fn recv_packet(&mut self, cx: &mut Context<'_>) -> Poll<Result<Bytes, ChannelError>> {
|
fn recv_packet(&mut self, cx: &mut Context<'_>) -> Poll<Result<Bytes, ChannelError>> {
|
||||||
let (cmd, packet) = ready!(self.receiver.poll_recv(cx)).ok_or(ChannelError)?;
|
let (cmd, packet) = ready!(self.receiver.poll_recv(cx)).ok_or(ChannelError)?;
|
||||||
|
|
||||||
if cmd == 0xa {
|
let packet_type = FromPrimitive::from_u8(cmd);
|
||||||
|
if let Some(PacketType::ChannelError) = packet_type {
|
||||||
let code = BigEndian::read_u16(&packet.as_ref()[..2]);
|
let code = BigEndian::read_u16(&packet.as_ref()[..2]);
|
||||||
error!("channel error: {} {}", packet.len(), code);
|
error!("channel error: {} {}", packet.len(), code);
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ pub use self::handshake::handshake;
|
||||||
use std::io::{self, ErrorKind};
|
use std::io::{self, ErrorKind};
|
||||||
|
|
||||||
use futures_util::{SinkExt, StreamExt};
|
use futures_util::{SinkExt, StreamExt};
|
||||||
|
use num_traits::FromPrimitive;
|
||||||
use protobuf::{self, Message, ProtobufError};
|
use protobuf::{self, Message, ProtobufError};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
|
@ -14,6 +15,7 @@ use tokio_util::codec::Framed;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::authentication::Credentials;
|
use crate::authentication::Credentials;
|
||||||
|
use crate::packet::PacketType;
|
||||||
use crate::protocol::keyexchange::{APLoginFailed, ErrorCode};
|
use crate::protocol::keyexchange::{APLoginFailed, ErrorCode};
|
||||||
use crate::version;
|
use crate::version;
|
||||||
|
|
||||||
|
@ -95,13 +97,14 @@ pub async fn authenticate(
|
||||||
.set_device_id(device_id.to_string());
|
.set_device_id(device_id.to_string());
|
||||||
packet.set_version_string(version::VERSION_STRING.to_string());
|
packet.set_version_string(version::VERSION_STRING.to_string());
|
||||||
|
|
||||||
let cmd = 0xab;
|
let cmd = PacketType::Login;
|
||||||
let data = packet.write_to_bytes().unwrap();
|
let data = packet.write_to_bytes().unwrap();
|
||||||
|
|
||||||
transport.send((cmd, data)).await?;
|
transport.send((cmd as u8, data)).await?;
|
||||||
let (cmd, data) = transport.next().await.expect("EOF")?;
|
let (cmd, data) = transport.next().await.expect("EOF")?;
|
||||||
match cmd {
|
let packet_type = FromPrimitive::from_u8(cmd);
|
||||||
0xac => {
|
match packet_type {
|
||||||
|
Some(PacketType::APWelcome) => {
|
||||||
let welcome_data = APWelcome::parse_from_bytes(data.as_ref())?;
|
let welcome_data = APWelcome::parse_from_bytes(data.as_ref())?;
|
||||||
|
|
||||||
let reusable_credentials = Credentials {
|
let reusable_credentials = Credentials {
|
||||||
|
@ -112,7 +115,7 @@ pub async fn authenticate(
|
||||||
|
|
||||||
Ok(reusable_credentials)
|
Ok(reusable_credentials)
|
||||||
}
|
}
|
||||||
0xad => {
|
Some(PacketType::AuthFailure) => {
|
||||||
let error_data = APLoginFailed::parse_from_bytes(data.as_ref())?;
|
let error_data = APLoginFailed::parse_from_bytes(data.as_ref())?;
|
||||||
Err(error_data.into())
|
Err(error_data.into())
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
extern crate num_derive;
|
||||||
|
|
||||||
use librespot_protocol as protocol;
|
use librespot_protocol as protocol;
|
||||||
|
|
||||||
|
@ -21,6 +22,7 @@ mod dealer;
|
||||||
pub mod diffie_hellman;
|
pub mod diffie_hellman;
|
||||||
mod http_client;
|
mod http_client;
|
||||||
pub mod mercury;
|
pub mod mercury;
|
||||||
|
pub mod packet;
|
||||||
mod proxytunnel;
|
mod proxytunnel;
|
||||||
pub mod session;
|
pub mod session;
|
||||||
mod socket;
|
mod socket;
|
||||||
|
|
|
@ -11,6 +11,7 @@ use futures_util::FutureExt;
|
||||||
use protobuf::Message;
|
use protobuf::Message;
|
||||||
use tokio::sync::{mpsc, oneshot};
|
use tokio::sync::{mpsc, oneshot};
|
||||||
|
|
||||||
|
use crate::packet::PacketType;
|
||||||
use crate::protocol;
|
use crate::protocol;
|
||||||
use crate::util::SeqGenerator;
|
use crate::util::SeqGenerator;
|
||||||
|
|
||||||
|
@ -143,7 +144,7 @@ impl MercuryManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn dispatch(&self, cmd: u8, mut data: Bytes) {
|
pub(crate) fn dispatch(&self, cmd: PacketType, mut data: Bytes) {
|
||||||
let seq_len = BigEndian::read_u16(data.split_to(2).as_ref()) as usize;
|
let seq_len = BigEndian::read_u16(data.split_to(2).as_ref()) as usize;
|
||||||
let seq = data.split_to(seq_len).as_ref().to_owned();
|
let seq = data.split_to(seq_len).as_ref().to_owned();
|
||||||
|
|
||||||
|
@ -154,14 +155,17 @@ impl MercuryManager {
|
||||||
|
|
||||||
let mut pending = match pending {
|
let mut pending = match pending {
|
||||||
Some(pending) => pending,
|
Some(pending) => pending,
|
||||||
None if cmd == 0xb5 => MercuryPending {
|
|
||||||
parts: Vec::new(),
|
|
||||||
partial: None,
|
|
||||||
callback: None,
|
|
||||||
},
|
|
||||||
None => {
|
None => {
|
||||||
warn!("Ignore seq {:?} cmd {:x}", seq, cmd);
|
if let PacketType::MercuryEvent = cmd {
|
||||||
return;
|
MercuryPending {
|
||||||
|
parts: Vec::new(),
|
||||||
|
partial: None,
|
||||||
|
callback: None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("Ignore seq {:?} cmd {:x}", seq, cmd as u8);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -191,7 +195,7 @@ impl MercuryManager {
|
||||||
data.split_to(size).as_ref().to_owned()
|
data.split_to(size).as_ref().to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn complete_request(&self, cmd: u8, mut pending: MercuryPending) {
|
fn complete_request(&self, cmd: PacketType, mut pending: MercuryPending) {
|
||||||
let header_data = pending.parts.remove(0);
|
let header_data = pending.parts.remove(0);
|
||||||
let header = protocol::mercury::Header::parse_from_bytes(&header_data).unwrap();
|
let header = protocol::mercury::Header::parse_from_bytes(&header_data).unwrap();
|
||||||
|
|
||||||
|
@ -208,7 +212,7 @@ impl MercuryManager {
|
||||||
if let Some(cb) = pending.callback {
|
if let Some(cb) = pending.callback {
|
||||||
let _ = cb.send(Err(MercuryError));
|
let _ = cb.send(Err(MercuryError));
|
||||||
}
|
}
|
||||||
} else if cmd == 0xb5 {
|
} else if let PacketType::MercuryEvent = cmd {
|
||||||
self.lock(|inner| {
|
self.lock(|inner| {
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ use byteorder::{BigEndian, WriteBytesExt};
|
||||||
use protobuf::Message;
|
use protobuf::Message;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
|
use crate::packet::PacketType;
|
||||||
use crate::protocol;
|
use crate::protocol;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
@ -43,11 +44,12 @@ impl ToString for MercuryMethod {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MercuryMethod {
|
impl MercuryMethod {
|
||||||
pub fn command(&self) -> u8 {
|
pub fn command(&self) -> PacketType {
|
||||||
|
use PacketType::*;
|
||||||
match *self {
|
match *self {
|
||||||
MercuryMethod::Get | MercuryMethod::Send => 0xb2,
|
MercuryMethod::Get | MercuryMethod::Send => MercuryReq,
|
||||||
MercuryMethod::Sub => 0xb3,
|
MercuryMethod::Sub => MercurySub,
|
||||||
MercuryMethod::Unsub => 0xb4,
|
MercuryMethod::Unsub => MercuryUnsub,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
37
core/src/packet.rs
Normal file
37
core/src/packet.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// Ported from librespot-java. Relicensed under MIT with permission.
|
||||||
|
|
||||||
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
|
|
||||||
|
#[derive(Debug, FromPrimitive, ToPrimitive)]
|
||||||
|
pub enum PacketType {
|
||||||
|
SecretBlock = 0x02,
|
||||||
|
Ping = 0x04,
|
||||||
|
StreamChunk = 0x08,
|
||||||
|
StreamChunkRes = 0x09,
|
||||||
|
ChannelError = 0x0a,
|
||||||
|
ChannelAbort = 0x0b,
|
||||||
|
RequestKey = 0x0c,
|
||||||
|
AesKey = 0x0d,
|
||||||
|
AesKeyError = 0x0e,
|
||||||
|
Image = 0x19,
|
||||||
|
CountryCode = 0x1b,
|
||||||
|
Pong = 0x49,
|
||||||
|
PongAck = 0x4a,
|
||||||
|
Pause = 0x4b,
|
||||||
|
ProductInfo = 0x50,
|
||||||
|
LegacyWelcome = 0x69,
|
||||||
|
LicenseVersion = 0x76,
|
||||||
|
Login = 0xab,
|
||||||
|
APWelcome = 0xac,
|
||||||
|
AuthFailure = 0xad,
|
||||||
|
MercuryReq = 0xb2,
|
||||||
|
MercurySub = 0xb3,
|
||||||
|
MercuryUnsub = 0xb4,
|
||||||
|
MercuryEvent = 0xb5,
|
||||||
|
TrackEndedTime = 0x82,
|
||||||
|
UnknownDataAllZeros = 0x1f,
|
||||||
|
PreferredLocale = 0x74,
|
||||||
|
Unknown0x4f = 0x4f,
|
||||||
|
Unknown0x0f = 0x0f,
|
||||||
|
Unknown0x10 = 0x10,
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ use byteorder::{BigEndian, ByteOrder};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use futures_core::TryStream;
|
use futures_core::TryStream;
|
||||||
use futures_util::{future, ready, StreamExt, TryStreamExt};
|
use futures_util::{future, ready, StreamExt, TryStreamExt};
|
||||||
|
use num_traits::FromPrimitive;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
@ -25,6 +26,7 @@ use crate::config::SessionConfig;
|
||||||
use crate::connection::{self, AuthenticationError};
|
use crate::connection::{self, AuthenticationError};
|
||||||
use crate::http_client::HttpClient;
|
use crate::http_client::HttpClient;
|
||||||
use crate::mercury::MercuryManager;
|
use crate::mercury::MercuryManager;
|
||||||
|
use crate::packet::PacketType;
|
||||||
use crate::token::TokenProvider;
|
use crate::token::TokenProvider;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
@ -184,11 +186,11 @@ impl Session {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::match_same_arms)]
|
|
||||||
fn dispatch(&self, cmd: u8, data: Bytes) {
|
fn dispatch(&self, cmd: u8, data: Bytes) {
|
||||||
match cmd {
|
use PacketType::*;
|
||||||
// TODO: add command types
|
let packet_type = FromPrimitive::from_u8(cmd);
|
||||||
0x4 => {
|
match packet_type {
|
||||||
|
Some(Ping) => {
|
||||||
let server_timestamp = BigEndian::read_u32(data.as_ref()) as i64;
|
let server_timestamp = BigEndian::read_u32(data.as_ref()) as i64;
|
||||||
let timestamp = match SystemTime::now().duration_since(UNIX_EPOCH) {
|
let timestamp = match SystemTime::now().duration_since(UNIX_EPOCH) {
|
||||||
Ok(dur) => dur,
|
Ok(dur) => dur,
|
||||||
|
@ -199,24 +201,36 @@ impl Session {
|
||||||
self.0.data.write().unwrap().time_delta = server_timestamp - timestamp;
|
self.0.data.write().unwrap().time_delta = server_timestamp - timestamp;
|
||||||
|
|
||||||
self.debug_info();
|
self.debug_info();
|
||||||
self.send_packet(0x49, vec![0, 0, 0, 0]);
|
self.send_packet(Pong, vec![0, 0, 0, 0]);
|
||||||
}
|
}
|
||||||
0x4a => (),
|
Some(PongAck) => {}
|
||||||
0x1b => {
|
Some(CountryCode) => {
|
||||||
let country = String::from_utf8(data.as_ref().to_owned()).unwrap();
|
let country = String::from_utf8(data.as_ref().to_owned()).unwrap();
|
||||||
info!("Country: {:?}", country);
|
info!("Country: {:?}", country);
|
||||||
self.0.data.write().unwrap().country = country;
|
self.0.data.write().unwrap().country = country;
|
||||||
}
|
}
|
||||||
|
|
||||||
0x9 | 0xa => self.channel().dispatch(cmd, data),
|
Some(StreamChunkRes) | Some(ChannelError) => {
|
||||||
0xd | 0xe => self.audio_key().dispatch(cmd, data),
|
self.channel().dispatch(packet_type.unwrap(), data)
|
||||||
0xb2..=0xb6 => self.mercury().dispatch(cmd, data),
|
}
|
||||||
_ => (),
|
Some(AesKey) | Some(AesKeyError) => {
|
||||||
|
self.audio_key().dispatch(packet_type.unwrap(), data)
|
||||||
|
}
|
||||||
|
Some(MercuryReq) | Some(MercurySub) | Some(MercuryUnsub) | Some(MercuryEvent) => {
|
||||||
|
self.mercury().dispatch(packet_type.unwrap(), data)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if let Some(packet_type) = PacketType::from_u8(cmd) {
|
||||||
|
trace!("Ignoring {:?} packet", packet_type);
|
||||||
|
} else {
|
||||||
|
trace!("Ignoring unknown packet {:x}", cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_packet(&self, cmd: u8, data: Vec<u8>) {
|
pub fn send_packet(&self, cmd: PacketType, data: Vec<u8>) {
|
||||||
self.0.tx_connection.send((cmd, data)).unwrap();
|
self.0.tx_connection.send((cmd as u8, data)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cache(&self) -> Option<&Arc<Cache>> {
|
pub fn cache(&self) -> Option<&Arc<Cache>> {
|
||||||
|
|
|
@ -2,6 +2,7 @@ use byteorder::{BigEndian, WriteBytesExt};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use librespot_core::channel::ChannelData;
|
use librespot_core::channel::ChannelData;
|
||||||
|
use librespot_core::packet::PacketType;
|
||||||
use librespot_core::session::Session;
|
use librespot_core::session::Session;
|
||||||
use librespot_core::spotify_id::FileId;
|
use librespot_core::spotify_id::FileId;
|
||||||
|
|
||||||
|
@ -13,7 +14,7 @@ pub fn get(session: &Session, file: FileId) -> ChannelData {
|
||||||
packet.write_u16::<BigEndian>(channel_id).unwrap();
|
packet.write_u16::<BigEndian>(channel_id).unwrap();
|
||||||
packet.write_u16::<BigEndian>(0).unwrap();
|
packet.write_u16::<BigEndian>(0).unwrap();
|
||||||
packet.write(&file.0).unwrap();
|
packet.write(&file.0).unwrap();
|
||||||
session.send_packet(0x19, packet);
|
session.send_packet(PacketType::Image, packet);
|
||||||
|
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue