mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Fix build on latest rust.
This commit is contained in:
parent
ab7b5ba69d
commit
267ccbe65e
14 changed files with 292 additions and 258 deletions
197
Cargo.lock
generated
197
Cargo.lock
generated
|
@ -2,27 +2,51 @@
|
||||||
name = "librespot"
|
name = "librespot"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bit-set 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"getopts 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clippy 0.0.12 (git+https://github.com/Manishearth/rust-clippy.git)",
|
||||||
|
"eventual 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"librespot-protocol 0.1.0",
|
"librespot-protocol 0.1.0",
|
||||||
"mod_path 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mod_path 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"portaudio 0.1.2 (git+https://github.com/mvdnes/portaudio-rs)",
|
"portaudio 0.1.2 (git+https://github.com/mvdnes/portaudio-rs)",
|
||||||
"protobuf 1.0.1 (git+https://github.com/plietar/rust-protobuf.git)",
|
"protobuf 1.0.1 (git+https://github.com/plietar/rust-protobuf.git)",
|
||||||
"protobuf_macros 0.1.0 (git+https://github.com/plietar/rust-protobuf-macros.git)",
|
"protobuf_macros 0.1.0 (git+https://github.com/plietar/rust-protobuf-macros.git)",
|
||||||
"rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"readall 0.1.0 (git+https://github.com/plietar/rust-readall.git)",
|
|
||||||
"rpassword 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rpassword 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rust-crypto 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rust-crypto 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rust-gmp 0.2.0 (git+https://github.com/plietar/rust-gmp.git)",
|
"rust-gmp 0.2.0 (git+https://github.com/plietar/rust-gmp.git)",
|
||||||
"shannon 0.1.0 (git+https://github.com/plietar/rust-shannon.git)",
|
"shannon 0.1.0 (git+https://github.com/plietar/rust-shannon.git)",
|
||||||
"tempfile 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tempfile 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"vergen 0.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vergen 0.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"vorbis 0.0.11 (git+https://github.com/plietar/vorbis-rs)",
|
"vorbis 0.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "advapi32-sys"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit-set"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"bit-vec 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit-vec"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
@ -35,39 +59,55 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "0.3.11"
|
version = "0.3.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gcc"
|
name = "clippy"
|
||||||
version = "0.3.8"
|
version = "0.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/Manishearth/rust-clippy.git#d3da9f6c81dd3e026bd679c09cea1d6b337ccd25"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getopts"
|
name = "eventual"
|
||||||
version = "0.2.11"
|
version = "0.1.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syncbox 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kernel32-sys"
|
name = "gcc"
|
||||||
version = "0.1.2"
|
version = "0.3.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
"advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi-build 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getopts"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kernel32-sys"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "0.1.11"
|
version = "0.1.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.1.8"
|
version = "0.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -80,10 +120,10 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.3.1"
|
version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -93,11 +133,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num"
|
name = "num"
|
||||||
version = "0.1.25"
|
version = "0.1.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -105,8 +145,8 @@ name = "ogg-sys"
|
||||||
version = "0.0.9"
|
version = "0.0.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gcc 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -121,7 +161,7 @@ version = "0.1.2"
|
||||||
source = "git+https://github.com/mvdnes/portaudio-rs#7c6d10f5edda0094cc33b682d88c3a6ea4919b9f"
|
source = "git+https://github.com/mvdnes/portaudio-rs#7c6d10f5edda0094cc33b682d88c3a6ea4919b9f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"portaudio_sys 0.1.0 (git+https://github.com/mvdnes/portaudio-rs)",
|
"portaudio_sys 0.1.0 (git+https://github.com/mvdnes/portaudio-rs)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -130,7 +170,7 @@ name = "portaudio_sys"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/mvdnes/portaudio-rs#7c6d10f5edda0094cc33b682d88c3a6ea4919b9f"
|
source = "git+https://github.com/mvdnes/portaudio-rs#7c6d10f5edda0094cc33b682d88c3a6ea4919b9f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -142,14 +182,16 @@ source = "git+https://github.com/plietar/rust-protobuf.git#dae87e292a52a66da7f78
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "protobuf_macros"
|
name = "protobuf_macros"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/plietar/rust-protobuf-macros.git#3b49de3937a34b7a21be1d13caea4348a93c6de4"
|
source = "git+https://github.com/plietar/rust-protobuf-macros.git#2b6a8129e015945300cb2bb7efae2ed78042ed48"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.3.8"
|
version = "0.3.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -162,10 +204,10 @@ name = "rpassword"
|
||||||
version = "0.0.5"
|
version = "0.0.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"termios 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"termios 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -173,24 +215,24 @@ name = "rust-crypto"
|
||||||
version = "0.2.31"
|
version = "0.2.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gcc 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-gmp"
|
name = "rust-gmp"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/plietar/rust-gmp.git#cc003c224559f6035cd34a7ed5c6284a49785816"
|
source = "git+https://github.com/plietar/rust-gmp.git#d1bb4448fdbfa2505edadb83b6aac6257fe08ba2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-serialize"
|
name = "rustc-serialize"
|
||||||
version = "0.3.15"
|
version = "0.3.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -198,7 +240,7 @@ name = "shannon"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/plietar/rust-shannon.git#c6be8a879a523a77d81c50df46faa891b76fea25"
|
source = "git+https://github.com/plietar/rust-shannon.git#c6be8a879a523a77d81c50df46faa891b76fea25"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"readall 0.1.0 (git+https://github.com/plietar/rust-readall.git)",
|
"readall 0.1.0 (git+https://github.com/plietar/rust-readall.git)",
|
||||||
"shannon-sys 0.1.0 (git+https://github.com/plietar/rust-shannon.git)",
|
"shannon-sys 0.1.0 (git+https://github.com/plietar/rust-shannon.git)",
|
||||||
]
|
]
|
||||||
|
@ -208,18 +250,27 @@ name = "shannon-sys"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/plietar/rust-shannon.git#c6be8a879a523a77d81c50df46faa891b76fea25"
|
source = "git+https://github.com/plietar/rust-shannon.git#c6be8a879a523a77d81c50df46faa891b76fea25"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gcc 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syncbox"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "1.0.0"
|
version = "1.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -227,34 +278,34 @@ name = "termios"
|
||||||
version = "0.0.5"
|
version = "0.0.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.1.30"
|
version = "0.1.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vergen"
|
name = "vergen"
|
||||||
version = "0.0.13"
|
version = "0.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vorbis"
|
name = "vorbis"
|
||||||
version = "0.0.11"
|
version = "0.0.12"
|
||||||
source = "git+https://github.com/plietar/vorbis-rs#78058c3341832969030f49cbc4b8bc9deb376776"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"vorbis-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vorbis-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"vorbisfile-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vorbisfile-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -265,8 +316,8 @@ name = "vorbis-sys"
|
||||||
version = "0.0.8"
|
version = "0.0.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gcc 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -276,8 +327,8 @@ name = "vorbisfile-sys"
|
||||||
version = "0.0.8"
|
version = "0.0.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gcc 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"vorbis-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vorbis-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -285,19 +336,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.1.23"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-build"
|
name = "winapi-build"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
|
32
Cargo.toml
32
Cargo.toml
|
@ -16,17 +16,22 @@ path = "src/main.rs"
|
||||||
path = "protocol"
|
path = "protocol"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mod_path = "*"
|
bit-set = "~0.2.0"
|
||||||
byteorder = "*"
|
byteorder = "~0.3.13"
|
||||||
num = "*"
|
eventual = "~0.1.4"
|
||||||
rand = "*"
|
getopts = "~0.2.14"
|
||||||
lazy_static = "0.1.*"
|
lazy_static = "~0.1.14"
|
||||||
rust-crypto = "*"
|
mod_path = "~0.1.5"
|
||||||
time = "*"
|
num = "~0.1.27"
|
||||||
tempfile = "*"
|
rand = "~0.3.11"
|
||||||
rpassword = "*"
|
rpassword = "~0.0.5"
|
||||||
getopts = "0.2.4"
|
rust-crypto = "~0.2.31"
|
||||||
|
time = "~0.1.32"
|
||||||
|
tempfile = "~1.1.1"
|
||||||
|
vorbis = "~0.0.12"
|
||||||
|
|
||||||
|
[dependencies.clippy]
|
||||||
|
git = "https://github.com/Manishearth/rust-clippy.git"
|
||||||
[dependencies.protobuf]
|
[dependencies.protobuf]
|
||||||
git = "https://github.com/plietar/rust-protobuf.git"
|
git = "https://github.com/plietar/rust-protobuf.git"
|
||||||
[dependencies.protobuf_macros]
|
[dependencies.protobuf_macros]
|
||||||
|
@ -35,12 +40,9 @@ git = "https://github.com/plietar/rust-protobuf-macros.git"
|
||||||
git = "https://github.com/plietar/rust-gmp.git"
|
git = "https://github.com/plietar/rust-gmp.git"
|
||||||
[dependencies.shannon]
|
[dependencies.shannon]
|
||||||
git = "https://github.com/plietar/rust-shannon.git"
|
git = "https://github.com/plietar/rust-shannon.git"
|
||||||
[dependencies.readall]
|
|
||||||
git = "https://github.com/plietar/rust-readall.git"
|
|
||||||
[dependencies.portaudio]
|
[dependencies.portaudio]
|
||||||
git = "https://github.com/mvdnes/portaudio-rs"
|
git = "https://github.com/mvdnes/portaudio-rs"
|
||||||
[dependencies.vorbis]
|
|
||||||
git = "https://github.com/plietar/vorbis-rs"
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
vergen = "*"
|
vergen = "~0.0.16"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
use bit_set::BitSet;
|
||||||
use byteorder::{ByteOrder, BigEndian};
|
use byteorder::{ByteOrder, BigEndian};
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::collections::BitSet;
|
|
||||||
use std::sync::{Arc, Condvar, Mutex};
|
use std::sync::{Arc, Condvar, Mutex};
|
||||||
use std::sync::mpsc::{self, TryRecvError};
|
use std::sync::mpsc::{self, TryRecvError};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
@ -9,27 +9,24 @@ use std::io::{self, Read, Write, Seek, SeekFrom};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use tempfile::TempFile;
|
use tempfile::TempFile;
|
||||||
|
|
||||||
use stream::StreamEvent;
|
|
||||||
use util::{FileId, IgnoreExt, ZeroFile, mkdir_existing};
|
use util::{FileId, IgnoreExt, ZeroFile, mkdir_existing};
|
||||||
use session::Session;
|
use session::Session;
|
||||||
|
use stream::StreamEvent;
|
||||||
|
|
||||||
const CHUNK_SIZE : usize = 0x20000;
|
const CHUNK_SIZE : usize = 0x20000;
|
||||||
|
|
||||||
pub enum AudioFile<'s> {
|
pub enum AudioFile {
|
||||||
Direct(fs::File),
|
Direct(fs::File),
|
||||||
Loading(AudioFileLoading<'s>)
|
Loading(AudioFileLoading)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AudioFileLoading<'s> {
|
pub struct AudioFileLoading {
|
||||||
read_file: TempFile,
|
read_file: TempFile,
|
||||||
|
|
||||||
position: u64,
|
position: u64,
|
||||||
seek: mpsc::Sender<u64>,
|
seek: mpsc::Sender<u64>,
|
||||||
|
|
||||||
shared: Arc<AudioFileShared>,
|
shared: Arc<AudioFileShared>,
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
thread: thread::JoinGuard<'s, ()>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AudioFileShared {
|
struct AudioFileShared {
|
||||||
|
@ -40,7 +37,7 @@ struct AudioFileShared {
|
||||||
bitmap: Mutex<BitSet>,
|
bitmap: Mutex<BitSet>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'s> AudioFileLoading<'s> {
|
impl AudioFileLoading {
|
||||||
fn new(session: &Session, file_id: FileId) -> AudioFileLoading {
|
fn new(session: &Session, file_id: FileId) -> AudioFileLoading {
|
||||||
let mut files_iter = TempFile::shared(2).unwrap().into_iter();
|
let mut files_iter = TempFile::shared(2).unwrap().into_iter();
|
||||||
let read_file = files_iter.next().unwrap();
|
let read_file = files_iter.next().unwrap();
|
||||||
|
@ -70,17 +67,20 @@ impl <'s> AudioFileLoading<'s> {
|
||||||
|
|
||||||
let (seek_tx, seek_rx) = mpsc::channel();
|
let (seek_tx, seek_rx) = mpsc::channel();
|
||||||
|
|
||||||
|
let _shared = shared.clone();
|
||||||
|
let _session = session.clone();
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
AudioFileLoading::fetch(&_session, _shared, write_file, seek_rx)
|
||||||
|
});
|
||||||
|
|
||||||
AudioFileLoading {
|
AudioFileLoading {
|
||||||
read_file: read_file,
|
read_file: read_file,
|
||||||
|
|
||||||
position: 0,
|
position: 0,
|
||||||
seek: seek_tx,
|
seek: seek_tx,
|
||||||
|
|
||||||
shared: shared.clone(),
|
shared: shared
|
||||||
|
|
||||||
thread: thread::scoped(move || {
|
|
||||||
AudioFileLoading::fetch(session, shared, write_file, seek_rx)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ impl <'s> AudioFileLoading<'s> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'s> Read for AudioFileLoading<'s> {
|
impl Read for AudioFileLoading {
|
||||||
fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
|
fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
|
||||||
let index = self.position as usize / CHUNK_SIZE;
|
let index = self.position as usize / CHUNK_SIZE;
|
||||||
let offset = self.position as usize % CHUNK_SIZE;
|
let offset = self.position as usize % CHUNK_SIZE;
|
||||||
|
@ -167,15 +167,15 @@ impl <'s> Read for AudioFileLoading<'s> {
|
||||||
}
|
}
|
||||||
drop(bitmap);
|
drop(bitmap);
|
||||||
|
|
||||||
let len = try!(self.read_file.read(&mut output[..len]));
|
let read_len = try!(self.read_file.read(&mut output[..len]));
|
||||||
|
|
||||||
self.position += len as u64;
|
self.position += read_len as u64;
|
||||||
|
|
||||||
Ok(len)
|
Ok(read_len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'s> Seek for AudioFileLoading<'s> {
|
impl Seek for AudioFileLoading {
|
||||||
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
||||||
self.position = try!(self.read_file.seek(pos));
|
self.position = try!(self.read_file.seek(pos));
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ impl <'s> Seek for AudioFileLoading<'s> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'s> Read for AudioFile<'s> {
|
impl Read for AudioFile {
|
||||||
fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
|
fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
|
||||||
match *self {
|
match *self {
|
||||||
AudioFile::Direct(ref mut file) => file.read(output),
|
AudioFile::Direct(ref mut file) => file.read(output),
|
||||||
|
@ -198,7 +198,7 @@ impl <'s> Read for AudioFile<'s> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'s> Seek for AudioFile<'s> {
|
impl Seek for AudioFile {
|
||||||
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
|
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
|
||||||
match *self {
|
match *self {
|
||||||
AudioFile::Direct(ref mut file) => file.seek(pos),
|
AudioFile::Direct(ref mut file) => file.seek(pos),
|
||||||
|
@ -215,7 +215,7 @@ impl AudioFileManager {
|
||||||
|
|
||||||
pub fn cache_dir(session: &Session, file_id: FileId) -> PathBuf {
|
pub fn cache_dir(session: &Session, file_id: FileId) -> PathBuf {
|
||||||
let name = file_id.to_base16();
|
let name = file_id.to_base16();
|
||||||
session.config.cache_location.join(&name[0..2])
|
session.0.config.cache_location.join(&name[0..2])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cache_path(session: &Session, file_id: FileId) -> PathBuf {
|
pub fn cache_path(session: &Session, file_id: FileId) -> PathBuf {
|
||||||
|
@ -223,7 +223,7 @@ impl AudioFileManager {
|
||||||
AudioFileManager::cache_dir(session, file_id).join(&name[2..])
|
AudioFileManager::cache_dir(session, file_id).join(&name[2..])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request<'a> (&mut self, session: &'a Session, file_id: FileId) -> AudioFile<'a> {
|
pub fn request (&mut self, session: &Session, file_id: FileId) -> AudioFile {
|
||||||
match fs::File::open(AudioFileManager::cache_path(session, file_id)) {
|
match fs::File::open(AudioFileManager::cache_path(session, file_id)) {
|
||||||
Ok(f) => AudioFile::Direct(f),
|
Ok(f) => AudioFile::Direct(f),
|
||||||
Err(..) => AudioFile::Loading(AudioFileLoading::new(session, file_id))
|
Err(..) => AudioFile::Loading(AudioFileLoading::new(session, file_id))
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use std::collections::{HashMap, LinkedList};
|
|
||||||
use std::sync::{mpsc, Future};
|
|
||||||
use std::io::{Cursor, Write};
|
|
||||||
use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
|
use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
|
||||||
use readall::ReadAllExt;
|
use eventual;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::io::{Cursor, Read, Write};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use util::{SpotifyId, FileId, IgnoreExt};
|
use util::{SpotifyId, FileId};
|
||||||
use session::Session;
|
use session::Session;
|
||||||
use connection::PacketHandler;
|
use connection::PacketHandler;
|
||||||
|
|
||||||
|
@ -15,7 +14,7 @@ pub type AudioKey = [u8; 16];
|
||||||
struct AudioKeyId(SpotifyId, FileId);
|
struct AudioKeyId(SpotifyId, FileId);
|
||||||
|
|
||||||
enum AudioKeyStatus {
|
enum AudioKeyStatus {
|
||||||
Loading(LinkedList<mpsc::Sender<AudioKey>>),
|
Loading(Vec<eventual::Complete<AudioKey, ()>>),
|
||||||
Loaded(AudioKey)
|
Loaded(AudioKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,17 +34,17 @@ impl AudioKeyManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request(&mut self, session: &Session, track: SpotifyId, file: FileId)
|
pub fn request(&mut self, session: &Session, track: SpotifyId, file: FileId)
|
||||||
-> Future<AudioKey> {
|
-> eventual::Future<AudioKey, ()> {
|
||||||
|
|
||||||
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 {
|
||||||
&mut AudioKeyStatus::Loaded(key) => {
|
AudioKeyStatus::Loaded(key) => {
|
||||||
Future::from_value(key.clone())
|
eventual::Future::of(key.clone())
|
||||||
}
|
}
|
||||||
&mut AudioKeyStatus::Loading(ref mut req) => {
|
AudioKeyStatus::Loading(ref mut req) => {
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = eventual::Future::pair();
|
||||||
req.push_front(tx);
|
req.push(tx);
|
||||||
Future::from_receiver(rx)
|
rx
|
||||||
}
|
}
|
||||||
}).unwrap_or_else(|| {
|
}).unwrap_or_else(|| {
|
||||||
let seq = self.next_seq;
|
let seq = self.next_seq;
|
||||||
|
@ -61,11 +60,9 @@ impl AudioKeyManager {
|
||||||
|
|
||||||
self.pending.insert(seq, id.clone());
|
self.pending.insert(seq, id.clone());
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = eventual::Future::pair();
|
||||||
let mut req = LinkedList::new();
|
self.cache.insert(id, AudioKeyStatus::Loading(vec!{ tx }));
|
||||||
req.push_front(tx);
|
rx
|
||||||
self.cache.insert(id, AudioKeyStatus::Loading(req));
|
|
||||||
Future::from_receiver(rx)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,14 +74,14 @@ impl PacketHandler for AudioKeyManager {
|
||||||
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();
|
||||||
let mut key = [0u8; 16];
|
let mut key = [0u8; 16];
|
||||||
data.read_all(&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) }) {
|
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 {
|
||||||
for cb in cbs {
|
for cb in cbs {
|
||||||
cb.send(key).ignore();
|
cb.complete(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use byteorder::{self, BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
|
use byteorder::{self, BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
|
||||||
use readall::ReadAllExt;
|
|
||||||
use shannon::ShannonStream;
|
use shannon::ShannonStream;
|
||||||
use std::convert;
|
use std::convert;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Write;
|
use std::io::{Read, Write};
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
use std::result;
|
use std::result;
|
||||||
|
|
||||||
|
@ -70,7 +69,7 @@ impl PlainConnection {
|
||||||
let mut buffer = vec![0u8; size];
|
let mut buffer = vec![0u8; size];
|
||||||
|
|
||||||
BigEndian::write_u32(&mut buffer, size as u32);
|
BigEndian::write_u32(&mut buffer, size as u32);
|
||||||
try!(self.stream.read_all(&mut buffer[4..]));
|
try!(self.stream.read_exact(&mut buffer[4..]));
|
||||||
|
|
||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
|
@ -98,7 +97,7 @@ impl CipherConnection {
|
||||||
let size = try!(self.stream.read_u16::<BigEndian>()) as usize;
|
let size = try!(self.stream.read_u16::<BigEndian>()) as usize;
|
||||||
|
|
||||||
let mut data = vec![0; size];
|
let mut data = vec![0; size];
|
||||||
try!(self.stream.read_all(&mut data));
|
try!(self.stream.read_exact(&mut data));
|
||||||
|
|
||||||
try!(self.stream.finish_recv());
|
try!(self.stream.finish_recv());
|
||||||
|
|
||||||
|
|
12
src/lib.rs
12
src/lib.rs
|
@ -1,25 +1,25 @@
|
||||||
#![crate_name = "librespot"]
|
#![crate_name = "librespot"]
|
||||||
|
|
||||||
#![feature(plugin,scoped,zero_one,iter_arith,slice_position_elem,slice_bytes,bitset,arc_weak,append,future,mpsc_select)]
|
#![feature(plugin,read_exact,zero_one,iter_arith,slice_bytes,arc_weak,append,mpsc_select)]
|
||||||
#![allow(deprecated)]
|
#![allow(needless_return)]
|
||||||
//#![allow(unused_imports,dead_code)]
|
|
||||||
|
|
||||||
|
#![plugin(clippy)]
|
||||||
#![plugin(protobuf_macros)]
|
#![plugin(protobuf_macros)]
|
||||||
#[macro_use] extern crate lazy_static;
|
#[macro_use] extern crate lazy_static;
|
||||||
|
|
||||||
|
extern crate bit_set;
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate crypto;
|
extern crate crypto;
|
||||||
|
extern crate eventual;
|
||||||
extern crate gmp;
|
extern crate gmp;
|
||||||
extern crate num;
|
extern crate num;
|
||||||
extern crate portaudio;
|
extern crate portaudio;
|
||||||
extern crate protobuf;
|
extern crate protobuf;
|
||||||
extern crate shannon;
|
extern crate shannon;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate readall;
|
|
||||||
extern crate vorbis;
|
|
||||||
extern crate time;
|
extern crate time;
|
||||||
extern crate tempfile;
|
extern crate tempfile;
|
||||||
|
extern crate vorbis;
|
||||||
|
|
||||||
extern crate librespot_protocol;
|
extern crate librespot_protocol;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#![feature(scoped)]
|
|
||||||
#![feature(result_expect)]
|
#![feature(result_expect)]
|
||||||
#![allow(deprecated)]
|
#![allow(deprecated)]
|
||||||
|
|
||||||
|
@ -71,9 +70,10 @@ fn main() {
|
||||||
session.login(username.clone(), password);
|
session.login(username.clone(), password);
|
||||||
session.poll();
|
session.poll();
|
||||||
|
|
||||||
let poll_thread = thread::scoped(|| {
|
let _session = session.clone();
|
||||||
|
thread::spawn(move || {
|
||||||
loop {
|
loop {
|
||||||
session.poll();
|
_session.poll();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -81,7 +81,5 @@ fn main() {
|
||||||
|
|
||||||
let mut spirc_manager = SpircManager::new(&session, player, username, name);
|
let mut spirc_manager = SpircManager::new(&session, player, username, name);
|
||||||
spirc_manager.run();
|
spirc_manager.run();
|
||||||
|
|
||||||
poll_thread.join();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
|
use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
|
||||||
|
use eventual;
|
||||||
use protobuf::{self, Message};
|
use protobuf::{self, Message};
|
||||||
use readall::ReadAllExt;
|
use std::collections::HashMap;
|
||||||
use std::collections::{HashMap, LinkedList};
|
|
||||||
use std::io::{Cursor, Read, Write};
|
use std::io::{Cursor, Read, Write};
|
||||||
use std::fmt;
|
|
||||||
use std::mem::replace;
|
use std::mem::replace;
|
||||||
use std::sync::{mpsc, Future};
|
use std::sync::mpsc;
|
||||||
|
|
||||||
use librespot_protocol as protocol;
|
use librespot_protocol as protocol;
|
||||||
use session::Session;
|
use session::Session;
|
||||||
|
@ -30,13 +29,13 @@ pub struct MercuryRequest {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MercuryResponse {
|
pub struct MercuryResponse {
|
||||||
pub uri: String,
|
pub uri: String,
|
||||||
pub payload: LinkedList<Vec<u8>>
|
pub payload: Vec<Vec<u8>>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MercuryPending {
|
pub struct MercuryPending {
|
||||||
parts: LinkedList<Vec<u8>>,
|
parts: Vec<Vec<u8>>,
|
||||||
partial: Option<Vec<u8>>,
|
partial: Option<Vec<u8>>,
|
||||||
callback: Option<mpsc::Sender<MercuryResponse>>
|
callback: Option<eventual::Complete<MercuryResponse, ()>>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MercuryManager {
|
pub struct MercuryManager {
|
||||||
|
@ -45,14 +44,14 @@ pub struct MercuryManager {
|
||||||
subscriptions: HashMap<String, mpsc::Sender<MercuryResponse>>,
|
subscriptions: HashMap<String, mpsc::Sender<MercuryResponse>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for MercuryMethod {
|
impl ToString for MercuryMethod {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn to_string(&self) -> String {
|
||||||
formatter.write_str(match *self {
|
match *self {
|
||||||
MercuryMethod::GET => "GET",
|
MercuryMethod::GET => "GET",
|
||||||
MercuryMethod::SUB => "SUB",
|
MercuryMethod::SUB => "SUB",
|
||||||
MercuryMethod::UNSUB => "UNSUB",
|
MercuryMethod::UNSUB => "UNSUB",
|
||||||
MercuryMethod::SEND => "SEND"
|
MercuryMethod::SEND => "SEND"
|
||||||
})
|
}.to_owned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +65,7 @@ impl MercuryManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request(&mut self, session: &Session, req: MercuryRequest)
|
pub fn request(&mut self, session: &Session, req: MercuryRequest)
|
||||||
-> Future<MercuryResponse> {
|
-> eventual::Future<MercuryResponse, ()> {
|
||||||
|
|
||||||
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);
|
||||||
|
@ -81,14 +80,14 @@ impl MercuryManager {
|
||||||
|
|
||||||
session.send_packet(cmd, &data).unwrap();
|
session.send_packet(cmd, &data).unwrap();
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = eventual::Future::pair();
|
||||||
self.pending.insert(seq.to_vec(), MercuryPending{
|
self.pending.insert(seq.to_vec(), MercuryPending{
|
||||||
parts: LinkedList::new(),
|
parts: Vec::new(),
|
||||||
partial: None,
|
partial: None,
|
||||||
callback: Some(tx),
|
callback: Some(tx),
|
||||||
});
|
});
|
||||||
|
|
||||||
Future::from_receiver(rx)
|
rx
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscribe(&mut self, session: &Session, uri: String)
|
pub fn subscribe(&mut self, session: &Session, uri: String)
|
||||||
|
@ -109,33 +108,25 @@ impl MercuryManager {
|
||||||
fn parse_part(mut s: &mut Read) -> Vec<u8> {
|
fn parse_part(mut s: &mut Read) -> Vec<u8> {
|
||||||
let size = s.read_u16::<BigEndian>().unwrap() as usize;
|
let size = s.read_u16::<BigEndian>().unwrap() as usize;
|
||||||
let mut buffer = vec![0; size];
|
let mut buffer = vec![0; size];
|
||||||
s.read_all(&mut buffer).unwrap();
|
s.read_exact(&mut buffer).unwrap();
|
||||||
|
|
||||||
buffer
|
buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
fn complete_request(&mut self, cmd: u8, mut pending: MercuryPending) {
|
fn complete_request(&mut self, cmd: u8, mut pending: MercuryPending) {
|
||||||
let header_data = match pending.parts.pop_front() {
|
let header_data = pending.parts.remove(0);
|
||||||
Some(data) => data,
|
|
||||||
None => panic!("No header part !")
|
|
||||||
};
|
|
||||||
|
|
||||||
let header : protocol::mercury::Header =
|
let header : protocol::mercury::Header =
|
||||||
protobuf::parse_from_bytes(&header_data).unwrap();
|
protobuf::parse_from_bytes(&header_data).unwrap();
|
||||||
|
|
||||||
let callback = if cmd == 0xb5 {
|
let response = MercuryResponse {
|
||||||
self.subscriptions.get(header.get_uri())
|
uri: header.get_uri().to_owned(),
|
||||||
} else {
|
payload: pending.parts
|
||||||
pending.callback.as_ref()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(ref ch) = callback {
|
if cmd == 0xb5 {
|
||||||
// Ignore send error.
|
self.subscriptions.get(header.get_uri()).map(|ch| ch.send(response).ignore());
|
||||||
// It simply means the receiver was closed
|
} else {
|
||||||
ch.send(MercuryResponse{
|
pending.callback.map(|cb| cb.complete(response));
|
||||||
uri: header.get_uri().to_string(),
|
|
||||||
payload: pending.parts
|
|
||||||
}).ignore();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +164,7 @@ impl PacketHandler for MercuryManager {
|
||||||
let seq = {
|
let seq = {
|
||||||
let seq_length = packet.read_u16::<BigEndian>().unwrap() as usize;
|
let seq_length = packet.read_u16::<BigEndian>().unwrap() as usize;
|
||||||
let mut seq = vec![0; seq_length];
|
let mut seq = vec![0; seq_length];
|
||||||
packet.read_all(&mut seq).unwrap();
|
packet.read_exact(&mut seq).unwrap();
|
||||||
seq
|
seq
|
||||||
};
|
};
|
||||||
let flags = packet.read_u8().unwrap();
|
let flags = packet.read_u8().unwrap();
|
||||||
|
@ -183,7 +174,7 @@ impl PacketHandler for MercuryManager {
|
||||||
pending
|
pending
|
||||||
} else if cmd == 0xb5 {
|
} else if cmd == 0xb5 {
|
||||||
MercuryPending {
|
MercuryPending {
|
||||||
parts: LinkedList::new(),
|
parts: Vec::new(),
|
||||||
partial: None,
|
partial: None,
|
||||||
callback: None,
|
callback: None,
|
||||||
}
|
}
|
||||||
|
@ -202,7 +193,7 @@ impl PacketHandler for MercuryManager {
|
||||||
if i == count - 1 && (flags == 2) {
|
if i == count - 1 && (flags == 2) {
|
||||||
pending.partial = Some(part)
|
pending.partial = Some(part)
|
||||||
} else {
|
} else {
|
||||||
pending.parts.push_back(part);
|
pending.parts.push(part);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use eventual::Async;
|
||||||
use protobuf::{self, Message};
|
use protobuf::{self, Message};
|
||||||
use std::any::{Any, TypeId};
|
use std::any::{Any, TypeId};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -11,7 +12,7 @@ use mercury::{MercuryRequest, MercuryMethod};
|
||||||
use util::{SpotifyId, FileId};
|
use util::{SpotifyId, FileId};
|
||||||
use session::Session;
|
use session::Session;
|
||||||
|
|
||||||
pub trait MetadataTrait : Send + Any + 'static {
|
pub trait MetadataTrait : Send + Sized + Any + 'static {
|
||||||
type Message: protobuf::MessageStatic;
|
type Message: protobuf::MessageStatic;
|
||||||
fn from_msg(msg: &Self::Message) -> Self;
|
fn from_msg(msg: &Self::Message) -> Self;
|
||||||
fn base_url() -> &'static str;
|
fn base_url() -> &'static str;
|
||||||
|
@ -29,7 +30,7 @@ impl MetadataTrait for Track {
|
||||||
type Message = protocol::metadata::Track;
|
type Message = protocol::metadata::Track;
|
||||||
fn from_msg(msg: &Self::Message) -> Self {
|
fn from_msg(msg: &Self::Message) -> Self {
|
||||||
Track {
|
Track {
|
||||||
name: msg.get_name().to_string(),
|
name: msg.get_name().to_owned(),
|
||||||
album: SpotifyId::from_raw(msg.get_album().get_gid()),
|
album: SpotifyId::from_raw(msg.get_album().get_gid()),
|
||||||
files: msg.get_file().iter()
|
files: msg.get_file().iter()
|
||||||
.map(|file| {
|
.map(|file| {
|
||||||
|
@ -59,7 +60,7 @@ impl MetadataTrait for Album {
|
||||||
type Message = protocol::metadata::Album;
|
type Message = protocol::metadata::Album;
|
||||||
fn from_msg(msg: &Self::Message) -> Self {
|
fn from_msg(msg: &Self::Message) -> Self {
|
||||||
Album {
|
Album {
|
||||||
name: msg.get_name().to_string(),
|
name: msg.get_name().to_owned(),
|
||||||
artists: msg.get_artist().iter()
|
artists: msg.get_artist().iter()
|
||||||
.map(|a| SpotifyId::from_raw(a.get_gid()))
|
.map(|a| SpotifyId::from_raw(a.get_gid()))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -89,7 +90,7 @@ impl MetadataTrait for Artist {
|
||||||
type Message = protocol::metadata::Artist;
|
type Message = protocol::metadata::Artist;
|
||||||
fn from_msg(msg: &Self::Message) -> Self {
|
fn from_msg(msg: &Self::Message) -> Self {
|
||||||
Artist {
|
Artist {
|
||||||
name: msg.get_name().to_string(),
|
name: msg.get_name().to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn base_url() -> &'static str {
|
fn base_url() -> &'static str {
|
||||||
|
@ -164,7 +165,7 @@ impl <T: MetadataTrait> MetadataState<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unwrap<'s>(&'s self) -> &'s T {
|
pub fn unwrap(&self) -> &T {
|
||||||
match *self {
|
match *self {
|
||||||
MetadataState::Loaded(ref data) => data,
|
MetadataState::Loaded(ref data) => data,
|
||||||
_ => panic!("Not loaded")
|
_ => panic!("Not loaded")
|
||||||
|
@ -180,7 +181,7 @@ pub enum MetadataRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MetadataManager {
|
pub struct MetadataManager {
|
||||||
cache: HashMap<(SpotifyId, TypeId), Box<Any + Send>>
|
cache: HashMap<(SpotifyId, TypeId), Box<Any + Send + 'static>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MetadataManager {
|
impl MetadataManager {
|
||||||
|
@ -204,7 +205,7 @@ impl MetadataManager {
|
||||||
cond: Condvar::new()
|
cond: Condvar::new()
|
||||||
});
|
});
|
||||||
|
|
||||||
self.cache.insert(key, Box::new(x.downgrade()));
|
self.cache.insert(key, Box::new(Arc::downgrade(&x)));
|
||||||
self.load(session, x.clone());
|
self.load(session, x.clone());
|
||||||
x
|
x
|
||||||
})
|
})
|
||||||
|
@ -219,10 +220,10 @@ impl MetadataManager {
|
||||||
});
|
});
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let response = rx.into_inner();
|
let response = rx.await().unwrap();
|
||||||
|
|
||||||
let msg : T::Message = protobuf::parse_from_bytes(
|
let msg : T::Message = protobuf::parse_from_bytes(
|
||||||
response.payload.front().unwrap()).unwrap();
|
response.payload.first().unwrap()).unwrap();
|
||||||
|
|
||||||
object.set(MetadataState::Loaded(T::from_msg(&msg)));
|
object.set(MetadataState::Loaded(T::from_msg(&msg)));
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
use eventual::Async;
|
||||||
use portaudio;
|
use portaudio;
|
||||||
use vorbis;
|
|
||||||
use std::sync::{mpsc, Mutex, Arc, Condvar, MutexGuard};
|
use std::sync::{mpsc, Mutex, Arc, Condvar, MutexGuard};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
use vorbis;
|
||||||
|
|
||||||
use metadata::TrackRef;
|
use metadata::TrackRef;
|
||||||
use session::Session;
|
use session::Session;
|
||||||
|
@ -9,13 +10,10 @@ use audio_decrypt::AudioDecrypt;
|
||||||
use util::{self, SpotifyId, Subfile};
|
use util::{self, SpotifyId, Subfile};
|
||||||
use spirc::{SpircState, SpircDelegate, PlayStatus};
|
use spirc::{SpircState, SpircDelegate, PlayStatus};
|
||||||
|
|
||||||
pub struct Player<'s> {
|
pub struct Player {
|
||||||
state: Arc<(Mutex<PlayerState>, Condvar)>,
|
state: Arc<(Mutex<PlayerState>, Condvar)>,
|
||||||
|
|
||||||
commands: mpsc::Sender<PlayerCommand>,
|
commands: mpsc::Sender<PlayerCommand>,
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
thread: thread::JoinGuard<'s, ()>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PlayerState {
|
pub struct PlayerState {
|
||||||
|
@ -27,10 +25,9 @@ pub struct PlayerState {
|
||||||
end_of_track: bool
|
end_of_track: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PlayerInternal<'s> {
|
struct PlayerInternal {
|
||||||
state: Arc<(Mutex<PlayerState>, Condvar)>,
|
state: Arc<(Mutex<PlayerState>, Condvar)>,
|
||||||
|
session: Session,
|
||||||
session: &'s Session,
|
|
||||||
commands: mpsc::Receiver<PlayerCommand>,
|
commands: mpsc::Receiver<PlayerCommand>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +39,7 @@ enum PlayerCommand {
|
||||||
Seek(u32)
|
Seek(u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'s> Player<'s> {
|
impl Player {
|
||||||
pub fn new(session: &Session) -> Player {
|
pub fn new(session: &Session) -> Player {
|
||||||
let (cmd_tx, cmd_rx) = mpsc::channel();
|
let (cmd_tx, cmd_rx) = mpsc::channel();
|
||||||
|
|
||||||
|
@ -55,17 +52,18 @@ impl <'s> Player<'s> {
|
||||||
}), Condvar::new()));
|
}), Condvar::new()));
|
||||||
|
|
||||||
let internal = PlayerInternal {
|
let internal = PlayerInternal {
|
||||||
session: session,
|
session: session.clone(),
|
||||||
commands: cmd_rx,
|
commands: cmd_rx,
|
||||||
state: state.clone()
|
state: state.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
internal.run()
|
||||||
|
});
|
||||||
|
|
||||||
Player {
|
Player {
|
||||||
commands: cmd_tx,
|
commands: cmd_tx,
|
||||||
state: state,
|
state: state,
|
||||||
thread: thread::scoped(move || {
|
|
||||||
internal.run()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +72,7 @@ impl <'s> Player<'s> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'s> PlayerInternal<'s> {
|
impl PlayerInternal {
|
||||||
fn run(self) {
|
fn run(self) {
|
||||||
portaudio::initialize().unwrap();
|
portaudio::initialize().unwrap();
|
||||||
|
|
||||||
|
@ -102,7 +100,8 @@ impl <'s> PlayerInternal<'s> {
|
||||||
|
|
||||||
let track : TrackRef = self.session.metadata(id);
|
let track : TrackRef = self.session.metadata(id);
|
||||||
let file_id = *track.wait().unwrap().files.first().unwrap();
|
let file_id = *track.wait().unwrap().files.first().unwrap();
|
||||||
let key = self.session.audio_key(track.id(), file_id).into_inner();
|
|
||||||
|
let key = self.session.audio_key(track.id(), file_id).await().unwrap();
|
||||||
decoder = Some(
|
decoder = Some(
|
||||||
vorbis::Decoder::new(
|
vorbis::Decoder::new(
|
||||||
Subfile::new(
|
Subfile::new(
|
||||||
|
@ -217,7 +216,7 @@ impl <'s> PlayerInternal<'s> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'s> SpircDelegate for Player<'s> {
|
impl SpircDelegate for Player {
|
||||||
type State = PlayerState;
|
type State = PlayerState;
|
||||||
|
|
||||||
fn load(&self, track: SpotifyId,
|
fn load(&self, track: SpotifyId,
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use crypto::digest::Digest;
|
use crypto::digest::Digest;
|
||||||
use crypto::sha1::Sha1;
|
use crypto::sha1::Sha1;
|
||||||
|
use eventual::Future;
|
||||||
use protobuf::{self, Message};
|
use protobuf::{self, Message};
|
||||||
use rand::thread_rng;
|
use rand::thread_rng;
|
||||||
use std::sync::{Mutex, Arc, Future, mpsc};
|
use std::sync::{Mutex, Arc, mpsc};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use connection::{self, PlainConnection, CipherConnection};
|
use connection::{self, PlainConnection, CipherConnection};
|
||||||
|
@ -26,7 +27,7 @@ pub struct Config {
|
||||||
pub cache_location: PathBuf,
|
pub cache_location: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Session {
|
pub struct SessionData {
|
||||||
pub config: Config,
|
pub config: Config,
|
||||||
|
|
||||||
mercury: Mutex<MercuryManager>,
|
mercury: Mutex<MercuryManager>,
|
||||||
|
@ -38,7 +39,8 @@ pub struct Session {
|
||||||
tx_connection: Mutex<CipherConnection>,
|
tx_connection: Mutex<CipherConnection>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type SessionRef = Arc<Session>;
|
#[derive(Clone)]
|
||||||
|
pub struct Session(pub Arc<SessionData>);
|
||||||
|
|
||||||
impl Session {
|
impl Session {
|
||||||
pub fn new(mut config: Config) -> Session {
|
pub fn new(mut config: Config) -> Session {
|
||||||
|
@ -114,7 +116,7 @@ impl Session {
|
||||||
|
|
||||||
let cipher_connection = connection.setup_cipher(shared_keys);
|
let cipher_connection = connection.setup_cipher(shared_keys);
|
||||||
|
|
||||||
Session {
|
Session(Arc::new(SessionData {
|
||||||
config: config,
|
config: config,
|
||||||
|
|
||||||
rx_connection: Mutex::new(cipher_connection.clone()),
|
rx_connection: Mutex::new(cipher_connection.clone()),
|
||||||
|
@ -125,7 +127,7 @@ impl Session {
|
||||||
stream: Mutex::new(StreamManager::new()),
|
stream: Mutex::new(StreamManager::new()),
|
||||||
audio_key: Mutex::new(AudioKeyManager::new()),
|
audio_key: Mutex::new(AudioKeyManager::new()),
|
||||||
audio_file: Mutex::new(AudioFileManager::new()),
|
audio_file: Mutex::new(AudioFileManager::new()),
|
||||||
}
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn login(&self, username: String, password: String) {
|
pub fn login(&self, username: String, password: String) {
|
||||||
|
@ -138,15 +140,15 @@ impl Session {
|
||||||
system_info => {
|
system_info => {
|
||||||
cpu_family: protocol::authentication::CpuFamily::CPU_UNKNOWN,
|
cpu_family: protocol::authentication::CpuFamily::CPU_UNKNOWN,
|
||||||
os: protocol::authentication::Os::OS_UNKNOWN,
|
os: protocol::authentication::Os::OS_UNKNOWN,
|
||||||
system_information_string: "librespot".to_string(),
|
system_information_string: "librespot".to_owned(),
|
||||||
device_id: self.config.device_id.clone()
|
device_id: self.0.config.device_id.clone()
|
||||||
},
|
},
|
||||||
version_string: util::version::version_string(),
|
version_string: util::version::version_string(),
|
||||||
appkey => {
|
appkey => {
|
||||||
version: self.config.application_key[0] as u32,
|
version: self.0.config.application_key[0] as u32,
|
||||||
devkey: self.config.application_key[0x1..0x81].to_vec(),
|
devkey: self.0.config.application_key[0x1..0x81].to_vec(),
|
||||||
signature: self.config.application_key[0x81..0x141].to_vec(),
|
signature: self.0.config.application_key[0x81..0x141].to_vec(),
|
||||||
useragent: self.config.user_agent.clone(),
|
useragent: self.0.config.user_agent.clone(),
|
||||||
callback_hash: vec![0; 20],
|
callback_hash: vec![0; 20],
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -156,14 +158,14 @@ impl Session {
|
||||||
|
|
||||||
pub fn poll(&self) {
|
pub fn poll(&self) {
|
||||||
let (cmd, data) =
|
let (cmd, data) =
|
||||||
self.rx_connection.lock().unwrap().recv_packet().unwrap();
|
self.0.rx_connection.lock().unwrap().recv_packet().unwrap();
|
||||||
|
|
||||||
match cmd {
|
match cmd {
|
||||||
0x4 => self.send_packet(0x49, &data).unwrap(),
|
0x4 => self.send_packet(0x49, &data).unwrap(),
|
||||||
0x4a => (),
|
0x4a => (),
|
||||||
0x9 => self.stream.lock().unwrap().handle(cmd, data),
|
0x9 => self.0.stream.lock().unwrap().handle(cmd, data),
|
||||||
0xd | 0xe => self.audio_key.lock().unwrap().handle(cmd, data),
|
0xd | 0xe => self.0.audio_key.lock().unwrap().handle(cmd, data),
|
||||||
0xb2...0xb6 => self.mercury.lock().unwrap().handle(cmd, data),
|
0xb2...0xb6 => self.0.mercury.lock().unwrap().handle(cmd, data),
|
||||||
0xac => eprintln!("Authentication succeedded"),
|
0xac => eprintln!("Authentication succeedded"),
|
||||||
0xad => eprintln!("Authentication failed"),
|
0xad => eprintln!("Authentication failed"),
|
||||||
_ => ()
|
_ => ()
|
||||||
|
@ -171,31 +173,31 @@ impl Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_packet(&self, cmd: u8, data: &[u8]) -> connection::Result<()> {
|
pub fn send_packet(&self, cmd: u8, data: &[u8]) -> connection::Result<()> {
|
||||||
self.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, ()> {
|
||||||
self.audio_key.lock().unwrap().request(self, track, file)
|
self.0.audio_key.lock().unwrap().request(self, track, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn audio_file(&self, file: FileId) -> AudioFile {
|
pub fn audio_file(&self, file: FileId) -> AudioFile {
|
||||||
self.audio_file.lock().unwrap().request(self, file)
|
self.0.audio_file.lock().unwrap().request(self, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stream(&self, file: FileId, offset: u32, size: u32) -> mpsc::Receiver<StreamEvent> {
|
pub fn stream(&self, file: FileId, offset: u32, size: u32) -> mpsc::Receiver<StreamEvent> {
|
||||||
self.stream.lock().unwrap().request(self, file, offset, size)
|
self.0.stream.lock().unwrap().request(self, file, offset, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn metadata<T: MetadataTrait>(&self, id: SpotifyId) -> MetadataRef<T> {
|
pub fn metadata<T: MetadataTrait>(&self, id: SpotifyId) -> MetadataRef<T> {
|
||||||
self.metadata.lock().unwrap().get(self, id)
|
self.0.metadata.lock().unwrap().get(self, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mercury(&self, req: MercuryRequest) -> Future<MercuryResponse> {
|
pub fn mercury(&self, req: MercuryRequest) -> Future<MercuryResponse, ()> {
|
||||||
self.mercury.lock().unwrap().request(self, req)
|
self.0.mercury.lock().unwrap().request(self, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mercury_sub(&self, uri: String) -> mpsc::Receiver<MercuryResponse> {
|
pub fn mercury_sub(&self, uri: String) -> mpsc::Receiver<MercuryResponse> {
|
||||||
self.mercury.lock().unwrap().subscribe(self, uri)
|
self.0.mercury.lock().unwrap().subscribe(self, uri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
38
src/spirc.rs
38
src/spirc.rs
|
@ -1,3 +1,4 @@
|
||||||
|
use eventual::Async;
|
||||||
use protobuf::{self, Message};
|
use protobuf::{self, Message};
|
||||||
use std::sync::{mpsc, MutexGuard};
|
use std::sync::{mpsc, MutexGuard};
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ impl <'s, D: SpircDelegate> SpircManager<'s, D> {
|
||||||
seq_nr: 0,
|
seq_nr: 0,
|
||||||
|
|
||||||
name: name,
|
name: name,
|
||||||
ident: session.config.device_id.clone(),
|
ident: session.0.config.device_id.clone(),
|
||||||
device_type: 5,
|
device_type: 5,
|
||||||
can_play: true,
|
can_play: true,
|
||||||
|
|
||||||
|
@ -97,7 +98,8 @@ impl <'s, D: SpircDelegate> SpircManager<'s, D> {
|
||||||
select! {
|
select! {
|
||||||
pkt = rx.recv() => {
|
pkt = rx.recv() => {
|
||||||
let frame = protobuf::parse_from_bytes::<protocol::spirc::Frame>(
|
let frame = protobuf::parse_from_bytes::<protocol::spirc::Frame>(
|
||||||
pkt.unwrap().payload.front().unwrap()).unwrap();
|
pkt.unwrap().payload.first().unwrap()).unwrap();
|
||||||
|
|
||||||
println!("{:?} {} {} {} {}",
|
println!("{:?} {} {} {} {}",
|
||||||
frame.get_typ(),
|
frame.get_typ(),
|
||||||
frame.get_device_state().get_name(),
|
frame.get_device_state().get_name(),
|
||||||
|
@ -127,7 +129,7 @@ impl <'s, D: SpircDelegate> SpircManager<'s, D> {
|
||||||
|
|
||||||
fn handle(&mut self, frame: protocol::spirc::Frame) {
|
fn handle(&mut self, frame: protocol::spirc::Frame) {
|
||||||
if frame.get_recipient().len() > 0 {
|
if frame.get_recipient().len() > 0 {
|
||||||
self.last_command_ident = frame.get_ident().to_string();
|
self.last_command_ident = frame.get_ident().to_owned();
|
||||||
self.last_command_msgid = frame.get_seq_nr();
|
self.last_command_msgid = frame.get_seq_nr();
|
||||||
}
|
}
|
||||||
match frame.get_typ() {
|
match frame.get_typ() {
|
||||||
|
@ -174,12 +176,12 @@ impl <'s, D: SpircDelegate> SpircManager<'s, D> {
|
||||||
let mut pkt = protobuf_init!(protocol::spirc::Frame::new(), {
|
let mut pkt = protobuf_init!(protocol::spirc::Frame::new(), {
|
||||||
version: 1,
|
version: 1,
|
||||||
ident: self.ident.clone(),
|
ident: self.ident.clone(),
|
||||||
protocol_version: "2.0.0".to_string(),
|
protocol_version: "2.0.0".to_owned(),
|
||||||
seq_nr: { self.seq_nr += 1; self.seq_nr },
|
seq_nr: { self.seq_nr += 1; self.seq_nr },
|
||||||
typ: protocol::spirc::MessageType::kMessageTypeNotify,
|
typ: protocol::spirc::MessageType::kMessageTypeNotify,
|
||||||
device_state: self.device_state(),
|
device_state: self.device_state(),
|
||||||
recipient: protobuf::RepeatedField::from_vec(
|
recipient: protobuf::RepeatedField::from_vec(
|
||||||
recipient.map(|r| vec![r.to_string()] ).unwrap_or(vec![])
|
recipient.map(|r| vec![r.to_owned()] ).unwrap_or(vec![])
|
||||||
),
|
),
|
||||||
state_update_id: self.state_update_id as i64
|
state_update_id: self.state_update_id as i64
|
||||||
});
|
});
|
||||||
|
@ -193,7 +195,7 @@ impl <'s, D: SpircDelegate> SpircManager<'s, D> {
|
||||||
uri: format!("hm://remote/user/{}", self.username),
|
uri: format!("hm://remote/user/{}", self.username),
|
||||||
content_type: None,
|
content_type: None,
|
||||||
payload: vec![ pkt.write_to_bytes().unwrap() ]
|
payload: vec![ pkt.write_to_bytes().unwrap() ]
|
||||||
});
|
}).await().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spirc_state(&self) -> protocol::spirc::State {
|
fn spirc_state(&self) -> protocol::spirc::State {
|
||||||
|
@ -259,23 +261,23 @@ impl <'s, D: SpircDelegate> SpircManager<'s, D> {
|
||||||
@{
|
@{
|
||||||
typ: protocol::spirc::CapabilityType::kSupportedContexts,
|
typ: protocol::spirc::CapabilityType::kSupportedContexts,
|
||||||
stringValue => [
|
stringValue => [
|
||||||
"album".to_string(),
|
"album".to_owned(),
|
||||||
"playlist".to_string(),
|
"playlist".to_owned(),
|
||||||
"search".to_string(),
|
"search".to_owned(),
|
||||||
"inbox".to_string(),
|
"inbox".to_owned(),
|
||||||
"toplist".to_string(),
|
"toplist".to_owned(),
|
||||||
"starred".to_string(),
|
"starred".to_owned(),
|
||||||
"publishedstarred".to_string(),
|
"publishedstarred".to_owned(),
|
||||||
"track".to_string(),
|
"track".to_owned(),
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@{
|
@{
|
||||||
typ: protocol::spirc::CapabilityType::kSupportedTypes,
|
typ: protocol::spirc::CapabilityType::kSupportedTypes,
|
||||||
stringValue => [
|
stringValue => [
|
||||||
"audio/local".to_string(),
|
"audio/local".to_owned(),
|
||||||
"audio/track".to_string(),
|
"audio/track".to_owned(),
|
||||||
"local".to_string(),
|
"local".to_owned(),
|
||||||
"track".to_string(),
|
"track".to_owned(),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -19,7 +19,7 @@ impl SpotifyId {
|
||||||
|
|
||||||
let mut n : u128 = std::num::Zero::zero();
|
let mut n : u128 = std::num::Zero::zero();
|
||||||
for c in data {
|
for c in data {
|
||||||
let d = BASE16_DIGITS.position_elem(c).unwrap() as u8;
|
let d = BASE16_DIGITS.iter().position(|e| e == c).unwrap() as u8;
|
||||||
n = n * u128::from(16);
|
n = n * u128::from(16);
|
||||||
n = n + u128::from(d);
|
n = n + u128::from(d);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ impl SpotifyId {
|
||||||
|
|
||||||
let mut n : u128 = std::num::Zero::zero();
|
let mut n : u128 = std::num::Zero::zero();
|
||||||
for c in data {
|
for c in data {
|
||||||
let d = BASE62_DIGITS.position_elem(c).unwrap() as u8;
|
let d = BASE62_DIGITS.iter().position(|e| e == c).unwrap() as u8;
|
||||||
n = n * u128::from(62);
|
n = n * u128::from(62);
|
||||||
n = n + u128::from(d);
|
n = n + u128::from(d);
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ impl SpotifyId {
|
||||||
data[15-i] = BASE16_DIGITS[(high.wrapping_shr(4 * i as u32) & 0xF) as usize];
|
data[15-i] = BASE16_DIGITS[(high.wrapping_shr(4 * i as u32) & 0xF) as usize];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::str::from_utf8(&data).unwrap().to_string()
|
std::str::from_utf8(&data).unwrap().to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_raw(&self) -> [u8; 16] {
|
pub fn to_raw(&self) -> [u8; 16] {
|
||||||
|
|
|
@ -33,8 +33,8 @@ impl io::Read for ZeroFile {
|
||||||
// TODO optimize with memset or similar
|
// TODO optimize with memset or similar
|
||||||
fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
|
fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
|
||||||
let len = min(output.len(), (self.size - self.position) as usize);
|
let len = min(output.len(), (self.size - self.position) as usize);
|
||||||
for i in 0..len {
|
for b in output {
|
||||||
output[i] = 0;
|
*b = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.position += len as u64;
|
self.position += len as u64;
|
||||||
|
|
Loading…
Reference in a new issue